Skip to content

feat(registry): schema-capture freshness, honest drift basis, and the parity ledger - #11217

Closed
JSONbored wants to merge 1 commit into
mainfrom
feat/schema-parity-freshness
Closed

feat(registry): schema-capture freshness, honest drift basis, and the parity ledger#11217
JSONbored wants to merge 1 commit into
mainfrom
feat/schema-parity-freshness

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #11146.

The epic measured three mechanisms that each silently broke "every subnet's API, exactly like using it directly". Phase 3 (the surface method dimension) landed in #11210 and the first declared mutation in #11212; this completes the remaining three in one change.

1. Freshness is visible

The capture lane's cadence is declared once (SCHEMA_CAPTURE_CADENCE_HOURS = 48) and every captured index entry carries capture_age_hours + capture_stale; the artifact carries capture_cadence_hours so a consumer can compute staleness itself.

The lane stays manual by ADR 0006 — declaring a cadence does not run it, it makes its silence visible, which is the difference between an unpublished gap and a published one.

An unusable clock is null, never zero. buildTimestamp() returns the 1970 epoch placeholder in every local and determinism build; an early Math.max(0, …) in this branch published a twelve-day-old capture as fresh — the exact dishonesty this phase removes. Caught in a built artifact, fixed, and pinned by a test.

2. Drift says what it measures

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 the opposite, and capture_stale tells a reader the comparison is old.

3. 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, captured_stale when the measurement rests on an old capture.

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_count so 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 28 against 53, matching the epic's fleet numbers.

Validation

  • typecheck, lint, format:check
  • validate, validate:api (215 routes), validate:openapi, validate:contract-drift, validate:published-names, validate:schema-enums, validate:schema-vocabularies, validate:mcp (240 tools), validate:schemas, validate:module-state-resets, validate:no-hand-written-mjs — all green
  • Full suite green, including the build-determinism and schema-index-preservation suites (both exercised directly against a pristine committed baseline)
  • Both clock arms proven end-to-end on real builds: epoch stamp → all 53 captured_stale: null; real stamp → all 53 true (captures are 12 days old against a 48h cadence)

… parity ledger (#11146)

Three mechanisms broke "every subnet's API, exactly like using it directly",
each silently. This closes the epic:

1. FRESHNESS IS VISIBLE. The capture lane's cadence is declared
   (SCHEMA_CAPTURE_CADENCE_HOURS), and every captured index entry carries
   capture_age_hours + capture_stale. The lane stays manual by ADR 0006 --
   declaring the cadence does not run it, it makes its silence VISIBLE, which
   is the difference between an unpublished gap and a published one. An
   unusable build clock yields null, never zero: buildTimestamp() is the 1970
   placeholder in every local build, and clamping would have republished a
   twelve-day-old capture as fresh.

2. DRIFT SAYS WHAT IT MEASURES. 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 instead of 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, flagged when the catalogue registers fewer routes than the
   subnet declares. Derived from schema INDEX entries only -- captured
   documents exist solely in credentialed builds -- with the capture lane now
   stamping non_get_operation_count so both sides are measured. First build
   measures 53 subnets and flags 27.

Closes #11146
@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-registry-sync-api 81d1ec0 Aug 14 2026, 12:54 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-data-api 81d1ec0 Aug 14 2026, 12:54 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-wss-lb 81d1ec0 Aug 14 2026, 12:54 PM

@JSONbored

Copy link
Copy Markdown
Owner Author

Closing on red CI rather than pushing over it. Two real defects, both mine:

  1. validate:unreferenced-exports — the branch added type exports nothing imports (SchemaParity, CaptureFreshness), pushing the count past the 731 ceiling. The ratchet only falls; the fix is to stop exporting them, not to raise it.
  2. artifacts-build-determinism — deriving capture age from the build clock is non-deterministic across two builds and wrong on arrival anyway (an artifact is served for hours; a build-stamped age is stale immediately). Freshness belongs at SERVE time, where 'now' is genuinely now.

Rebuilding as one PR that closes #11146.

@JSONbored JSONbored closed this Aug 14, 2026
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.

epic(parity): "every subnet's API, exactly like using it directly" is not what we serve — three mechanisms measured, and what each one costs

1 participant