Skip to content

feat(measurement): Advanced Measurement v2 contracts, migrations and route surface - #915

Merged
arberx merged 1 commit into
mainfrom
ax/measurement-v2-contracts
Aug 2, 2026
Merged

arberx merged 1 commit into
mainfrom
ax/measurement-v2-contracts

Conversation

@arberx

@arberx arberx commented Aug 2, 2026

Copy link
Copy Markdown
Member

Slice 1 of Advanced Measurement v2: the contracts, migrations and route surface
everything else builds on. Nothing here changes behaviour. Every new route
answers 501 until the services behind it land.

It exists so the remaining slices can be written against fixed contracts instead
of invented ones, and so four of them can run in parallel without fighting over
the same registration files.

Schema v2. A published plan with Branded/Non-brand assignments, frozen
per-Group competitor identities, revision-frozen project identity, and query
snapshots so a later rename cannot rewrite history. The v1 decoder is untouched
and stored v1 plans stay byte-compatible: the version switch gains a v2 case, and
a new any-version reader returns the union.

Two checksums, deliberately. compiled_checksum is a new nullable column,
not a redefinition of the existing checksum. checksum hashes the whole
document including revision, so reusing it as the publish guard would mean no two
revisions could ever compare equal, and neither republishing identical content
nor reverting to an earlier configuration could be recognised. Redefining it
instead would break byte-identity for already-published v1 rows. Its index is
non-unique on purpose: a unique index makes reverting a plan impossible, which
contradicts the rule that restoring old content creates a new revision.

Migrations v122 and v123 add the draft, query-set, template,
discovery-config and idempotency-receipt tables. The drizzle schema is mirrored
column by column with a test that fails when the two disagree, because that drift
corrupts reads silently and no other gate catches it.

Read surfaces now decode any schema version. Three call sites went through
the v1-only reader, so the first published v2 revision would have turned plan
reads, revision detail and the report adapter into 500s. The segment retirement
guard sees v2 plans too, which matters: it is what stops a segment being retired
out from under an active revision. Execution and reporting refuse a v2 revision
with a domain error rather than crashing, and are marked as the seams the runner
and reporting slices replace.

Every behaviour is pinned by a test proven by reverting the production change.
Backend only; nothing under apps/web is touched.

570 test files, 6776 tests, typecheck, lint and codegen all green.

…route surface

The foundation for Advanced Measurement v2. Nothing here changes behaviour: every
new route answers 501 until the services behind them land. It exists so the rest
of the work can proceed against fixed contracts rather than invented ones.

Adds schema v2 as a published plan shape with Branded/Non-brand assignments,
frozen per-Group competitor identities, revision-frozen project identity, and
query snapshots that keep a later rename from rewriting history. The v1 decoder
is untouched and stored v1 plans stay byte-compatible; the version switch gains a
v2 case, and a new any-version reader returns the union.

The new compiled_checksum is a separate, nullable, separately indexed column
rather than a redefinition of the existing checksum. They are not
interchangeable: checksum hashes the whole document including revision, so
reusing it as the publish guard would mean no two revisions could ever compare
equal, and republishing identical content or reverting to an earlier
configuration could never be recognised. Its index is deliberately non-unique,
because a unique one makes reverting a plan impossible.

Adds migrations v122 and v123 for the draft, query-set, template,
discovery-config and idempotency-receipt tables, with the drizzle schema mirrored
column by column and a test that fails when the two disagree, since that class of
drift corrupts reads silently and nothing else catches it.

Read surfaces now decode any schema version. Previously three call sites went
through the v1-only reader, so the first published v2 revision would have turned
plan reads, revision detail and the report adapter into 500s. The segment
retirement guard now sees v2 plans too, which matters: it is what stops a segment
being retired out from under an active revision. Execution and reporting refuse a
v2 revision with a domain error and are marked as the seams the runner and
reporting slices replace.

Every behaviour is pinned by a test proven by reverting the production change.
@arberx
arberx merged commit b118967 into main Aug 2, 2026
13 checks passed
@arberx
arberx deleted the ax/measurement-v2-contracts branch August 2, 2026 09:18
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.

1 participant