… parity ledger (#11146)
Three mechanisms broke "every subnet's API, exactly like using it directly",
each silently. Phase 3 (the surface method dimension) landed in #11210 and the
first declared mutation in #11212; this closes the rest.
FRESHNESS IS MEASURABLE. The capture lane's cadence is declared
(SCHEMA_CAPTURE_CADENCE_HOURS = 48) and published on the schema index. No age
is baked into the artifact on purpose: it is served for hours after it is
built, so a build-stamped age is wrong on arrival, is not reproducible across
two builds, and -- because buildTimestamp() is the 1970 placeholder in every
local build -- would have published a twelve-day-old capture as FRESH. Each
entry already carries observed_at; the subtraction belongs to the reader,
whose clock is the only one that says now.
DRIFT SAYS WHAT IT MEASURES. Captured entries carry drift_basis:
"previous-capture". drift_status compares our snapshot to OUR previous
snapshot, never upstream -- which is why 23 of 24 measurably-drifted subnets
reported "unchanged". The payload now says so rather than implying otherwise.
THE PARITY LEDGER. Each gaps row gains schema_parity: captured paths and
declared mutations against registered route surfaces and registered mutations,
flagged when the catalogue registers fewer routes than the subnet declares.
Derived from schema INDEX entries only, with the capture lane now stamping
non_get_operation_count so both sides are measured; unmeasured counts report
null, never zero. First build: 53 subnets measured, 27 flagged.
Closes #11146
Closes #11146.
The epic measured three mechanisms that each silently broke "every subnet's API, exactly like using it directly". Phase 3 (the surface
methoddimension) landed in #11210 and the first declared mutation in #11212; this completes the rest in one change.1. Freshness is measurable
The capture lane's cadence is declared once (
SCHEMA_CAPTURE_CADENCE_HOURS = 48) and published on the schema index ascapture_cadence_hours. The lane stays manual by ADR 0006 — declaring the cadence does not run it, it makes its silence measurable, which is the difference between an unpublished gap and a published one.No age is baked into the artifact, deliberately. The index is served for hours after it is built, so a build-stamped age is wrong on arrival; it is also not reproducible across two builds; and because
buildTimestamp()returns the 1970 epoch placeholder in every local build, an earlier revision of this branch published a twelve-day-old capture as fresh — caught in a built artifact, and the reason the design changed. Every entry already carriesobserved_at, so the subtraction belongs to the reader, whose clock is the only one that says now.2. Drift says what it measures
Captured entries carry
drift_basis: "previous-capture".drift_statuscompares our snapshot to our previous snapshot, never upstream — which is why 23 of 24 measurably-drifted subnets reportedunchanged. The payload now says so rather than implying the opposite.3. The parity ledger
Each gaps row gains
schema_parity: captured paths and declared mutations against registered route surfaces and registered mutations,flaggedwhen the catalogue registers fewer routes than the subnet declares.Derived from schema index entries only — captured documents exist solely in credentialed builds, so a rollup reading them would not be reproducible — with the capture lane now stamping
non_get_operation_countso both sides of the mutation ledger are measured. Counts absent on pre-stamp entries report null, never zero.First measurement: 53 subnets measured, 27 flagged — sn-3 registers 8 routes against 208 declared paths; sn-105 registers 29 (including the
POSTsurface from #11212, which the ledger counts as its 1 registered mutation) against 53.Validation
typecheck,lint,format:checkvalidate(129 subnets / 3,330 surfaces),validate:api(215 routes),validate:openapi,validate:contract-drift,validate:published-names,validate:unreferenced-exports(731 — at the ceiling, not raised; the earlier revision's new type exports were removed rather than ratcheted),validate:schema-enums,validate:schema-vocabularies,validate:mcp(240 tools),validate:schemas,validate:no-hand-written-mjsartifacts-build-determinismand the schema-index-preservation suite — both re-run against a pristine committed baseline, which is how the build-clock defect above was found