Skip to content

feat(contracts): actuate single-authority percolation — retrospective + 2 layers/gap - #285

Merged
mdheller merged 1 commit into
mainfrom
feat/contract-reconciliation-percolation
Aug 4, 2026
Merged

feat(contracts): actuate single-authority percolation — retrospective + 2 layers/gap#285
mdheller merged 1 commit into
mainfrom
feat/contract-reconciliation-percolation

Conversation

@mdheller

@mdheller mdheller commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

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. All sourceos-spec workflows 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) and QuorumProof (mcp-a2a-zero-trust) are live in services and absent here.

Three gaps, each with two layers:

Gap Detection layer Actuation layer
1 · no upstream percolation --check-consumer flags ORPHAN (vendored, owned by no authority) consumer CI opens an upstream PR to spec adding it
2 · no propagation on merge STALE check (vendored sha256 ≠ canonical) propagate-contracts-on-merge.yml dispatches a re-sync to every consumer on a schema merge — the self-heal responder lands it
3 · no canonical authority UNREGISTERED check + dup-id guard (every $id resolves to the registry) registry/contract-registry.json + ownedSchemas/authorityRepos make "authored in spec" the single truth

What'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.
  • Two workflows — detection (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; wire CONSUMER_DISPATCH_TOKEN.

Touches workflows — flagged for human review; not auto-merging.

…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
mdheller merged commit 71c6fda into main Aug 4, 2026
10 checks passed
@mdheller
mdheller deleted the feat/contract-reconciliation-percolation branch August 4, 2026 07:47
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant