Repository navigation
feat(0.7.1g1P2-1): bind M34 to a canonical authority projection, not raw PIT status - #470
Conversation
…raw PIT status
Step 1 of the design record (TASK-0.7.1g1P2-AUTHORITY-MODEL-RECONCILIATION.md): the semantic
split, with no certificate logic.
MutationPopulationEvolutionProof now carries two hashes, both computed by the verifier from the
same fresh measurement:
- projectionHash (unchanged): the raw-exact canonical comparison projection, raw status included.
It remains the measurement proof (M21, exactComparison) and is deliberately NOT relaxed.
- authorityProjectionHash (new): identity|outcome|family|module plus family/module topology and
analyzer semantics, with raw PIT status deliberately excluded.
M34 now consumes the authority projection. C7 (BaselineModel.kt) declares raw PIT status
diagnostic evidence and not authority, and four complete unrestricted campaigns at identical
effective PIT inputs produced four distinct raw-status digests - three identities of 2544
oscillating only between SURVIVED and TIMED_OUT, all NON_KILLED in every campaign - while this
projection was byte-identical every time. M34's previous digest was the measurement proof, so a
scheduler race on unrelated neighbours invalidated adjudicated authority; that was an unintended
reuse of one hash for two different trust questions, not a deliberate override of C7.
Raw status stays authoritative where it belongs: the fresh<->committed exact comparison (M21) and
each individual authorization's exact row (M32, unchanged and still status-inclusive - the 67
authorized rows were byte-identical across all four campaigns).
Discriminators: T1 (a neighbour's raw status movement leaves the authority projection unchanged,
while the raw-exact proof still distinguishes the populations) and T2/T8 (outcome and analyzer
semantics changes do move it) at pure-verifier level; T1 again at ceremony level, where an
authorization minted while a neighbour was SURVIVED must remain consumable when it is TIMED_OUT.
Two test corrections, both evidenced:
- the M34 negative test asserted a diagnostic substring ('complete measured population') that the
deliberate rewording removes; it now asserts 'authority projection' and still asserts rejection.
- MutationRatchetAuthorityTest passed admissions = NONE in the candidate while the real base holds
67 pending authorizations, which asserts a transition M37 forbids. This failure reproduces with an
identical signature at the pristine base ec8b4da (8 tests, 1 failure, M37 on 050d2b83), so it is
pre-existing and not caused by this change; the candidate now retains the base authorizations, so
absent targets are M39 warnings as designed.
No certificate, no consumption rule changes, no P2. The 67 admissions, baseline, classifications,
evolution records, M06/M13/M36/M37 and the canonical outcome mapping are untouched.
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
This change to core authority-digest semantics is high-risk governance machinery, and the required real-task authority-transport test (MutationPopulationAdmissionIntegrationTest, outside the diff) still mints populationDigest from the raw projectionHash, which would be non-consumable under the new M34 — a cross-file inconsistency that needs human verification.
Review effort: Balanced
Findings: 1
What changed in this PR
This PR is step 1 of 3 of the authority-model reconciliation for the mutation ratchet (build-logic quality governance). It changes the M34 population-context check so that a population authorization is bound to a new authority projection (identity, canonical outcome, family, module, topology, analyzer semantics) rather than the raw PIT-status–inclusive measurement digest. The motivation (documented in design record #469 and BaselineModel.kt C7) is that raw PIT status is diagnostic evidence, not authority: SURVIVED↔TIMED_OUT scheduler races on unrelated neighbours were able to invalidate already-adjudicated authority even though the authority content was byte-identical across four campaigns. The raw-exact paths (matches(), canonicalProjection(), M21, M32) are deliberately left unchanged.
Changes:
- Add
authorityProjection()/authorityProjectionHash()to the verifier and a secondauthorityProjectionHashfield onMutationPopulationEvolutionProof, both computed by the verifier from the same fresh measurement. - Make M34 compare the authority hash, renaming
freshProjectionHash → freshAuthorityProjectionHashthrough the whole chain, and update the M34 diagnostic and trust-properties docs. - Update test support (
digestOfnow returns the authority digest; newrawDigestOf) and add discriminator tests T1/T2/T8 plus a ceremony-level T1; fix a pre-existingMutationRatchetAuthorityTestfixture (admissions = authority.admissions).
| File | Description |
|---|---|
MutationRatchetVerifier.kt |
Adds authorityProjection()/authorityProjectionHash(), a second proof hash, and the freshAuthorityProjectionHash plumbing/docs. |
MutationPopulationAdmissionCeremony.kt |
M34 now compares the authority hash; parameter renamed end-to-end; diagnostic/trust-doc updated to state raw status is excluded. |
MutationRatchetTestSupport.kt |
digestOf returns the authority digest; adds rawDigestOf for raw-exact (M21) assertions. |
MutationPopulationEvolutionProofTest.kt |
Adds T1/T2/T8 verifier-level discriminators for the authority projection. |
MutationPopulationAdmissionCeremonyTest.kt |
Adds ceremony-level T1; updates the M34 negative test's expected diagnostic substring. |
MutationRatchetAuthorityTest.kt |
Retains base admissions in the self-ratchet fixture to fix a pre-existing M37 false failure. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…edup projection suffix Two review corrections on #470, both narrow. 1. The real authority-transport fixture derived the wrong digest semantics. MutationPopulationAdmissionIntegrationTest.projectionDigest() returned exactComparison(...).proof?.projectionHash - the raw-v1 measurement digest - while production M34 now compares authorityProjectionHash. The fixture therefore minted a digest the verifier no longer consumes, and the lane passed while the real transport was broken. It now derives the authority projection, and is renamed authorityProjectionDigest so its semantics are explicit; the doc comment records why minting projectionHash here is the wrong thing. This was the miss in the previous head: the support-helper digest was corrected but the task-level fixture is a separate implementation. Verifier tests prove semantics; real-task tests prove authority transport, and only the former was fixed. 2. The Copilot suggestion: canonicalProjection() and authorityProjection() duplicated the topology= and analyzer= serialization verbatim. Both now end with append(contextLines()), one private helper. Output is byte-identical (same appendLine calls, same order, same buffer), so no digest moves - the assertion that the authority projection is exactly the raw projection minus raw status is now structural rather than incidental. Callers swept, not just the reported file: the discriminator test's uses are proof.matches(...) - the measurement proof, which correctly stays raw - and the wiring test derives no digest. No raw digest derivation remains in any transport fixture. Verification: - :build-logic:test (mutation-authority family, --rerun-tasks) - BUILD SUCCESSFUL, 142 tests, 0 failures - spotlessKotlinCheck -PtramaiFormattingBaseRef=ec8b4da5... - BUILD SUCCESSFUL - :build-logic:canonicalProbeIntegrationTest - fails on CanonicalProbeFunctionalTest.kt:507 with an identical signature at the pristine base ec8b4da (BASE_INTEGRATION_RC=1), so it is pre-existing and NOT regenerated here. No Step 2, no certificate, no P2, no authority or config migration.
MutationPopulationAdmissionIntegrationTest.kt:466 exceeded MaxLineLength after the rename to authorityProjectionDigest. Wrapped into the standard multiline form rather than baselined or suppressed: the Detekt baseline is unchanged (base 4792 -> current 4792, 0 added, 0 removed). Gate: verifyStaticAnalysis - no new findings. spotlessKotlinCheck - clean. verifyChangePolicy - PASSED, 7 changed files, change class build-logic, no policy violations.
e6e0d69
into
epic/0.7.1-control-plane-authority

Base
ec8b4da59bc9e22711b0cd802417d297f803b4e0— the#469design record is already authority on the Epic.Step 1 of three from
TASK-0.7.1g1P2-AUTHORITY-MODEL-RECONCILIATION.md: the authority-v2 projection. No certificate logic, no consumption rules, no P2.Scope
Seven files, all intentional:
build-logic/.../quality/MutationRatchetVerifier.kt— newauthorityProjection()/authorityProjectionHash():identity|outcome|family|module, sorted, plus the sharedtopology=/analyzer=suffix.MutationPopulationEvolutionProofnow carries two hashes, both computed by the verifier from the same fresh measurement. The suffix both projections share is serialized by one private helper,contextLines(), so "the authority projection is exactly the raw projection minus raw status" is structural rather than incidental (byte-identical output, so no digest moved).build-logic/.../quality/MutationPopulationAdmissionCeremony.kt— M34 compares the authority hash; the parameter is renamedfreshAuthorityProjectionHashthrough the whole chain (verifier → context → ceremony →appearanceVerdict) so the name cannot lie; the diagnostic and the trust-properties doc now state that an authorization binds the measured population's authority content and deliberately not raw PIT status.MutationRatchetTestSupport.kt—digestOfreturns the authority digest (its own doc already said it is "the value the admission ceremony compares against"); newrawDigestOffor M21 assertions. One line, 18 call sites.MutationPopulationEvolutionProofTest.kt— T1, T2, T8.MutationPopulationAdmissionCeremonyTest.kt— T1 at ceremony level; the M34 negative test's expected diagnostic substring.MutationRatchetAuthorityTest.kt— one fixture line, evidenced below.MutationPopulationAdmissionIntegrationTest.kt— the real mint→transport fixture, changed from the rawprojectionHashtoauthorityProjectionHash, withprojectionDigest()renamedauthorityProjectionDigest()so the semantics are explicit at every call site. This is the fixture that actually writes the admission ledger and drives the task end to end, so minting the raw-v1 measurement digest there meant the lane passed while the real transport was broken. Both call sites (writeAdmissionLedger(...)and the base≠candidate precondition) were updated, and the assertion exceedingMaxLineLengthafter the rename was wrapped rather than baselined.Why
C7 (
BaselineModel.kt:348-354) declares raw PITstatusdiagnostic evidence and not authority, and explicitly anticipates TIMED_OUT↔SURVIVED scheduler races. Four complete unrestricted campaigns at identical effective PIT inputs produced four distinct raw-status digests — three identities of 2544 oscillating only SURVIVED↔TIMED_OUT, all NON_KILLED in every campaign — while the authority content was byte-identical:e6ad01dc1d2966894a6555304bc8ca9a04c8174e3c83ae88760fcfebf1464dad.M34's digest was
projectionHash, the measurement proof, whose raw-status content is correct for its own purpose. Reusing that one hash for the population-context question let a scheduler race on unrelated neighbours invalidate adjudicated authority. This was not a deliberate override of C7 — it was one hash serving two different trust questions.Invariants preserved
exactComparison(),matches(),canonicalProjection()and M21 stay raw-exact. No relaxation where raw status genuinely is authority.NO_COVERAGE → SURVIVEDreading would falsify the UNREACHABLE proof.Verification
./gradlew :build-logic:compileKotlin— BUILD SUCCESSFUL./gradlew :build-logic:test --tests 'dev.tramai.build.quality.MutationPopulation*' --tests '...MutationRatchet*' --tests '...MutationEvolution*' --tests '...MutationEnrollment*' --rerun-tasks— BUILD SUCCESSFUL, 8 tasks executed, 12 classes / 142 tests / 0 failures (a genuine execution, not an up-to-date pass)./gradlew verifyCancellationSafety— PASSED: 317 findings in scoped modules, no new critical/high findings or risk worsenings againstorigin/master(auto-resolved merge base41ac9151)./gradlew spotlessKotlinCheck -PtramaiFormattingBaseRef=ec8b4da59bc9e22711b0cd802417d297f803b4e0— BUILD SUCCESSFUL (three violations in the touched files fixed by hand;spotlessApplydeliberately not used because the ratchet reformats legacy files whole)./gradlew verifyStaticAnalysis— no new findings; Detekt baseline unchanged (base 4792 → current 4792, 0 added, 0 removed). TheMaxLineLengthfinding introduced by the transport-fixture rename was wrapped into the standard multiline form, not baselined and not suppressed../gradlew verifyChangePolicy -PchangePolicyBase=ec8b4da59bc9e22711b0cd802417d297f803b4e0— PASSED, 7 changed files, change classbuild-logic, no policy violations./gradlew :build-logic:canonicalProbeIntegrationTest— fails onCanonicalProbeFunctionalTest.kt:507(IllegalStateException) with an identical signature at the pristine base (BASE_INTEGRATION_RC=1), so pre-existing and not regenerated.MutationPopulationAdmissionIntegrationTest— the authority-transport lane this PR actually fixes — is not among the failures../gradlew :build-logic:test --tests 'dev.tramai.build.quality.MutationPopulation*' --tests '...MutationRatchet*' --tests '...MutationEvolution*' --tests '...MutationEnrollment*' --rerun-tasks— BUILD SUCCESSFUL, 8 tasks executed, 12 classes / 142 tests / 0 failures (a genuine execution, not an up-to-date pass)./gradlew verifyPr -PchangePolicyBase=ec8b4da59bc9e22711b0cd802417d297f803b4e0— red only on pre-existing failures, each reproduced at the exact base (below). Development-time runs that overlapped each other produced additional spurious failures inFormattingGateConfigCacheTestandverifyCancellationSafety; both pass when run alone, and the concurrency was self-inflicted.Pre-existing failures, classified with base evidence
CancellationWiringTest > C1 cancellation authority remains exact base task()— reproduces at the pristine baseec8b4da5(3 tests, 1 failure), same assertion. Left alone: out of scope for this slice.TramaiDocsGuardsPluginTest > verifyVersionAlignment …(4 failures) — reproduces at the pristine base on a branch checkout (fresh worktree, branchtmp-base-branchatec8b4da5,BASE_BRANCH_DOCS_RC=1). Branch-dependent: the same test passes in a detached-HEAD worktree at the same SHA. Environment/workflow-dependent, not caused by this change, and evidently not in CI's filtered matrix.MutationRatchetAuthorityTest > certified authority passes its own ratchet against identical candidate— reproduces at the pristine base with an identical signature (8 tests, 1 failure,M37 ... 050d2b83), and the changed code path cannot reach it (consumed = mutant != null && …short-circuits before M34 when the identity is absent from the candidate). Diagnosedtest-defect: the candidate passedadmissions = NONEwhile the real base holds 67 pending authorizations, asserting a transition M37 forbids. Corrected to retainauthority.admissions, so absent targets are M39 warnings as designed. Now passes.TramaiDocsGuardsPluginTest/ReleaseVerificationPluginTestalso show red in a full local run and are not classified — they cannot exercise the changed code path, and CI's filteredcontract-testsmatrix is the authority on them.Discriminators added (design record §7, T1/T2/T8)
Quality impact
MutationPopulationEvolutionProofgains a field on a private constructor)Not run
:build-logic:testsuite does not pass locally for reasons unrelated to this change (see above); CI's filtered matrix is the final authority.Remaining risks
9aebd320…, so under authority-v2 they are not consumable until the migration certificate exists in a base. P2 stays blocked; nothing here consumes them.--rerun-tasksexecution.