The "BNS Resolver Daemon" and "BNS Sia Bridge" scheduled tasks were
registered with New-ScheduledTaskSettingsSet's defaults, which include
DisallowStartIfOnBatteries and StopIfGoingOnBatteries. On a laptop booted
on battery the system-wide resolver and gateway never started, and an
already-running daemon was killed the moment the charger was unplugged,
so BNS names silently stopped resolving.
install.ps1 (which the Inno installer runs on every install and upgrade)
now registers both tasks with -AllowStartIfOnBatteries
-DontStopIfGoingOnBatteries. The Argus copy of install.ps1 gets the same
change.
Existing installs keep the old task definitions until reinstalled, so the
daemon (running as SYSTEM) now checks both tasks 30 s after start and
flips just those two flags in place via Set-ScheduledTask. Every other
setting and the running instance are left untouched. The fix lands on the
first boot on mains power after the upgrade; battery boots work from then
on.
Feature. The daemon now hot-reloads C:\ProgramData\Ariadne\policy.json every
5 s (fs.stat mtime check, only opens the file when it actually changed) and
flips its DNS collision policy between bcnr-first and icann-first in place.
Every browser on the machine follows within seconds -- no daemon restart,
no reinstall, no UAC. The next Ariadne panel in Theseus will edit this file
directly; a text editor works too.
install.ps1 seeds the file with the current -Policy default on FIRST install
only (an upgrade never clobbers a user's later flip) and grants BUILTIN\Users
Modify on it so an unprivileged app can rewrite it. Invalid values keep the
last good policy (logged). File deleted -> daemon falls back to the CLI
policy the scheduled task was registered with.
Also fixes an intermittent "config unreadable" on daemon startup when
ariadne.config.json had a UTF-8 BOM -- same class of PS-writes-BOM bug 0.1.6
fixed in the TLD-sync path, this time in bnsd.js's own config loader.
Verified live on this box with a second daemon running on port 15353:
bnsd policy: bcnr-first -> icann-first (from C:\ProgramData\Ariadne\policy.json)
bnsd policy: icann-first -> bcnr-first (from C:\ProgramData\Ariadne\policy.json)
bnsd policy: ... has invalid policy 'cash-first' -- keeping bcnr-first
ACL check: BUILTIN\Users has Modify on policy.json, non-elevated write succeeds.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.7.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.7.exe
- silentmode.st manifest advertises 0.1.7
- sha256 742f8005c2dfb47929287c009cddf7738f0d12bd56fb8f8a837df3e9b435f47f
Theseus UI wiring for this file NOT touched -- settings-preload.js has 31
lines of uncommitted work from another session; a Theseus panel selector
belongs in that session's next commit so it doesn't collide.
Other browsers stopped opening most BNS names because two lists had
drifted. The installer took its TLD set from the gateway's `advertised`
field — the legacy tlds.bch record, nine TLDs — while the registry had
moved to per-TLD NFTs with twenty (including .x, where most Silent Mode
sites live). And the daemon's permitted-TLD list came from the bundled
ariadne.config.json (seven TLDs) rather than the CA the installer had
just minted, so only the overlap — .bch, .p2p, .deviant, .nav — actually
worked; .sia, .nt and the rest got no certificate, .x got no route at
all.
Now: the gateway publishes `routable` (every live TLD on the public
listing plus the legacy advertised set); the installer routes and
certifies that, skipping ICANN-delegated collision TLDs (.cash, .gt,
.sc — checked against the live IANA root zone, bundled snapshot as
fallback) since the local CA must never be constrained to a real
internet TLD; it writes the certified list into ariadne.config.json;
and the daemon reads its permitted list from the installed CA's own
name constraints, so the two can no longer disagree.
Symptom: on any machine that had been through a series of installs, one or
more older "BNS Local Root CA" certs from earlier builds could accumulate in
LocalMachine\Root -- an unconstrained root from before 2026-07, or a rotated
one -- and every install added the current constrained root ALONGSIDE the
stale ones. Two certs with the same Subject-DN defeat browser chain-builders:
Chromium/Edge/Firefox pick one candidate and refuse to try the others, so
every .bch site failed with ERR_CERT_AUTHORITY_INVALID / SEC_ERROR_BAD_SIGNATURE
in every browser EXCEPT Theseus (which trusts the on-chain tls fingerprint
directly, not the machine store).
Reproduced on the dev box: two BNS Local Root CAs present (thumbprints
EB5DBE98... constrained + 23538FD7... unconstrained), DNS answered correctly,
strict Invoke-WebRequest to https://coinspectrum.bch/ failed. Removing the
stale one and re-running the chain-build restored HTTPS 200.
Fix (install.ps1):
- Before Add(imported), enumerate the store and $store.Remove() every
"BNS Local Root CA" whose thumbprint differs from the one we're about
to trust. Post-condition: exactly one BNS root remains after install.
Fix (uninstall.ps1):
- Switched from `Get-ChildItem Cert:\LocalMachine\Root` to X509Store direct.
The Cert: PSDrive is not always loaded in Inno's [UninstallRun] -NoProfile
context, so uninstall could silently leave the CA behind on the store side
even while it removed everything else.
Verified end-to-end on this box: 0.1.4 upgrade over 0.1.3 finished cleanly,
BNS Resolver Daemon Running, 127.0.0.1:53 open, exactly one BNS Local Root
CA in the machine store, strict HTTPS to https://coinspectrum.bch/ returned
200 (506,997 bytes) with X509Chain.Build ok=true leaf -> BNS root.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.4.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.4.exe
- silentmode.st manifest advertises 0.1.4
- sha256 30ed5e3bb6d6da5325f854c97976410b4fc63067ed52c810a55e9d2e1bdc4e17
install.ps1 root-cause fix
- Every `& $node ... 2>&1` had been tripping PS 5.1's "$ErrorActionPreference=Stop +
native-command stderr = terminating error" quirk. Trap-and-log added in 0.1.1 EXPOSED
the bug (0.1.0 died at the exact same line -- silently). 0.1.2 routes both node calls
through a new Invoke-NodeCapture helper that uses Start-Process
-RedirectStandardOutput/Error to file, so PS 5.1 never touches the streams.
Multi-source TLD cascade with on-disk cache
- -Indexer now accepts a comma-separated list; default "https://navigate.st,https://silentmode.st".
- Cascade (first hit wins): indexer[s] HTTPS -> local cache
(C:\ProgramData\Ariadne\tlds-cache.json) -> electrum WSS (fetchTldList / legacy
fetchBcnrTlds) -> bundled ariadne.config.json snapshot -> bootstrap [bch].
- Authoritative fetches (indexer or electrum) refresh the cache. Second install on a
machine that has ever succeeded before is instant + always works offline.
- Per-source deadlines kept tight (5s for indexer HTTPS) so a slow source can't stall
the install.
Upgrade over live install
- .iss CurStepChanged(ssInstall) stops "BNS Resolver Daemon" + "BNS Sia Bridge" via
schtasks + 1.5s pause before file replacement. Fixes "DeleteFile failed; code 5.
Access is denied" on runtime\node.exe when upgrading a machine where the daemon is
currently running.
CA import
- Switched Import-Certificate -CertStoreLocation Cert:\... to direct X509Store('Root',
'LocalMachine').Add(). Cert: PSDrive is not always loaded in -NoProfile elevated
shells, which had broken the standalone unblock scripts.
Verified end-to-end on this box: silent install -> exit 0, clean install.log,
BNS Resolver Daemon running, 127.0.0.1:53 open, 9 NRPT rules (all TLDs including .bch),
coinspectrum.bch resolves system-wide, tlds-cache.json populated.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.2.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.2.exe
- silentmode.st + navigate.st/bns/silentmode.bch manifests advertise 0.1.2
- sha256 5a2c9e4f3c5e1a162008641019f5ffc35968751c0440f94d3c5fe67aafb8cc5e
Local Dev <noreply@localhost>
Ariadne 0.1.1
- install.ps1 primary TLD source: HTTPS $Indexer/api/tlds -> advertised[]
(electrum fetchTldList / legacy fetchBcnrTlds / ariadne.config.json /
bootstrap kept as fallbacks in that order). Silent installs no longer
stall when WSS is blocked.
- Persistent transcript at C:\ProgramData\Ariadne\install.log; separate
install-error.log on any uncaught exception. Top-level trap logs the full
stack, then exit 1 so Inno/NSIS silent-install callers see a real failure.
- .iss: SetupLogging=yes; DeinitializeSetup() copies Inno's log to
C:\ProgramData\Ariadne\inno-setup.log on every exit path.
- Version bumped to 0.1.1. sha256=be1fa8841919b321841d90f8147abe1b1d7604fe7fff6c2e271dc47c4c24a2b6
Theseus decoupled from Ariadne
- Removed nsis/installer.nsh (custom Ariadne chain-install page).
- Removed extraResources entry for AriadneResolver-Setup-*.exe.
- Removed build.nsis.include from package.json.
- Settings > System-wide resolver panel now fetches the .exe from
https://silentmode.st/releases-manifest.json, streams the download while
hashing, refuses to spawn on SHA-256 mismatch. 30-min in-memory manifest
cache so opening Settings doesn't spam the endpoint. Offline gracefully
degrades to installedVersion-only / canUpdate:false.
- "bundledVersion" IPC field kept for renderer compatibility; it now
carries "latest advertised by the site's manifest".
Deployed to silentmode.st:
- dl.silentmode.st/AriadneResolver-Setup-0.1.1.exe (25 MB)
- silentmode.st/releases-manifest.json (schema/2, updated 2026-09-08)
- silentmode.st/releases/ + silentmode.st/tools/ show 0.1.1
Local Dev <noreply@localhost>
Per-TLD certificates on a distinct TLD beacon supersede the legacy list-in-one-NFT
model. TLD label is the NFT commitment; TREG/TUPD payloads on the TLD beacon
mirror REG/UPD on the name beacon. Chipnet TLD beacon:
bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh
scripthash c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8
* config.js, resolver-web.{js,d.ts} — TLD_BEACON + TLD_BEACON_SCRIPTHASH
* bns.js — KNOWN_OPS { REG, UPD, TREG, TUPD }, registerTld/updateTld/normalizeTld
* bns.js + resolver-web.js — buildIndex({enforceTld:false}) drops name REGs
whose TLD lacks a live TLD cert at their block height (mempool-friendly).
Lockstep across both files.
* lib/tld-index.js — buildTldSnapshot({history,txs}) → deterministic root over
canonicalised tlds[]. Pure, importable, and stable across insertion order.
* indexer/bns-indexer.js — BeaconIndex is multi-beacon; ws handler dispatches
by scripthash; new HTTP endpoint GET /tld-list.json + /health behind
BNS_HTTP_PORT; state file v1 → v2 migrates in fromJSON.
* publish-tld-mirror.mjs — S3 (floating + immutable content-addressed) plus
NIP-33 kind 30078 d:bns-tld-list to Nostr relays, signed via nostr-tools
(libauth's Schnorr differs from BIP-340 and relays reject it).
* seed-tld-beacon.mjs — idempotent chipnet seed. Current set on the beacon:
bch p2p bit nav test x asm neo gt sc sia com dex cex nt (15). `.com` is
held by the operator: cert on-chain, excluded from public registrar UI.
Design + docs:
* Decentralized.DNS/DESIGN-tld-registry.md — schema, enforcement,
operator-countersig gate, USD-tiered pricing floors, fee splits,
tracker/mirror mechanics, migration/grandfathering.
* INSTRUCTIONS.md §3 rewritten for the 4-step flow (TREG → UI → deploy →
republish snapshot).
* site/tlds/ — public docs page listing current TLDs + verification paths.
* site/sirius/register.html — dropdown removed; parallel search across
every TLD in the TLDS array, sorted available → taken → not-on-registry.
Config:
* ariadne.config.json tlds → [bch, p2p, bit, nav, test, x] (CA constraints;
on-chain registry is now the authoritative source, config is fallback).
* setup/install.ps1 — reads TLD list via fetchTldList (per-TLD registry)
with fallback to fetchBcnrTlds (legacy tls.bch list-NFT) then config.
Tests:
* test/tld-index.test.mjs — 30 self-contained checks (multi-beacon dispatch,
state migration, ws routing, snapshot shape + root recomputability).
* test/tld-enforcement.test.mjs — synthetic + live chipnet integration
(with-gate correctly drops all pre-seed names).
Three doc-alignment changes shipping in AriadneResolver-Setup-0.1.0.exe
sha256 c5efae43af6cc163f468f1dc73d08939db32a9a6db52298ba18b2d9a2aee1292:
1. install.ps1 fetches the activated TLD list from the on-chain root
TLD certificate (tlds.bch, per START-HERE §1) via
resolver-web.js fetchBcnrTlds(), then:
- regenerates the CA's nameConstraints extension from that list
(rotates the CA when the on-chain set changes so leaves for the
newly-activated TLDs actually validate)
- adds one NRPT rule per activated TLD in surgical mode
- falls back to bootstrap ["bch"] if the chain is unreachable
Result: adding a TLD on-chain is picked up by re-running the
installer, no code release needed.
2. bnsd.js honors --policy / BNS_POLICY (bcnr-first | icann-first,
alias bns-first) per START-HERE §4b. bcnr-first is default and
preserves prior behavior. icann-first forwards to upstream first
and only substitutes a BCNR answer on NXDOMAIN. install.ps1
accepts -Policy and passes it into the scheduled task action.
3. ca.js loadOrCreateRootCA() now accepts a runtime TLD list; the
old callers still work (fall back to PERMITTED_TLDS from tlds.js).
Doc: RESOLVER-PACKAGING-PROMPT.md rewritten to reflect current
shipping reality; original 2026-07-26 packaging brief preserved
in the "Archival" section.
Deployed to dl.silentmode.st (nginx serves from /opt/silent-mode/dl/)
and mirrored to Sia bns/silentmode/. VPS bns-indexer.service reports
tlds.bch currently activates: bch p2p deviant nav sia dgb nt sm lm.
Was only .bch. The daemon and CA already handle these four TLDs; the NRPT
rule was the missing piece that made .p2p / .bit / .nav queries never reach
the daemon at all (they went to ICANN's normal DNS and NXDOMAIN'd).
Dual TLDs (.de .ru .dev .ltd) intentionally NOT here. They need the
daemon's DNS-forwarding path to work reliably for unregistered names,
and there's still an open EDNS/AAAA forwarding bug in bnsd.js that
would break most German/Russian sites if we NRPT'd .de.
Adding more native TLDs (.x .sia .dgb .nt from Theseus's expanded set)
needs a CA rotation first — the current CA's nameConstraints only permit
bch/p2p/bit/deviant/nav/test/bcnr. Deferred.
- Security popover redesigned to resemble Firefox's site-info panel:
lock/shield hero, "Connection secure" status, host, plain-language
subtitle, and a details grid; the overlay view auto-sizes to content.
- Search-engine picker returned to the toolbar with an "Add / edit engines…"
entry that opens Settings; added Ecosia, Mojeek, Presearch.
- Custom search engines: add (name + URL template with %s) / remove in
Settings > General; used by address-bar search.
- Address-bar placeholder: "Ask a search engine or enter web address".