theseus/GOTCHAS.md
Local Dev c2ba26877f Theseus: download tracker, search split, discover-more tier, UX polish
Bundle of UX + feature work. Split from packaging by intent so the diff
is reviewable; the next Theseus rebuild ships it.

Features
- Download tracker (new): session.on("will-download") → per-item state
  {id, filename, url, mime, total, received, state, savePath, startedAt}
  with updated/done event handlers. New downloadsPop WebContentsView
  loads downloads.html (new file) + downloads-preload.js (new file);
  panel positioned under a new #downloads toolbar button between search
  and Tor. Full IPC: downloads-get, toggle/close/resize-downloads,
  download-open/show/cancel/clear, downloads-clear-all. In-memory only —
  cross-session persistence is a future addition. Button badge shows
  active count + spin/done/err color.

- Search engines split by kind + tier:
  * kind: "search" | "llm" — separate headers in picker + settings
    ("Search with" / "Ask an AI"). Empty sections hidden.
  * tier: "catalog" | "extra" — Settings now has THREE panes behind the
    "+ Add search engine" button: curated catalog, wider discoverable
    bank filtered by a live search input, custom URL form.
  * DEFAULT_ENABLED unchanged (5 major engines).
  * Custom user-added engines carry tier="custom" (never in catalog/extra
    panes).

- 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract,
  Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule
  as LLMs: if one starts bouncing to a login gate, drop it.

Bug fixes
- Loadbar collapses to 0px when idle (was reserving a permanent 2px
  strip below the address bar). .loadbar {height:0} + .loadbar.on
  {height:2px} + 120ms transition.
- Native <select> popup theme sync via :root { color-scheme: dark } +
  @media(prefers-color-scheme: light). nativeTheme.themeSource already
  drives prefers-color-scheme, so the OS popup color follows the app
  theme automatically (fixed light popup on dark app / vice versa).
- .ctl layout flipped to flex-direction: row with flex-wrap so
  anti-fingerprint mode + value fields fit side-by-side.

Settings restructure
- General section: Startup group at the top ("Open previous windows and
  tabs" toggle), then Appearance below with three visual THEME CARDS
  (System / Light / Dark) — small mock-browser previews per theme,
  Firefox-style, active card gets a blue ring. System pipes through to
  nativeTheme.themeSource = "system".
- Search promoted to a top-level sidebar item between General and
  Naming. Search-engine controls moved out of General into Search.
- Search section: enabled list shows only enabled engines, grouped by
  kind, drag-reorder within a kind. "+ Add search engine" opens the
  catalog/extras/custom-URL panel.

Search engine catalog trims (already flagged in prior work)
- Removed ChatGPT / Claude / You.com (login-gated ?q=).
- Removed SearXNG (federated; every single-instance default rots).

Docs
- TheseusNavigator/PENDING.md and GOTCHAS.md born with this work
  (see the HANDOFF.md commit for the convention).
- PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be
  emptied after this ship lands.

Preview harness
- _preview.html + _settings-preview.html stubs updated with kind + tier
  + downloads seed + tier="extra" samples so the preview reflects reality.
  Both files are gitignored — local only.

Coordination
- Parallel session's collision-policy work (chrome.html registry chips,
  popover switcher, Naming section, in-tab collision prompt) already
  landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds
  cleanly on top.
2026-08-02 15:31:47 +02:00

5.3 KiB

Theseus gotchas

Non-obvious things sessions keep re-deriving. If you found this file because something broke in a way that felt spooky, the answer is probably here.

build.files in package.json is EXPLICIT

electron-builder ships only what's listed in build.files. Every runtime- loaded HTML/preload/module MUST be there. A missing entry causes the loadFile("foo.html") in a WebContentsView to silently open blank in the packaged app — visually indistinguishable from "the button does nothing".

npm start (dev) never catches this because it reads from the source tree directly. Only a real npm run dist + install exposes it.

Every time you add a new WebContentsView or loadFile, add its HTML and preload to the files array. Sanity check after building:

node -e "const b = require('fs').readFileSync('dist-public/win-unpacked/resources/app.asar'); for (const n of ['engine-picker.html','popover.html','downloads.html','engine-picker-preload.js','popover-preload.js','downloads-preload.js']) console.log(n, b.indexOf(Buffer.from(n)) >= 0 ? 'OK' : 'MISSING');"

