docs(qa): classify the five UNCLASSIFIED capability ledgers — four REST-config kinds authored, realtime_subscription waived - #15541
Conversation
…ST-config kinds authored, realtime_subscription waived `check:platform-checklist` was red on `main`: five capability ledgers had neither checklist items nor a waiver. The card names four (`batch_endpoints`, `crud_endpoints`, `metadata_endpoints`, `route_generation`); `realtime_subscription` was enrolled the morning of dispatch and the gate reports it too, which the card's triage anticipated by asking for a re-run on today's `origin/main`. Four new items in `areas/api-backend.json`, authored against the shipped REST surface rather than the ledgers' prose — each covers the deployment config that decides which routes exist, not the routes' behaviour (which existing items already drive): - `rest-crud-config-contract` — five switches gate six mounts (`operations.list` also gates `POST /:object/query`), `dataPrefix` moves the routes and the `/discovery` advertisement together, both #14691 tombstones refuse at construction. - `rest-batch-config-contract` — `enableBatchEndpoint` gates only the per-object door (the cross-object `POST /batch` is unconditional), each bulk gate is an AND with its protocol member, `maxBatchSize` is the one cap all five doors measure. - `rest-metadata-config-contract` — `prefix` moves the surface and its advertisement, the three endpoint switches gate more routes than their declared meaning says (`endpoints.items` also gates the `_migrate-stored` write door), `maskObjectFields` is the ADR-0106 D8 disclosure gate, six cache carve-outs. - `rest-route-generation-tombstones` — the one kind with no live property left: all four selectors were retired 2026-09-03, and the refusal-with-a-prescription IS the shipped behaviour, so it is authored rather than waived. `realtime_subscription` is waived with the measurement written out: `SubscriptionSchema` has zero runtime readers (every property `dead` at a same-day census, the shipped adapter reads `RealtimeSubscriptionOptions` instead), and `/discovery` advertises realtime with `handlerReady: false` and no route — the open decision on whether a transport is mounted at all is #14646. The waiver names both of its exits. `FOLLOW-UPS.md` §10 records what is not a checklist item: the `endpoints.items` radius, that no shipped boot path authors `RestServerConfig` at all, and that the mount half of every switch is unpinned. §10 is the first FOLLOW-UPS section to carry symbol anchors, so the anchor baseline gains a floor for it at the censused count. Verified: `pnpm check:platform-checklist` exit 0 (35 kinds mapped, 1 waived; 624/624 anchors resolved, 17 file floors held) · `--self-test` 176 assertions exit 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
E1 → #15542 (the `endpoints.items` radius), E2 → #15543 (no boot path authors `RestServerConfig`), E3 → #15544 (the mount half of every switch is unpinned). The rows said "filed"; a register that does not carry the reference makes the next sweep re-derive the finding to discover it already has a card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
|
ACCEPT + ruling — PM seat Reviewed against the three-dot diff This gate is not CI-wired (#11730), so this seat MEASURED it in a detached worktree at against main's Ruling on the open question: A — keep the waiver. It claims the READER is missing (measured by a census that states its method and scope, plus the
Generated by Claude Code |
Fixes #14961
check:platform-checklistwas red onmain: capability ledgers existed with neither checklist items nor a waiver. Every capability is now classified, and the gate exits 0.The kind set had moved — five, not four
The card was measured at
ca3fd4b1(2026-09-03) and names four kinds. Re-run on today'sorigin/main(6f944589, as the card's triage asked), the gate reports five:realtime_subscriptionwas enrolled that same morning by the SubscriptionSchema liveness enrolment. Clearing the four named kinds alone would have left the gate red, so all five are classified here. The drift happened inside the lifetime of the card filed against the red — recorded inFOLLOW-UPS.md§10a as the sharpest available evidence for the standing channel decision card #11730, which this PR does not touch and does not answer.Before (base
6f944589, exit 1, five findings):Per capability: authored or waived, and why
Four of the five ledgers govern
RestServerConfigsub-objects — deployment construction arguments, not stored metadata. The checklist already drove the routes; nothing covered the config that decides the routes exist. That is the gap the four new items inareas/api-backend.jsonfill, authored againstpackages/restandpackages/spec/src/api/rest-server.zod.tsrather than against the ledgers' prose.crud_endpointsapi-backend.rest-crud-config-contract+ the two existing items that drive the mounted data routes. Five liveoperations.*switches gate six mounts —operations.listalso gatesPOST /:object/query, which has no switch of its own —dataPrefixre-bases the CRUD, data-action, sharing and batch registrars and the/discoveryroutes.dataadvertisement together (ADR-0076 D12), and the two #14691 tombstones (patterns,objectParamStyle) refuse at construction.batch_endpointsapi-backend.rest-batch-config-contract+bulk-write-contract+batch-transactional-discovery. Two asymmetries were read out of the registrar rather than assumed: the cross-objectPOST /batchis not underenableBatchEndpoint(only the per-object door is), and all four bulk gates are ANDs with a protocol member, so a false switch and a missing protocol member look identical from the route table.maxBatchSizeis the one cap all five doors measure (400BATCH_TOO_LARGE). Tombstones:operations.upsertMany,defaultAtomic.metadata_endpointsapi-backend.rest-metadata-config-contract(P1 — it carries the disclosure gate) +platform-core.metadata-registry-serving.prefixmoves the surface and its/discoveryroutes.metadataadvertisement; the three endpoint switches gate more than their declared meaning says (endpoints.itemsalso gates/diagnostics,/_draftsand thePOST /_migrate-storedwrite door;endpoints.itemalso gates the book-tree read);maskObjectFieldsis the ADR-0106 D8 per-caller field mask, default on, with six carve-outs on theenableCachepath. Tombstones:cacheTtl,endpoints.schema.route_generationapi-backend.rest-route-generation-tombstones. This is the one kind with no live property left — all four selectors were retired 2026-09-03 under ADR-0049 — and a waiver was still the wrong answer: the sub-object stays declared precisely so an authored key is refused with its prescription instead of silently stripped, and that refusal is shipped behaviour a checklist can drive (constructor, plugin path, and tsc). The item also scores whether each prescription names a replacement that actually exists, and keeps the two controls the retirement must not break (routes: {}still constructs; an unknown key is still stripped).realtime_subscriptioncoverage.jsonSubscriptionSchemahas zero runtime readers — its ledger records every propertydeadat a same-day census whose method and scope it declares, nothing outsidepackages/specimports it, and the shipped in-memory adapter readsRealtimeSubscriptionOptions, a different type. There is also nothing to connect to:/api/v1/discoveryadvertises realtimeenabled: truewithstatus: degraded,handlerReady: falseand no realtime route, which is the open decision on #14646 (whether the open framework mounts a transport at all — that card stays open and is not addressed here). An item authored today could only assert absence. The waiver names both of its exits: a mounted transport that parses this schema (author items, flip toitems), or ADR-0049 retiring the schema (the ledger goes and the ratchet reports this entry as an ORPHAN to delete).SWEEP.mdrecords 6 of 6 waivers ever written turning out stale, and every one of those claimed "no independent runtime behaviour" about a surface that had some. This one claims the opposite kind of thing — that the reader is missing — and is grounded in a census plus a discovery reading, not in the schema's own prose.FOLLOW-UPS.md§10d says so, and asks the next sweep to re-audit it like any other waiver.Sweep honesty
This was a scoped sweep (SWEEP.md permits one for a "does the checklist cover X?" question): angle 3 (routes and runtime) only, against⚠️ It was executed sequentially by one reader — no sub-agent tool in the session — which SWEEP.md allows as a degraded path with a declaration. The authored items stand on their own evidence; this run supports no claim that nothing else is missing in these areas. Declared in
packages/rest, the REST config schema and the five ledgers.FOLLOW-UPS.md§10.Also in this PR
FOLLOW-UPS.md§10 — what is not a checklist item: E1 theendpoints.itemsradius (a listing switch that also disarms a migration write door), E2 that no shipped boot path authorsRestServerConfigat all (os servefixes it, the dev plugin passes none — so the sub-objects are embedder-only, which is why every non-default clause is scoredoracle: testand says so), E3 that the mount half of every switch is unpinned (the existing pins assert the normalized config, not the route table). §10c records five behaviours checked and CLEAN so the next sweep does not re-derive them. Each of E1-E3 is also filed as its own issue, unassigned and unlabelled for triage: E1 is [finding]metadata.endpoints.itemsgates four routes — the_migrate-storedwrite door and the diagnostics sweep among them — while its declared meaning names only the type listing #15542, E2 is [finding] No shipped boot path authorsRestServerConfigat all —os servefixes it and the dev plugin passes none, so every livecrud/metadata/batchkey is embedder-only #15543, E3 is [finding] The MOUNT half of everyRestServerConfigswitch is unpinned — the tests assert what a switch normalizes to, never that the route leaves the table #15544 (E2 sharpens the already-open [finding] The client SDK hard-codes/data/${object}…whilecrud.dataPrefixis live and discovery advertisesroutes.data = base + dataPrefix— a non-default prefix makes the SDK disagree with the mounts #14879).scripts/checklist-symbol-anchor-baseline.json— §10 is the first FOLLOW-UPS section to carry symbol anchors, so the file gains a floor at the count--anchor-censusmeasured (2). Adding a floor for a newly-anchored file is additive; lowering one stays maintainer-only..changeset/entry: docs/QA ledger plus one gate baseline, nothing published from any package.skip-changesetapplied.⛔
areas/records-forms.jsonis untouched (draft PR #15395 owns it this cycle). The one records-forms item this PR needs is referenced by id fromcoverage.json, which that PR does not edit.Verification — every verdict line, exit code captured before any pipe
All of it re-run on this branch's head
00b063dcd— the ratchet families (check:platform-checklist,check:nul-bytes) were re-run on the exact tree that commit carries, after the last content edit.The gate itself
ca3fd4b1's count; 176 is what6f944589reports, and it is unchanged by this PR — the gate script is not edited here (git diff --stattouches four files, none of themscripts/check-platform-checklist.mjs). Noted inFOLLOW-UPS.md§10e: quote the count from the run you actually made.The runner's selector — the new items resolve by id and, via their
sourcecitations, by source file:The derived gate family.
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 19 commands for this changeset (check:platform-checklistis not among them — it is not CI-wired, which is #11730's subject). All 19 exit 0 afterpnpm installand building the two packages two of them need:First pass, 7 of them answered
EXIT=3/ERR_MODULE_NOT_FOUNDon a fresh worktree — NOT MEASURED, not findings, exactly as their own text says. All were the missing install;@objectstack/formulaand@objectstack/lintadditionally needed building (both under the shared verify lock,OS_VERIFY_LOCK_SLOT=issue-14961).The roster gates the derivation flags as unreadable-from-silence (their allowlists live under
scripts/, which one of this diff's paths is in) were run rather than assumed:check:published-readme-exportsprints its own verdict:160 package(s) are not built, so this run measured nothing there— its--self-testis green and it reports zero content findings. Measuring it needs a whole-repo build, and this diff touches no README and no package. Recorded as NOT MEASURED, never as a pass, and left to CI.Not owed:
pnpm lintis not in the derived family for these paths. Two derivation caveats recorded rather than hidden: the tool warns the tree is 3 commits behindorigin/main(this branch is based on6f944589; the two files that moved are unrelated durability gates), and 16 families "apply once this card's changeset exists" — there is deliberately no changeset here.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code