Session Handoff — 2026-05-14 (institutional domain spec)
Session Goal
Define InstitutionalDomain and DomainPolicy as design-level forward-direction primitives so that the next layer of work — schemas, identity recovery, agreement registry, route-binding contracts — can be filed safely against a clear authority model.
Decisive Test
Can a downstream implementer — looking only at this spec plus the existing canon it harmonizes with — name (1) what a domain is and what it is not, (2) which fields the domain object carries vs which adjacent concepts are deferred, (3) where DomainPolicy is evaluated and where it is forbidden to run, (4) which lifecycle stage requires which authority basis and which receipt class? If yes, the spec has done its job.
Final State (Verified)
main HEAD
494dce9fa — docs(spec): add accepted-proposal effect dispatch contract (#1819) (merged earlier today).
Open PRs
| PR | Branch | State | CI Status | Blocker |
|---|---|---|---|---|
| #1820 | spec/institutional-domain-policy |
OPEN | All required checks pass after the initial push at commit 880d06105; a review-feedback fix commit followed and must re-run CI before merge |
Awaiting CI re-run on the fix commit, then mergeability re-check |
| #1790 | dependabot (pilot-ui dev deps) | OPEN | n/a | Out of session scope |
| #1791 | dependabot (ts-sdk dev deps) | OPEN | n/a | Out of session scope |
Branches
spec/institutional-domain-policy— pushed to origin. Initial head880d06105(spec doc, registry, handoff). A review-feedback commit lands after the initial PR and changes the head; checkgit rev-parse HEADon the branch for the current SHA after that commit.- Local
mainsynced to494dce9fa(unchanged this session).
Issues
- #1794 — OPEN. This session writes the candidate spec doc. PR will use
Refs:, notCloses:. - #1793 — closed (merged via #1814).
- #1797 — closed (merged via #1819, user closed manually).
- #1815, #1816, #1817, #1818 — sibling spec issues, all OPEN.
What Changed
1. Spec doc drafted (docs/spec/institutional-domain.md, ~310 lines)
The doc:
- Names what a domain is and what it is not. Boundary table separating domain from DNS name, node, federation, institution package, app/tool, member account, storage bucket, CCL document, and tenant.
- Places
InstitutionalDomainin the civic loop at the Authority stage. Every later stage derives legitimacy from a decision rooted in some domain. - Outlines
InstitutionalDomainfields at design granularity. Identity (DID + owning entity class), constitutional inputs (charter refs, adopted CCL policy refs), membership/standing/role-authority, device/service identities, workspace/tool/agreement registries, storage/compute/routing policy refs, receipt policy, accessibility/translation policy, export/backup/recovery policy, federation agreements, challenge/repair/exit paths. No Rust types, no JSON schemas, no field order fixed. - Outlines
DomainPolicyrule bundle. Storage / replication / backup / privacy / compute / receipt retention / tool install authority / route authority / service identity authority / member recovery / accessibility / language / authority class / amendment / versioning / inertness rule. Adopted via governance; unadopted policy is inert. - Specifies
DomainPolicyevaluation rules. Consulted at decision admission, mandate composition (Stage 2 of effect dispatch), effect plan generation (Stage 3), and binding adoption. Never consulted inside the kernel. Cross-link toeffect-dispatch-contract.mdandKERNEL_APP_SEPARATION.md. - Specifies a nine-stage domain lifecycle table. Declare → adopt charter/policy → initialize standing/membership → bind routes/services/tools → operate → amend → federate → suspend/repair → export/exit/archive. Each row names the authority required and the receipt class emitted. Lifecycle invariants: no transition without authority basis, no transition without receipt expectation, no silent transition, reversal is a separate transition (chain is append-only), exit is constitutional and unblockable.
- Maps the relationship to effect dispatch. Five-row table aligning
DomainPolicy's role to the five dispatch stages. - Cross-links every sibling future-work issue. #1815, #1816, #1817, #1818, #1798, #1801, #1799, #1795. No duplication.
- Names adjacent concepts as deferred.
DomainSession,DeviceIdentity/DeviceEnrollment,ServiceIdentity,Workspace,AgreementRegistry,ToolRegistry,DnsBinding— each named, none redefined. - Lists open questions and deferred decisions. Nine items, each with a named follow-up location.
2. Registered the doc (docs/registry.toml, +14 lines after the effect-dispatch entry)
category = "architecture", status = "draft", title, description, last_updated, last_reviewed, owner, audiences, domain_tags, depends_on, recommended_action. No truth_class or role overrides — the docs/spec/ prefix default applies (truth_class = "normative", role = "spec", canonical = "no", freshness = "unknown"), matching the convention the #1819 review settled on.
3. Followed the #1819 review lessons proactively
- YAML frontmatter is
Status: normative(matches the prefix default; matches the doc's tone). - Doc opening labeled "spec, work-in-progress" — honest about which clauses are forward-direction.
- Handoff written in
docs/dev/HANDOFF_TEMPLATE.mdstructure from the start (not after review). Unsafe Assumptions section is concrete and lists five things. - Used canon vocabulary verbatim (
AuthorityClass,AuthorityGrant,TypedScope,Mandate,ServiceIdentity,ToolBinding,DnsBinding,StorageClass,DataLocality,EffectManifest,GovernanceDecisionReceipt, etc.). - No schema, no wire format, no MUST that requires fields the existing canon does not yet declare.
4. Drafted follow-up issues (not filed)
Per the user's instruction: drafts in handoff only, not auto-filed. See "Next Move" §5.
What's Open
- Run validation suite. (All four scripts: doc_control_check pass with 53 pre-existing unrelated warnings; lint-arch CLEAN; compliance_linter clean; freshness-check exit 1 from pre-existing
docs/ARCHITECTURE.mdstaleness.) - Commit with scoped message. (Initial commit
880d06105; review-feedback commit follows.) - Push branch.
- Open PR with non-claims body. (PR #1820.)
- Watch CI on the initial head — all required checks pass; non-required skip (docs-only).
- Re-run CI on the review-feedback fix commit and recheck
mergeStateStatus. - Reply to the two valid Copilot review threads (handoff "Final State" staleness; spec doc Federation row casing) with the fix commit SHA.
- Codex thread (handoff-removal) — already replied with verification chain; no further edit since
docs/dev-journal/does not exist and the user's PR instructions explicitly directed thedocs/dev/path. Leave as is; carry the AGENTS.md / HANDOFF_TEMPLATE.md drift as a separate follow-up. - Squash-merge if clean.
- Decide whether to file the follow-up issue drafts listed in §"Next Move §5" (deferred to user).
- After #1794 lands, the next safe spec is
#1817(CCL policy registry). #1817 operationalizes the §"DomainPolicy evaluation" hook and the §"Stage 2 / Stage 3" CCL hook points named ineffect-dispatch-contract.md.
Unsafe Assumptions
COOPERATIVE_DOMAIN_INFRASTRUCTURE.mdis the canonical home for the domain-infrastructure overview. I treated it as design-direction and extended it without superseding. If a more recent doc has been written that I did not catch, my "harmonize, don't duplicate" framing may need revisiting.InstitutionalDomainandDomainPolicyare not yet defined in Rust types. I assumed both are forward-direction primitives based onICN_INTEGRATED_SYSTEM_MODEL.mdline 106's explicit "tracked under #1794" framing. If types namedInstitutionalDomainorDomainPolicyhave landed inicn-governanceor another crate since the spine merged, my "no Rust types defined" framing is wrong.ADR-0014's threeAuthorityClassvariants are still authoritative. I citedRepresentation/Execution/Attestationas the closed set. If a later ADR has amended that enum, the spec needs adjustment.DnsBindingis already adequately specified byDOMAIN_ROUTING_AND_DNS_BINDINGS.md. I cross-linked rather than re-specified. If reviewers find that doc inadequate for the contract this spec implies, aspec(routing): …follow-up is needed.- The
docs/spec/prefix default in the registry setstruth_class = "normative"androle = "spec". Confirmed viagrepagainstdocs/registry.toml's[[doc_path_defaults]]block during the #1819 review. If that default has been amended since, the YAMLStatus: normativemay produce a mismatch warning. - The 25 cross-link targets I cite all exist at session start. Verified by file-existence sweep before committing. If a downstream PR renames or removes one of them before #1794 lands, the spec's link will rot.
Next Move
- Run the validation suite:
cd /home/matt/projects/icn python3 docs/scripts/doc_control_check.py --repo . --registry docs/registry.toml --strict python3 docs/scripts/lint-arch.py docs/spec/institutional-domain.md --cargo icn/Cargo.toml python3 .github/scripts/compliance_linter.py python3 docs/scripts/freshness-check.py --freshness docs/freshness.toml --status docs/status.toml --repo . - Commit with the scoped message
docs(spec): define institutional domain and policy primitive. - Push the branch and open the PR with the non-claims body.
- Monitor CI; reply to any AI-reviewer threads using the same pattern as #1819.
- Follow-up issue drafts (deferred; not filed in this PR):
schema(domain): define InstitutionalDomain and DomainPolicy persisted records— the wire-stable schema that this spec deliberately does not introduce.spec(identity): define ServiceIdentity and DeviceIdentity issuance, rotation, recovery inside domains— the full lifecycle for the identity primitives this spec only names.spec(agreement): define federation/domain AgreementRegistry shape and lifecycle— the registry shapeCOOPERATIVE_DOMAIN_INFRASTRUCTURE.mdnamed eight classes for.spec(routing): clarify DomainRouteBinding authority and receipt contract— optional;DOMAIN_ROUTING_AND_DNS_BINDINGS.mdmay already be sufficient. Flagged for human triage.
- After #1794 lands, the recommended next spec PR is #1817 (CCL policy registry / versioning / governance-effect hook contract). It operationalizes the §"DomainPolicy evaluation" hook this spec names.
Architectural Decisions
- Domain object stays at design granularity. The spec deliberately does not name Rust types, JSON schemas, or wire formats. Schema work is a separate follow-up.
DomainPolicyevaluation never runs in the kernel. Confirms and extends the meaning firewall (perKERNEL_APP_SEPARATION.md). Evaluation happens at decision admission, mandate composition, effect plan generation, and binding adoption — all in the app layer.- Unadopted
DomainPolicyis inert. Mirrors the rule already established for CCL documents (pereffect-dispatch-contract.md§"CCL hook points") and forMandates (per ADR-0019 conservative-broadening invariants). - The nine-stage lifecycle is the canonical sequence. Each transition requires authority basis and emits a receipt; reversal is a separate transition; exit is constitutional and unblockable.
- Adjacent concepts (DomainSession, DeviceIdentity, ServiceIdentity, Workspace, AgreementRegistry, ToolRegistry, DnsBinding) are named, not redefined. Where they have existing canonical sources, the spec cross-links and notes deferrals.
- Tenant is rejected as an analog. A domain is a self-governing jurisdiction, not a billing entity inside someone else's product.
Verification Commands
cd /home/matt/projects/icn
# Branch + PR state
git branch --show-current
gh pr view <pr-number> --json state,mergeable,mergeStateStatus
# Validation suite
python3 docs/scripts/doc_control_check.py --repo . --registry docs/registry.toml --strict
python3 docs/scripts/lint-arch.py docs/spec/institutional-domain.md --cargo icn/Cargo.toml
python3 .github/scripts/compliance_linter.py
python3 docs/scripts/freshness-check.py --freshness docs/freshness.toml --status docs/status.toml --repo .
# Review thread state
gh api repos/InterCooperative-Network/icn/pulls/<pr-number>/comments \
--jq '.[] | {id, user: .user.login, line, in_reply_to_id, created_at}'
Expected: doc_control passes with 53 pre-existing unrelated warnings, none on the new doc; lint-arch CLEAN (already verified); compliance_linter no violations; freshness-check exit 1 from pre-existing docs/ARCHITECTURE.md staleness (recorded honestly, not in this PR's scope).
Truth-Plane Notes
- Declared project truth: loaded from
docs/STATE.md(last reviewed 2026-05-07, current as of the #1819 merge earlier today). No conflict surfaced. - Implementation truth: verified by reading
icn-governance/src/proof.rs,mandate.rs,authority.rsfor the constitutional types (AuthorityClass,AuthorityGrant,TypedScope,Mandate) the spec leans on; checked thatInstitutionalDomainandDomainPolicydo not yet have Rust types (consistent with the "forward-direction" framing). - Execution truth: confirmed
mainHEAD494dce9fa, two dependabot PRs open, no other open PRs. - Known truth-plane conflict:
freshness-check.pyreportsdocs/ARCHITECTURE.mdas carrying stale sections. CI workflow treats this as informational and reports SUCCESS; the script itself exits 1. This PR does not broaden scope to address it (same pattern recorded in #1814 and #1819 handoffs).