Skip to content

Commit af1b3f8

Browse files
docs(qa): 18.0 sweep anchor round 2 — expression-editors' RLS clauses to the engine's error tier, a consumed-changeset citation, and §3 accuracy corrections in five areas (#24632)
Refs #24579 Clause-②: no Part of #24579: the wave anchor's second dispatch (round 1, #24622, landed §1's five rows). This PR lands three parts: (a) the §1 row round 2 added, (b) the rider from the #24622 review, and (c) §3's checklist-accuracy findings for platform-core, access-security, attachments-storage, identity-auth and approvals. The card stays open for §2, §4, the other areas' §3 bullets and round 2's other additions. The diff edits checklist content only (`docs/qa/platform-checklist/areas/`, seven files). No product code, test or pin changes. Every finding below was re-derived from source at the base `8fbbd5082f` (and, for console claims, objectui at the console pin `4016370a`) before the item was edited. A finding that did not hold is in the left-alone list with the reading that refuted it. Each edited item takes one `revision` bump and one `history` row that names its run record(s) and carries this PR as `ref`. Several findings on one item make one revision. ## (a) §1 — the round-2 row | item | fields edited | revision | run record | |:--|:--|:--|:--| | `studio-authoring.expression-editors` | `acceptance[2].clause`, `acceptance[2].verify`, `acceptance[4].clause`, `acceptance[4].evidence`, `acceptance[4].verify`, `fixtures.knownGaps[3]` (added), `steps[0]`, `steps[4]`, `variants[2]` | 3 → 4 | #24604, #24571 | acceptance[2] and acceptance[4] required a non-pushdownable USING read filter to be an advisory WARNING with Save enabled and fail-open framing. The engine refuses that predicate at ERROR tier: `packages/lint/src/validate-rls-predicate-enforceability.ts` emits `rls-predicate-unenforceable` with severity `error` (ADR-0056 D4), the rule `os build` and publish run, and the runtime fails CLOSED (the dropped policy grants no access). negative[0] already fails any editor verdict that differs from the engine, so the item contradicted itself (#24604 scored acceptance[4] "pass (as written)" beside a negative[0] FAIL). Both clauses now expect the error tier. Four more fields ride the same re-point so the item stays consistent: - steps[4] and variants[2] expect the error tier. - steps[0] names the build/publish gate as the RLS probes' engine truth, because `validate_expression` has no RLS site. - acceptance[4] names the Studio package door's autosave-held status beside the environment door's disabled Save (#24604: the package door has no Save button). - A new knownGap records that at the console pin the editor still warns (objectui `celAuthoring.ts` `lintCelPredicate`). The clauses therefore FAIL until objectstack-ai/objectui#13061 lands. ## (b) the #24622 rider | item | fields edited | revision | run record | |:--|:--|:--|:--| | `cli.organization-ownership-ceremony` | `source`: the path entry `.changeset/pre/15212-180-guards-fresh-single-only.md` removed, `15212-180-guards-fresh-single-only` appended to the prose entry "v18 changesets (.changeset/pre/, consumed into 18.0.0-next.*): …" | 2 (unchanged — no history row) | the #24622 review | The path entry dangles once 18.0.0 is versioned, because the version render consumes `.changeset/pre/*.md`. Ledger rule, measured: `check:platform-checklist` requires only `revision` equal to the last `history` row's revision, and the README bumps "on any semantic edit", meaning one that would let an old run result read as valid against changed clauses. A citation fold changes no clause, step or fixture a run judges, and this item already took a revision today for #24622, so no revision and no history row. Counter-reading, for the record: the ledger has bumped for a source-only addition before (`platform-core.boot-health`, its "source-ref addition" row). If the seat reads the rule that way, the fix is a revision-3 row naming this PR. The item's `fixtures.knownGaps[0]` prose also names `.changeset/pre/15212-180-guards-fresh-single-only.md` in a sentence, and that mention was left as it is: the ruling names the source entry only. ## (c) §3 — five areas Run records: platform-core #24557 (with round 2's #24603, whose accuracy section is empty); access-security #24559 (with #24601); attachments-storage #24560; identity-auth #24538; approvals #24542. Each area stays at or below 15 edited items: 12, 13, 2, 8 and 6. ### platform-core | item | fields edited | revision | run record | |:--|:--|:--|:--| | `platform-core.builtin-apps-nav-render` | `steps[2]`, `steps[5]` | 6 → 7 | #24557 | | `platform-core.package-lifecycle-enable-disable` | `steps[0]` | 1 → 2 | #24557, #24571 | | `platform-core.notification-center` | `acceptance[0].verify`, `acceptance[5].clause`, `acceptance[5].verify`, `steps[0]`, `steps[7]` | 2 → 3 | #24557 | | `platform-core.docs-audience-gate` | `acceptance[3].clause`, `acceptance[3].verify`, `fixtures.knownGaps[0]` | 1 → 2 | #24557 | | `platform-core.manifest-install-contract` | `fixtures.knownGaps[3]`, `negative[2]` | 3 → 4 | #24557 | | `platform-core.activation-ledger-row-contract` | `acceptance[4].clause`, `acceptance[4].verify`, `fixtures.knownGaps[0]`, `fixtures.requires[1]`, `negative[5]`, `steps[0]`, `steps[2]`, `title`, `variants[4]` (added) | 4 → 5 | #24557, #24601 | | `platform-core.marketplace-install-local-lifecycle` | `fixtures.requires[0]`, `personas[1]`, `steps[3]` | 4 → 5 | #24557 | | `platform-core.runtime-config-boot-read` | `steps[1]` | 1 → 2 | #24557 | | `platform-core.url-overlay-contract` | `acceptance[4].clause`, `acceptance[4].evidence`, `acceptance[4].verify`, `automated.ref`, `steps[5]` | 1 → 2 | #24557 | | `platform-core.home-admin-cluster-links` | `acceptance[3].clause`, `acceptance[3].verify` | 3 → 4 | #24557 | | `platform-core.v18-boot-refusals` | `acceptance[1].clause`, `acceptance[1].verify`, `acceptance[3].verify`, `steps[1]` | 2 → 3 | #24557 | | `platform-core.serve-composition-v18` | `fixtures.requires[1]` | 1 → 2 | #24557 | ### access-security | item | fields edited | revision | run record | |:--|:--|:--|:--| | `access-security.record-access-explain` | `steps[1]` | 2 → 3 | #24559 | | `access-security.fls-mask-and-strip` | `steps[5]` | 4 → 5 | #24559 | | `access-security.scope-depth-asymmetry` | `automated.ref`, `steps[0]` | 2 → 3 | #24559, #24598 | | `access-security.sharing-rules-widen` | `acceptance[4].clause`, `acceptance[4].evidence`, `acceptance[4].verify`, `steps[6]` | 2 → 3 | #24559, #24601 | | `access-security.record-share-grant-revoke` | `acceptance[6].clause`, `acceptance[6].evidence`, `acceptance[6].verify` | 5 → 6 | #24559 | | `access-security.audit-log-browser` | `acceptance[5].verify`, `steps[7]` | 6 → 7 | #24559 | | `access-security.permission-matrix-edit-loop` | `steps[0]`, `steps[1]`, `steps[3]` | 3 → 4 | #24559 | | `access-security.capability-declaration-lifecycle` | `acceptance[1].verify`, `steps[7]` | 4 → 5 | #24559 | | `access-security.anonymous-floor-v18-doors` | `fixtures.knownGaps[1]` | 1 → 2 | #24559 | | `access-security.meta-authoring-trail-and-audience-gates` | `acceptance[2].clause`, `acceptance[2].verify`, `steps[1]` | 1 → 2 | #24559 | | `access-security.grant-table-write-contract` | `acceptance[2].clause`, `acceptance[2].verify` | 1 → 2 | #24559 | | `access-security.deployment-tables-platform-only` | `automated.ref`, `steps[2]` | 1 → 2 | #24559 | | `access-security.share-link-combined-gates` | `automated.ref` | 2 → 3 | #24559 (round 1 note) | ### attachments-storage | item | fields edited | revision | run record | |:--|:--|:--|:--| | `attachments-storage.orphan-tombstone-reap` | `acceptance[0].verify`, `automated.ref` | 1 → 2 | #24560 | | `attachments-storage.chunked-upload-integrity` | `acceptance[0].clause`, `fixtures.knownGaps` (new, one entry) | 2 → 3 | #24560 (round 1 note) | Area-level edit, no item: the `qa-media-constraints` recipe's `provenance` said "not yet proven by a live run". QA run #24560 replayed it cleanly and scored `attachments-storage.field-accept-maxsize-server-enforced` on it, and the provenance now says so. Recipes carry no `revision` or `history` of their own (the validator's #10885 note), so this edit has no history row. ### identity-auth | item | fields edited | revision | run record | |:--|:--|:--|:--| | `identity-auth.invitation-scope-gates` | `automated.ref`, `fixtures.requires[0]`, `fixtures.requires[1]` | 4 → 5 | #24538 | | `identity-auth.api-key-ui-lifecycle` | `source[2]` | 3 → 4 | #24538 | | `identity-auth.self-service-profile-password` | `fixtures.knownGaps[0]`, `fixtures.requires[2]`, `steps[7]` | 1 → 2 | #24538 | | `identity-auth.org-membership-team-management` | `acceptance[3].clause`, `steps[5]` | 4 → 5 | #24538 | | `identity-auth.self-service-password-reset` | `acceptance[0].oracle` | 2 → 3 | #24538 | | `identity-auth.self-signup-gate` | `steps[0]` | 4 → 5 | #24538 | | `identity-auth.auth-gate-held-session-raw-host-families` | `fixtures.requires[1]` | 1 → 2 | #24538 | | `identity-auth.default-organization-boot-invariant` | `acceptance[1].verify`, `steps[0]` | 1 → 2 | #24538 | ### approvals | item | fields edited | revision | run record | |:--|:--|:--|:--| | `approvals.per-group-signoff` | `acceptance[3].verify` | 7 → 8 | #24542 | | `approvals.quorum-m-of-n` | `fixtures.requires[1]` | 4 → 5 | #24542 | | `approvals.decision-action-matrix` | `acceptance[1].verify`, `steps[7]` | 5 → 6 | #24542 | | `approvals.account-app-entry` | `acceptance[6].verify`, `fixtures.requires[2]` | 2 → 3 | #24542 | | `approvals.approver-resolution-matrix` | `acceptance[3].verify`, `acceptance[4].verify`, `acceptance[5].verify`, `steps[6]`, `steps[7]` | 4 → 5 | #24542 | | `approvals.request-page-reply-and-reader-visibility` | `automated.ref`, `steps[1]` | 1 → 2 | #24542 | Pin-coverage additions (PM hypothesis 2: added only where the file exists, reports at least 1 test under its package's vitest at the base, and asserts a clause the item states). Each was run singly under the shared verify lock after building the dependency closure (`turbo run build`, 34 tasks, exit 0): | added to `automated.ref` | item | vitest | |:--|:--|:--| | `packages/runtime/src/domains/share-links-messages-audience.test.ts` | access-security.share-link-combined-gates (acceptance[3]) | 1 file, 85 passed | | `packages/services/service-automation/src/sys-flow-dispatch.object.test.ts` | access-security.deployment-tables-platform-only (acceptance[0]) | 1 file, 4 passed | | `packages/services/service-realtime/src/objects/sys-presence.object.test.ts` | access-security.deployment-tables-platform-only (acceptance[0]) | 1 file, 12 passed | | `packages/services/service-storage/src/attachment-lifecycle.test.ts` | attachments-storage.orphan-tombstone-reap (acceptance[0]) | 1 file, 47 passed | | `packages/plugins/plugin-approvals/src/request-read-gate.integration.test.ts` | approvals.request-page-reply-and-reader-visibility (acceptance[2]) | 1 file, 16 passed | `attachments-storage.chunked-upload-integrity` gets no pin: no test drives a chunked door after an organization switch. The guard's only door-level pin is the presigned commit door's in `error-envelope.conformance.test.ts`. So acceptance[0] stops claiming the org-switch guard, and a knownGap records the unpinned leg. ## Findings left alone, each with the reading that refuted or excluded it - `platform-core.boot-health`, round 2's "the check-console-injection replay line still says 'not the published one'": no area file carries a check-console-injection line. At the base, a search of all 16 area files for `check-console-injection`, `console-injection` and `published one` finds zero matches. The sentence is the output of `scripts/check-console-injection.mjs` (its success line), which is product text and outside this checklist-only ruling. - `platform-core.settings-hub-roundtrip` (`value_domain`; no user-scoped namespace): excluded, because open PR #24590 holds the item. - `platform-core.settings-organization-isolation-and-platform-rung`, plus the walled legs of `access-security.walled-environment-metadata-operator-only`, `activation-write-operator-gate`, `grant-table-write-contract` acceptance[4] and `parent-and-organization-write-guards`: §2 (walled posture), so not this round. The record's "the minimal object body must declare sharingModel" note sits on `walled-environment-metadata-operator-only` steps[0], a walled-boot step, and is left for that item's §2 revision. - `platform-core.metadata-authoring-roundtrip` (the objectui `studio-record-page` / `studio-object-designer` specs are red at their own pin): §2's "objectui live e2e is not green at its pin" theme. - `platform-core.docs-audience-gate` acceptance[2] (the unknown-audience-shape branch is unreachable live and has no test), `access-security.rls-both-sides` acceptance[5], `access-security.crud-permission-matrix` acceptance[5], the marketplace-browse egress gap, `access-security.parent-and-organization-write-guards` (no controlled_by_parent fixture), `access-security.platform-owner-email-anchor` (no HTTP verified-email path), every identity-auth "Fixture gaps" row, and every approvals "Fixture gaps" row (including `request-page-reply-and-reader-visibility` acceptance[2]/[3] being unreachable on stock): §4, not this round. - `attachments-storage.chunked-upload-integrity` acceptance[1] (chunk numbering base): already corrected on main by #24622 (revision 2 numbers chunks from 0 and expects `missingChunks` [1]). Its second-organization fixture is §2. - `access-security.share-link-combined-gates`, "showcase has no ai_conversations object": already in acceptance[3] since #24622 ("the stock showcase has no ai_conversations object, so 400 UNSUPPORTED is the open answer there"). The item is otherwise one of the round-1 items excluded by the ruling. - `access-security.owd-save-gate` negative[0] "skipped": a run note (that runner booted before the console build landed), not a statement the item gets wrong. - `access-security.capability-declaration-lifecycle`, "DELETE /api/v1/meta/capability/NAME is a 200 no-op": no clause or step asserts the DELETE door, so nothing in the item is inaccurate. The 200-that-deletes-nothing answer is a product observation and is not encoded here (see Acceptance notes). - `attachments-storage.inline-grid-receipt-cells` (objectui-only pin scored by hand): a run-method note under RUNNER's objectui-pin protocol, not an inaccuracy. - identity-auth, accurate as written: `auth-method-matrix` (discovery also answered under /api/v1/auth, which the record calls harmless; the item requires only the root mount) and `two-factor-enrollment-reveal` (the record calls the anonymous 400 "consistent with the clause"). `admin-lifecycle-operations`'s impersonation-banner note is a UX observation outside every clause. - identity-auth, suggestions rather than errors: `two-factor-verify-to-activate` / `-backup-codes` / `-disable-lifecycle` ("worth naming" a SQLite-file rig as an alternative to the in-process read, which still works). `auth-gate-held-session-raw-host-families` boots with `pnpm dev -- --fresh`, AGENTS.md's documented backend-only boot. - approvals, suggestions rather than errors: `inbox-metadata-actions` (a simpler persona path; the reassign path the item names works). `decision-only-via-service` steps[6] (the run drove the trigger API instead of the row action; the step is accurate). `request-page-reply-and-reader-visibility`'s boot line (accurate). - `approvals.email-action-token-door` (all three of its rows): excluded, because it turns on #24620. - `approvals.act-door-and-admin-rescue-slate` fixtures.requires ("no mail harness needed — the raw links sit in sys_notification.payload.actions after a remind"): refuted since #24620 landed (`65a8eeb7d4`, merged into this branch). A reminder's notification payload carries no one-tap action token any more, so that alternative no longer exists. It belongs with email-action-token-door's #24620 follow-up. - Round 2 part 1's Tier 1 `automated.ref` quality list: `access-security.scope-depth-asymmetry` is taken above. The other named items (`flow-node-type-matrix`, `trigger-type-matrix`, `crud-roundtrip`, `connector-declarative-boot`, the `hook-wrappers` / `hook-binder` refs) are in other areas and not this round's. ## PM hypotheses, measured 1. **Stale findings because main moved — partly confirmed.** Diffed between run subject `5b14b7f3` and base `8fbbd5082f`, the cited sources changed in three files. `packages/objectql/src/registry.ts` (#24526) and `packages/plugins/plugin-auth/src/auth-manager.ts` (#24587) changed, but not in the cited symbols (NamespaceConflictError, the org-MFA cache). `packages/plugins/plugin-approvals/src/approval-service.ts` changed with #24527 and then #24620 (merged here); neither touches `rowFromRequest` or `comment`. Main's movement staled one finding (act-door, by #24620). Two more were already handled on main (chunked numbering and share-link ai_conversations, both by #24622). One was wrong at the base itself (boot-health). 2. **"automated.ref omits X" is a pin-coverage claim — confirmed.** Five pins were added after measurement (table above). One claim had no pin to add (chunked-upload-integrity), and the item records the gap instead. 3. **Symbol-anchor count must not drop — confirmed.** `check:platform-checklist` read 860/870 resolved at the base and 872/882 at head: 12 anchors added, none lost, the 10 on the named #16898 residual unchanged, 18 file floors held. No re-pointed anchor was refused. ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` from the merge-base (13 families), run at head `0b5ec6bc9e`, each exit code captured before any pipe: | command | exit | |:--|:--| | `node scripts/check-ci-filter-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | | `node scripts/check-comment-mask-corpus.mjs` | 0 | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | | `pnpm check:cross-package-test-inputs` | 0 | | `pnpm check:doc-authoring` | 0 | | `pnpm check:driver-memory-census` | 0 | | `pnpm check:gitlink-declared` | 0 | | `pnpm check:nul-bytes` | 0 | | `pnpm check:platform-checklist` | 0 | | `pnpm check:refd-timer-probe` | 0 | | `pnpm check:watch-hint-literal` | 0 | `--ran` reconciliation: "13 derived famil(ies) accounted for — 13 run, 0 NOT-MEASURED (a DERIVED zero — all 13 recorded an exit code and none of them is 3)". `check:platform-checklist` runs in no per-PR CI, so its local reading is the evidence: "check-platform-checklist: OK — 16 areas, 327 items (322 active, 1 planned) … symbol anchors: 872/882 resolved … 10 on the named #16898 residual, 18 file floors held". The history `ref` of the 42 revised items is a placeholder until this PR has a number. The fill commit after creation changes exactly those 42 strings, and the gates are re-run on that head (reported on the card). No exported symbol was renamed or removed, so `check-platform-checklist.mjs --changed-from` has nothing to judge. Changeset: none. No published package's `files[]` lists `docs/qa`, so `skip-changeset`. ## Acceptance notes - `access-security.capability-declaration-lifecycle`: QA run #24559 measured `DELETE /api/v1/meta/capability/NAME` answering 200 while removing nothing, on a code-only type whose PUT answers 403 NOT_CREATABLE. No clause covers it, and it is noted here for the seat rather than filed from a checklist PR. - `platform-core.boot-health`: the "not the published one" wording lives in `scripts/check-console-injection.mjs`'s success line. Whether it is stale is a product-text question for the seat that owns that script. --- _Generated by [Claude Code](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4ff18d3 commit af1b3f8

7 files changed

Lines changed: 422 additions & 166 deletions

File tree

‎docs/qa/platform-checklist/areas/access-security.json‎

Lines changed: 122 additions & 44 deletions
Large diffs are not rendered by default.

‎docs/qa/platform-checklist/areas/approvals.json‎

Lines changed: 59 additions & 23 deletions
Large diffs are not rendered by default.

‎docs/qa/platform-checklist/areas/attachments-storage.json‎

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
"qa-media-constraints": {
136136
"title": "Scratch object qa_media carrying FIELD-level accept/maxSize (plus an extension-only accept field)",
137137
"why": "The showcase declares accept/maxSize ONLY on action params (examples/app-showcase/src/ui/actions/index.ts,337 — the dialog-widget/ADR-0059 upload-guard lane), never on an object FIELD, so the server-side record-write re-enforcement (field-accept-maxsize-server-enforced) has no stock target: without this recipe every clause of that item is blocked(fixture) on every run. Landing one constrained field in the showcase seeds proper would retire this recipe.",
138-
"provenance": "authored from source in the 2026-08-20 scoped scan-functionality sweep (claude/new-session-0pv25p); call shapes copied from qa-scratch-authz (#7670), constraint keys from the FieldSchema declaration — not yet proven by a live run",
138+
"provenance": "authored from source in the 2026-08-20 scoped scan-functionality sweep (claude/new-session-0pv25p); call shapes copied from qa-scratch-authz (#7670), constraint keys from the FieldSchema declaration. Proven live by QA run #24560 (framework 5b14b7f3, 2026-10-19): the sequence replayed cleanly and attachments-storage.field-accept-maxsize-server-enforced was scored on it",
139139
"app": "showcase",
140140
"requires": [
141141
"an admin session that holds the `manage_metadata` capability — same gate as qa-scratch-authz (PUT /api/v1/meta/:type/:name is capability-gated per ADR-0066 D1, packages/rest/src/rest-route-ledger.ts)",
@@ -642,7 +642,7 @@
642642
"title": "The platform lifecycle sweep reaps expired tombstones and abandoned pending uploads WITH byte reclaim; sweep-time re-verification vetoes rather than losing data",
643643
"since": "v15.1",
644644
"status": "active",
645-
"revision": 1,
645+
"revision": 2,
646646
"priority": "P2",
647647
"surface": "api",
648648
"personas": ["admin (setup access, drives the sweep)"],
@@ -663,7 +663,7 @@
663663
{
664664
"clause": "each reap-guard verdict variant behaves per its declared contract: pending → bytes best-effort deleted + row confirmed; deleted with zero references and no field owner → bytes reclaimed BEFORE the row delete; deleted-but-regained-reference → un-tombstoned and vetoed; non-attachments-scope tombstone with the ADR-0104 migration gate closed → kept (vetoed, still tombstoned); byte-delete failure → vetoed and retried next sweep",
665665
"oracle": "test",
666-
"verify": "the dogfood lifecycle describe block ('sys_file orphan lifecycle (ADR-0057 reap guard)') passes; its cases map one-to-one onto these variants",
666+
"verify": "the dogfood lifecycle describe block ('sys_file orphan lifecycle (ADR-0057 reap guard)') passes, and so does attachment-lifecycle.test.ts's createSysFileReapGuard block. The dogfood cases cover the pending, zero-reference, regained-reference and abandoned-upload variants; the byte-delete failure (vetoed, retried next sweep) and the non-attachments-scope tombstone with the migration gate closed (vetoed) are pinned only in the unit block — so neither file alone covers every variant",
667667
"evidence": "test run output"
668668
},
669669
{
@@ -697,14 +697,20 @@
697697
"byte-delete failure (veto, retry next sweep)"
698698
],
699699
"traps": ["stale-dist"],
700-
"automated": { "kind": "api", "ref": "packages/qa/dogfood/test/attachments-permission-matrix.dogfood.test.ts" },
700+
"automated": { "kind": "api", "ref": "packages/qa/dogfood/test/attachments-permission-matrix.dogfood.test.ts + packages/services/service-storage/src/attachment-lifecycle.test.ts (its createSysFileReapGuard block: the byte-delete-failure veto and the field-file-with-the-gate-closed veto, the two variants the dogfood block does not drive)" },
701701
"source": [
702702
"packages/services/service-storage/src/attachment-lifecycle.ts#createSysFileReapGuard (createSysFileReapGuard — the verdict variants are its documented branch set, incl. the ADR-0104 isCollectionOpen gate re-read each sweep)",
703703
"packages/services/service-storage/src/objects/system-file.object.ts#deleted_at (lifecycle: ttl deleted_at+30d, retention 7d onlyWhen pending)",
704704
"docs/plans/release-15.1-test-plan.md §C4 (#2755/#2970)"
705705
],
706706
"history": [
707-
{ "revision": 1, "date": "2026-08-07", "change": "new item: reap-guard verdict matrix enumerated from createSysFileReapGuard's source, pinned to the dogfood lifecycle suite; TTL/retention figures from the sys_file lifecycle declaration", "ref": "claude/platform-test-checklist-ocwugl" }
707+
{ "revision": 1, "date": "2026-08-07", "change": "new item: reap-guard verdict matrix enumerated from createSysFileReapGuard's source, pinned to the dogfood lifecycle suite; TTL/retention figures from the sys_file lifecycle declaration", "ref": "claude/platform-test-checklist-ocwugl" },
708+
{
709+
"revision": 2,
710+
"date": "2026-10-19",
711+
"change": "automated.ref and acceptance[0].verify corrected — a checklist-accuracy finding of the 18.0 QA sweep (QA run #24560, attachments-storage.orphan-tombstone-reap acceptance[0]; wave anchor #24579 §3): the verify said the dogfood block's cases map one-to-one onto the five variants, but two of them — the byte-delete-failure veto and the field file kept while the gate is closed — are pinned only by packages/services/service-storage/src/attachment-lifecycle.test.ts (createSysFileReapGuard), which automated.ref did not name. The run ran it singly and scored the clause on both files. automated.ref now names it and the verify says which file pins which variant. No clause changed",
712+
"ref": "#24632"
713+
}
708714
]
709715
},
710716
{
@@ -1080,7 +1086,7 @@
10801086
"title": "Chunked upload integrity on v18: complete with a missing chunk is 409 with details.missingChunks and the session stays in_progress, a re-sent chunk counts once, parallel chunks all record, and an org switch mid-upload answers 409 on chunk and complete, and on progress only once the session's expiry stamp is due",
10811087
"since": "v18",
10821088
"status": "active",
1083-
"revision": 2,
1089+
"revision": 3,
10841090
"priority": "P2",
10851091
"surface": "api",
10861092
"personas": [
@@ -1090,6 +1096,9 @@
10901096
"app": "showcase",
10911097
"requires": [
10921098
"a fresh boot of the showcase: `pnpm dev -- --fresh -p PORT --seed-admin` (ephemeral DB; the seeded admin is printed)"
1099+
],
1100+
"knownGaps": [
1101+
"acceptance[0] names the org-switch guard among what the pins prove, but none of the three automated.ref files drives a CHUNKED door after an organization switch, so the door-level 409 of acceptance[3] (chunk PUT, chunked complete, a progress read whose expiry stamp is due) is unpinned. The guard is the doors' shared requireStartingOrganization (packages/services/service-storage/src/storage-routes.ts, asking packages/services/service-storage/src/metadata-store.ts#organizationOutOfWriteReach); the one door-level pin of it is the presigned COMMIT door's 409 RESOURCE_CONFLICT in packages/services/service-storage/src/error-envelope.conformance.test.ts, a sibling door, and chunk-part-record-concurrency.test.ts pins only the store-level miss. Score acceptance[0] on chunk accounting and the missing-chunk refusal alone, and do not cite the pins for the org-switch guard. acceptance[3]'s live leg also needs a second organization, which a stock 18.0 boot refuses (403 ORGANIZATION_CREATION_DISABLED, QA runs #24560 / #24558) — the wave's no-second-organization theme, parked on #24579 §2"
10931102
]
10941103
},
10951104
"steps": [
@@ -1100,7 +1109,7 @@
11001109
],
11011110
"acceptance": [
11021111
{
1103-
"clause": "chunk accounting, missing-chunk refusal and the org-switch guard — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand)",
1112+
"clause": "chunk accounting and the missing-chunk refusal — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand). The org-switch guard of acceptance[3] has no chunked-door pin (knownGaps[0])",
11041113
"oracle": "test",
11051114
"verify": "run each file named in automated.ref with its package's vitest (`pnpm --filter PKG exec vitest run --maxWorkers=2 FILE`, never through a bare `--`); every named file reports ≥1 test and 0 failed. A file that reports 0 tests or is not found is NOT a pass — it is a stale ref, fix the item",
11061115
"evidence": "the vitest summary line per pin file, with the package name and the subject sha"
@@ -1144,6 +1153,12 @@
11441153
"date": "2026-10-19",
11451154
"change": "acceptance[3] re-pointed and the chunk numbering made the API's (QA run #24560 acceptance[3] fail, disposition stale spec; parked on #24579 §1). #24560: \"the progress door (#22218, storage-routes.ts) deliberately keeps answering the uploader from any organization when there is nothing to stamp\" — packages/services/service-storage/src/storage-routes.ts#registerStorageRoutes asks the starting-organization gate on progress only when the expiry stamp is due, so after an org switch progress answers 200 unless the session's expires_at has passed, and 409 then; chunk PUT and complete answer 409 as before. The steps numbered chunks from 1 while the API numbers them from 0 (#24560 and #24558: the server answered missingChunks [1] for the step's \"chunk 2\"), so the steps now number from 0, acceptance[1] expects [1], and the org-switch step names all three calls. The title follows; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3",
11461155
"ref": "#24622"
1156+
},
1157+
{
1158+
"revision": 3,
1159+
"date": "2026-10-19",
1160+
"change": "acceptance[0].clause narrowed to what its pins prove and fixtures.knownGaps added — the out-of-scope §3 note of #24622's round (wave anchor #24579 §3; QA run #24560): none of the three automated.ref pins drives a chunked door after an organization switch, so the door-level 409 acceptance[3] asserts is unpinned. The only door-level pin of the shared guard (storage-routes.ts requireStartingOrganization) is the presigned commit door's, in error-envelope.conformance.test.ts, and chunk-part-record-concurrency.test.ts pins the store-level miss only. acceptance[0] no longer claims the org-switch guard. The knownGap records the unpinned leg, and points at §2 for its live half, which needs a second organization stock 18.0 refuses. acceptance[1]–[3] (#24622) are unchanged",
1161+
"ref": "#24632"
11471162
}
11481163
]
11491164
}

‎docs/qa/platform-checklist/areas/cli.json‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,11 +1897,10 @@
18971897
"source": [
18981898
"packages/cli/src/commands/migrate/organization-ownership.ts",
18991899
"packages/cli/src/commands/migrate/organization-ownership.ts#ORGANIZATION_OWNERSHIP_UPGRADE_UNAVAILABLE",
1900-
".changeset/pre/15212-180-guards-fresh-single-only.md",
19011900
"packages/spec/src/system/fate-supplement.zod.ts#OrganizationOwnershipSupplementSchema",
19021901
"packages/cli/src/utils/organization-ownership-drop-gate.ts",
19031902
"docs/adr/0131-total-organization-ownership-no-null-organization-id.md",
1904-
"v18 changesets (.changeset/pre/, consumed into 18.0.0-next.*): 22617-cli-organization-ownership-plan, 22937-cli-ceremony-promotions, 22937-cli-organization-ownership-apply, 22937-core-email-template-row-definition, 22937-core-row-definition-mappers, 15211-ceremony-metadata-promotion, 15211-cli-apply-reviewed-plan, 23280-host-fate-supplement, 23400-ownership-occupancy-gate, 23429-sys-metadata-family-organization-column-retired, 23558-ceremony-dialect-resolver, 23684-drop-gate-host-tables, 23281-comment-reactions-upgrade-conversion"
1903+
"v18 changesets (.changeset/pre/, consumed into 18.0.0-next.*): 22617-cli-organization-ownership-plan, 22937-cli-ceremony-promotions, 22937-cli-organization-ownership-apply, 22937-core-email-template-row-definition, 22937-core-row-definition-mappers, 15211-ceremony-metadata-promotion, 15211-cli-apply-reviewed-plan, 23280-host-fate-supplement, 23400-ownership-occupancy-gate, 23429-sys-metadata-family-organization-column-retired, 23558-ceremony-dialect-resolver, 23684-drop-gate-host-tables, 23281-comment-reactions-upgrade-conversion, 15212-180-guards-fresh-single-only"
19051904
],
19061905
"history": [
19071906
{

0 commit comments

Comments
 (0)