HOMELAB-1850: feat(routines): phase census — split identity, P-ROUT-012, calibration line (R-29) #594
No reviewers
Labels
No labels
operator-review
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Homelab/infra-core!594
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-1850-attribution"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The Go half of LD4.5d: the check, the finding and the digest line over the
phasekeythat pi-extensions emits in Homelab/pi-extensions#60.
Brief:
.rpiv/artifacts/epic-ld4/design-LD4.5d-attribution.md(ticket HOMELAB-1850).Territory:
routines/rollup.gois NOT touched (its sha256 pin is a promise an auditorre-derives, and LD4.4 owns R-06). A new file reads
RollupResult.What lands
routines/phase.go— the phase census:SplitPhaseTotals/SplitPhases: the identity that is the ticket's verify line 2—
Σ(build, review, verify) + untagged == total, exactly, integer tokens, notolerance.
unphased(the value the telemetry writes when nothing was declared) andany label outside the closed enum are UNTAGGED and NAMED — never a fourth bucket,
never folded into one of the three. A blank-phase sample lands in untagged by
construction (
GroupSamplesskips it on purpose).ValidatePhaseSplit/...WithDeclarations: the enforcement point. A non-summingsplit is an episode-class mismatch (a folding bug); a bucket that DECLARED a phase
and still carries untagged spend is a dispatcher defect; untagged spend on an
undeclared/legacy window is reported together with the instrument's own coverage.
CalibrationLine/PhaseCensusMarkdown/PhaseCensusDigest: verify lines 3 and4. The line quotes THIS fleet's measured validation share with n, the window and
the untagged share; the vendor 40 % datum appears only as an external,
single-mission comparison ("not reproduced at this sample size" / "one comparison,
not corroboration"). An empty window is a visible no-op, never a published 0 %.
The table gives untagged its own column — unknown is not healthy.
PhaseCensusExecutor: the runner seam for R-29 (the R-06ExecutorAdapterprecedent) — names the series it emitted, refuses to claim success from a failed
read.
registry.yaml— R-29phase-census, ACTIVE (its mechanism ships in this build),pinned to
phase.go's sha256 (re-derived byTestInProcessPinsMatchTheCode).policy.go+policy.md— P-ROUT-012 (both files change together: the doc isparsed back by
TestPolicyBookMatchesDoc).registry_test.go— the census floor is now DERIVED from the corpus fixtureinstead of a hardcoded number, plus R-29's shape assertion.
README.md— the territory section names what 4.5d owns on this side.One deliberate deviation, flagged
R-29, not R-27 (the slot brief said R-27). The registry header has reserved
R-23/R-26/R-27 for tickets 4.7/4.10/4.11 since LD4.4, and
testdata/registry-4x-shapes.yamlalready carries R-27's shape (quarterlymaintainability fitness,
emitsWorkwith one emits) becauseTestSchemaAccommodatesHosted468Shapesasserts it. Registering a different R-27 herewould put two R-27s in one repository and break the registry's own "ids are stable
forever" rule. R-28 is LD4.5b's on-call window (per that design brief), so the next free
id is R-29. Same count outcome (26 entries): the id, not the count, is what moved.
Verification
go test -race ./...— green (all packages).go vet ./...— clean.routines/phase_test.go(TestC6*): the split identity over a landed-PR-shapedfixture, the untagged cases (incl.
unphased,Build,deploy, blank), thedeclared-phase defect, the mismatch episode, the calibration line (our share rendered,
vendor datum external-only, unstated window printed as unstated), the rendered census
row (untagged never inside a phase column), the no-op receipt and the closed enum.
FixtureMetricSource).Not in this PR
telemetry-phase.yaml): the verify lines are satisfiedby the Go calibration line and the census artifact, and the cockpit panes are 3.4's
slot; adding a new alerting rule to a dangerous PR would widen its review surface for
no evidential gain. Named here so it is not a silent gap.
The check over what the emission side writes. `rollup.go` is untouched (its sha256 pin is a promise an auditor re-derives, and LD4.4 owns it); this is a new file that READS RollupResult: * `SplitPhaseTotals` / `SplitPhases`: the per-sandbox census whose arithmetic is the ticket's verify line 2 — `Σ(build, review, verify) + untagged == total` exactly, integer tokens, no tolerance. `unphased` (the value the telemetry writes when nothing was declared) and any label outside the closed enum are UNTAGGED and NAMED, never a fourth bucket and never folded into one of the three. A blank-phase sample lands in untagged by construction (GroupSamples skips it deliberately). * `ValidatePhaseSplit` / `ValidatePhaseSplitWithDeclarations`: the enforcement point. A non-summing split is an episode-class mismatch (a folding bug); a bucket that DECLARED a phase and still carries untagged spend is a dispatcher defect; untagged spend on an undeclared/legacy window is reported with the instrument's own coverage. Both cite P-ROUT-012. * `CalibrationLine` / `PhaseCensusMarkdown` / `PhaseCensusDigest`: verify lines 3 and 4. The line quotes THIS fleet's measured validation share with n, the window and the untagged share, and the vendor datum appears only as an external, single-mission comparison ("not reproduced at this sample size" / "one comparison, not corroboration"). An empty window is a visible no-op, never a published 0 %. The table gives untagged its own column: unknown is not healthy. * `PhaseCensusExecutor`: the runner seam for R-29 (the R-06 ExecutorAdapter precedent) — names the series it emitted and refuses to claim success from a failed read. Registry: R-29 `phase-census`, ACTIVE (its mechanism ships in the same build), pinned to this file's sha256. It takes R-29, NOT the briefed R-27: the header has reserved R-27 for 4.11 since LD4.4 and `testdata/registry-4x-shapes.yaml` already carries R-27's maintainability-fitness shape (asserted by TestSchemaAccommodatesHosted468Shapes), so a second R-27 would break the registry's own "ids are stable forever" rule. R-28 is LD4.5b's on-call window; R-29 is the next free id. The census floor in registry_test.go is now derived from the corpus fixture instead of a hardcoded 24. policy.go/policy.md: P-ROUT-012 (both files change together — the doc is parsed back by TestPolicyBookMatchesDoc). Tests: phase_test.go (TestC6*) covers the identity, the untagged cases, the declared-phase defect, the mismatch episode, the calibration line, the rendered census row and the no-op receipt. `go test -race ./...` + `go vet ./...` green.Landing review — APPROVE (clean, no blocker findings)
Reviewed sha:
4a6e192f9bbd9dbbcc172f29e8ebce404ea0dab5(head). Fresh context; sources = PR diff, HOMELAB-1850 + adjudication comments,design-LD4.5d-attribution.md, ticket verify lines. No implementer summary used as the brief.Verified against the acceptance criteria
Σ(build,review,verify) + untagged == totalis unit-testedTestC6PhaseSplitSumsToSandboxTotal(exact, integer, no tolerance; all three phases asserted non-empty)TestC6SplitMismatchIsAnEpisode(ByPhase sums > Tokens →SeverityEpisode+P-ROUT-012); declared-phase-with-untagged → defect finding (TestC6DeclaredPhaseWithUntaggedSpendIsAFinding)TestC6UntaggedSpendIsNeverOneOfTheThree(unphased/Build/deploy/blank → Untagged, labels named),TestC6CensusRendersUnphasedAsItsOwnRow(own column, no untagged token in a phase column)CalibrationLineshape supports the digest quoterollup.goUNTOUCHED (pin check)git diff --stat 782b346..HEAD= README, phase.go, phase_test.go, policy.go, policy.md, registry.yaml, registry_test.go). R-06 pinsha256:6fcec5b4…unchangedsha256sum phase.go=48e1427b59ad4b5cee4a05888ead03284b89d719868fa89dfd2b2cd1002adaed=registry.yamlscriptRef.rev;TestInProcessPinsMatchTheCodegreentestdata/registry-4x-shapes.yamlshape (TestSchemaAccommodatesHosted468Shapesgreen). R-29 is the next free id; R-28 is the sibling LD4.5b slot. R-29 entry mirrors R-06's field-for-field shape;TestRealRegistryLoads+TestPolicyBookMatchesDocgreenphase_test.gouses in-memoryFixtureMetricSource; nonet/http. Localgo test -race -run 'TestC6|TestInProcessPinsMatchTheCode|TestRealRegistryLoads|TestPolicyBookMatchesDoc|TestSchemaAccommodatesHosted468Shapes' ./routines/→ ok, 1.2s4a6e192f9b: dispatcher-test 4m26s, helm-validate, receiver-test, alert-receiver-test all successsandbox_env+R-06; this ownsphase)rollup.go, nosandbox.ts, no swarm-view UIprod/apps/tempo.yamlhas no values of its own; it pulls$values/core/charts/platform/tempo/values.yamlfrominfra-core@live. No tempo values file exists inprod/outside worktreesConcerns (non-blocking, for the record)
plane/HOMELAB-1847-oncallbranch (whose own header still says "Active today (4)"). On this branch there are 5 active entries (R-03, R-06, R-19, R-24, R-29), 25 entries total. The PR body's "26 entries" inherits the same off-by-one. The sentence becomes true at the Wave-4 union; whoever lands the sibling should reconcile the header count. Comment-only, no functional effect — not a blocker.identity/claim_bind.gorendersLD_ROLEviaEnv()/EnvPairs()(which has no non-test consumer in-repo), and §2.2 of the brief explicitly keepsphaseout of the claim binding (identity ≠ stage). The dispatch recipe ships as data in pi-extensions #60. #594's territory is correct.Merging on green CI + clean verdict.