Handover: incident.identity@web-summit.dinis
Kept by incident.identity@web-summit.dinis, 11 November 2026, 10:24 UTC
For the session that takes this role next. Written at incident.conductor@'s ask (the session had grown past 330k tokens a call). It holds no key material. Read first: CLAUDE.md, SECURITY.md (the design and every decision so far), status.json (the log, wake by wake), account/account.md.
What this role owns
app/login/**, account/**, data/lanes.json, tools/lane-*.mjs, SECURITY.md, agents/identity/**, and its own entry in data/keys.json (agents/policy.json). Each wake it also appends one line to accounts/ledger/identity.jsonl (the accountant's file; the path check warns, as expected).
What is live
- /account/ ("Log in"): a key made in Dinis's browser behind a passkey (or a passphrase), its public half and fingerprint, the conductor's replies opened. Hand-written
account/index.html, outside the site's frame on purpose, under a Content-Security-Policy with no inline script and nothing from another origin (decided with the conductor, 00:28; do not mount it through the frame). Its menu and breadcrumb are filled by the build from the<!--menu:…-->and<!--crumbs-->marks in the page; its notice and footer caption are copied from the frame bynode tools/lane-frame.mjs. It loads the designer'sapp/design/theme.jsandframe.js. - The feedback box (
app/login/feedback.js, on every page from the frame): drawn only in a browser that holds a key; signs and seals to the conductor's public key; with no lane it shows anm1.…code to copy. - pki.sgit.ai's code, byte for byte:
app/login/pki/with PIN.json. Never edit those four files. Known quirk:message.jsvaultKeysInmisses a vault key written with sgit's prefix;lane-handover.mjstakes the prefix off first.
Tools, and how to run them
| Command | What |
|---|---|
node tools/lane-test.mjs | the check, throwaway keys (it builds the site; about 8 s). Run it every wake |
node tools/lane-e2e.mjs | the same in Chromium with a virtual passkey (needs Playwright; skips without) |
node tools/lane-frame.mjs | copy the frame's notice and footer caption into account/index.html when lane-test says they drifted |
node tools/lane-keys.mjs | check every entry of data/keys.json. Run it every wake |
node tools/lane-sign.mjs / --check | sign SECURITY.md, PIN.json, data/lanes.json into signed.json; check them. Re-sign after any edit to those three |
node tools/lane-open.mjs '<m1>' | (conductor) open and judge what Dinis sealed |
node tools/lane-seal.mjs --to <key id> --text … | (conductor) reply sealed to Dinis; --inbox only after his yes to decision 3 |
node tools/lane-handover.mjs seal / open | a vault key sealed to the conductor; saved outside git on arrival |
node tools/lane-configure.mjs (--dry-run) | open the lane on an existing vault: not run, needs the token and Dinis's yes |
node tools/lane-drain.mjs | the conductor's drain: not run against the real server |
Release: commit (trailers Agent:, Issue: WS-214, For: in one final paragraph), then AGENT=incident.identity@web-summit.dinis admin/tools/release.sh.
Keys and signatures
- The third session's key (since 10:22 UTC, 11 November): record
sha256:4576d54b573c363f(encryptionsha256:c3f77eedf6884139), idincident-identity-dinis-3indata/keys.json. Its private half is in that session's container only and ends with the session. Used for the three signatures in signed.json. The first and second sessions' entries are markedhanded over. - The next session must: make its own session key (
pki-agent.mjs keygen --session, sha256fcb28a1c…02ab), add its public half todata/keys.jsonasincident-identity-dinis-4, set the entry before it tohanded over(that word: the pack's, and every other agent's) in the same commit, and runnode tools/lane-sign.mjs(until then--checkfails, because the signer is no longer an active key: expected). node tools/lane-keys.mjschecks the whole key list (both keys parse, fingerprints are theirs, no private half, one active key per agent and it is the latest session). Run it every wake: other agents add entries as their sessions hand over. To see who pushed a change:git log -p -- data/keys.json(the clone is shallow).- No token, no vault key and no enum key has ever been in either session. No lane and no vault exists.
data/lanes.json:enabled: false,senders: [], recipientincident-conductor-dinis. - The feedback box seals to the conductor's key: if the conductor's session and key change,
data/lanes.jsonto_conductor.recipientmust name the new key id (then re-sign).
In flight
Nothing half-done.
The conductor's append lanes are open (since 09:39 UTC, 11 November, at Dinis's yes in the second session): vault wowyrqlr on dev.send.sgraph.ai, two lanes: Dinis's feedback (to_conductor, still enabled: false until his key is a sender) and the agents' vault keys (keys_to_conductor, enabled). The enum key and tokens are inside the vault (drain/lanes.json); the vault key went to the conductor sealed. The second session's copy of the vault key (~/.incident-lane/) ends with that session: after it, the conductor holds the only copy. To add a lane: lane-configure.mjs needs that vault key and re-sends the existing tokens (the server replaces the list).
What waits on Dinis
- His key: open Log in, press "Log in with a passkey", read the fingerprint to the conductor, paste the public half. Then the conductor adds it to
data/keys.jsonand its id todata/lanes.jsonto_conductor.senders(re-sign after). Until then his sealed messages open withaccept: false. - Three decisions (end of SECURITY.md): which key is him here; how far a signed message carries; where the SG/Send token lives and whether replies may sit in the repository as ciphertext.
- The SG/Send access token as an environment secret, and his yes: then the bridge vault (sgit),
lane-configure.mjs, the first real drain. A real passkey on a real device is also still unchecked (only Chromium's virtual one).
What wakes this role
The routine "incident.identity@web-summit.dinis hourly" (trig_01KBoiikSQeY2Ze8RN4fTgV7) fired into the first session at about :21 each hour (a fact about that session; the second session's wake, at :20, is the conductor's to set). Each wake: pull, lane-test, lane-keys, lane-sign --check, look for Dinis's key in data/keys.json, measure tokens (tools/accounts-measure.mjs --append), status, release. When nothing changed, do not message the conductor.
Things learned the hard way
- The frame changes often. Never copy its menu by hand: the marks do it.
- Other agents' scripts write to localStorage on framed pages; only
sc.id.*andpki.local.v1.*are the key's. - The gate now refuses a vault-key-shaped string in any tracked file (
<20 to 64 characters>:<8 characters>): tests build such strings at run time. status.jsontimestamps: usedate -u, do not guess.