MutationPlanRecordedReceipt — Design/Audit Contract
Status: draft — design/audit
Truth class: descriptive
Canonical: no
Last reviewed: 2026-07-04
Source basis: read against origin/main @ 2652a8d6 (re-verify before relying on exact line numbers or hashes — they drift)
Related: #2299 (this contract's issue), #1748 (Institutional Process Substrate), #2141 (vertical institutional spine), #2041 (human/AT pass — open/parked), #2296 (ActivationCrossedReceipt implementation), #2298 (activation render in the process-evidence member-shell demo), ADR-0026 (receipt & provenance proof envelope), ADR-0027 (action cards)
This is the design/audit contract #2299 requires before any implementation. It scopes a candidate
MutationPlanRecordedReceiptas the next narrow process-transition receipt rung under #1748 / #2141 — the receipt that would witness that a mutation plan was recorded after an activation crossing, before any mutation is applied.This document adds no runtime code and asserts no implementation.
MutationPlanRecordedReceiptdoes not exist anywhere in the runtime today. This contract audits current state honestly, proposes a candidate contract subject to implementation proof, and names the blockers that a narrow decision rung must resolve before an implementation PR can begin. Receipts record facts and grant no authority. This is not a mutation, not a workflow engine, and not mutation application.
1. Purpose
The process-transition receipt lane under #1748 / #2141 has landed five runtime classes that make institutional process legible as replayable, hash-anchored evidence:
ProcessSessionOpenedReceipt(anchor);DeliberationEntryRecordedReceipt;DecisionRecordedReceipt;ProcessGateResultReceipt;ActivationCrossedReceipt(#2296, now also rendered read-only in the fixture-only process-evidence member-shell demo per #2298).
The framing spine (ops/ideas/framing/institutional-process-substrate.md) orders the substrate as:
preview → deliberation → decision → activation → mutation plan → action cards → receipts → evidence
The five landed classes cover preview → activation. The next narrow, VM-executable rung is mutation plan — the plan-of-record for what runtime should do as a consequence of an activation, recorded before any mutation is applied. This document is the design/audit contract for the receipt that would witness the fact that such a plan was recorded.
It is deliberately not mutation application, not a general workflow engine, and not evidence-packet production. It is one receipt rung, and — as the audit below shows — like the activation rung before it (#2294 → #2295 → #2296), it needs a narrow decision rung of its own before implementation.
2. Status basis
Verified live at authoring time (origin/main @ 2652a8d6):
- #2296 —
ActivationCrossedReceiptruntime implementation — landed (merged; fifthProcessTransitionReceiptclass). - #2298 — activation render in the fixture-only process-evidence member-shell surface (
?mode=demo&set=process-evidence) — landed (merged,2652a8d6). - #2293 —
ActivationCrossedReceiptruntime dogfood slice — closed / completed (by #2294 contract + #2295 decision rung + #2296 implementation). - #2297 — activation member-shell render — closed / completed (by #2298).
- #2041 — real screen-reader / low-vision / switch / AT-compat human pass — open / parked for a broader human-testing phase; not attempted here.
No production, pilot, organizer-ready, member-ready, live-federation, NYCN-activation, or Phase-2 claim is made or implied by this document.
3. Current repo audit
Classification of every mutation-plan / mutation-applied / evidence-packet term, read against origin/main @ 2652a8d6:
| Term | State | Where |
|---|---|---|
ProcessSessionOpenedReceipt / DeliberationEntryRecordedReceipt / DecisionRecordedReceipt / ProcessGateResultReceipt / ActivationCrossedReceipt |
runtime (Rust) | icn/crates/icn-governance/src/proof.rs; wired in apps/governance/{manager,receipt_backend}; per-class *_runtime_slice.rs tests. These five are the only runtime ProcessTransitionReceipts. |
MutationPlanRecordedReceipt |
docs/framing only | framing (institutional-process-substrate.md §"Receipt classes for process transitions"), dogfood MVP, ideas.yaml, the activation design docs, STATE/PHASE_PROGRESS, dev handoffs. No Rust struct, tag, manager method, backend class constant, route, or test. |
MutationPlan (the planned artifact the receipt would witness) |
docs/framing only | framing §"MutationPlan": "the plan-of-record for what runtime should do as a consequence of the activation … the kernel does not read the plan semantically … the plan is for human and partner review, audit, and replay." No Rust type. |
PreviewReviewPacket / pending_publish_summary (framing's proposed read-model of a MutationPlan) |
docs/framing only | framing pins "a MutationPlan is preview-shaped: a PreviewReviewPacket with preview_kind = pending_publish_summary … the plan is the upstream artifact the pending-publish preview renders." Audit found no PreviewReviewPacket and no pending_publish_summary in icn/crates or icn/apps — the proposed read-model is itself not-yet-runtime. |
ActivationRequest (gate object) |
docs/framing only | framing + dogfood MVP. No Rust gate object; the #2295 activation decision rung deliberately reused the closed ProcessGateKind and added no ActivationRequest. |
MutationAppliedReceipt |
docs/framing only | framing notes it exists "only in concept" via existing action-item/governance receipt families; no dedicated class. Out of scope here (§13). |
EvidencePacketProducedReceipt |
docs/framing only | framing/dogfood/STATE. No Rust process class. Note: icn-baseline-lock/src/evidence.rs defines a separate EvidencePacket — a baseline-lock evidence/test bundle with its own type, not a governance ProcessTransitionReceipt and not prior art for this lane. |
Honest bottom line: the five landed classes are the only ProcessTransitionReceipt runtime types. Everything from mutation plan onward — including this contract's subject and even the read-model shape (PreviewReviewPacket) the framing proposes for it — is a named candidate with no runtime seam. This class is entirely seam-discovery work, exactly as ActivationCrossedReceipt was before #2296.
3.1 The pattern the five landed classes share (what a sixth class would mirror)
#[derive(Clone, Debug, Serialize, Deserialize)]; hand-writtenPartialEq/Eqanchored only torecord_hash.- A
DOMAIN_TAGconst followingicn:gov:<class_snake_case>:v1, hashed first, required to be disjoint from every other tag. - Anchor is always the
(domain_id, session_id)pair —session_idis meaningful only withdomain_id; a receipt requires the session to have been opened first (ProcessSessionOpenedReceiptprecondition). - A caller-opaque per-item id (
entry_id/decision_id/activation_id). recorded_by/crossed_by/author: a DID string, actor evidence that grants zero authority ("recorder, not decider/crosser").recorded_at: u64(Unix seconds), hashed intorecord_hashbut excluded from duplicate identity — a retry never restamps.body_hash: Hash(Deliberation/Decision): a caller-supplied 32-byte fingerprint; the body is never stored.record_hash: Hash: canonical blake3 overDOMAIN_TAG+ length-prefixed variable-length strings + explicit-u8enum ordinals (if any) + raw fixed-size 32-byte hashes +recorded_at.to_le_bytes().- Uniqueness/idempotence via the
put_opaque_if_absentbackend primitive; duplicate identity is the stable fields only (recorded_at/record_hashexcluded). - Inter-receipt reference (new since #2296):
ActivationCrossedReceiptestablished the lane's first inter-receipt link — it names the activated decision by both the caller-opaquedecision_idand the content-addresseddecision_record_hash, verified fail-closed against the recorded decision in the same session (the #2295 B1 decision). A sixth class linking to the activation would be the lane's second such reference and would mirror that verified-not-asserted posture.
4. Problem statement
An activation can be recorded today (ActivationCrossedReceipt, #2296): a recorded decision, with required gates observed as passed, crossed from decision toward later action planning. But there is not yet a narrow, receipt-backed plan of record for what that later action planning proposes to do — recorded before anything is applied, so the plan is auditable and replayable independently of any mutation.
Framing (institutional-process-substrate.md §"MutationPlan") states the artifact directly:
"a decision is not a mutation. A decision authorizes a mutation; a mutation plan describes one; an activation request crosses the boundary; only then does runtime mutate."
"The plan-of-record for what runtime should do as a consequence of the activation. Names the affected objects, the specific operations (create, update, retire, reassign, allocate, settle, install, bind), and the expected receipts. The kernel does not read the plan semantically … The plan is for human and partner review, audit, and replay."
For this dogfood slice, a mutation plan recorded is a local/dev/fixture institutional fact: a plan-of-record was recorded against an activation crossing, before any mutation is applied. The receipt witnesses that the plan was recorded — not its contents, not that it is valid, authorized, or safe to apply, and not that any mutation happened. Applying the plan is a strictly later rung (MutationAppliedReceipt, §13).
This is not production mutation, service deployment, pilot readiness, or mutation application. It records a receipt of the planning fact and nothing else; it mutates no domain state and grants no authority.
5. Mutation-plan boundary definition (for this slice)
For this dogfood slice, mutation plan recorded means: a plan-of-record (an app-side
MutationPlanartifact whose body is never stored by the receipt) was recorded after anActivationCrossedReceiptfor the same session, before any mutation is applied. The receipt records only the fact and fingerprint of that planning step.It is not mutation application, not service deployment, not an authorization to act, and not a kernel-readable operation list. Recording a plan produces a receipt of the planning and nothing else; it mutates no domain state and grants no authority. Whether the plan may ever be applied is a charter/gate/authority question upstream of this type.
6. Proposed receipt contract (candidate — subject to implementation proof)
Candidate tag: icn:gov:mutation_plan_recorded:v1 (must hash-separate from all existing tags, and must never converge with icn:gov:activation_crossed:v1, icn:gov:decision_recorded:v1, icn:gov:process_gate_result:v1, or the proposal/vote icn:gov:decision:v1/v2/v3 lineage).
Candidate fields (naming follows the landed classes; anything marked OPEN is a blocker deferred to §14's decision rung, not an asserted field):
| Field | Type | Notes |
|---|---|---|
domain_id |
String |
anchor half; hashed length-prefixed |
session_id |
String |
anchor half; session must be opened first (precondition) |
plan_id |
String |
caller-opaque per-plan id (mirrors activation_id/decision_id); the key2 uniqueness half |
activation_id |
String |
the activation this plan follows — caller-opaque handle (lane's second inter-receipt reference; see M1) |
activation_record_hash |
Hash (32) |
content-addressed record_hash of the ActivationCrossedReceipt this plan follows; the cryptographic proof link (M1) |
recorded_by |
String (DID) |
actor evidence — the recorder of the plan, not an authority to plan or act ("recorder, not planner"); grants zero authority |
body_hash |
Hash (32) |
caller-supplied fingerprint of the MutationPlan body; the plan body is never stored (M2) |
recorded_at |
u64 |
caller-supplied Unix seconds; hashed into record_hash, excluded from duplicate identity (M3) |
record_hash |
Hash (32) |
canonical blake3 per §3.1 hashing discipline; the sole PartialEq/Eq anchor |
Canonical hashing (candidate): DOMAIN_TAG first → length-prefixed domain_id, session_id, plan_id, activation_id, recorded_by → activation_record_hash raw 32 (no length prefix) → body_hash raw 32 (no length prefix) → recorded_at.to_le_bytes(). Exact layout is fixed by the implementation PR and pinned by a golden vector (§12).
Deliberately absent (must never appear in v1):
- no kernel-readable operation list, target object list, or effect payload (the plan body is fingerprinted, never stored — meaning firewall);
- no mutation content, applied-effect, or "what actually changed" — that is
MutationAppliedReceiptterritory (§13); - no authority grant, capability, mandate, or token; no "this plan may be applied" assertion;
- no proposal/vote/tally/quorum/outcome semantics;
- no new
ProcessGateKindsemantics and noActivationRequestgate object (the #2295 decisions stand); - no
target_ref/effect_ref(deferred — §14 M2); - no stored plan/decision/deliberation body (fingerprints only).
Session precondition & duplicate semantics: identical to the landed classes — the (domain_id, session_id) session must be opened first (fail-closed otherwise); at most one plan per (domain_id, session_id, plan_id); a same-identity retry returns the original receipt un-restamped; a different activation_id/activation_record_hash/recorded_by/body_hash for the same identity is a fail-closed conflict.
7. ADR-0026 envelope usage
MutationPlanRecordedReceipt should sit where the other five landed process classes sit: ADR-0026 Layer 2, as a self-contained record carrying its own canonical blake3 record_hash.
Honest layering caveat the implementation PR must respect (unchanged from the activation contract): ADR-0026's written Layer-2 model (ArtifactReceipt wrapping a signed, merkle-rooted Layer-1 GovernanceProof) predates the process-transition classes. Those classes reuse the Layer-2 slot but use a lighter model — a self-hashed blake3 record_hash, no signature, no merkle root. This contract does not claim the plan receipt inherits the signed-proof envelope; it inherits the process-transition discipline (self-contained record hash, opaque-store persistence). Any future signature/merkle upgrade is out of scope here and would be an ADR-0026 revision, not a receipt rung.
8. Links and provenance
How the receipt would link back (design-level):
- process/session — via the
(domain_id, session_id)anchor (existing pattern; no new seam). - activation — via
activation_id+activation_record_hash(M1): naming theActivationCrossedReceiptthis plan follows. This is the lane's second inter-receipt reference; it mirrors the verified-not-asserted posture the #2295 B1 decision set for the activation→decision link (the referencedActivationCrossedReceiptmust exist in the same session, and itsactivation_idmust match). - decision / gate basis — inherited transitively through the activation (the
ActivationCrossedReceiptalready bindsdecision_id,decision_record_hash, andgate_basis). The plan does not re-reference the decision or gates directly in:v1(see M1); the activation link is the single upstream anchor. - proof/envelope metadata — the receipt's own
record_hashis the provenance pointer; persistence and retrieval go through the same opaque receipt store as the other five landed classes.
9. Idempotence and replay
Design requirements (mechanism already exists for the landed classes; this class would reuse it):
- Emission goes through the backend primitive
put_opaque_if_absent(GovernanceReceiptBackend; production impl inicn-gateway'sReceiptStore, atomic within one sled transaction).Nonereturned ⇒ this write won;Some(existing)⇒ hydrate and return the original persisted receipt — never re-stamp. - The uniqueness marker is keyed on
(class, key1, key2)wherekey1is an injective netstring-style composite of(domain_id, session_id)andkey2isplan_id. Injectivity must be tested (("ab","c")vs("a","bc")must not alias; two domains sharing asession_idmust never mix). - Stable duplicate identity is
(domain_id, session_id, plan_id, activation_id, activation_record_hash, recorded_by, body_hash). Same-identity retry ⇒ idempotent return of the original; a different value for any identity field for the same key ⇒ fail-closed conflict (e.g.mutation_plan_recorded_conflict, mirroringactivation_crossed_conflict). - Concurrent duplicate records must serialize to exactly one winner; losers observe the winner.
- Timestamp doctrine (blocker M3, but the invariant holds regardless): a timestamp may live in
record_hashonly because the receipt is idempotent on stable, non-timestamp identity — so two nodes replaying the same logical plan converge on the original receipt (original timestamp, original hash) rather than minting divergent wall-clock hashes. Local wall-clock must not be an input to any cross-node-deterministic identity (per #2283/#2284). Theactivation_record_hashlink is a content-addressed hash, so it introduces no node-local nondeterminism.
10. Privacy boundary
- No plan body text, operation list, target object list, or effect payload in the receipt — a caller-supplied
body_hashfingerprints theMutationPlanbody; the body itself is never stored (exactly as Deliberation/Decision storebody_hashand never the body). - The kernel never reads the plan semantically; the receipt carries no kernel-readable operation content (meaning-firewall discipline).
- Only hashes, opaque ids, DIDs, and repo-safe metadata are carried.
- Any private content behind a
MutationPlanstays fixture-safe or redacted; the receipt proves a plan was recorded, not that all audiences may read its contents. - A future evidence/export summary of a plan receipt must be a repo-safe fixture summary (the #2289/#2291 pattern:
record_hash/body_hashproof pointers with redaction reasons, never private text).
11. Authority non-claim
Recording a mutation plan records an institutional fact and grants zero authority. recorded_by is the recorder of the plan — recorder evidence, not an authority to plan, to act, or to apply anything. A recorded plan is not an approval to apply it, not a mandate, not a capability, and not a kernel-enforced permission. Whether the plan may ever be applied is a charter/gate/authority question strictly upstream of this type and deferred to later rungs. The receipt witnesses "a plan was recorded here," nothing more.
12. Validation plan (for the future implementation PR)
The implementation PR must include both test tiers the landed classes use:
proof.rsunit tests: a golden vector pinning the v1record_hashof a fixed sample; a determinism test (same inputs ⇒ same hash); a per-field test (every field change — includingactivation_record_hashandbody_hash— ⇒ different hash); and a tag-disjointness test assertingicn:gov:mutation_plan_recorded:v1never collides with — and carries a comment that it must never converge with —activation_crossed,decision_recorded,process_gate_result, and the proposal/voteicn:gov:decision:vNlineage.- Runtime-slice integration test (mirror
activation_crossed_receipt_runtime_slice.rs): emission + field round-trip + non-zerorecord_hash+ retrieval; same-identity retry returns original, never restamped; different-activation_id/activation_record_hash/recorded_by/body_hashconflicts fail closed; unopened-session fails closed and creates nothing; empty/whitespace ids rejected pre-persistence; missing receipt store / backend failure fail closed; concurrent duplicates serialize to one winner; composite key injective (no aliasing); two domains sharing asession_idnever mix. - Activation-reference precondition test: the referenced
ActivationCrossedReceipt(byactivation_record_hash) must exist in the same(domain_id, session_id)and itsactivation_idmust match; an absent, wrong-session, wrong-domain, oractivation_id-mismatched reference is refused fail-closed and persists nothing (mirroring the #2295 B1 verified-not-asserted test). - Privacy grep: no plan body / operation list / target / effect text in any serialized receipt or fixture — fingerprints only.
- No-overclaim grep: no "mutation applied / plan applied / production / pilot / organizer-ready / member-ready / live federation / NYCN / Phase-2" claims introduced by the change.
- ADR-0026 envelope check: the receipt sits at Layer 2, self-hashed, no signature/merkle inheritance claim (§7).
- Protected close-keyword grep: the implementation PR carries no closing keyword adjacent to a protected issue number —
Refsonly.
13. Deferred work (explicitly out of scope of this contract and its future implementation)
MutationAppliedReceipt— the receipt that would witness a mutation actually applied (the plan executed, with real effects). This contract stops strictly at plan recorded; applying a plan, and any receipt of application, is a separate, later rung.EvidencePacketProducedReceipt— a runtime evidence-packet producer.- Any typed, kernel-readable
MutationPlanoperation model,target_ref/effect_refon the receipt, orPreviewReviewPacketruntime type (see §14 M2). - The actual #2041 human/AT pass (screen-reader / low-vision / switch / AT-compat) — parked for a real human-testing phase.
- Member-shell / process-evidence rendering of
MutationPlanRecordedReceipt(§15). - Production / pilot / NYCN activation / live federation / Phase-2 work.
- Action-card triggers (ADR-0027 / #1713); entity-auth enforcement (#2081), trusted token issuance (#2080), UnknownLegacy repair (#2274); service hosting, K3s/DNS/Forgejo.
14. Implementation sequencing
Implementation cannot begin from this contract alone. Mirroring the activation lane (#2294 contract → #2295 decision rung → #2296 implementation), the blockers below have no existing seam and should be resolved by a narrow decision rung (a sibling decision doc, in the activation-crossed-receipt-decision-rung.md cadence) before an implementation PR:
- M1 — plan → activation reference posture. Does
MutationPlanRecordedReceiptname the activation it follows byactivation_id, byactivation_record_hash, or both? (This contract's candidate: both, verified fail-closed, mirroring the #2295 B1 decision.) And: is the activation link sufficient, or must the plan also directly reference the decision and/or gate basis? (Candidate: activation link only; decision + gate basis are inherited transitively through the activation.) - M2 — plan-body representation. Is the receipt
body_hash-only (like deliberation/decision), or does it carry a typed minimal operation/target model? (Candidate:body_hash-only for:v1— preserves the meaning firewall and privacy; the plan body and anyPreviewReviewPacket/typed-operation model stay app-side and are not stored by the receipt.) And: is a plan-kind taxonomy (à laDeliberationEntryKind/ProcessGateKind) needed? (Candidate: no kind in:v1.) - M3 — plan timestamp source. Caller-supplied
recorded_atexcluded from identity (current receipt pattern), consistent with the #2295 B3 decision. *(Candidate: singlerecorded_at, hashed, excluded from identity; no distinctplanned_at.)*
Recommendation (Option C, matching the ActivationCrossed lane cadence): land this design/audit contract; then a narrow decision doc resolving M1/M2/M3; only then a contract-conformant implementation PR. The implementation PR must keep #1748 / #2141 / #2041 open unless separately reviewed, and must leave its issue open for maintainer disposition rather than auto-closing it by side effect.
15. Member-shell / evidence-surface follow-up
Recommendation: defer rendering. Member-shell rendering is out of scope for the design contract, the decision rung, and the first implementation PR. The #2291 / #2298 process-evidence surface is fixture-only and read-only; wiring a real MutationPlanRecordedReceipt into it should follow the receipt landing, as a later, separately-scoped fixture-only surface extension (exactly as #2298 did for ActivationCrossedReceipt after #2296), and must preserve the redaction/privacy discipline (proof pointers only, no plan body text) and the doctrine that the receipt records a process fact and grants zero authority.
16. Non-goals
Restated from #2299 — this contract and its future implementation are:
- not
MutationAppliedReceipt; not mutation application; not applying any plan; - not
EvidencePacketProducedReceipt; not an evidence-packet producer; - not an action-card trigger; not a general workflow engine; not a policy/authority engine;
- not a new
ProcessGateKind; not anActivationRequestobject; not new authorization semantics; - not OpenAPI / SDK / served-schema work; not member-shell implementation;
- not #2041 completion; not human/AT execution;
- not production / pilot / organizer-ready / member-ready readiness; not live federation; not NYCN activation; not Phase-2 completion;
- not proposal / vote / quorum / mandate / outcome semantics;
- not #2081 / #2080 / #2274; not entity-auth enforcement; not trusted token issuance; not UnknownLegacy repair; not service hosting; not K3s/DNS/Forgejo.
Receipts record institutional facts. They grant zero authority.
17. Related
Refs #2299. Refs #1748. Refs #2141. Refs #2041. Refs #2296. Refs #2298.