This has bit us once (search-picker dropdown, shipped 6bbccf9c, blank picker). Do not let it bite twice.

Building — admin terminal the first time

npm run dist needs an admin terminal on the machine's first Theseus build so electron-builder's winCodeSign package can extract its darwin/ symlinks (requires SeCreateSymbolicLink). Subsequent builds reuse the cache under $LOCALAPPDATA/electron-builder/Cache/winCodeSign/ and don't need admin.

If DNS is misbehaving on the machine, pin these hosts in C:\Windows\System32\drivers\etc\hosts before building so electron-builder can fetch: github.com, codeload.github.com, objects.githubusercontent.com, release-assets.githubusercontent.com. Strip them after.

Reproducible builds

Set both before npm run dist:

  • SOURCE_DATE_EPOCH — freezes timestamps so a rebuild with no content changes produces the same hash. Bump per release, not per rebuild.
  • CSC_IDENTITY_AUTO_DISCOVERY=false — stops electron-builder searching for a signing cert (we don't sign; SECURITY.md rule 2).

Native <select> popup theme

Chromium's native <select> popup uses the page's color-scheme. When it's "light dark" (both accepted), Chromium picks by the OS scheme — so a dark-themed app on a light OS shows a light popup and vice versa.

Fix, currently in settings.html:

:root { color-scheme: dark; }
@media (prefers-color-scheme: light) { :root { color-scheme: light; } }

nativeTheme.themeSource (driven by settings.theme) sets prefers-color-scheme, so this stays in sync automatically. Do not remove.

Chromium also respects select option { background; color } in the popup on Windows — a belt-and-braces override alongside color-scheme.

The resolver in Theseus is resolver-web.mjs, not .js

Packaged builds ship Argus/src/lib/resolver-web.js as resolver-web.mjs (see extraResources in package.json). Renamed because resources/ has no adjacent package.json so a .js gets treated as CommonJS and its exports fail. Dev reads the engine copy directly (Argus is type: module so .js works there).

The resolver's electrum WS directIP fallback

main.js passes directIP: true to resolveHost so the engine can dial the chipnet electrum servers by pinned IP if system DNS is dead. Do not remove — this is what keeps .bch resolution working when the adapter DNS is broken (a real failure mode we've hit).

Publishing new hashes end-to-end

  1. Build (see above).
  2. Update ../site/releases-manifest.json AND ../site/tools/index.html AND ../site/releases/index.html with the fresh SHA-256s + release date. All three must match.
  3. Deploy:
    scp dist-public/*.exe ../site/releases-manifest.json coinspectrum:/opt/silent-mode/dl/
    cd ../Argus && node src/lib/sia-upload.js ../site bns/silentmode
    
  4. On-chain (wallet spend, user's action): releases.silentmode.bch currently publishes {"u":"https://dl.silentmode.st/releases-manifest.json"} — a compact u record because on-chain hashes wouldn't fit the 200-byte OP_RETURN. Only re-publish if the URL changes or if we ever put full hashes on-chain.

Sia upload from this machine fails without a hosts pin

node src/lib/sia-upload.js fails with getaddrinfo EAI_FAIL coinspectrum.duckdns.org unless the host is pinned in C:\Windows\System32\drivers\etc\hosts: 195.184.247.106 coinspectrum.duckdns.org. This is a DNS quirk of the machine, not a code bug — related to the strict-resolver behavior the Ariadne daemon's EDNS fix addresses.

Deploy directory quirks

  • /opt/silent-mode/dl/ is served as dl.silentmode.st — installers + manifest live here.
  • silentmode.st proxies to Sia (bns/silentmode/) — the HTML pages live there.
  • The bns gateway does NOT auto-index directories. silentmode.st/apps/ is a 404 (NoSuchKey); users must hit /apps/index.html. Fix upstream in bnsd.js if it ever matters.

Firefox needs a restart after Ariadne CA install/rotation

Firefox only reads root CAs at startup. The Ariadne installer offers a -CloseFirefox task by default when Firefox is running so this doesn't bite. Chrome/Edge pick up the new root immediately.