feat(contracts): actuate single-authority percolation — retrospective + 2 layers/gap - #285
Merged
Merged
Conversation
…ive + 2 layers/gap)
The self-updating design existed (SourceOSRepoManifest.ownedSchemas/authorityRepos,
auditEvents: spec.schema.added) but was VALIDATED, never ACTUATED — so contracts got
authored elsewhere and never percolated back. Proof, caught by this tool: the spec has
355 canonical contracts but AutonomyAdmissionReceipt (prophet-platform) and QuorumProof
(mcp-a2a-zero-trust) are live in services and ABSENT here.
Detection spine (tools/reconcile_contracts.py, 6 tests):
- --emit-registry builds registry/contract-registry.json — the canonical {name→$id→sha256}
index (the single authority).
- --check-consumer catches, fail-closed, the three drift gaps:
ORPHAN vendored but owned by no authority repo (GAP 1: no upstream percolation)
STALE vendored sha256 != canonical (GAP 2: no propagation on merge)
UNREGISTERED $id resolves to no registry entry (GAP 3: no canonical authority)
Actuation (workflows):
- contract-reconciliation.yml — registry can never go stale (regenerate-or-fail) + the tests.
- propagate-contracts-on-merge.yml — a merge changing schemas/** DISPATCHES a re-sync to every
registered consumer (registry/consumers.json), which the self-heal responder lands. This is
the "merge to main solves its own updates" mechanism, finally executed instead of only declared.
CONTRACTS.md maps each gap to its detection + actuation layer. Follow-up: consumers adopt
--check-consumer in CI + a .sourceos/manifest.json; upstream the two orphan contracts into spec.
mdheller
added a commit
that referenced
this pull request
Aug 4, 2026
…rift (359) (#289) The reconcile gate (just merged in #285) correctly flagged main as stale: AgentImage and ImageTrustReport schemas were added to main without regenerating registry/contract-registry.json (they predate / bypassed the gate, which is advisory not required yet). Regenerates 357->359. Lesson: make the reconcile gate a REQUIRED check so a schema PR cannot merge without it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Retrospective — why the canon doesn't self-update
The self-updating machinery was designed (
SourceOSRepoManifest.ownedSchemas/authorityRepos,auditEvents: [spec.schema.added]) but validated, never actuated. Allsourceos-specworkflows are inward validation; merge to main fires no outward dispatch, and there's no channel to pull contracts in from consumers. So contracts get authored elsewhere and never percolate back.Empirical proof, caught by this PR's tool: the spec has 355 canonical contracts, but
AutonomyAdmissionReceipt(prophet-platform) andQuorumProof(mcp-a2a-zero-trust) are live in services and absent here.Three gaps, each with two layers:
--check-consumerflags ORPHAN (vendored, owned by no authority)propagate-contracts-on-merge.ymldispatches a re-sync to every consumer on a schema merge — the self-heal responder lands it$idresolves to the registry)registry/contract-registry.json+ownedSchemas/authorityReposmake "authored in spec" the single truthWhat's here
tools/reconcile_contracts.py— the detection spine (--emit-registry,--check-consumer), fail-closed. 6 tests (orphan / stale / owned / clean / fail-closed).registry/contract-registry.json— 355 canonical contracts, the single authority. CI regenerates-or-fails, so it can never go stale.registry/consumers.json— the consumers that receive the merge dispatch.contract-reconciliation.yml) + actuation (propagate-contracts-on-merge.yml).CONTRACTS.md— the two-way flow + the gap→layers map.Follow-ups
Consumers adopt
--check-consumer+ a.sourceos/manifest.json; upstream the two orphan contracts (AutonomyAdmissionReceipt,QuorumProof) into spec; wireCONSUMER_DISPATCH_TOKEN.Touches workflows — flagged for human review; not auto-merging.