You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(migrate): advertise the value-shape gate, and stop counting fields nothing enforces (#3438)
The scan shipped with no way to find out it exists. ADR-0104's rollout asked
for two advertisements and neither was built: `os migrate meta` — the command
a 16→17 upgrade already runs — never mentioned the data migrations, and a
warn-first deployment booted silently. The command landed and the posture it
governs never changed, because a gate nobody is told about is served by nobody.
`os migrate meta` now closes by naming both gated data migrations with what
each covers and the gate it records, on the human path and in `--json` alike,
including the run that rewrote nothing — an upgrade needing no source change is
exactly where "already done" is easy to assume. A kernel booting with covered
fields and no verified `adr-0104-value-shapes` row logs one line naming the
command that ends warn mode; every case where that line would be false or
useless (an env switch already settled the posture, no covered field is
registered, the gate is already open) answers null and stays silent.
Deliberately WITHOUT reading gate status from the datastore inside `os migrate
meta`, which the ADR's sketch of this advisory assumed it would show. That
command rewrites metadata SOURCE and has never opened a database — its e2e test
spawns the real CLI against a project in a tmpdir. Booting one to decorate a
hint would hand a read-only command a `.objectstack/` side effect and a new way
to hang on an unreachable database, a poor trade for two words of status.
Status is served where a datastore is already open: both commands report before
they write anything, and the boot line carries the live verdict.
Building the advisory surfaced a defect in the gate that shipped with the scan.
`objectHasCoveredValueField` — the dormancy short-circuit meant to spare an
object with no covered field the flag query — tested raw type membership, while
the registry INJECTS covered-type fields into every object it registers:
`organization_id` and `owner_id` (both `system`), `created_by` and `updated_by`
(both in `SKIP_FIELDS`), four `lookup`s. `validateRecord` skips every one of
them before the value-shape check, so the short-circuit answered true for
literally every object, never fired, and its cache memoized a constant. It now
uses the validator's own `isScannableValueShapeField`, the predicate the
scanner already imports — three readings of "a covered field" drifting by one
clause is how a gate ends up governing fields nothing enforces. The flag read
was already memoized per process, so this corrects the property the ADR states
rather than a user-visible cost. The silent-when-uncovered test pins it: an
object declaring only text still carries those four injected lookups, and
counting by type made the advisory fire on every deployment that exists.
Verified: objectql 1326, cli 625, spec 7154, platform-objects 253,
service-storage 252, driver-memory 265, runtime 954; check:generated 8/8;
release-notes and doc-authoring gates pass; docs site and all 71 packages
build; ESLint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgA8CQMJeJbFEjnbib1Uv
0 commit comments