Skip to content

feat(0.7.1g1P2-2): digest-migration certificate as a first-class authority object (M45/M46/M47) - #471

Merged
GionaGranchelli merged 2 commits into
epic/0.7.1-control-plane-authorityfrom
task/0.7.1g1P2-2-digest-migration-certificate
Oct 1, 2026
Merged

GionaGranchelli merged 2 commits into
epic/0.7.1-control-plane-authorityfrom
task/0.7.1g1P2-2-digest-migration-certificate

Conversation

@GionaGranchelli

Copy link
Copy Markdown
Owner

Base

e6e0d69ed2adfa47c6cdfa4485ef30bc184bb881 — the post-merge Epic tip from #470.

Step 2 of TASK-0.7.1g1P2-AUTHORITY-MODEL-RECONCILIATION.md §6.2. The mechanism only, as scoped: type + ledger + loader + the mint/retention/removal lifecycle (M45/M46/M47) with its own fail-closed tests. No certificate-aware consumption, no M40-M44, no P2, no mutation of the 67 admissions.

Scope

Five new files, 843 insertions, nothing modified:

  • MutationAuthorityDigestCertificate.kt — the certificate type, its ledger, and the bounded admission-set digest.
  • MutationAuthorityDigestCertificateLoader.kt — parses config/quality/mutation-authority-digest-certificates.yml.
  • MutationAuthorityDigestCertificateCeremony.kt — the lifecycle: M45, M46, M47.
  • Two test files, 22 tests.

