Merge branch 'claude/agitated-bell-bd4ac2'

This commit is contained in:
Local Dev 2026-10-03 16:37:03 +02:00
commit c74d2183e3

View file

@ -7,6 +7,10 @@ Already implemented:
- Theseus's indexer process `bns-indexer.js`, which becomes the last-resort - Theseus's indexer process `bns-indexer.js`, which becomes the last-resort
fallback here; fallback here;
- Theseus's quick single-name lookup while no index exists. - Theseus's quick single-name lookup while no index exists.
- Migration steps 1, 2 and 4 (Ariadne 0.2.0, not released yet): the shared
modules, the indexer/resolver split, the installer. See "Implementation
notes" at the end for where the code deviates from this text, and what
step 3 (the Theseus client) gets from the pipe.
## The model ## The model
@ -357,6 +361,145 @@ settings:
5. **Pages:** the tools page and theseus.x describe Ariadne's Thread as part 5. **Pages:** the tools page and theseus.x describe Ariadne's Thread as part
of Theseus, with All browsers as the default mode. of Theseus, with All browsers as the default mode.
## Implementation notes (steps 1, 2, 4)
### Where the code is
- Shared, in `Argus/src/lib/` (Theseus already loads its engine from there):
`bns-index-core.js` (the indexer), `bns-source-chain.js` (the reader),
`bns-pipe.js` (protocol, server, checked client). Ariadne vendors them,
together with `resolver-web.js`, through
`AriadneResolver/ariadne-resolver/scripts/sync-shared.mjs` (`--check` fails
on drift).
- Ariadne: `src/daemon/indexer.js`, `src/daemon/resolver.js` (`bnsd.js` is
now a shim for task definitions from older installers),
`src/ctl/ariadne-ctl.js` (mode / power / start-at-boot / status), and
`src/helper/ariadne-helper.cs`, compiled at install by the in-box C#
compiler into `tools\ariadne-helper.exe` and `tools\ariadne-run.exe`.
### Deviations from the text above
- **Index folder:** the copies live in `<state>\index\`, not the state root.
`%ProgramData%\Ariadne\` inherits ProgramData's "Users may create files",
so a user could plant the snapshot there before the indexer first writes
it. `index\` has users-read / SYSTEM+Administrators-write, set by
install.ps1 and re-applied by the indexer at every start. It also holds
`bns-index-state.json` (gen, builtAt, paused, pid: when the state was last
confirmed, since the snapshot is only rewritten on change),
`electrum-servers.json` (a writable pool file would choose the evidence),
the resolver's own copy, and `machine-install.json`, the marker that makes
a Just-me install stand down.
- **Server check:** Node cannot reach a pipe's handle, so the client spawns
`ariadne-helper pipe <name> <scope> <imagePrefix>`. The helper connects,
checks the process on the other end of that same connection, prints one
JSON verdict line, then relays the pipe over its stdin/stdout. The checks:
- the image path is under the prefix;
- All users: the token user is SYSTEM, or, when a standard user may not
open a SYSTEM token, the server runs in session 0;
- Just me: the server runs as the same account.
Node's pipe server grants everyone the right to add instances
(`writableAll`), so every connection is checked, not only the first.
Without the exe the same C# source runs through PowerShell (~0.6 s
instead of ~0.1 s).
- **Restart:** Task Scheduler's "restart on failure" only covers a task that
fails to *start*. A node process that exits with an error leaves the task
"Ready" until the next boot, and that was also true of the old daemon.
`ariadne-run.exe` supervises both tasks: it restarts after 1 min, 5 tries
(the count resets after 10 min up), and exit 0 means a deliberate stop. It
holds node in a kill-on-close job, and it is windowless, so Just-me tasks
show no console.
- **Mode:** in Theseus-only mode the resolver task stays registered. The
resolver removes its routing and exits when it sees the mode, at start or
on a switch. Switching back has to run the task (`ariadne-ctl mode
all-browsers` does). Authenticated users may run, not change, the
All-users tasks.
- **No owners on `/api/*`:** the resolver's HTTP endpoints carry records but
not `owner`. Owner data only travels over the checked pipe.
- **Installer scope question:** Inno's built-in dialog always pre-selects "for
me only" under `PrivilegesRequired=lowest`. Setup therefore asks scope and
mode on its own page and relaunches itself with `/ALLUSERS` or
`/CURRENTUSER` when needed (`PrivilegesRequiredOverridesAllowed=commandline`).
- **Scope switch and the snapshot:** All users -> Just me copies the machine
snapshot. Just me -> All users does not: the per-user file is
user-writable, and the machine indexer must not start from it. It takes
the public snapshot instead, one download.
- **Just me + Firefox:** HKCU\Software\Policies is not writable without
admin, so no Firefox policy is set. Firefox trusts the user-store root
only through its own "use the operating system's certificates" setting.
Not yet verified.
### What the Theseus client (step 3) needs from the pipe
- **Name:** `\\.\pipe\ariadne-bns` (All users), else
`\\.\pipe\ariadne-bns-<own user SID>`. If both answer, use the machine
pipe.
- **Connecting:** through Ariadne's `tools\ariadne-helper.exe` with
`connectIndexerPipe` from `Argus/src/lib/bns-pipe.js`.
- `imagePrefix` is the folder of Ariadne's `runtime\node.exe`: the
`InstallLocation` from Ariadne's uninstall key, HKLM for All users, HKCU
for Just me.
- A rejected verdict (`{verified:false, reason}`) means: skip to the local
files.
- **Requests,** newline JSON `{id, op}` / `{id, ok, ...}`:
- `hello` returns `{version, network, gen, builtAt, snapshotPath, paused,
pid}`;
- `snapshot` returns `{network, gen, builtAt, tlds, names: [[key, entry]]}`;
the entries carry `owner`;
- `get {name}` returns `{gen, entry|null}`;
- `subscribe` returns `{gen}`;
- `poll` returns `{gen, polled}`, or `ok:false, error:"paused"` under
Economy. The indexer runs at most one on-demand poll per 5 s.
- **Pushes after `subscribe`:**
- `{event:"change", gen, changed, entries}`. `entries` is absent when more
than 500 names changed. Take `snapshot` again whenever `gen` skips.
- `{event:"fresh", gen, builtAt}` after each poll that changed nothing.
- `{event:"paused", paused}`.
- **Health:** a missing `fresh` is not by itself unhealthy. Under Economy
there are none, and Theseus must not take over then: that would undo
Economy. Use `hello.paused`, or the `paused` push. Unhealthy means:
- the pipe fails the check;
- `hello` gets no answer;
- or the indexer is not paused, yet `builtAt` has not moved for the
heartbeat window.
`bns-source-chain.js` already implements the reader side (heartbeat via
`hello` after 3 silent minutes).
- **Warm start for Theseus's own indexer** when taking over: `snapshotPath`
from `hello`, or `<state>\index\bns-name-snapshot.json` / `.prev.json`. Pass
them to `createIndexer({warmPaths})`.
- **Settings:** edit `policy.json` directly (`mode`, `power`, `economyWhen`,
`startAtBoot`), and run the task where `ariadne-ctl` does (mode ->
all-browsers, start-at-boot -> on). Task names:
- All users: `BNS Indexer`, `BNS Resolver Daemon` (unchanged, so 0.3.70's
panel still finds it);
- Just me: `BNS Indexer (<user>)`, `BNS Resolver (<user>)`.
- **Until step 3 ships:** Theseus 0.3.70's Ariadne panel only knows `BNS
Resolver Daemon`. In Theseus-only mode that task is Ready, not Running, so
the panel shows Ariadne as off.
### Bundling Ariadne into the Theseus installer (designed, not wired)
- **Payload:** the Ariadne setup exe, as an `extraResources` file of
Theseus's NSIS build, so the two keep separate version lifecycles.
- **Running it:** from NSIS after Theseus's own files are in place:
`AriadneResolver-Setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
/ALLUSERS|/CURRENTUSER /BROWSERMODE=<mode>`.
- Theseus's installer shows the two questions itself (one custom NSIS
page, the same pre-selection rule) and passes them on, so the user sees
one page, not two installers.
- An existing Ariadne keeps its scope unless the user changed it.
- **Elevation:**
- Theseus per-user + Ariadne All users: one UAC prompt, from Ariadne's
setup (`/ALLUSERS` respawns elevated).
- Theseus per-machine: already elevated, so no extra prompt.
- A declined prompt leaves Theseus installed and Ariadne absent. Theseus
then runs its own indexer (source 6) and offers the install again from
the Ariadne panel.
- **Updates:** Theseus's updater chains Ariadne's, as with the add-ons. The
manifest entry stays `ariadne-resolver` / `win-x64`, and the update passes
the installed scope (`/ALLUSERS` or `/CURRENTUSER`, read from which
uninstall key exists), so an update never asks the scope question.
- **Uninstalling Theseus** asks whether to keep Ariadne (default: keep in
All browsers mode) and runs Ariadne's `QuietUninstallString` only if not.
- **Portable Theseus** never bundles it (see open questions).
## Open questions ## Open questions
- **System-level fallback while the resolver restarts:** - **System-level fallback while the resolver restarts:**