Repository navigation
Description
Design (design-architect pass 23): reconstruction is admission — validate authority-bearing inputs where they are rebuilt.
Design doc: files/designs/code-id-reconstruction-validation.md in the keep-the-four-repos-healthy goal workspace. Audited against origin/main 206f4fd7.
Summary
Six issues filed independently in one evening are one defect with six addresses: in pkgs/id, data that carries authority is validated when it is created live, and trusted when it is reconstructed — a world journal being restored, an attestation being computed from decoded objects, a manifest being parsed, a schedule cap being checked. The live path enforces invariants (only issued, JOIN-holding participants act; claims answer the agreement they name; a manifest step means what it says); the reconstruction paths enforce almost none of them, so a crafted or corrupted artefact acquires authority the live path would never have granted.
The recorded rule: reconstruction is admission. Anywhere pkgs/id rebuilds authority-bearing state from stored or supplied data, the rebuilding code validates the same invariants the live path enforces at creation, and refuses (never partially applies, never silently repairs) data that violates them. Corollaries: validate against state you hold, not claims the input makes; unnamed means refused (scope bits, manifest keys, outcomes); the system shape (sequence 0 / participant 0) is not borrowable by authority-carrying entries.
Evidence (origin/main 206f4fd)
pkgs/id/src/world/core.rsrestore: theCommittedarm's only check is sequence continuity, thencommit_preparedspends byevent.participant_idwith no record lookup (id(world): journal restore never validates Committed/Checkpoint event authors — inputs and chat from never-issued participants restore, replay, and project #2894); theCheckpointarm validates ordering/schedules but no author; theIssuedarm validates digest/parent/expiry/uses but never scopes — unnamed bits and CHAT/INPUT without JOIN restore clean (id(world): journal restore never validates Issued scopes — unnamed bits and JOIN-less capabilities restore clean, and a CHAT-/INPUT-only token can act without ever joining #2890). The function's own doc comment promises "unknown participants" are refused.- The live invariants exist: issuance requires JOIN (
core.rsissuance path,scopes.contains(WorldScopes::JOIN)), delegation subsets keep JOIN (world/mod.rsWorldScopes), admission runsauthorize(token, required)per act. Restore consults none of it. pkgs/id/src/attestation.rscompute_state: signatures (verified bychain::decode) prove who signed, not that the agreement is well-formed —players = [A, A]computesAgreedfrom one key (id(attestation): compute_state never checks the two players are distinct — players=[A,A] attests Agreed from one key's single genesis + single claim #2863), and a claim's free-formwinnernaming a third party computesAgreed(id(attestation): compute_state never validates the claim outcome's domain — claims naming a third party (or any string) as winner compute Agreed #2868).check_schedule_replacingtrusts a caller-suppliedreplacing: boolfor the pending-schedule cap restore enforces — a mismatched flag admits a 65th pending schedule and underflows on an empty map (id(world): check_schedule_replacing trusts a caller-supplied replacing flag — a mismatched flag admits a 65th pending schedule past the cap restore enforces, and underflows on an empty map #2882). The ground truth is inself.schedules.pkgs/id/src/world_manifest.rs: serde with defaults, nodeny_unknown_fields— a typo'd grants/ceiling revocation parses clean, plans zero steps, diff says "no drift" (id(world-manifest): unknown or misspelled world.toml keys are silently ignored — a typo'd grants/ceiling revocation parses clean, plans zero steps, and diff reports 'no drift' #2876).- Safety of strictness: there are no
Revokedjournal entries in the enum yet, and every capability live code has issued satisfies JOIN + named bits — a strict restore cannot refuse a journal the live code actually wrote.
Phases (adopted origins — no parallel issues filed)
- Phase 1 — journal restore validates authors and scopes. id(world): journal restore never validates Committed/Checkpoint event authors — inputs and chat from never-issued participants restore, replay, and project #2894 (Committed + Checkpoint author check: author issued, holding the scope its kind requires) + id(world): journal restore never validates Issued scopes — unnamed bits and JOIN-less capabilities restore clean, and a CHAT-/INPUT-only token can act without ever joining #2890 (Issued scope check: named bits only, JOIN required). One seam, the security core. Independent.
- Phase 2 — attestation agreement validity. id(attestation): compute_state never checks the two players are distinct — players=[A,A] attests Agreed from one key's single genesis + single claim #2863 (players must be distinct, else
Proposed) + id(attestation): compute_state never validates the claim outcome's domain — claims naming a third party (or any string) as winner compute Agreed #2868 (claim outcome domain: winner isNoneor one of the two players; out-of-domain claims ignored under the existing non-player rule). Independent of Phase 1. - Phase 3 — derive-don't-trust + closing audit. id(world): check_schedule_replacing trusts a caller-supplied replacing flag — a mismatched flag admits a 65th pending schedule past the cap restore enforces, and underflows on an empty map #2882 (schedule predicate derived from
self.schedules; trusted parameter removed) + id(world-manifest): unknown or misspelled world.toml keys are silently ignored — a typo'd grants/ceiling revocation parses clean, plans zero steps, and diff reports 'no drift' #2876 (deny_unknown_fieldson the manifest's authority-bearing structs) + a closing inventory audit of the remaining reconstruction seams (sandbox snapshot restore,world_storerestore_program, directory/petname persistence), each dispositioned already-validating / fixed / exempt-with-reason, and the rule written into the restore and attestation module docs.
Alternatives considered
- Fix the six sites independently: each lands, the rule stays unstated, the next seam re-opens the hole — the six-in-one-evening pattern is the evidence this is a family.
- Validate at write time only: journals outlive and out-travel the writer (forks copy them, backups restore under newer binaries); restore is the only point where data, invariants and refusal coexist.
- Sanitise at consumers: many consumers, one state; a phantom capability record has no single consumer to patch.
- Version-gate strictness: the invariants are not new, so no legitimately-written old journal can violate them; a gate would only protect journals that were never valid.
Risks / open questions
- Restore corpus (v1/v2 headers, delegate expiry, fork fixtures) must pass unchanged; if Phase 1 triage finds a legitimate historical scope/kind mismatch, the issued-author check stands and the mismatch is filed as evidence — the check is not silently dropped.
- Manifest strictness: Phase 3 greps the repo's own manifest writers/fixtures for extra keys before the attribute lands.
- Open questions stay in the design doc (Revoked-entry semantics when that feature arrives; payload-shape validation at replay is execution, not admission; outcome domains for non-duel agreements; sandbox snapshot integrity if the audit finds authority flowing through it).
Agent note: this issue is the design of record for #2894, #2890, #2863, #2868, #2882, #2876 — they are adopted as its phases and linked as sub-issues. Their triage should record the phase structure, not re-file or split them.
Acceptance criteria
- Every authority-bearing reconstruction path in
pkgs/idnamed by this design (journal restore, attestation computation, manifest parsing, schedule checks) validates the same invariants its live creation path enforces, and refuses — never partially applies, never silently repairs — violating input. - Each of the six filed instances (id(world): journal restore never validates Committed/Checkpoint event authors — inputs and chat from never-issued participants restore, replay, and project #2894, id(world): journal restore never validates Issued scopes — unnamed bits and JOIN-less capabilities restore clean, and a CHAT-/INPUT-only token can act without ever joining #2890, and the siblings named in the design doc) is either fixed under this contract or explicitly dispositioned against it.
- Regression tests exist for at least the journal-restore and attestation paths proving crafted/corrupted artefacts are refused.
- The recorded rule ("reconstruction is admission") is documented where a future reconstruction path author will find it.
Activity
dezren39 commentedon Oct 31, 2026
Agent note (design-architect, 2026-10-30): design of record for the six adopted origins, linked as sub-issues and labelled
source/design-architect: Phase 1 = #2894 + #2890 (journal restore), Phase 2 = #2863 + #2868 (attestation), Phase 3 = #2882 + #2876 (derive-don't-trust + manifest strictness + closing audit). Each origin already carries a queued triage packet (queue/queuedverified at filing); no new implementation issues or packets were created by this design — triage of each origin should record its phase structure and the decisions noted on it, not re-file or split. Phase 3 closes this issue with the closing-audit evidence. Register: added tofiles/potential-projects.md(status: proposed).dezren39 commentedon Oct 31, 2026
Correction (design-architect, same pass): the design doc has been amended after a full read of the six origins' acceptance criteria. Three corrections of record:
ProgramInstalled, per id(world): journal restore never validates Committed/Checkpoint event authors — inputs and chat from never-issued participants restore, replay, and project #2894's acceptance) — the author rule is "0, or issued earlier in the journal and not revoked before that entry"; events by a participant revoked later stay valid. An earlier draft of the doc wrongly implied participant-0 events were borrowable system shape only, and wrongly statedRevokedentries do not exist — they do, and their restore arm already validates; the Committed/Checkpoint arms simply never consult revocation state."draw"sentinel (documented onResultClaim.outcome) alongside the two seat players' id-as-hex — not aNonewinner. Whether an out-of-domain claim is ignored or counts as a position is id(attestation): compute_state never validates the claim outcome's domain — claims naming a third party (or any string) as winner compute Agreed #2868's triage pin.WorldExecutionProfile(world_limits.rs) plus thecommands/world.rsJSON round-trip check from id(world-manifest): unknown or misspelled world.toml keys are silently ignored — a typo'd grants/ceiling revocation parses clean, plans zero steps, and diff reports 'no drift' #2876's acceptance.The design doc (
files/designs/code-id-reconstruction-validation.md) now states all three; the per-issue notes have matching corrections.62 remaining items
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
opencode; the claimant launches the bound session. Fresh revalidation: issue Design: reconstruction is admission — validate authority-bearing inputs where they are rebuilt (pkgs/id) #2898 OPEN, no held / user/owned / do-not-merge / do-not-auto-edit labels. Design triage (epic); prior progress already handed off once at 14:33Z - this is a re-handoff after lease expiry.dezren39 commentedon Nov 4, 2026
agent-note:v1
task: 9204
lane: code-y
stage: handed_off
execution_lane: opencode
Issue #2898 verified OPEN (expedite), no hard-stop labels; parked labels resynced to queue/claimed + status/in-progress. Task 9204 claimed by lane code-y (attempt 4/6) and handed off to the opencode claimant for triage and routing.
dezren39 commentedon Nov 5, 2026
agent-note:v1
event: handed_off
task: 9204
worker: repo-worker-code (lane code-f)
stage: handed_off
summary: Task 9204 (triage) re-claimed by lane code-f; execution-lane assignment again returned assigned_lane=opencode (session_id null), so this lane hands off per the runbook without working it directly. The opencode claimant remains the owner for launching the bound session.
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
opencode, so the task is handed off — the laptop opencode-claimant launches a bound session to drive it to its terminal state. Caution: task 9204 is at attempt 11 of 12 — if the claim lease expires unbound once more it may hit the attempts cap.dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
Agent note — picked up, handed off to opencode claimant (task 9204)
opencode, so this worker does not work the task directly.handed_off; the laptop opencode-claimant launches the bound session for task 9204.