ICN Organizational Technical Alpha — Control Plan
What this document is. One navigable reconstruction of the entire Organizational Technical Alpha program: the bounded claim, the proof chain, the dependency graph, the containment ledger, and the owner boundaries. It exists so that a maintainer who has never seen a planning conversation can reconstruct the program from the repository alone.
What this document is not. It is not a truth owner. It owns no domain fact. Every status below is a snapshot taken at one revision, and
ops/state/truth/sources.jsonroutes each underlying fact to its real owner. Where this document and an owner disagree, the owner wins and this document is the stale layer.Live state is owned by
live_issue_state/live_pr_state/live_ci_state(github-api), not by this file. Re-resolve withghbefore acting on any status here. Snapshot revision:82030804dc26003bf7e1d6e289166989108bcd63, taken 2026-09-13.Post-snapshot addenda. A row that changed because of the commit carrying it is marked inline as a post-snapshot addendum rather than silently refreshed, so this file never reads as a single reproducible snapshot when it is really mixed. Re-taking the snapshot means re-verifying every row, which is a deliberate act and not a side effect of one row moving.
1. The bounded claim
The Technical Alpha is not "make ICN production ready." It is one bounded, independently witnessed proof at one exact reviewed revision and profile.
The strongest intended eventual claim, in full:
On one exact reviewed ICN Alpha profile, a fresh context-scoped human Subject used a separately keyed, explicitly delegated device Principal to act as a recognized member of an institution; that standing authorized participation in a frozen governance process over one exact bounded resource action; the resulting decision was cryptographically committed to a canonical decision hash; existing ICN economic and execution machinery carried that same hash through the bounded resource action and retained provenance; an independent Node B verified the retained evidence offline while Node A was unreachable; and the verifier/recovery node subsequently survived the separately specified encrypted destroy/restore proof.
Anything stronger is not part of A1 unless added through reviewed owner work.
The program's own exit criteria are owned by icn#2689 section 10 — seventeen checkboxes, all unchecked at this snapshot. They are not duplicated here.
Standing non-claims
A1 does not claim any of:
- production readiness, availability, or operational maturity;
- federation, multi-institution operation, or cross-institution identity;
- that a contained defect is fixed;
- hot or live backup;
- generalized N3/N4/N5 protocol completeness;
- that any downstream repository lock is human-signed;
- that an HTTP fetch from Node A constitutes independent verification;
- native cryptographic binding between a governance decision and a ledger entry (see 6.4 — this specifically does not exist today).
2. Proof chain, with every arrow resolved
Each arrow resolves to exactly one of: an existing reviewed owner primitive, a bounded implementation slice, an explicit containment, or an explicit non-claim. There is no "then somehow this works" edge.
| # | Link | Resolves to | State at snapshot |
|---|---|---|---|
| 1 | substrate to reproducible node/profile | appliance image + manifest; icnctl appliance verify-manifest |
EXISTS; (post-snapshot addendum) ADR-0086 reached status: accepted on 2026-09-15 through ADR-0018's lifecycle and the profile is frozen at 860c6f6c22f1; at the snapshot revision it was still proposed. implementation_status remains a separate axis and is still partially implemented |
| 2 | to two-node communication | isolated QEMU topology in the two-node plan | EXISTS (plan, Canonical: no) |
| 3 | to institution package/domain | InstitutionBootstrapManifest (icn-governance/src/bootstrap.rs:14); icnctl institution runtime-root |
EXISTS but disclaims canonical institution genesis (6.6) |
| 4 | to fresh current-semantic human Subject | SubjectContextGenesisV1 |
SLICE — icn#2695 (design-reviewed, unimplemented) |
| 5 | to separately keyed delegated device Principal | DeviceGrant (icn-identity/src/authority_log/derive.rs:25) |
PRIMITIVE EXISTS; unreferenced outside icn-identity |
| 6 | to explicit institutional recognition | SubjectRecognitionV1 |
SLICE — no owner issue |
| 7 | to frozen governance process | VotingProcessSnapshotV1 |
SLICE — no owner issue |
| 8 | to exact bounded resource-action commitment | SemanticProposalCommitmentV1 |
SLICE — no owner issue |
| 9 | to signed Subject ballot(s) | MemberVoteActionV1 + immutable ballot slot |
SLICE — no owner issue |
| 10 | to deterministic tally | SubjectVoteSetHashV1 + tally |
SLICE — no owner issue |
| 11 | to GovernanceDecisionReceiptV4 |
V4 | DOES NOT EXIST. V1 evidence is path-dependent across five separable surfaces — Rejected/NoQuorum construct no gate or chain-store V1 but do produce a signed V1 inside durable proof_bytes when a signing key is configured; non-executing and forced-accept closes persist no chain-store V1 (matrix in 6.3). A1 must pin a close path on two axes: decision-hash-addressable and proposal-id-addressable evidence are different things. |
| 12 | to canonical decision_hash |
compute_decision_hash_bytes (icn-governance/src/proof.rs:300) |
EXISTS and exposes canonical bytes |
| 13 | to existing AllocationReceipt |
icn-kernel-api/src/receipts.rs:121 |
EXISTS; canonical bytes private (6.2); unsigned in practice |
| 14 | to existing SettlementIntent |
icn-kernel-api/src/economics.rs:80 |
EXISTS; canonical bytes private; no signature field |
| 15 | to execution | ExecutionRecord (execution.rs:78) |
EXISTS; mutable operational state, not a canonical receipt |
| 16 | to ledger/provenance evidence | JournalEntry + ProvenanceRef |
EXISTS; provenance is not in the hash and not signed (6.4) |
| 17 | to self-contained offline evidence | offline bundle contract | SLICE — icn#2465 (spec only, no implementation) |
| 18 | to Node A unreachable | two-node plan Gate 4 step 5 is literally "Disconnect Node A" — isolation, not a service or VM stop | Gate 4 BLOCKED |
| 19 | to Node B independently verifies | reviewed offline verifier | SLICE — icn#2465 |
| 20 | to encrypted destroy/restore continuity | recovery bundle | SLICE — icn#2466; Gate 6 BLOCKED |
| 21 | to same evidence still independently verifiable | re-run of 19 post-restore | depends on 19 + 20 |
Eleven of twenty-one links are unbuilt. Links 11, 13, 14 and 16 carry concrete owner problems documented in section 6, not merely missing code.
3. Dependency DAG
SAFETY / CORRECTNESS FRONTIER
|
v
EXACT ALPHA DEPLOYMENT PROFILE
|
+--------------+--------------+
v v v
icn#2694 icn#2465 icn#2466
semantic offline recovery
convergence evidence proof
| | |
| | |
+--------------+--------------+
v
TWO-NODE A1 WITNESS
v
FREEZE EXACT SHA/PROFILE
v
NYCN LOCK BUMP
v
HUMAN REHEARSAL / A11Y
v
BOUNDED PUBLIC CLAIM
This diagram is reconciled, not immutable. Two edges are sharper than the ASCII suggests:
- #2465 depends on #2694 for its subject matter (there is no decision receipt to export until the ladder produces one), but its substrate work (slice B) does not — that can start immediately. Slice A is conditional and gates nothing until the verifier model selects a cross-language or raw-preimage requirement (5.6, 6.2).
- #2466 is independent of #2694 entirely. It is a sovereignty proof about node state, not about semantics.
4. icn#2694 — semantic convergence ladder
The missing proof is generation convergence, not invention of another economic system. The target path, in the issue's own vocabulary:
context-bound N1 Subject genesis -> N1 device authorization
-> institutional Subject recognition -> context-scoped session
-> immutable voting-process snapshot -> preview
-> device-signed member vote action -> immutable Subject ballot
-> Subject tally -> GovernanceDecisionReceiptV4 -> canonical decision_hash
-> existing AllocationReceipt -> existing SettlementIntent
-> existing ExecutionRecord -> existing journal/provenance
-> offline evidence bundle
#2694 states that each numbered item becomes a bounded child issue only when its direct owner contracts have been reverified and implementation is authorized. That gate has fired exactly once.
| # | Slice | Owner issue | Upstream contract owner | State |
|---|---|---|---|---|
| 1 | GEN-A context binding + SubjectContextGenesisV1 |
icn#2695 | #2602 GEN | OPEN, status:needs-design, design-reviewed, unimplemented |
| 2 | N1-D restart-durable AuthorityFactStore |
none | #2607 | named by #2695 as the next child |
| 3 | GEN-B SubjectRecognitionV1 |
none | #2602 GEN | unowned |
| 4 | HumanActorModel / legacy-rail firewall |
none | — | unowned; appears in no other issue |
| 5 | N4-alpha relying-party prefix evaluation | none | #2599 N4 | unowned |
| 6 | G1-A commitment + frozen VotingProcessSnapshotV1 |
none | #2600 G1 | unowned |
| 7 | context-aware session rail | none | — | unowned; no artifact name |
| 8 | N5-A MemberVoteActionV1 + ballot slot |
none | #2605 N5 | unowned |
| 9 | Subject vote-set hash + deterministic tally | none | — | unowned |
| 10 | GovernanceDecisionReceiptV4 |
none | — | unowned; see 6.3 |
| 11 | V4 decision_hash through the economic chain |
none | #2625 identifier domain | unowned |
| 12 | offline evidence convergence | partially #2465 / #2466 | — | composition step itself unowned |
None of the twelve artifact names exists in icn/crates or icn/apps at this
revision. No PR references #2694 or #2695.
5. icn#2465 — offline evidence architecture
5.1 Architecture
bundle transport / exact bytes
|
v
existing owner artifact verification
|
v
cross-artifact binding verification
|
v
externally pinned A1 policy
|
v
composed verdict
Do not invent a parallel evidence ontology. The repository already owns the
verdict vocabulary: VerificationStatus at
icn/crates/icn-governance/src/verify.rs:46 — Pass / Fail / Unresolved /
NotApplicable, fail-closed, with fold severity
Fail > Unresolved > Pass > NotApplicable. Normative spec:
docs/spec/receipt-chain-verification.md (status: draft). Reuse it; do not mint
a second verdict set.
Keep distinct: integrity, authenticity, authorization, legitimacy.
verify.rs is explicit that a Pass means integrity — and authenticity when keyed
— and never authorization or legitimacy.
5.2 Two hard criteria (verbatim, do not weaken)
- The bundle exports no DIDs or credentials beyond the producer identity the contract explicitly requires.
- Verification never falls back to contacting the producer — a network call in the verify path is a defect, not a convenience.
Neither admits tiering. Missing required evidence yields Unresolved or failure —
never a network lookup. No gateway URL, no producer callback, no remote DID
resolver, no HTTP client anywhere in the verify path.
If the chosen A1 economic action cannot satisfy the privacy criterion, that is a concrete owner/integration problem to surface — not a licence to redact a security-critical owner-canonical field and still call it independently verifiable.
5.3 Evidence strength — additive planning vocabulary
This taxonomy does not exist in the repository. It is proposed here, not established.
| Tier | Meaning | Expected members |
|---|---|---|
OwnerCanonical |
owner computes and owns the canonical identity | GovernanceDecisionReceiptV4, AllocationReceipt, SettlementIntent |
OwnerAuthenticated |
owner-canonical and signed by a named key | none today — see 6.2 |
ProducerAttestedSnapshot |
producer asserts it exported this view | ExecutionEvidenceSnapshotV1, JournalProvenanceWitnessV1 |
It must not be used to soften 5.2.
5.4 Two digest meanings — never collapse
| Meaning | Algorithm today | Subject |
|---|---|---|
| owner canonical identity | blake3 over bincode (receipts.rs:100); blake3 over a domain-tagged stream (governance) |
domain-semantic identity |
| exact exported payload | SHA-256 | these exact bytes were retained/exported |
These are different algorithms over different subjects. Conflating them is a defect, because canonical hashes intentionally exclude fields — see 6.2.
5.5 Producer attestation
A producer signature means "this producer exported this exact manifest/artifact-byte set." It does not mean "everything in this bundle is legitimate." Policy and trust are pinned externally; the bundle must not choose how it is judged:
verify_offline_bundle(retained_bundle, externally_pinned_policy, externally_pinned_trust)
5.6 Decomposition
#2465 defines no bounded slices. A search of 400 issues found zero hits for
TechnicalAlphaA1Policy, RecoveryBundle, JournalProvenanceWitness or
ExecutionEvidenceSnapshot — in issues or in the checkout.
| Slice | Scope | Owner |
|---|---|---|
| A owner canonical export surfaces | expose owner-controlled canonical bytes for AllocationReceipt / SettlementIntent |
CONDITIONAL — do not schedule yet. Needed only if A1 selects a cross-language/non-linking verifier or a raw-preimage requirement (6.2). A Rust-linked verifier recomputes through the public trait, and 5.4's SHA-256 over the exported payload already catches changes to excluded fields such as memo. |
| B deterministic generic offline-bundle substrate | byte-stable bundle, digest manifest, no network | needs an issue |
| C bounded A1 execution/journal evidence adapters | ExecutionEvidenceSnapshotV1, JournalProvenanceWitnessV1 |
needs an issue |
D TechnicalAlphaA1PolicyV1 + composed proof |
externally pinned policy, tamper-negative test | needs an issue |
Slice A must not change the semantic hashes of those types merely to support export, and must not be scheduled at all until the A1 verifier model picks one of the two narrower requirements in 6.2. Together, the owner hash (recomputed through the public trait) and the exported-payload SHA-256 already cover both canonical-field tampering and tampering with fields the canonical hash excludes.
6. Owner boundaries, seams, and live contradictions
This section records what the code actually does. It is the part most likely to invalidate planning vocabulary.
6.1 No registered owner for economics
ops/state/truth/sources.json has 26 domains, and only two touch this proof
chain: identity_semantics (docs/architecture/IDENTITY_SEMANTICS.md) and
adr_decisions (docs/adr/). There is no registered truth domain for receipts,
provenance, ledger, settlement, treasury or economics. For those, the ADRs plus
the code are the only authority.
6.2 Canonical bytes are private for both economic receipts
AllocationReceiptCanonical (receipts.rs:148) and SettlementIntentCanonical
(economics.rs:122) are module-private, and no API returns the preimage
bytes — only the blake3 digest escapes. The governance path is the opposite:
compute_decision_hash_bytes (proof.rs:300) is pub.
This is not a blocker for every verifier, and an earlier revision overstated
it. AllocationReceipt, SettlementIntent and CanonicalReceipt are all
publicly re-exported (lib.rs:83, :121), so a Rust verifier that links
icn-kernel-api recomputes owner hashes through the public trait, exactly as
the gateway already does (receipt_store.rs:504, api/receipts.rs:65). Slice A
is therefore not a precondition for a Rust-linked verifier.
It remains a real limitation for exactly two cases, and A1 should state which it needs:
- a cross-language or non-linking verifier, which would have to
reverse-engineer an unpublished bincode layout — field order, the exclusion of
receipt_id/signature, and the sorting ofintent_hashes; - any verifier needing raw preimage bytes for a byte-level tamper manifest, since no public surface yields them.
Two live traps for any bundle contract, stated per type because they differ:
AllocationReceipt::canonical_hashsorts intent hashes, so the canonical identity is order-independent. Itssignatureis#[serde(skip_serializing_if = "Option::is_none")]— serialized whenever present, not skipped — so an exported payload does carry a signature that the canonical hash excludes.SettlementIntenthas no signature field at all. Onlyintent_idis#[serde(skip)];memoisskip_serializing_if, so it is exported when present while being excluded from the canonical hash.
So the exported payload is strictly wider than the canonical preimage, and
mutating memo leaves canonical_hash unchanged. A digest manifest covering
only canonical hashes would therefore pass #2465's "flip one byte, must fail"
criterion on a genuinely tampered bundle.
This is not an argument for slice A, and an earlier revision wrongly called it
"the sharpest reason slice A exists." Exposing the owner-canonical preimage cannot
detect a changed memo either — SettlementIntentCanonical excludes that field
for exactly the same reason canonical_hash does. The mutation is caught by
5.4's SHA-256 over the exact exported payload, which is a separate mechanism
and needs no new API. Slice A's justification rests solely on the two narrower
requirements above, if A1 selects one.
Also: AllocationReceipt::with_signature has no production caller (unsigned in
practice), and SettlementIntent has no signature field at all. Hence
OwnerAuthenticated in 5.3 currently has no members.
6.3 Governance receipt versions
V1 (proof.rs:226), V2 (:541, defined but never emitted), V3 (:820).
V4 does not exist — zero repo-wide hits for ReceiptV4.
An earlier revision of this document described the seam as "V3 emitted, V1
persisted." Review corrected that, and re-verification against main agrees.
The accurate shape is:
Treating "V1 constructed" and "V1 persisted" as one property is too coarse: there are five separable surfaces, and no close path has all of them.
- gate/hash V1 — a receipt built only to derive the gate/decision hash, never stored
- chain-store V1 — persisted via
put_governance(decision-hash addressable) - V1 inside
GovernanceProofV2— a receipt constructed during proof construction - durable
proof_bytes— those signed proof bytes written to the proposal state store - V3 — persisted opaquely via
put_opaque
| Close path | gate V1 | chain-store V1 | V1-in-ProofV2 | durable proof_bytes | V3 |
|---|---|---|---|---|---|
| Actor Accepted, non-exec-required | yes | no | if signing_key |
if signing_key |
if capability_scope and receipt_store |
| Actor Accepted, exec-required | yes | yes (fatal on failure) | if signing_key |
if signing_key |
if capability_scope |
| Actor Rejected | no | no | if signing_key |
if signing_key |
if capability_scope + receipt_store |
| Actor NoQuorum | no | no | if signing_key |
if signing_key |
if capability_scope + receipt_store |
| Timer / scheduler | by outcome | by outcome | if signing_key |
if signing_key |
never — capability_scope: None is hardcoded |
ForceCloseProposal |
Accept only | no | no | no — bare save_proposal, no journal |
no |
GovernanceManager::close_proposal_inner |
n/a | yes, all outcomes (requires receipt_store) |
no | no | if capability_scope |
The proof path is gated on signing_key alone — not on outcome, not on
receipt_store, not on capability_scope — and it covers all three terminal
outcomes. Its bytes are genuinely durable: close journal save_close_intent
then commit then save_proof_bytes, landing under the sled key
governance:proof:{proposal_id}.
So "no chain-store persistence" does not mean "no durable V1." An
actor-driven Rejected, NoQuorum or non-execution-required Accepted close writes a
complete signed GovernanceDecisionReceipt inside proof_bytes while
put_governance is never called.
But that evidence is differently addressable: it lives in the proposal state
store rather than the receipt backend, under a proposal-id key, behind a
different reader, and it carries no decision_hash index. The chain read
surfaces — get_governance_by_decision, the receipt-chain endpoint, and
icnctl audit verify — structurally cannot see it.
- V3 is emitted conditionally and additionally, not as a replacement:
actor.rs:2561gates on a presentcapability_scopeand a configured receipt store. - V3 is persisted, but opaquely —
receipt_backend.rs:509writes it throughput_opaque, so it never crosses the gateway's typed boundary. - The real seam is the read surface. The gateway store's typed API is V1 only
(
receipt_store.rs:386put_governance,:426get_governance), andicnctl audit verifyrecomputes the V1 decision hash (icnctl/src/main.rs:12752) through a localverify_receipt_chain(:12702) rather than throughicn-governance::verify.
So a V4 does not have to reconcile a persistence mismatch. It has to decide what the typed chain/audit read surface returns, whether conditional V3 emission becomes unconditional, and whether decision-hash-addressable evidence is required at all when proposal-id-addressable signed evidence already exists.
A1 must pin a close path on two independent axes, not one:
signing_key: Somebuys proposal-id-addressable V1 evidence for every terminal outcome, viaproof_bytes;- only execution-required Accepted (actor), or any outcome under the standalone manager with a receipt store, buys decision-hash-addressable chain evidence.
If the A1 read surface is decision-hash-keyed — which every existing chain reader
is — the proof-bytes route does not satisfy it. Note also that signing_key
is a node-configuration fact, not a governance fact, so this evidence's existence
depends on deployment wiring rather than on the decision itself.
A stale comment at proof.rs:817 still reads "No handler emits a v3 receipt yet
— this is schema preparation only." That is now false, and is recorded here as a
follow-up rather than fixed, because this is a control-plane document and that is
a Rust change.
6.4 The ledger provenance limitation — be exact
compute_entry_hash (icn-ledger/src/hash.rs:9) is serde_json then SHA-256 over
HashableEntry (hash.rs:37-45), which carries timestamp, author, contract_ref, accounts, parents, nonce. ProvenanceRef is absent. sign_entry
(entry.rs:28) signs entry.id.
Therefore: the author signature does not bind the governance decision_hash.
Provenance can be altered without invalidating either the hash or the signature.
An earlier revision went further and said no production code cross-verifies the correspondence at all, and that the gateway "only echoes" the hash. That was wrong. Correspondence is checked, at three clearly different strengths — A1 should neither duplicate the real ones nor inherit the weak one:
| Strength | Where | What it establishes |
|---|---|---|
| Existence — real | gateway loads the receipt by hash (api/receipts.rs:397) |
a hash with no stored receipt yields governance: None and fails closed (icnctl/src/main.rs:12628) |
| Self-consistency by recomputation — real | recompute_decision_hash_matches (main.rs:12617), surfaced as "Decision hash integrity (recomputed)" (:12752) |
the V1 hash rebuilt from proposal_id/domain_id/outcome/tally/vote_hash matches |
| Journal-to-decision linkage — NOT established | "check 13" (main.rs:12909) |
tautological. The gateway selects entries by that predicate (api/receipts.rs:515), so no entry with a different hash can be in the set. A filter restated as an assertion. |
None of it is cryptographic: vote_hash and the tally come from the gateway
response and are never checked against actual votes, and the receipt carries no
verified signature. The recompute proves internal consistency of server-supplied
fields, not authorization — as its own comment concedes. The A1 position is
therefore unchanged in substance — the governance-to-ledger link is not
owner-authenticated — but the plan must not claim the correspondence is wholly
unchecked.
Do not rewrite ledger identity casually, and do not claim native cryptographic
strength that does not exist. For A1 the bounded evidence architecture may use a
producer-attested witness connecting entry_hash, decision_hash and
provenance_kind, while explicitly reporting that proof strength. A future
owner-defined governance-to-ledger binding receipt may supersede it.
6.5 Three incompatible canonical-hash schemes
| Layer | Scheme |
|---|---|
| kernel-api receipts | bincode then blake3 |
| governance proof | domain-tagged byte stream then blake3 |
| ledger journal | serde_json then SHA-256 |
No single re-verification primitive spans them. A bundle verifier must dispatch per artifact class rather than assume one hash function.
6.6 Institution genesis is not canonical yet
icnctl institution runtime-root (shipped in #2744/#2749) creates two keystores, a
cooperative record, a treasury registration, trust edges and a receipt — but its
own doc comments disclaim canonical institution genesis: no EntityId, no
signed founding act, no institution DID, and genesis_authority_did is today the
same principal as node_did. It is not idempotent and not restartable. ADR-0083's
"runtime root" is a different, not-started concept.
6.7 The fail-closed verifier is wired to nothing
icn-governance/src/verify.rs is a four-valued fail-closed verifier with zero
callers repo-wide. But "just wire it up" understates the work, and an earlier
revision implied otherwise.
What it actually provides is a reusable verdict framework (the
VerificationStatus taxonomy and its fold) plus a V1 receipt verifier: its
public functions cover the unversioned V1 GovernanceDecisionReceipt, the legacy
GovernanceProof, generic chain links and hash-conflict claims. There are no
V2/V3/V4 adapters, and none for AllocationReceipt, SettlementIntent,
execution, or the journal — the module's own header records per-ladder recompute
shims as follow-up.
So A1 should reuse the verdict framework and the V1 path rather than mint a third verification vocabulary, and must schedule the missing adapters explicitly as part of #2465 slice C. The gap is adapter work, not wiring.
6.8 Identity primitives exist but are unreferenced
N1's authority log (icn-identity/src/authority_log/) is described by its owner as
"a library primitive only" with zero references outside icn-identity.
AuthorityFactStore, SubjectContextGenesis, SubjectRecognition,
HumanActorModel, VotingProcessSnapshot, MemberVoteAction and
SubjectVoteSetHash do not exist in code. Session authority exists under
different names (SessionAuthority, AuthorityProfile, AuthorityCapabilities in
icn-gateway/src/session_authority.rs). ScopeLevel is network reach, not
authority — do not conflate. NodeId is pub type NodeId = String; Node has no
durable domain.
6.10 Gate 5 is not an executable sequence as written
This contradiction is in the linked source procedure, not introduced here, and this plan exposes rather than repairs it — correcting it is the two-node plan's own change, not #2783's.
docs/demo/TWO_NODE_APPLIANCE_PROOF_V0.2_PLAN.md Gate 5 requires all three of:
| Step | Requirement |
|---|---|
| 2 | restart icnd; wait for authenticated health and peer reconnection |
| 3 | re-run receipt verification on Node B while Node A remains disconnected |
| 4 | reboot both VMs; wait for first-boot marker, active service and peer reconnection |
Steps 2 and 4 require the peer link to be up; step 3 requires it to be down. No single run satisfies all three as written, so Gate 5 cannot be executed and the critical path is blocked at it.
The owner decision that must be made — one of:
- offline isolation ends after Gate 4, the witness link is restored, and Gate 5 proves restart/reboot continuity rather than continued isolation (step 3's "while Node A remains disconnected" is then the clause to drop or reword); or
- Gate 5's intended topology is genuinely isolated, in which case steps 2 and 4 must stop requiring peer reconnection and the source procedure is corrected.
Until that is decided, this plan does not present Gate 5 as runnable, and no A1 claim may depend on having passed it.
6.9 Unresolved owner contradictions
- Two competing decompositions. #2694 defines a 12-step semantic ladder. #2689's 2026-09-02 checkpoint defines an overlapping P0-P10 proof ladder with six lanes, adds N3-A two-node authority reconciliation (which #2694 explicitly non-goals) and a mobile edge. Neither supersedes the other in writing. #2689's body still describes the older four-lane model. A maintainer decision is required.
ops/state/truth/program.jsondoes not exist onmain. A checkpoint claimed the ladder was "durably encoded" in a registeredprogram_structuredomain. It is not. Verified at this snapshot: the file is absent frommain,sources.jsonregisters noprogram_structuredomain, and PR #2690 (OPEN) carries bothops/state/truth/program.jsonand asources.jsonchange among its fifteen files. Note #2690's headline contract is the agent registry, so the program surface rides along inside a PR about something else — which is part of why it has not landed. Until it does, the only durable record of the ladder is the #2694 issue body and this document. This document deliberately does not create a competing machine-readable program surface; when #2690 lands, this file should link to it rather than duplicate it.- The typed chain/audit read surface is V1-only (6.3). The dataflow is now traced, and the earlier "V3 emitted / V1 persisted" model is disproven — V3 is persisted, opaquely. What remains unresolved is what a V4 read surface should return, and whether decision-hash-addressable evidence is required when proposal-id-addressable signed evidence already exists.
- The two-node plan is
Canonical: no, last reviewed 2026-07-27 — predating #2689. (Post-snapshot addendum.) It references ADR-0086, which was accepted 2026-09-15; at the snapshot revision that status was stillproposed. The two-node plan's ownCanonical: noand review date are what remain stale here, not the ADR's status.
7. icn#2466 — recovery
A separate sovereignty proof, independent of #2694.
#2466 specifies no field list and no ordered ceremony — it specifies a drill plus
invariants. The expected artifact shape (planning vocabulary, RecoveryBundleV1)
is: exact profile/revision, encrypted state, encrypted effective secret material,
node identity commitment, config commitment, institutional/runtime-root
commitments, retained evidence commitments, extent/completeness manifest, bundle
root digest.
Its binding invariants, which are from the issue: secrets never written to an unencrypted archive at any point including temporary files; an explicit custody model; restore into a fresh overlay assumes the prior node's identity, state and relationships and reopens its keystore without operator re-entry outside the documented custody path; continuity asserted over identity, machine ID, configuration and genesis hashes; missing required material refuses to restore rather than half-restoring.
capture known state -> encrypt -> destroy/remove Node B
-> recreate from fresh appliance overlay -> restore -> reopen keystore
-> compare identity/config/state commitments
-> independently verify retained Alpha evidence again
Do not claim hot backup. Do not let recovered-prefix behaviour masquerade as complete recovery proof.
Completeness dependencies
| Issue | Defect | Effect on recovery claims |
|---|---|---|
| icn#2746 | a truncated ledger reopens via sled recovery and scans short without error, and nothing in the artifact distinguishes that from a ledger that always held that many | Still blocks completeness. (Post-snapshot addendum — see the note under the snapshot revision above; the rest of this row's evidence predates it.) At the snapshot revision the verifier still printed BACKUP VERIFICATION PASSED for a short ledger. icn#2787 stops that overclaim — it reports ledger completeness: unresolved and fails closed instead of certifying — which removes a false positive without being detection. A backup-time extent record does not close this: if the damage precedes the backup the count records the already-reduced extent, and post-capture damage is already caught by the whole-directory checksum. Detection needs an independent commitment that advances on append and survives loss of the journal: icn#2786. |
| icn#2739 | the verifier writes into the tree it inspects (sled has no read-only open; the N2-A gate writes into the audited tree) | Caps claim strength, does not falsify it. Blocks "verified a write-protected medium" and "two verifications observed the same bytes". |
Note also: CI invokes the weak verify-backup form, without --verify-ledger
(.github/workflows/ci.yml:530), and the command prints its own non-claims at
icnctl/src/main.rs:7133-7134.
8. Two-node roles
Node A institution host / producer / artifact source
Node B independent technical witness / verifier
Node B is not a second institution, not federation, not a production peer and not a governance participant. Two-institution operation requires a later ratified enrollment ceremony.
For offline evidence, Node A must actually be unreachable from Node B. The
selected procedure proves isolation, not shutdown: Gate 4 step 5 is
"Disconnect Node A", and nothing in it stops the service or the VM. This plan
therefore claims only what the procedure establishes — the verifier did not reach
Node A — and deliberately does not say "stopped", which would be a stronger
property nobody tests. Strengthening it would require changing the upstream
procedure, which is out of scope here. A Node B
curl back to Node A is transfer evidence only. The plan's Gate 4 step 5 is
literally "Disconnect Node A"; Gate 5 re-runs verification while Node A remains
disconnected.
For recovery, Node B is the natural destroy/restore witness.
9. Containment ledger
A contained flaw is not fixed. Each row names the exact profile restriction that prevents it from invalidating A1.
| Issue | Disposition | Containment / profile restriction |
|---|---|---|
| #2750 trust bloom scores persisted edges 0.0 | MUST FIX | None available. Rejects entries authored by the institution treasury principal at the ledger author-trust gate — directly on the A1 economic chain. |
| #2779 snapshot-delete path traversal | FIXED / LANDED (PR #2781, squash 08f5bc2cc) |
— |
| #2748 keystore files at umask | FIXED / LANDED (PR #2782, squash 82030804d) |
— |
| #2777 exclusion domain (#2758/#2759) | IN PROGRESS (draft PR) | — |
| #2746 truncated ledger certified complete | MUST FIX for #2466 | Cannot be contained if recovery completeness is claimed. |
| #2739 verifier writes the audited tree | CONTAIN | Claim recovery verification over a mutable copy; do not claim read-only-medium verification. |
| #2778 backup reads a data root with no exclusion | CONTAIN or FIX | Take A1 backups only with the node stopped. |
#2755 native icnd ignores runtime-root config |
MUST FIX, or pin a unit | The earlier entry excluded "the native service path", which is self-defeating: ADR-0086's appliance baseline is native systemd, and the two-node plan starts and restarts icnd under systemd in Gates 1, 2 and 5. Excluding it excludes the profile. The concrete defect is that deploy/icnd.service invokes icnd --data-dir ROOT without --config ROOT/icn.toml, so a provisioned runtime root has no effect. Containment therefore requires a pinned unit or drop-in that passes the managed runtime-root configuration, recorded as a profile artifact — otherwise this is a required fix. |
#2747 init-coop emits an icn.toml icnd cannot load |
CONTAIN | A1 uses institution runtime-root, not init-coop. |
| #2757 no trusted bootstrap authority for first gateway token | CONTAIN | Single-institution A1; trusted-local mint only; no generalized remote bootstrap. |
| #2772 node-authority migration across DID change | EXCLUDE | A1 does not rotate the node DID. |
#2627 N2-A Did equality/hashing |
PARTIALLY LANDED | Owns the legacy compute_vote_hash DID-spelling defect; must be resolved before Subject ballots are trusted. |
| TIME / deadline semantics (#2601) | EXCLUDE | Explicitly out of Alpha scope. |
| vote amendments | EXCLUDE | Frozen process snapshot only. |
| cross-institution identity federation | EXCLUDE | Node B is a witness, not an institution. |
| generalized N3/N4/N5 | EXCLUDE | Only the N4-alpha prefix slice is in scope. |
| mobile / QR workflow | EXCLUDE | Not on the A1 chain. |
| generic installer claims | EXCLUDE | One pinned appliance profile only. |
| live / hot backup | EXCLUDE | Cold ceremony only. |
| historical DID-member migration | EXCLUDE | Fresh context-scoped Subjects only. |
Other .mode(0o600) creation sites (data_dir_lock.rs, institution_runtime_root.rs) reachable at mode 000 under an extreme umask |
FOLLOW-UP — not a blocker | Surfaced by the #2782 review and deliberately left outside #2748. .mode() is a request and mode & !umask can clear owner bits, so an extreme umask could make a lock anchor or runtime-root file unusable. It cannot invalidate A1 provided the pinned appliance profile fixes the service umask — confirm that at profile freeze. No owner issue yet; it needs one only if the profile does not pin the umask. |
10. Status snapshot
Program-level evidence maturity: how well-established a fact about the Alpha
is. This is a different axis from the per-PR delivery lifecycle, whose states and
transitions are owned by ops/state/truth/delivery.json — read them there. A PR
can be DONE on that axis while the fact it delivered is still only
LANDED / UNVERIFIED on this one.
The vocabulary below is this document's own, and is deliberately not a restatement of the owner's lifecycle.
| Term | Meaning |
|---|---|
| IDENTIFIED | a defect or need is described, nothing built |
| IMPLEMENTED / UNLANDED | code exists on a branch; not on main |
| LANDED / UNVERIFIED | merged to main; not exercised on the Alpha profile |
| VERIFIED | exercised and witnessed on the pinned profile |
| BLOCKED | cannot proceed until a named dependency resolves |
| CONTAINED | not fixed; excluded by a named profile restriction |
| DEFERRED | deliberately out of A1 |
How merge readiness is actually gated here
Recorded because the first pass guessed wrong and the #2781/#2782 merges settled
it. Live branch protection on main:
| Gate | Value |
|---|---|
required_approving_review_count |
0 — no second-identity approval is required |
required_conversation_resolution |
true — unresolved review threads block the merge |
strict |
true — the branch must be level with main, so every merge puts every other PR BEHIND |
enforce_admins |
true — no admin bypass |
| required contexts | 11 named checks. Security Audit and Compare Against Base are not among them. |
So a mergeStateStatus of BLOCKED on this repository usually means unresolved
threads, not red CI and not a missing approval; UNSTABLE means only
non-required checks are red. Read the protection API before concluding a PR is
waiting on a human.
Safety / correctness frontier
| Item | State | Evidence at snapshot |
|---|---|---|
| PR #2781 (#2779 traversal) | LANDED | merged as 08f5bc2cc; #2779 CLOSED/COMPLETED. |
| PR #2782 (#2748 keystore mode) | LANDED | merged as 82030804d; #2748 CLOSED/COMPLETED. Also normalises a newly created keystore, since .mode() is a request and a hostile umask can clear owner bits. |
| PR #2777 (#2758/#2759 exclusion) | IMPLEMENTED / UNLANDED | draft; mergeStateStatus: BLOCKED. |
| #2750 trust bloom filter | IDENTIFIED | no PR. Next correctness blocker. |
| #2746 / #2739 verify-backup | IDENTIFIED | no PR. |
| N2-A principal-state lane | LANDED / UNVERIFIED | #2700-#2716 merged; not exercised on an Alpha profile. |
| Institutional genesis (#2744) | LANDED / UNVERIFIED | merged as fc9e7b8b6 (#2749); disclaims canonical genesis (6.6). |
Alpha lanes
| Lane | State | Blocking fact |
|---|---|---|
| Deployment profile | FROZEN | (Post-snapshot addendum.) ADR-0086 was accepted 2026-09-15 and the Alpha profile is frozen at 860c6f6c22f18de0f7bc4cfb55e35b1143b3b4f1. Freeze prerequisites closed: icn#2755 (native + every shipped drop-in pass the provisioned configuration) and the UMask=0077 pin on both units that create icnd's files. implementation_status stays partially implemented — a separate axis. Two-node plan is still Canonical: no. |
| #2694 semantic convergence | IDENTIFIED | 1 of 12 slices owned (#2695); none implemented; no artifact exists in code. |
| #2465 offline evidence | IDENTIFIED | spec only; 0 of 4 slices owned. Slice A is conditional, not a blocker (5.6). |
| #2466 recovery | IDENTIFIED | spec only; completeness blocked by #2746. |
| Two-node witness | BLOCKED | Gate 4 and Gate 6 blocked; Gate 5 is not executable as written (6.10). |
| NYCN lock bump | BLOCKED | requires a frozen SHA and a human signature. |
| Public claim | BLOCKED | requires all seventeen #2689 section 10 criteria. |
11. Critical path and parallel work
Critical path
(Post-snapshot addendum: the first two rows below changed with the commit
carrying them. At the snapshot revision #2750 was the open blocker and the
profile freeze was pending status: accepted.)
#2750 MERGED 2026-09-14 (80a5faf2c) — was the ONLY uncontained defect here
v
Alpha profile freeze DONE 2026-09-15 -> frozen at 860c6f6c22f1
v
#2694 slice 1 (#2695 GEN-A) -> slice 2 (N1-D) -> ... -> slice 10 (V4)
v
V4 decision_hash through AllocationReceipt / SettlementIntent
v
#2465 slice C (execution/journal evidence adapters)
v
#2465 slice D (composes C; tamper-negative proof)
v
Gate 4 (Node A disconnected — isolation, not shutdown)
v
Gate 5 (restart + reboot continuity) <-- BLOCKED: see 6.10
v
#2466 -> Gate 6
v
freeze SHA -> NYCN lock -> rehearsal/a11y -> bounded public claim
Safely parallel right now
- #2465 slice B (bundle substrate) — generic and deterministic, and the only #2465 slice that is unconditionally ready. Slice A is conditional (5.6) and should not be started until the verifier model requires it.
- #2466 completeness prerequisite (#2746 extent record) — independent of #2694 entirely.
- #2627 DID-spelling defect in legacy
compute_vote_hash— must precede trusting Subject ballots. - Resolving the 6.9 decomposition contradiction — a maintainer decision, no code.
Blocked, not worth starting
Slices 3-12 of #2694 (each gated on its predecessor and on owner-contract reverification); #2465 slice C (needs the execution/journal shape the ladder produces); Gates 4, 5 and 6; anything downstream of the profile freeze.
12. Navigation
| Question | Authority |
|---|---|
| What is being worked on right now? | gh issue list / gh pr list — domain live_issue_state |
| Program control surface and exit criteria | icn#2689 |
| Semantic convergence ladder | icn#2694; GEN-A child icn#2695 |
| Offline evidence contract | icn#2465 |
| Encrypted recovery contract | icn#2466 |
| Two-node acceptance gates | docs/demo/TWO_NODE_APPLIANCE_PROOF_V0.2_PLAN.md (Canonical: no) |
| Identity semantics | docs/architecture/IDENTITY_SEMANTICS.md (normative) |
| Receipt/provenance envelope | docs/adr/ADR-0026-receipt-and-provenance-proof-envelope.md |
| Verification vocabulary | icn/crates/icn-governance/src/verify.rs; docs/spec/receipt-chain-verification.md |
| Fact ownership | ops/state/truth/sources.json |
| PR delivery lifecycle | ops/state/truth/delivery.json |
| Merge policy | ops/state/truth/policy.json |
| Contract document conventions | docs/contracts/ (.md + .schema.json + .example.json) |
13. Maintainer decisions outstanding
- Reconcile the two decompositions (6.9.1): #2694's 12-step ladder versus #2689's P0-P10 proof ladder. Pick one, or state how they compose. Until then the program has two disagreeing structures.
- Land or close PR #2690 (6.9.2), which carries the machine-readable
program_structuredomain this document deliberately does not duplicate. Move ADR-0086 to— RESOLVED 2026-09-15. Accepted through ADR-0018's lifecycle after the freeze prerequisites closed; the Alpha profile is frozen atstatus: accepted, or decline it860c6f6c22f18de0f7bc4cfb55e35b1143b3b4f1.implementation_statusremains partially implemented, which is a separate axis. Still open: whether the two-node plan should be promoted fromCanonical: no.- Decide what the typed chain/audit read surface returns (6.3) before a V4 is specified, and whether conditional V3 emission becomes unconditional first.
- Accept or reject the 5.3 evidence-strength taxonomy, which is proposed here and exists nowhere in the repository.
- Decide whether economics needs a registered truth domain (6.1).