Repository navigation
Description
From the #2041 investigation (token issuance in the ID graph)
The landed investigation doc for #2041 (doc/2026-10-30T19-18-00Z_investigation_token_issuance_id_graph/, §10 case 7) identifies issuer key compromise as the catastrophic case for any issuer system: an attacker mints/converts as the issuer until the compromise is noticed. The model names the mitigations — supply caps bound mint damage, registries/views can pin issuer key generations — but the rotation mechanics were explicitly not designed. This issue designs them, so the #2043 synthesis adopts a designed answer instead of an afterthought.
Design to produce
- Signed rotation object: format and chain semantics for an issuer key rotation (old key names successor), as an ID-graph object consistent with the signed-event envelope in
pkgs/id/src/chain.rs; what happens to currency definitions issued pre-rotation (investigation position: they keep their identity — verify or amend). - Counting-view pinning: how counting views (id: investigate: trust/visibility model — servers accept all signed objects; views count only allowed writers #2030) and wallets pin which issuer key generation(s) they count for a currency, and how a view learns of a rotation/compromise.
- Anchored path handling: registry/gateway treatment of rotation and of a declared compromise — minter-set updates via signed registry writes (id: design: currency control plane — registry, account factory, gateway #2062 §2.5), in-flight issuance/conversion treatment, and the compromise-declaration flow (who can declare, what freezes, what stays valid).
- Graph-native path handling: the same questions where there is no gateway to enforce anything.
Acceptance criteria
- Design recorded in a doc under
doc/(or inpkgs/id/doc/if the id: design: graph token object formats + snapshot anchoring spec (from #2041) #2251 spec has set that convention by then) and linked from this issue - Rotation object + pinning rules specified precisely enough for id: design: graph token object formats + snapshot anchoring spec (from #2041) #2251's wire-format spec and the id: design: currency control plane — registry, account factory, gateway #2062 gateway follow-ups to implement against
- Compromise walkthrough: attacker mints with a stolen issuer key — what is bounded by caps, what the rotation/compromise declaration stops, what remains exposed
- Anything buildable that falls out is filed as its own issue(s)
Program: ID platform expansion, epic #2056. Parent investigation: #2041. Related: #2251 (object-format spec), #2062 (control plane), #2030 (counting views), #2043 (currencies v1 synthesis — consumes the outcome).
Activity
dezren39 commentedon Oct 31, 2026
Intake review
pkgs/id/src/chain.rsenvelope semantics first, then counting-view pinning; record the adoption decision on id: design: ID currencies v1 #2043.dezren39 commentedon Nov 1, 2026
agent-note:v1 — task 5743 design triage record (lane A shift, 2026-11-01). Decision-ready record for issuer key rotation + compromise recovery, from the #2041 investigation (doc
doc/2026-10-30T19-18-00Z_investigation_token_issuance_id_graph/, §10 case 7, §11 hand-off). Consumer: the #2043 currencies v1 synthesis (OPEN, gated on this outcome among its inputs).Grounding (verified today, main 51919e9)
pkgs/id/srcyet — this is a design-first topic; nothing shipped constrains the mechanics.pkgs/id/src/chain.rs—Event(:262) andsign()(:282).The decision
The exact format/chain semantics of the rotation object, the pinning rules counting views apply, and the compromise-declaration flow — for both the anchored path (registry/gateway, #2062) and the graph-native path (no enforcer).
Recommendation — the v1 design in one pass
Compromise walkthrough (acceptance scenario)
Attacker mints with a stolen issuer key. Bounded immediately by: the currency supply cap (mint damage ceiling even with the key — investigation §10 case 7). The issuer publishes a recovery-key-signed compromise rotation (rule 5): anchored gateways freeze the stolen generation on receipt (rule 6); counting views stop counting post-frontier issuance from it and mark the asserted-compromise window disputed (rule 4). Remains exposed, honestly: issuance between the actual theft and the declaration counts unless the declaration asserts the earlier start (then it is disputed, and counterparties decide) — no design without a trusted clock does better; conversion attempts with the stolen key after the frontier fail at gateways and do not count in pinned views.
Invariants
Rotation never rewrites history; generation forks are signals, not ties; no authoritative compromise state from the compromised key alone; every count names its frontier; caps are load-bearing and stay mandatory for issuers.
Phasing
doc/expanding this record to id: design: graph token object formats + snapshot anchoring spec (from #2041) #2251-implementable precision (wire format via id: design: graph token object formats + snapshot anchoring spec (from #2041) #2251, registry-write shape via id: design: currency control plane — registry, account factory, gateway #2062 §2.5), including the walkthrough as a worked example. That doc is this issue's own acceptance deliverable.Question for Drew (explicit, non-blocking)
Recovery-key pre-commitment (rule 5): mandate it for registry-anchored currencies (recommended — without it, compromise recovery has no authoritative signer, and anchored issuance is exactly where real value concentrates), or make it optional everywhere (more graph-native in spirit; anchored issuers who skip it get advisory-only recovery)? Default until ruled: the recommendation — mandatory on the anchored path, optional graph-native. Ruling goes on this issue; the doc packet proceeds either way and records the ruling.
80 remaining items
dezren39 commentedon Nov 3, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 3, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 3, 2026
🤖 Agent note · handed off
handed_off(prior handoff lease expired, where applicable). Fresh revalidation: issue id: design: issuer key rotation and compromise recovery for currency issuers (from #2041) #2804 is OPEN, no hard-stop labels (held / user/owned / do-not-merge / do-not-auto-edit absent).dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
opencode; handed off to the laptop claimant (opencode-claimant), which launches the bound session that drives task 7983 to its terminal state.dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
fix(id): carry the rotation in the signed extension; recovery resolve…
feat(id): issuer key rotation and compromise recovery — protocol core (…
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off