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
Every client hard-coded the chipnet beacons, address prefix and electrum
servers on its own: resolver, registrar config, wallets, gateway, indexer,
mirror scripts, the browser bundle and the mobile Java. A mainnet launch would
have meant finding all of them and hoping none was missed.
The table now lives in resolver-web.js, the one file every client already
shares, so it stays a single-file drop-in. BNS_NETWORK selects the record;
unset means chipnet, so nothing changes today: the live index resolves the
same 60 names and 20 TLDs, the 67 offline tests pass, and the dashboard,
market and studio load the same values through BNS.NETWORK.
The mainnet record carries the verified public servers, the prefix and its
own Sia bucket, but its beacons, start height and operator address are
deliberately null: requireBeacons() refuses to scan until they are pinned in
the order ROADMAP-MAINNET.md §6 requires. Bns.java reads a generated
BnsNetwork.java so the phone cannot drift from the desktop clients.
NETWORK-CONFIG.md records what reads the table and what a launch still pins.
The page assigned free to sm-1, but sm-1 was the primary infra box —
public gateway, BNS indexer, site, mailbox. Free carries the most
traffic, so the exits were renumbered to put free on the lightest box
and max-only on the busiest, and the page now matches: sm-1 is the
free-and-up exit, sm-3 is max-only, and each carries the Reality
steering domain it is really fronted by.
site/brand/social/ and site/brand/icon/ carry ready-to-upload PNGs at the
sizes X, LinkedIn, Facebook, Instagram, GitHub and PWA manifests want:
X header 1500x500, post 1200x675, LinkedIn 1584x396, Facebook 820x312,
Instagram 1080, avatars 400/1024, icons 512/192, favicons 64/32, plus the
Open Graph 1200x630 that every page already advertises. The brand page
gained a "Social media and icons" section with download links.
scripts/brand-assets.mjs renders the whole set from one HTML template via
scripts/render-html-png.cjs (Electron offscreen). Windows clamps even an
offscreen window to the work area, so captures taller than the screen are
rendered as strips and stitched on a canvas inside the page.
The VPS serves silentmode.st with Angie, not nginx (nginx.service is dead
there), so the URL rules now live in VPS/SilentMode/silentmode-st.angie.conf,
deployed and live. try_files lists $uri/index.html before $uri because a
bare $uri also matches a directory and would 301 to add the slash back.
GOTCHAS and the URL-scheme notes corrected accordingly.
Addon:
- Paste any https:// URL that returns a list of vless:// (either
newline-separated or base64) and the extension fetches, decodes,
parses, and adds every server to the dropdown. The full vless URL
never leaves the panel — the addon holds it in its own storage and
passes an opaque "sub-<hash>" id back for selection.
- Subscription CRUD on the addon side (listSubscriptions,
addSubscription, refreshSubscription, removeSubscription). A refresh
is a no-op inside the 6-hour TTL to avoid pounding the provider.
- Merges subscription servers with the baked-in three and gateway
overlay by id; the dropdown groups them under one banner.
Site:
- silentmode.st/vpn landing page: three-plan grid (Free, Pro at $1/mo
BCH, Max at $4/mo BCH), how-it-works four-step block, "the three
servers" strip with per-tier availability, why-this-VPN cards, FAQ.
Priced in USD, paid in BCH via the oracle at pay-time — same pattern
as the marketplace's USD-listing covenant, no reintroduction of
fiat/card processors.
Fraunces/Ubuntu font picker is gone. theme.js used to persist the
choice in localStorage and paint a pill in the corner; now it just
sets data-font-cmp="ubuntu" on <html> so every page that already
carries the html[data-font-cmp="ubuntu"] rules in its stylesheet
switches to Ubuntu — the Bitcoin Cash brand face — on load. Same
one-line runtime on both sirius-x and hephaestus.x theme.js.
Mobile bottom nav rail was rgba(11,14,20,.52) with no blur, so
whatever body text was scrolled behind it bled straight through the
half-transparent bar — first sentence of How it works ended up
visually merged with the sidebar icons on hephaestus.x, section
headings ran under the Sirius.x rail. Bumped to rgba(...,.94) and
added backdrop-filter:blur(12px); content underneath is now covered
instead of showing through. Same tweak on all six Sirius.X pages
plus Hephaestus.X home.
Every pantheon card and footer entry across Sirius.X and Hephaestus.X
was routing through the gateway path form
(silentmode.st/bns/<name>.x/) instead of the sibling's own BCNR name.
Inside Theseus that meant every "Open →" bounced through the relay to
reach a site the browser could have resolved directly — and Silentmode
was linked as silentmode.st/bns/silentmode.x/ even though silentmode.x
resolves the same way in Theseus.
Rewrote every pantheon href to https://<name>.x/. Silentmode, Sirius,
Theseus, Hephaestus, Prometheus, Helios, Hermes all reach each other by
name.
Sirius.X pantheon also picked up the same polish Hephaestus already
carried: acid .X on every title, Theseus.X card gets its own compass
brand mark instead of the generic 🧭 emoji, the Hephaestus.X card
swaps its old 🔥 emoji for the forge ⚒️ mark, the .lbl wrapper
collapses the h3's own 8px gap so "Silentmode .X" stops splitting
across the name and the suffix.
Brand mark carried "Hephaestus" in forge orange and ".X" in plain ink
white, so the .X tail read as page chrome rather than part of the
brand — inconsistent with the acid .X pattern every other .x site now
uses. Wrapped the .X in <span class="x"> and gave .topnav .brand .x
the acid tint on both index and docs pages. Forge orange stays on the
name because that is Hephaestus's identity; the .X now signs off in
the ecosystem's shared colour.
Also aligned the footer's Pantheon column with the main pantheon
section: dropped the stale Fly.X entry, added Prometheus.X, Helios.X,
Hermes.X, and gave every entry the same Silentmode<span class="g">.X</span>
split so the acid tint on the suffix is consistent between the site
and the footer index.
The pantheon grid was labelling siblings with generic emoji — ⭐ for
Sirius.X, 🧭 for Theseus.X — and rendering each name as plain text.
Sirius.X and Theseus.X get their own SVG brand marks now (the same
4-point sparkle Sirius ships as its favicon; the same red-and-acid
compass Theseus uses in its tab strip), so a reader who has seen
either site recognises the tile at a glance.
Every .X suffix inside a card title picks up the .g acid tint —
Sirius.X, Theseus.X, Hephaestus.X, Silentmode.X, Prometheus.X,
Helios.X, Hermes.X — matching the naming style used everywhere else
in the ecosystem. Wrapped the name + suffix in a single .lbl
inline-flex so the h3's own 8px gap only sits between the status dot,
the label, and the "you're here" pill instead of splitting the name
into "Silentmode .X".
Version and hashes matched to the just-published installer + portable.
The /latest/… redirect will follow within five minutes of the manifest
update landing (dl-latest.sh regenerates the redirect table off
releases-manifest.json on a cron).
Home page: How it works, Source and Pantheon were in the topnav next
to cross-site tabs. Moved them plus Sign in and Verify into an overlay
sidebar on the left edge — same shape as Sirius.X and Theseus.X —
pointer-events:none, opacity 0.35 by default, hover brightens with a
blurred backdrop, active section painted acid green,
IntersectionObserver replaced with scroll-position tracking so the
final section still activates when the reader hits the page end.
Topnav collapses to the site tabs the header still owns: Hephaestus.X ·
Docs · Explore repos · Sign in.
Docs page: the two-column grid with an inline .toc left column has
been swapped for the same overlay rail. The 13 chapter titles now sit
at the left edge, keep their numbered mono prefix via CSS counter,
and stay legible under the semi-transparent hover backdrop. Content
column is centred at 820px so the reading axis is on the middle of
the viewport rather than shifted right by a sidebar. Icon rail at
64px on medium; sidebar hidden altogether on mobile because there is
no room for a 13-item rail.
A BCH-priced offer is a signed transaction with a fixed amount, so a
seller who wants "$500" had to relist whenever the rate moved. The new
USD mode moves the certificate into a small CashScript covenant
(contracts/usd-listing.cash). Anyone may buy it by paying the seller
target_cents / price, where the price comes from a message signed by the
gateway's oracle key — the median of five exchanges the site already
uses. The payout is clamped to a floor/ceiling band the seller sets, and
the seller can reclaim the certificate at any time.
What the chain can and cannot enforce, stated plainly in the contract and
the UI: script can require a transaction to be mined no earlier than a
time, never no later, so a quote cannot expire on-chain. The band is the
guarantee, and quotes are bound to the listing's outpoint so cancelling
and relisting voids every quote ever issued. An offline libauth VM test
covers list, buy, underpayment, foreign-listing quotes, forged quotes,
band clamping, cancel and a non-seller cancel; on chipnet aloevera.test
was listed at $0.30, bought by a second wallet for 119,090 sat at
$251.91, listed again by the new owner and cancelled.
Gateway: GET /api/price/oracle[?txid=] serves the oracle public key and
per-listing signed quotes; the key lives in oracle.key beside the
gateway, never in the repo. POST /api/market accepts kind "usd" after
reproducing the redeem script from the stated terms and finding the
certificate in that covenant; such listings are pruned once the covenant
output is spent; DELETE accepts the listing's seller while the index
shows the covenant as holder.
Dashboard: the Sell tab has "Price is fixed in: US dollars / BCH", a
band control with the resulting BCH range, and cancel through the
covenant. Market: USD listings show the dollar price, today's BCH
equivalent and the band; buying fetches a quote and completes the
covenant spend. Studio no longer sends a needless UPD when the registry
view is stale, and missing files on a name now get a real 404 page.
Canonical silentmode.st URLs no longer carry a trailing slash (/tools, not
/tools/). nginx (tracked now in VPS/SilentMode/silentmode-st.nginx) 301s
the old form and serves <dir>/index.html; sub-sites deployed from other
repos with relative asset paths (deviant, sirius-x, theseus-x, hephaestus.x,
fly.x, code) keep their directory URLs. Every page's internal links are
now site-root-relative, which resolves correctly both at /x on nginx and
under the BNS gateway's injected <base href="/bns/silentmode.bch/"> — the
old ../x/ links were already broken on the gateway route.
/theseus becomes the Silent Mode-headered Theseus page (what it is, what's
inside, Windows + Android downloads with manifest hashes, verify), linking
out to the sovereign theseus.x whose VPS mirror moves to /theseus-x/, the
same split as /sirius vs /sirius-x/. /tools is repurposed as the overview:
every site, the on-chain twins, the other clients (relay, Firefox, the
standalone Ariadne Resolver) and the machine endpoints. The old tools page
carried stale APK and resolver hashes; the new pages use the manifest's,
verified against the files on dl.silentmode.st.
scripts/serve-site.mjs mirrors the nginx rules for local preview.
Same class of bug as the Sirius .X space on theseus.x: .topnav .brand
carries display:inline-flex + gap:6px, and the mark, brand span and
".X" tail were three separate flex items so the browser drew a 6px gap
between each. Wrapped the mark and the label in two spans so the flex
gap only applies once, between mark and label, and "Hephaestus.X"
renders as one word.
theseus.x, sirius.x and hephaestus.x had a 1px border-bottom under the
sticky/fixed topnav that read as a visible separator between the
navigation and the page. The topnav's own translucent-blur backdrop is
enough of a distinction already — the line is redundant and, on the
theseus.x sidebar layout, made the top of the sidebar look like it was
overhanging the header.
theseus.x tabs also had a "Sirius .X" gap because the topnav <a> is a
flex container and the icon + "Sirius" text + ".X" span were three
flex items with a 6px gap between each. Wrapping the label in one
<span> collapses the gap to a single space between icon and label.
Sidebar border-right and mobile bottom-bar border-top also dropped —
the panel tint carries the boundary; a hard line was too heavy.
The home / new-tab page declared no icon, so those tabs sat blank in the
strip; the compass mark is now inline in home.html as a data: URI (no file
path, no network). The silentmode.st copy of the Theseus page pointed its
icon at /assets/favicon.svg, which only exists on theseus.x — page-relative
now, so the tab shows the mark there too.
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
Section covers both paths — Forgejo GUI and curl/git/docker CLI — so the
heading now reflects that. Anchor #sessions preserved so external links
still work. Follow-up to 980fbd4.
Parallel session assumed (a) Forgejo usernames can't contain dots, and (b) a
wallet mnemonic has to be pasted into a browser to sign in. Both wrong — the
docs now show that.
- §4 gets an 'Allowed characters' subsection listing what Forgejo actually
accepts (letters, digits, hyphens, underscores, dots). game.x works as-is
as a username or an org name.
- New §12 'Working with other sessions' — the wallet-vs-PAT split, a full
five-step recipe for delegating a namespace to a parallel session
(create org / bootstrap user / add to Owners / mint PAT / clone+push),
a scriptable programmatic sign-in template so mnemonics never touch a
browser, and a scope-per-session-shape table.
- TOC + §13 (Help+source) renumbered.
Parallel session had to synthesize two things the page should have handed
them upfront. Fixing that:
- §11 (Gotchas) now links from each entry to its full-recipe section:
HTTPS+PAT → §5+§6, em-dash mojibake → §8, admin-rename → §4. New leading
entry explicitly separates 'PAT vs wallet passphrase' since it's the most
common wallet-flow confusion.
- §7 (Container registry) gets a 'Worked example: publish an app's backend as
an image' subsection — Node/alpine Dockerfile + build+push pair, so the
next reader doesn't have to compose it from the Log-in and Push blocks.
Follow-up to cc544c8.
/docs/ covers sign-in flow, rename, repos, PATs, container registry, API,
storage layout, self-hosting, and known gotchas — 12 sections with a
sticky TOC on the left. Any session (human or LLM) hitting hephaestus.x
now has a one-shot map of the forge.
Landing footer replaced with a four-column layout (Product / Source+spec
/ Pantheon + brand) matching the docs page, with a mono bottom bar. Topnav
gets a Docs link between How-it-works and Source.
Until now only the gateway, Theseus and the desktop reader applied the
TLD co-sign rule; phones and the Windows resolver still admitted every
registration under a cosign or hidden TLD, so the network disagreed
about which names exist. Both shipped builds now carry the rule.
Android 0.19: the JSON helpers in the new TLD-map code used throwing
getters inside methods that do not declare the checked exception, which
javac rejected under the real build (the earlier compile check ran
without -bootclasspath and stopped at the aapt R errors first). Switched
to the non-throwing opt* forms. Release-signed with the existing key.
Resolver 0.1.3: no source change beyond the resolver library already
committed; the installer picks up the source tree, so this is a version
bump and a rebuild.
Manifest, releases page, tools page and theseus page point at the new
files; dl.silentmode.st/latest redirects regenerated.
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
BuiltInWallet.signMessage read `recovery` from libauth's recoverable
signature, but libauth v3 names it `recoveryId`. The flag byte came out as
0, so verifiers recovered the right key only when the true recovery id
happened to be 1. Signed DNS manifests and Studio uploads failed with
"signature does not match current on-chain NFT owner" and a different
derived address each attempt. Read the right field, fail loudly if it is
missing, rebuild the browser bundle and move every importer to the new
bundle URL. Also lands the registrar's signRecordsManifest that the bundle
already shipped.
The tools page and the Theseus page pointed at versioned files; the Theseus
page still linked 0.3.44, archived long ago, and showed 0.0.9 as the latest
version. Both now use the stable /latest/ redirects, and the Theseus page is
rebuilt from the theseus.x source (versions and hashes refreshed from the
releases manifest at load, current values baked in as fallback). The
releases ledger keeps versioned filenames, since each entry pairs a file
with its hash.
Direct answers to the three complaints in one release.
"Doesn't load any results even if I type a keyword" — navigateTo used to
always append .bch to any bare label. So "bitcoin" became
https://bitcoin.bch/ and NXDOMAINed. Now: input with a space, or bare
label with no dot, routes to the user's chosen search engine. Input with
a dot (hello.bch, example.com) stays a URL. Matches Chrome/Firefox
omnibox behaviour exactly.
"Has no check for updates in settings" — new Updates section shows the
installed version + signing-cert SHA-256, with a "Check for updates now"
button that manually polls dl.silentmode.st and toasts the result. If a
newer version exists, the standard silent-prefetch → green-chip → tap-to
-install flow (unchanged from 0.15) kicks in.
"Looks poor compared to a regular browser" — Settings gains three more
sections beyond Resolution / Ariadne's Thread / Maintenance:
- Search: segmented picker for DuckDuckGo (default), Startpage, Brave
Search, Google, Kagi. Persists via SharedPreferences.
- Updates: version + cert + manual check.
- Privacy: "Clear browsing data" — cookies (CookieManager), form data,
cache, per-tab history, all in one tap. Bookmarks + tabs preserved.
- About: silentmode.st/theseus + theseus.x links, brand credit.
serveSettingsPage() signature grew to take (indexerOn, searchKey,
currentVersion) so it can render the current selection + version. Added
searchEngineSegment() helper for the picker layout.
Release: ariadne-v0.17.apk sha256
8a655081782ecc17a50a7fcd67c28625ccb0c905cf6b583bdd703a128b2b9b10
Deployed to dl.silentmode.st + silentmode.bch (Sia mirror). Site pages
bumped: silentmode.st/tools + /releases + /theseus + theseus.x.
Users on 0.15 reported "Ariadne can't open many websites" and "start page
is full of dead links". Two independent stale-data issues, both fixed.
Start page — replaces the featured-hero + beacon-fallback grid with the
same nine curated cards navigate.st serves (hello.bch, siatest.bch,
SilentMode.X, Theseus.X, Sirius.X, Hephaestus.X, Prometheus.X, Helios.X,
Hermes.X). No more auto-iteration over every registered name on the
beacon — which is what was surfacing smtest-dc5563.bch, uitest-e20579.p2p,
qrtest-e21970.nav etc. Added product-role badges (infrastructure /
navigator / registrar / code-host / app-store / search / messaging) with
the same acid/blue/purple/green/gold/pink vocabulary Theseus uses.
Bundled snapshot at app/assets/bns-index.json regenerated from the live
chain via the resolver-web.js buildIndex path. Up from 44 entries to 54,
now including all 13 .x names (was 6 — silentmode.x, theseus.x,
hephaestus.x, prometheus.x, helios.x, hermes.x etc. were entirely
missing). So cold-start resolution finds the .x brands without waiting
for a network trip.
Also regenerated dl.silentmode.st/bns-name-index.json — same 54-entry
JSON. That file hadn't been rebuilt since 2026-08-30 and is what every
client's CDN pull path reads on cold start (mobile, extension, resolver).
There's no timer that regenerates it; scratchpad/build-snapshot.mjs is
the reproducible one-shot: node build-snapshot.mjs <cdn-path>.
Sites updated in the same commit (all four surfaces need to advertise the
same version — silentmode.st/tools + /releases + /theseus + theseus.x
were still linking 0.15). APK also mirrored to bns/silentmode/ so
silentmode.bch/ariadne-v0.16.apk serves the same bytes.
Release: ariadne-v0.16.apk sha256
fa58aa7642319faaa6b23f0f0a46c0adad2ce1f3c5957f4d527ac09241b76574
Old links pointed users at ariadne-v0.11.apk from three separate pages
while the in-app auto-updater was already pulling 0.15. New downloaders
got 4 versions behind.
- site-theseus-x/index.html — v0.11 → v0.15, hash updated, meta noting
in-app auto-update. Sia-uploaded to bns/theseus/ so theseus.x reflects
it now.
- site/releases/index.html — bumps the Ariadne row from 0.11 to 0.15
with the new hash and a release note covering the DOWNLOADING/READY/
RETRY chip states shipped in 0.15.
- site/tools/index.html — same v0.11 → v0.15 bump. Also retitled from
"Theseus — Silent Mode" / "Theseus — the browsers" to "Tools — Silent
Mode" / "Silent Mode tools" because the page actually lists every
client (Theseus Win + Android, Ariadne extension, navigate.st relay,
Ariadne standalone Windows resolver) — a tools directory, not a
Theseus-dedicated page. Intro now points at /theseus/ for the
dedicated Theseus landing.
- site/theseus/ NEW — clearnet mirror of theseus.x. Same page, retitled
"Theseus Navigator — Silent Mode" with canonical URL pointing at
silentmode.st/theseus/. Users on the resolver reach theseus.x for the
same content trustlessly; the /theseus/ path is the always-reachable
fallback with a real cert. Also pushes the APK itself to
bns/silentmode/ so silentmode.bch/ariadne-v0.15.apk works too
(dl.silentmode.st and silentmode.bch now serve the same bytes with
identical SHA-256).
Silent-background prefetch was already the model in 0.12+, but the chip
showed the same "▲ 0.14" text whether the download was running, done, or
failed. Users had no way to know they'd get "Install now" instead of
"Download & install" until they tapped.
Chip is now a small state machine driven off UpdateInstaller.Progress:
- DOWNLOADING — muted amber pill, text "▲ 0.15 · 45%" ticking live from
onProgress. Tap = "Downloading in the background, tap again when green."
- READY — green pill, "▲ Install 0.15". A brief toast fires on state entry
so the user sees the prefetch just completed. Tap = short confirmation
dialog, then straight to the platform package installer.
- RETRY — appears when the prefetch fails. One tap re-runs prefetch and
the chip returns to DOWNLOADING.
The confirmation dialog now spells out that Android replaces Ariadne in
place and reopens on the new version — matches Android's actual behaviour.
saveSession() runs before launchInstall so the newly-launched v0.15
restores tabs cleanly.
Dead code drop: promptToUpdate + downloadThenInstall (the old on-demand
progress-dialog path) — the state machine handles both silent and
tap-first flows.
Release: ariadne-v0.15.apk sha256
35532e596ec43a2da0cf49496640c72972321f5a44fa2e16d259d281a021b425
Deployed to dl.silentmode.st; site/releases-manifest.json bumped.
Browsers held a stale shared.css (no Cache-Control on .css, weeks-old
Last-Modified → long heuristic freshness), so the .brand .logo rule added
on 2026-09-07 never applied for returning visitors and the brand wrapped
onto its own nav row on every page except Hephaestus. All 13 pages now
link shared.css?v=YYYYMMDD; bump it on every shared.css change (GOTCHAS).
d78dd6d turned /sirius/ into a redirect to /sirius-x/, so the Sirius nav tab
left the shared header and dropped visitors into the sovereign Sirius.X site.
Per user: /sirius/ is the subdirectory page with the common header; Sirius.X
stays the sovereign registrar. Restored the page from 944080d and pointed
every register CTA at /sirius-x/#search-input, with a note listing the
mirror, gateway and native sirius.x URLs. register.html keeps its redirect.
Answers a community question ("how would one run this if it's not on GitHub?")
by putting the source repo front and centre, plus a runnable docker-compose
recipe for self-hosting.
- Palette + typography (Fraunces / DM Sans / JetBrains Mono / Ubuntu) and
layout (topnav, radial-stack background, .card, .steps, .verify, .note)
aligned with site-sirius-x. Adds js/theme.js (copied from sirius-x) for
the Fraunces↔Ubuntu font toggle.
- Sticky topnav: brand, section links, Explore repos, wallet dropdown at right.
- Hero: "The forge on Bitcoin Cash" — BCH-green accent, matched serif hierarchy.
- New "See the source. Verify the deploy." section — three cards for the repo,
auth-proxy, and PROTOCOL.md; below that a docker-compose run-your-own recipe
with git clone + cp .env.example + docker compose up.
- Pantheon and Verify-against-the-chain sections mirror Sirius.X's structure so
the seven .x pillars feel like one product.
- Browse repos link fixed to be absolute (https://code.silentmode.st/explore/repos)
so it works through navigate.st gateway too, not just BCNR-aware browsers.
hephaestus/index.html inlines its own nav CSS instead of loading shared.css,
so the injected logo SVG had no size rule and rendered at 300x150, pushing
the brand onto its own row. Added the three .logo rules to its inline style.
tools/ and releases/ were parked during the 0.3.18 ship; now carry the same
inline logo and Open Graph tags as the rest of the site.
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>
Bookmarks (A1). ⭐ button in the address row toggles the current URL;
long-press opens the list; a Your-bookmarks section appears above Featured
on the start page. Storage in filesDir/bookmarks.json, plain JSON,
most-recent first.
Undo close tab (A2). Floating pill "Tab closed · UNDO" for 5s after any
closeTab; tap UNDO → reopen in a new tab.
Long-press link menu (A3). WebView.HitTestResult drives an Open in new tab
/ Copy link / Share link sheet; no JavaScript injection.
Downloads (A5). WebView.setDownloadListener wired to Android's system
DownloadManager. Files land in the public Downloads dir with the platform
notification. URLUtil.guessFileName picks the name.
Pull-to-refresh (A4). New PullWebView subclasses WebView with hand-rolled
overscroll detection; a gold chip fades in (pull to reload → release to
reload) as the user drags. No AndroidX SwipeRefreshLayout dependency.
Share-target intent (A6). Manifest gains SEND text/plain and VIEW
http/https filters. urlFromIntent() feeds the payload through newTab (which
inherits navigateTo's .bch shortcut and .bch.bch collapse from 0.12).
Address bar polish (B2/B3/B5). Idle display strips https:// + trailing /
(focus regains restore the full URL, select-all). Long-press copies. A
compound-drawable ic_close × appears while focused + non-empty; tap clears.
Branded splash (E1). New SplashTheme + splash_background paint the Ariadne
mark on #0B0F1A during cold start; MainActivity.onCreate swaps to
AriadneTheme before layout.
Build: d8 classes.dex step ran over Windows's 32k command-line limit; now
Push-Locations into build/classes and passes relative paths.
Release: ariadne-v0.14.apk sha256
0deace437ccde7709cd21486c9b7b37b2a57463cead79b75672d974d3e5b11b0
site/releases-manifest.json bumped. Steps in RELEASE-HANDOFF-v0.14.md.
Start page grows a Theseus-style hero: big Ariadne mark, tagline, search
input that navigates the tab. Section header separates hero from the
featured-card grid. New ariadne-search:// scheme handled in
MainActivity.handleChoice routes submissions through navigateTo (so it
inherits the .bch shortcut and .bch.bch collapse from 0.12).
Tab strip auto-hides while there's only one tab — Chrome pattern, reclaims
~44dp of top chrome for the common case. A compact tab-count button now
lives in the address row (always visible, gold when many tabs), tapping it
opens a lightweight tab switcher (title + active-mark + New tab item).
Address bar polish: 15px → 16sp text, focus outline in gold via
StateListDrawable, slightly taller padding (48dp touch target).
Bottom navbar: ⟳ reload → ⌂ home (the actually-missing action); Reload
moves into the overflow ⋮ menu as the first item.
Motion: 150ms alpha crossfade on tab switch; :active card scale on the
start page.
Release: ariadne-v0.13.apk sha256
aab1f1e1aa4654c6d2d21ee09e3067d8344697609900d6ccdbd082af95dc9ddc
site/releases-manifest.json bumped. Steps in RELEASE-HANDOFF-v0.13.md.