No config/quality/** file is touched: no ledger instance is created, because minting the P1M certificate is a later base transition. This change introduces only the machinery that transition will use.

Design

The certificate carries a semantic upgrade of the whole-population authority digest without rewriting historical authority. The 67 P1 authorizations stay bound to their raw-v1 digests and byte-identical; the certificate stands beside them in its own ledger and states, in base authority, that one exact fromDigest is equivalent to one exact toDigest for one exact bounded set of authorizations. M36's payload comparison never sees it, so M36 and M37 stay literally unchanged — no exception branch, no permitted-field list.

Fields exactly as designed: fromAlgorithm, fromDigest, toAlgorithm, toDigest, admissionSetDigest, fromBaseSha, reason. enforcedPayload() is that set, with authorizedBy/authorizedAt excluded as audit-only — so M46 judges byte-identity over bound fields while touching who/when can never manufacture authority.

  • M45 mint-time base binding: a newly introduced certificate whose fromBaseSha ≠ the authority base fails. Anti-replay at introduction only, exactly as MutationPopulationAdmission.fromBaseSha.
  • M46 retained immutability: a base certificate whose enforced payload differs in any field fails. Correcting a certificate means minting a new one later, never editing a retained one.
  • M47 removal custody: a base certificate absent from the candidate fails.

The admission-set recipe (sorted identities joined with a newline plus a trailing newline, SHA-256) is documented as contract, not implementation detail, because whoever mints the P1M certificate must reproduce it exactly and M42 will compare against it.

Deliberate scope boundary — the T19 half

M47 takes its strictly fail-closed half. With no certificate-aware consumption path there is no way to prove a valid consumption, so any disappearance fails. That is documented in the rule, in the type, and in the test — not left as an unfinished branch. A disappearance must never become its own evidence. When M40-M44 land it becomes "unless validly consumed by the same transition", judged against an independently established consumption. This is the T19 boundary flagged during Step 1.

Tests (22)

  • Loader shape contract, every fail-closed case: malformed digest, short fromBaseSha, unknown digest semantics, missing reason, absent schemaVersion, duplicate source digest (two certificates claiming one source contradict each other), and a certificate that migrates a digest to itself.
  • The admission-set recipe pinned against the real committed 67-admission set (98a9587a…), so the value P1M must reproduce is testable now.
  • M45 in both directions, plus the discriminator that binding is enforced at mint only — a retained certificate survives intermediate merges, which is what makes delayed consumption possible.
  • M46 driven as a loop over each bound field: adding a field to the type without classifying it into the enforced payload fails this test.
  • Audit-only metadata changing without failing, in both directions.
  • M47 in both directions, including that a mere absence is never a consumption.

Verification

  • ./gradlew :build-logic:test --tests 'dev.tramai.build.quality.MutationAuthorityDigestCertificate*' --rerun-tasks — BUILD SUCCESSFUL, 8 tasks executed
  • ./gradlew spotlessKotlinCheck (ratchet-scoped to the base) — BUILD SUCCESSFUL
  • ./gradlew verifyStaticAnalysis — no new findings; Detekt baseline unchanged (4792 → 4792, 0 added, 0 removed). Four findings in the first draft were fixed properly, by constants and by restructuring the test builders — not baselined and not suppressed.
  • ./gradlew verifyChangePolicy -PchangePolicyBase=e6e0d69… — PASSED, 5 changed files, change class build-logic, no policy violations

Not run

Consumption (M40-M44), certificate-aware M34, the full T1-T19 matrix, and the task-level authority transport for certificates — all Step 3. No P2, no campaign rerun, no baseline regeneration, no classification or evolution change.

Remaining risks

  • The 67 admissions remain bound to their raw-v1 digests and are not consumable under authority-v2 until the P1M certificate is minted in a base transition and Step 3 consumes it. That is the designed ordering, not a regression.
  • M47 is stricter than its final form until M40-M44 exist (above). Step 3 must relax it only against a proven consumption.
  • The certificate ledger file does not exist yet, so every real invocation loads the fail-closed empty ledger. The loader is exercised against fixtures, including the real admission ledger for the set-digest recipe.

…ority object

Step 2 of TASK-0.7.1g1P2-AUTHORITY-MODEL-RECONCILIATION.md 6.2: the mechanism only. No
certificate-aware consumption, no M40-M44, no P2, and the 67 admissions untouched.

The certificate carries a *semantic* upgrade of the whole-population authority digest without
rewriting historical authority. The 67 P1 authorizations stay bound to their raw-v1 digests and
byte-identical; the certificate stands beside them in its own ledger and states, in base authority,
that one exact fromDigest is equivalent to one exact toDigest for one exact bounded set of
authorizations. M36's payload comparison never sees it, so M36 and M37 stay literally unchanged - no
exception branch, no permitted-field list.

Three files, mirroring the admissions trio:

- MutationAuthorityDigestCertificate.kt - the type, the ledger, and the bounded admission-set digest.
  Fields exactly as designed: fromAlgorithm, fromDigest, toAlgorithm, toDigest, admissionSetDigest,
  fromBaseSha, reason. enforcedPayload() is that field set with authorizedBy/authorizedAt excluded as
  audit-only, so M46 judges byte-identity over bound fields while touching who/when can never
  manufacture authority. The admission-set recipe (sorted identities joined with a newline plus a
  trailing newline, SHA-256) is documented as contract, not implementation detail.
- MutationAuthorityDigestCertificateLoader.kt - parses
  config/quality/mutation-authority-digest-certificates.yml. An absent file means no certificates,
  which is fail-closed: no migration is possible and pre-authority-v2 authorizations stay
  unconsumable. A present but malformed file is a hard failure. Validates shape only - required
  fields, 64-hex digests, 40-hex fromBaseSha, known digest semantics, unique source digest, and no
  certificate that migrates a digest to itself.
- MutationAuthorityDigestCertificateCeremony.kt - the lifecycle: M45 mint-time base binding, M46
  retained immutability, M47 removal custody. Standalone over the two ledgers plus the authority
  baseSha, because a lifecycle rule is a transition property that cannot be expressed by parsing one
  file.

M47 takes its strictly fail-closed half. With no certificate-aware consumption path there is no way
to *prove* a valid consumption, so any base certificate absent from the candidate fails. That is
deliberate and documented in the rule and the test, not an unfinished branch: a disappearance must
never become its own evidence. When M40-M44 land it becomes "unless validly consumed by the same
transition", judged against an independently established consumption. This is the T19 boundary
flagged during Step 1.

No ledger instance is created: minting the P1M certificate is a later base transition, so this
change touches no config/quality file and no authority record.

Tests (22 new): loader shape contract including every fail-closed case; the admission-set recipe
pinned against the real committed 67-admission set; M45 in both directions plus the discriminator
that binding is enforced at mint only, so a retained certificate survives intermediate merges; M46
driven as a loop over each bound field, which fails if a field is ever added to the type without
being classified into the enforced payload; audit-only metadata changing without failing; and M47's
removal custody in both directions.

Verification:
- :build-logic:test --tests 'dev.tramai.build.quality.MutationAuthorityDigestCertificate*' --rerun-tasks
  - BUILD SUCCESSFUL, 8 tasks executed
- spotlessKotlinCheck, verifyStaticAnalysis, verifyChangePolicy - see the pull request
Copilot AI balanced review requested due to automatic review settings October 1, 2026 19:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

This is high-stakes build-authority governance machinery with subtle fail-closed semantics that warrants final human review despite only minor convention findings.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

This PR implements Step 2 of the authority-model reconciliation task, introducing the digest-migration certificate as a first-class, base-side authority object within the build-logic mutation-ratchet governance machinery. The certificate lets the whole-population authority digest be semantically upgraded (raw-v1 → authority-v2) over a bounded, named set of authorizations without rewriting the 67 historical P1 authorizations or touching the M36/M37 admission-payload comparison. The change is mechanism-only: it adds the type, its ledger, a fail-closed loader, and the mint/retention/removal lifecycle (M45/M46/M47), plus tests. It deliberately omits certificate consumption (M40–M44), task wiring, and any config/quality/** ledger instance, all deferred to Step 3.

Changes:

  • Adds MutationAuthorityDigestCertificate (immutable type with an audit-excluded enforcedPayload()) and its MutationAuthorityDigestCertificates ledger plus the bounded admission-set digest recipe.
  • Adds a shape-only, fail-closed YAML loader and a transition-level ceremony enforcing mint-time base binding (M45), retained immutability (M46), and strictly fail-closed removal custody (M47).
  • Adds 22 tests covering loader shape/fail-closed cases, the pinned admission-set digest recipe, and bidirectional lifecycle discriminators.
File Description
MutationAuthorityDigestCertificate.kt Certificate type + ledger + admissionSetDigest recipe; documents field semantics and rule ownership.
MutationAuthorityDigestCertificateLoader.kt Fail-closed, shape-only parser for the certificate YAML; validates every enforcement-critical field.
MutationAuthorityDigestCertificateCeremony.kt Transition-level M45/M46/M47 lifecycle checks producing VerificationDiagnostics.
MutationAuthorityDigestCertificateLoaderTest.kt Loader shape contract, fail-closed cases, and the admission-set recipe pinned to the committed 67-admission set.
MutationAuthorityDigestCertificateCeremonyTest.kt Bidirectional discriminators for M45/M46/M47, including the fail-closed removal half.

The implementation closely and faithfully mirrors the existing sibling MutationPopulationAdmissionLoader/ceremony patterns, is well-documented, and is backed by strong, behavior-level assertions. My two findings are minor convention items (parameter shadowing in the loader; non-robust repo-root resolution in the test) and are documented inline.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

1. Medium, valid: MutationAuthorityDigestCertificateLoaderTest.repositoryRoot() assumed the test
   starts exactly one level below the repository by using a single parent hop. This test is
   deliberately pinned against the real committed 67-admission ledger, so a brittle path guess would
   make it fail for a reason unrelated to the recipe. It now walks upward to the `gradlew` marker,
   the same idiom CanonicalProbeFunctionalTest uses, and fails with an explicit message naming the
   starting directory if no root is found.

2. Low, readability: parseCertificates declared `val raw = raw["certificates"]`, shadowing its own
   parameter. The parameter is now `ledger` and the binding `certificatesRaw`, so the two are
   distinguishable at the point of use.

Both fixes are narrow: no rule, field, threshold or test expectation is weakened, and no suppression
or baseline entry was added.

Verification:
- :build-logic:test --tests 'dev.tramai.build.quality.MutationAuthorityDigestCertificate*' --rerun-tasks
  - BUILD SUCCESSFUL
- spotlessKotlinCheck -PtramaiFormattingBaseRef=e6e0d69... - BUILD SUCCESSFUL
- verifyStaticAnalysis - Detekt baseline unchanged (4792 -> 4792, 0 added, 0 removed), no new findings
- verifyChangePolicy -PchangePolicyBase=e6e0d69... - PASSED, 5 changed files, class build-logic
@GionaGranchelli
GionaGranchelli merged commit 64d0545 into epic/0.7.1-control-plane-authority Oct 1, 2026
19 checks passed
GionaGranchelli added a commit that referenced this pull request Oct 2, 2026
…igration certificate (#472)

P1M: the single isolated transition between Step 2 and Step 3. It establishes certificate authority;
it does not consume it.

One certificate, derived from repository truth rather than chosen:

- fromAlgorithm raw-v1 / fromDigest 9aebd3202288c82ff006f2db33c95cac0772746fa3c3061569167cd3f45df9b0
  This is the digest every one of the 67 committed P1 admissions is bound to. The ledger holds
  exactly one distinct populationDigest value across 67 admissions, so the historical authority
  source is coherent; nothing was changed to make it match.
- toAlgorithm authority-v2 / toDigest e6ad01dc1d2966894a6555304bc8ca9a04c8174e3c83ae88760fcfebf1464dad
  Recomputed independently over the frozen unrestricted measurement (2544 identities, the population
  the raw-v1 digest was taken over) from the canonical authority projection semantics: identity,
  canonical outcome, family, module, topology, analyzer. The same value was byte-identical across all
  four preserved campaigns. It is not copied from any candidate.
- admissionSetDigest 98a9587a1068ec0cd7158a05ba6909c61c522308c272e7fa9cb27d5edd93a79c
  Reproduced from the exact 67 committed identities using the Step-2 contract (sorted, joined with a
  newline plus the trailing newline, SHA-256). It equals the value pinned by the Step-2 test.
- fromBaseSha 64d0545 - the exact post-#471 epic tip, so M45's
  mint-time binding is against the real authority base and not a provisional preview SHA.
- reason records the migration without implying any historical admission was upgraded or rewritten.

The certificate ledger is the only changed path. The 67 admissions are byte-identical: no admission
was modified, no digest rewritten, no metadata touched, and no mutation authority was re-measured.

Ordering this preserves: a candidate may only consume migration authority that already existed in
its base. A later transition (Step 3) consumes this certificate; P1M minting and consuming its own
authority in one transition is exactly what the M43 analogue forbids.

Mechanical gate P1-P8 (changed-path isolation, admission byte identity, semantic population
identity, certificate cardinality, M45 binding, bounded admission set, source binding, independent
target recomputation) is recorded in the pull request. No permanent rule was added for this
migration, and no gate, threshold, suppression or baseline was weakened.
GionaGranchelli added a commit that referenced this pull request Oct 2, 2026
…igration certificate (#472)

P1M: the single isolated transition between Step 2 and Step 3. It establishes certificate authority;
it does not consume it.

One certificate, derived from repository truth rather than chosen:

- fromAlgorithm raw-v1 / fromDigest 9aebd3202288c82ff006f2db33c95cac0772746fa3c3061569167cd3f45df9b0
  This is the digest every one of the 67 committed P1 admissions is bound to. The ledger holds
  exactly one distinct populationDigest value across 67 admissions, so the historical authority
  source is coherent; nothing was changed to make it match.
- toAlgorithm authority-v2 / toDigest e6ad01dc1d2966894a6555304bc8ca9a04c8174e3c83ae88760fcfebf1464dad
  Recomputed independently over the frozen unrestricted measurement (2544 identities, the population
  the raw-v1 digest was taken over) from the canonical authority projection semantics: identity,
  canonical outcome, family, module, topology, analyzer. The same value was byte-identical across all
  four preserved campaigns. It is not copied from any candidate.
- admissionSetDigest 98a9587a1068ec0cd7158a05ba6909c61c522308c272e7fa9cb27d5edd93a79c
  Reproduced from the exact 67 committed identities using the Step-2 contract (sorted, joined with a
  newline plus the trailing newline, SHA-256). It equals the value pinned by the Step-2 test.
- fromBaseSha 64d0545 - the exact post-#471 epic tip, so M45's
  mint-time binding is against the real authority base and not a provisional preview SHA.
- reason records the migration without implying any historical admission was upgraded or rewritten.

The certificate ledger is the only changed path. The 67 admissions are byte-identical: no admission
was modified, no digest rewritten, no metadata touched, and no mutation authority was re-measured.

Ordering this preserves: a candidate may only consume migration authority that already existed in
its base. A later transition (Step 3) consumes this certificate; P1M minting and consuming its own
authority in one transition is exactly what the M43 analogue forbids.

Mechanical gate P1-P8 (changed-path isolation, admission byte identity, semantic population
identity, certificate cardinality, M45 binding, bounded admission set, source binding, independent
target recomputation) is recorded in the pull request. No permanent rule was added for this
migration, and no gate, threshold, suppression or baseline was weakened.
GionaGranchelli added a commit that referenced this pull request Oct 2, 2026
…igration certificate (#472)

P1M: the single isolated transition between Step 2 and Step 3. It establishes certificate authority;
it does not consume it.

One certificate, derived from repository truth rather than chosen:

- fromAlgorithm raw-v1 / fromDigest 9aebd3202288c82ff006f2db33c95cac0772746fa3c3061569167cd3f45df9b0
  This is the digest every one of the 67 committed P1 admissions is bound to. The ledger holds
  exactly one distinct populationDigest value across 67 admissions, so the historical authority
  source is coherent; nothing was changed to make it match.
- toAlgorithm authority-v2 / toDigest e6ad01dc1d2966894a6555304bc8ca9a04c8174e3c83ae88760fcfebf1464dad
  Recomputed independently over the frozen unrestricted measurement (2544 identities, the population
  the raw-v1 digest was taken over) from the canonical authority projection semantics: identity,
  canonical outcome, family, module, topology, analyzer. The same value was byte-identical across all
  four preserved campaigns. It is not copied from any candidate.
- admissionSetDigest 98a9587a1068ec0cd7158a05ba6909c61c522308c272e7fa9cb27d5edd93a79c
  Reproduced from the exact 67 committed identities using the Step-2 contract (sorted, joined with a
  newline plus the trailing newline, SHA-256). It equals the value pinned by the Step-2 test.
- fromBaseSha 64d0545 - the exact post-#471 epic tip, so M45's
  mint-time binding is against the real authority base and not a provisional preview SHA.
- reason records the migration without implying any historical admission was upgraded or rewritten.

The certificate ledger is the only changed path. The 67 admissions are byte-identical: no admission
was modified, no digest rewritten, no metadata touched, and no mutation authority was re-measured.

Ordering this preserves: a candidate may only consume migration authority that already existed in
its base. A later transition (Step 3) consumes this certificate; P1M minting and consuming its own
authority in one transition is exactly what the M43 analogue forbids.

Mechanical gate P1-P8 (changed-path isolation, admission byte identity, semantic population
identity, certificate cardinality, M45 binding, bounded admission set, source binding, independent
target recomputation) is recorded in the pull request. No permanent rule was added for this
migration, and no gate, threshold, suppression or baseline was weakened.
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.

2 participants