Skip to content

Commit 407f870

Browse files
docs(qa): re-point five 18.0 sweep red-row clauses to the shipped contract (#24622)
Refs #24579 (§1) Clause-②: no Part of #24579: this PR lands §1 of that wave anchor, the five red-row re-points. §2 (wave-wide themes), §3 (checklist-accuracy findings), §4 (fixture gaps, partials, not-run handover), §6 and §7 stay on the card. ## What The 18.0 release sweep (subject `5b14b7f3`) scored five checklist clauses `fail`. Each run record disposed its row as a stale spec or an assertion defect against a documented contract: the product is right and the clause is wrong. This PR re-points those five clauses. Each item bumps `revision` 1 → 2 and gains one `history` row that names its run record and has this PR as its `ref`. Ledger only. No product code, test or pin changes. Diff: 5 files under `docs/qa/platform-checklist/areas/`, one item per file, and no other item or area-level key moves (checked by parse against the base). | item · clause | run record | disposition | edited fields | revision | |---|---|---|---|---| | `cli.organization-ownership-ceremony` acceptance[1]–[4] | #24551 (verdict word reconciled with #24556) | stale spec | title, `fixtures.knownGaps` (new), steps, acceptance[0]–[3] (old [4] removed), `automated.ref`, source | 1 → 2 | | `automation.flow-authoring-refusals-v18` acceptance[2] | #24545 (and #24558's "PUT 422 too broad") | stale spec | title, steps[1], acceptance[2] | 1 → 2 | | `api-backend.error-sentences-and-unique-violation-wire-code` acceptance[2] | #24541 | assertion defect | acceptance[2] (acceptance[1] untouched: product defect #24561) | 1 → 2 | | `access-security.share-link-combined-gates` acceptance[3] | #24559 | assertion defect | title, acceptance[3] | 1 → 2 | | `attachments-storage.chunked-upload-integrity` acceptance[3] | #24560 | stale spec | title, steps (renumbered from 0), acceptance[1] (index), acceptance[3] | 1 → 2 | ## Each re-point, against `main` `5a871e4e41` Every source cited below is byte-identical between the run subject `5b14b7f3` and `main` `5a871e4e41`. The one file that moved, `metadata-protocol/src/protocol.ts`, changed by a perf commit whose hunks are nowhere near the two refusals cited from it. 1. **`cli.organization-ownership-ceremony`.** By ruling, 18.0 is fresh installs only. The registered `os migrate organization-ownership` (`MigrateOrganizationOwnership`) refuses plan and apply alike, with `NOT_IMPLEMENTED` / `upgrade-unavailable`, before it opens anything. The changes: - acceptance[1] scores the bare-run refusal: no plan file, DB checksum unchanged. - acceptance[2] scores every `--apply` arm refusing the same way. - acceptance[3] keeps the drop-gate half (`refused_organization_ownership_unmigrated` with `tables`). The sys_migration checkpoint half is dropped. - Revision 1's acceptance[4] (the migrated copy boots) is removed. - `automated.ref` gains `organization-ownership.release-refusal.test.ts`, the pin of the registered command. The other seven pins drive the ceremony class beneath it. - **The mechanism (PM hypothesis 1, falsified):** the ledger has no clause-level skip. 1788 clauses across 16 areas carry only `clause`/`oracle`/`verify`/`evidence` (one `$comment`). `check-platform-checklist.mjs` reads no such key, and RUNNER's `skipped` is a run verdict, not an item field. The nearest legal shape is the one the ledger already uses for a half an item does not score: a `fixtures.knownGaps` line saying the half is deliberately not scored here. Precedents are `cli.plugin-manifest-build-contract` knownGaps[1] and `platform-core.manifest-install-contract` knownGaps[0]. - **The knownGaps line:** `knownGaps[0]` lists the ceremony's withdrawn arms with the ruling quoted from #24551 ("ruling records 6259608309 (item 1) and 6259698357 then cut 18.0 to fresh installs on the single posture…"). It tells a runner to score those arms neither `fail` (#24551's reading of revision 1) nor `skipped` (#24556's, c1/c2/c4), because they are not on the item. That is the single reading for both runs: each run captured the refusal that each re-pointed clause now asserts. - `knownGaps[1]` says acceptance[3] scores the drop gate's exit, `message` and `tables`, not its prose. That prose still prescribes the withdrawn command, which is row 3 of #24567. 2. **`automation.flow-authoring-refusals-v18`.** - **Root-scope arms:** `packages/lint/src/flow-cel-root-scope.ts#perWriteSnapshotEntrance` stands the CEL root-scope judgment down at the runtime publish gate. This is by design, under rulings 5791822697 (item 3) and 6104584601 (letter B), and the item's own pin `validate-expressions.flow-cel-root.test.ts` asserts it. So the `record.x` and `user.id` arms expect 200 and a stored row at PUT, and `os validate` (acceptance[1]) still refuses them. - **Job and endpoint arms:** these are not PUT /meta/flow bodies. `job` and `api` are code-only types (`allowRuntimeCreate: false`, so PUT answers 403 `NOT_CREATABLE`). The clause names the flow-side twins the door does refuse: a `try_catch` node's `retry.maxRetry`, and the `runAs: "system"` flow that a code-declared `authRequired: false` endpoint names (`anonymousElevatedFlowRefusal`, 422 at `runAs`). 3. **`api-backend.error-sentences-and-unique-violation-wire-code`.** On a tenant-scoped object, driver-sql builds a field's `unique: true` as the `(organization, field)` composite, so the driver names no single column. `dispatcher-unique-violation-wire-code.test.ts` pins `details` keys as exactly `developerMessage` and `object`, and adds `field` only when `DuplicateRecordError` states a column. The clause now asserts that composite shape. 4. **`access-security.share-link-combined-gates`.** In `share-link-routes.ts#registerShareLinkRoutes`, `/messages` passes `resolveToken` the same audience inputs `/resolve` does. It answers every refusal with one `404 NOT_FOUND`, and a resolved non-`ai_conversations` link with `400 UNSUPPORTED`. `runtime/src/domains/share-links-messages-audience.test.ts` holds both mounts to one open/refused verdict per audience. The clause becomes "`/messages` is open iff `/resolve` is open", where open means the call passed the link's gates. A malformed password header is refused `400 VALIDATION_FAILED` by both routes, before either reads the link. 5. **`attachments-storage.chunked-upload-integrity`.** - **Progress:** `registerStorageRoutes` asks the starting-organization gate on progress only when `expiryStampDue` holds. So after an org switch, progress answers 200 unless the session's `expires_at` has passed, and 409 after that. Chunk PUT and complete answer 409 either way. - **Numbering:** the steps numbered chunks from 1 while the API numbers them from 0 (the server answered `missingChunks: [1]` for the step's "chunk 2"). Steps now number from 0, acceptance[1] expects `[1]`, and the org-switch step names all three calls. Titles that contradicted a re-pointed clause follow it: cli, automation, access-security and attachments. No `file:line` citation is written. The new `#symbol` anchors are `MigrateOrganizationOwnership`, `ORGANIZATION_OWNERSHIP_UPGRADE_UNAVAILABLE`, `perWriteSnapshotEntrance`, `registerShareLinkRoutes` and `registerStorageRoutes`, and all five resolve. ## Verification (at `1f7239d717`) - `pnpm check:platform-checklist` exits 0. This gate runs in no per-PR CI, so this local reading is its evidence: ```text check-platform-checklist: OK — 16 areas, 327 items (322 active, 1 planned); coverage: 39 kinds mapped, 2 waived; traps: 19 documented, 19 in use; … line citations: 0 survive across 21 swept documents …; symbol anchors: 860/870 resolved … across 21 swept documents against 406 cited sources, 10 on the named residual, 18 file floors held ``` The symbol-anchor count was 855/865 against 404 cited sources at base `5a871e4e41`. This diff adds +5 resolved anchors and loses none, and the residual is unchanged at 10. - `node scripts/pm/dispatch-gates.mjs --commands` derives 13 commands on this diff (5 paths vs merge base `5a871e4e4`, +73 / −45). All 13 exit 0: - `check-ci-filter-parity` - `check-closing-keyword-parity` and its `--self-test` - `check-comment-mask-corpus` - `check:doc-formula-expressions` (lint). This one first exited 3 (PREREQUISITE: formula and lint unbuilt, nothing measured). It exits 0 after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`. - `check:cross-package-test-inputs` - `check:doc-authoring` - `check:driver-memory-census` - `check:gitlink-declared` - `check:nul-bytes` - `check:platform-checklist` - `check:refd-timer-probe` - `check:watch-hint-literal` - `--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)". - No package is touched, so there is no dependency-closure build, package test or typecheck. The rest of the farm is CI's. - `skip-changeset`, re-measured: the only `package.json` whose directory contains `docs/qa/` is the private repo root (`@objectstack/spec-monorepo`, `private: true`), so this diff ships nothing. - The PR opens with each new `history` row's `ref` set to a placeholder, because the PR number does not exist until the PR does. The next commit replaces those five strings with this PR's number and changes nothing else. The gate re-run on that final head is recorded in the `os-dev-report` comment on #24579. ## Acceptance notes Noted, not filed. Each item is already parked on #24579 by its run record unless another carrier is named. - `access-security.share-link-combined-gates` `automated.ref` does not name `packages/runtime/src/domains/share-links-messages-audience.test.ts`, the pin of the parity acceptance[3] now asserts. Carrier: #24579 §3. Not added here, because §1 changes `automated.ref` for the cli row only. - `attachments-storage.chunked-upload-integrity` acceptance[3] still needs a second organization, and stock 18.0 refuses one with 403 `ORGANIZATION_CREATION_DISABLED`. Carrier: #24579 §2, the "no second organization" theme. Separately, none of its three pins asserts the door-level org-switch 409. Carrier: #24579 §3, from #24560. - `automation.flow-authoring-refusals-v18` has three steps-level accuracy findings. Carrier: #24579 §3, from #24545 and #24558. - The anonymous-endpoint arm needs an armed `rateLimit`. - "A REST-triggered flow reading record.x" is ambiguous. - acceptance[1]'s schema-layer arms surface as `STACK_SCHEMA_INVALID` with a contract sentence, not as a rule id. - `api-backend.error-sentences-and-unique-violation-wire-code`: a package cannot author a hook on `sys_sharing_rule`, so the fixture line and step 1 are unrunnable as written. Carrier: #24579 §3, from #24541 and #24558. acceptance[1] is the product defect #24561. - `cli.organization-ownership-ceremony`: there is no v17-shaped SQLite fixture in the tree. Carrier: #24579 §4. The drop-gate prose naming the withdrawn command is row 3 of #24567. --- _Generated by [Claude Code](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 23dae89 commit 407f870

5 files changed

Lines changed: 73 additions & 45 deletions

File tree

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,10 +3805,10 @@
38053805
},
38063806
{
38073807
"id": "access-security.share-link-combined-gates",
3808-
"title": "Share links with two gates combined: signed_in + password answers an anonymous caller 401 SIGN_IN_REQUIRED whatever password is sent, email + password answers a uniform 404 INVALID_OR_EXPIRED, and /messages answers exactly like /resolve",
3808+
"title": "Share links with two gates combined: signed_in + password answers an anonymous caller 401 SIGN_IN_REQUIRED whatever password is sent, email + password answers a uniform 404 INVALID_OR_EXPIRED, and /messages opens exactly where /resolve opens",
38093809
"since": "v18",
38103810
"status": "active",
3811-
"revision": 1,
3811+
"revision": 2,
38123812
"priority": "P2",
38133813
"surface": "api",
38143814
"personas": [
@@ -3847,9 +3847,9 @@
38473847
"evidence": "the bodies"
38483848
},
38493849
{
3850-
"clause": "/messages answers identically to /resolve on every call",
3850+
"clause": "/messages is open iff /resolve is open on the same call — open meaning the call passes the link's token, audience and password gates: where /resolve refuses at a gate (401 / 404 / 410), /messages answers its one refusal, 404 NOT_FOUND; where /resolve passes, /messages answers 200 for an `ai_conversations` link and 400 UNSUPPORTED for any other object (the stock showcase has no ai_conversations object, so 400 UNSUPPORTED is the open answer there). The refusal codes differ by pinned design, so only the open/refused verdict is compared (a malformed password header is refused 400 VALIDATION_FAILED by both, before either reads the link)",
38513851
"oracle": "api",
3852-
"verify": "status+code pairs",
3852+
"verify": "pair each /resolve answer with the /messages answer to the same call: refused → 404 NOT_FOUND, passed → 200 or 400 UNSUPPORTED; a /messages 200 or 400 UNSUPPORTED where /resolve refused is a fail",
38533853
"evidence": "the paired lines"
38543854
}
38553855
],
@@ -3871,6 +3871,12 @@
38713871
"date": "2026-10-16",
38723872
"change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it",
38733873
"ref": "#23879"
3874+
},
3875+
{
3876+
"revision": 2,
3877+
"date": "2026-10-19",
3878+
"change": "acceptance[3] re-pointed to open/refused parity (QA run #24559 acceptance[3] fail, disposition assertion defect; parked on #24579 §1; QA run #24558 scored the same clause on that corrected intent). #24559 records the divergence as \"the pinned design (share-link-envelope.conformance.test.ts: messages for an unresolvable token → 404 NOT_FOUND; for a non-ai_conversations link → 400 UNSUPPORTED)\" and re-points the clause to \"/messages opens iff /resolve opens\". packages/plugins/plugin-sharing/src/share-link-routes.ts#registerShareLinkRoutes hands /messages the same audience inputs and answers every refusal 404 NOT_FOUND, and packages/runtime/src/domains/share-links-messages-audience.test.ts holds both mounts to one open/refused verdict per audience. The clause asked for identical status+code pairs, which the design contradicts on every refused call. The title follows; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3",
3879+
"ref": "#24622"
38743880
}
38753881
]
38763882
}

‎docs/qa/platform-checklist/areas/api-backend.json‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,7 @@
28232823
"title": "Error answers made honest on v18: a hook refusal on a hand-built write route answers 400 with the hook's own sentence, a crash answers a generic 500 that withholds the caught message, and a unique-constraint refusal is 409 UNIQUE_VIOLATION with details at the action door, MCP and sandboxed bodies too",
28242824
"since": "v18",
28252825
"status": "active",
2826-
"revision": 1,
2826+
"revision": 2,
28272827
"priority": "P2",
28282828
"surface": "api",
28292829
"personas": [
@@ -2856,9 +2856,9 @@
28562856
"evidence": "the body"
28572857
},
28582858
{
2859-
"clause": "the duplicate insert through the action door → 409 UNIQUE_VIOLATION with details naming the field",
2859+
"clause": "the duplicate insert through the action door → 409 UNIQUE_VIOLATION with `details` in the composite shape: exactly `object` (the object's name) and `developerMessage`, no `field` — a field's `unique: true` is a tenancy-scoped composite index, so the driver names no single column (`field` is added only when the refusal states one)",
28602860
"oracle": "api",
2861-
"verify": "status + code + details",
2861+
"verify": "status + error.code + the key set of error.details (exactly developerMessage and object) + details.object",
28622862
"evidence": "the body"
28632863
},
28642864
{
@@ -2885,6 +2885,12 @@
28852885
"date": "2026-10-16",
28862886
"change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it",
28872887
"ref": "#23879"
2888+
},
2889+
{
2890+
"revision": 2,
2891+
"date": "2026-10-19",
2892+
"change": "acceptance[2] asserts the composite details shape (QA run #24541 acceptance[2] fail, disposition assertion-defect; parked on #24579 §1). #24541: \"details carry field only when the driver names a single column; a tenancy-scoped composite unique names none\" — the pin packages/runtime/src/dispatcher-unique-violation-wire-code.test.ts asserts the details keys are exactly developerMessage and object for an engine write, adding field only when DuplicateRecordError states a column, and driver-sql builds a field's unique: true as the (organization, field) composite. The clause asked for details naming the field, which no stock unique field produces. acceptance[1] is unchanged: QA run #24558's fail there is the product defect #24561; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3",
2893+
"ref": "#24622"
28882894
}
28892895
]
28902896
}

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,10 +1077,10 @@
10771077
},
10781078
{
10791079
"id": "attachments-storage.chunked-upload-integrity",
1080-
"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 complete / chunk / progress",
1080+
"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",
10811081
"since": "v18",
10821082
"status": "active",
1083-
"revision": 1,
1083+
"revision": 2,
10841084
"priority": "P2",
10851085
"surface": "api",
10861086
"personas": [
@@ -1093,10 +1093,10 @@
10931093
]
10941094
},
10951095
"steps": [
1096-
"start a chunked upload of 3 chunks; PUT chunks 1 and 3; POST complete",
1097-
"PUT chunk 1 again; GET progress",
1098-
"PUT chunk 2; POST complete",
1099-
"start another, switch active organization (POST /api/v1/auth/organization/set-active) and PUT a chunk"
1096+
"start a chunked upload of 3 chunks, numbered from 0 as the API numbers them (0, 1, 2); PUT chunks 0 and 2; POST complete",
1097+
"PUT chunk 0 again; GET progress",
1098+
"PUT chunk 1; POST complete",
1099+
"start another, switch active organization (POST /api/v1/auth/organization/set-active), then PUT a chunk, POST complete and GET progress"
11001100
],
11011101
"acceptance": [
11021102
{
@@ -1106,7 +1106,7 @@
11061106
"evidence": "the vitest summary line per pin file, with the package name and the subject sha"
11071107
},
11081108
{
1109-
"clause": "complete with a missing chunk → 409 RESOURCE_CONFLICT with details.missingChunks [2]; progress still in_progress",
1109+
"clause": "complete with a missing chunk → 409 RESOURCE_CONFLICT with details.missingChunks [1] (the chunk not sent, numbered from 0); progress still in_progress",
11101110
"oracle": "api",
11111111
"verify": "status + details + progress",
11121112
"evidence": "answers"
@@ -1118,9 +1118,9 @@
11181118
"evidence": "the progress body"
11191119
},
11201120
{
1121-
"clause": "after the org switch chunk PUT / complete / progress → 409",
1121+
"clause": "after the org switch: chunk PUT → 409 and complete → 409 (RESOURCE_CONFLICT); progress → 200 unless the session's expiry stamp is due (its own expires_at has passed), and 409 then — a progress read writes nothing else, so it has no reach to miss",
11221122
"oracle": "api",
1123-
"verify": "status per call",
1123+
"verify": "status per call; for progress, also the session's expiresAt against the clock of the call",
11241124
"evidence": "three lines"
11251125
}
11261126
],
@@ -1138,6 +1138,12 @@
11381138
"date": "2026-10-16",
11391139
"change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it",
11401140
"ref": "#23879"
1141+
},
1142+
{
1143+
"revision": 2,
1144+
"date": "2026-10-19",
1145+
"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",
1146+
"ref": "#24622"
11411147
}
11421148
]
11431149
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,10 +1987,10 @@
19871987
},
19881988
{
19891989
"id": "automation.flow-authoring-refusals-v18",
1990-
"title": "Flow authoring contract on v18, refused at `os validate` AND at PUT /meta/flow: single-brace {…} value tokens (CEL only; text slots use {{ }}), $-prefixed bound variable names, builtin node config keys/values the executor does not declare, dangling or repeated edges, `record`/`user.id` roots a flow cannot bind, retryPolicy.maxRetry, and an anonymous endpoint targeting a runAs:\"system\" flow",
1990+
"title": "Flow authoring contract on v18, refused at `os validate` — and at PUT /meta/flow for every flow-body arm but the CEL root scope, which only `os validate` judges: single-brace {…} value tokens (CEL only; text slots use {{ }}), $-prefixed bound variable names, builtin node config keys/values the executor does not declare, dangling or repeated edges, `record`/`user.id` roots a flow cannot bind, retryPolicy.maxRetry, and an anonymous endpoint targeting a runAs:\"system\" flow",
19911991
"since": "v18",
19921992
"status": "active",
1993-
"revision": 1,
1993+
"revision": 2,
19941994
"priority": "P1",
19951995
"surface": "cli",
19961996
"personas": [
@@ -2006,7 +2006,7 @@
20062006
},
20072007
"steps": [
20082008
"for each arm run `os validate` in the scratch app and record exit code + rule id + located path: fields:{owner:\"{record.owner}\"}; notify title \"{record.name}\"; screen field named \"$x\"; create_record outputVariable:42; notify bogusKey; an edge to a removed node; a REST-triggered flow reading record.x; `user.id` in CEL; job retryPolicy:{maxRetry:3}; an authRequired:false flow endpoint targeting a runAs:\"system\" flow",
2009-
"PUT the same flow bodies to a fresh showcase boot at /api/v1/meta/flow/qa_ARM (scratch names)",
2009+
"PUT the flow-body arms acceptance[2] lists to a boot of the scratch app at /api/v1/meta/flow/qa_ARM (scratch names); the endpoint arm PUTs the `runAs: \"system\"` body of the flow its code-declared endpoint names",
20102010
"controls: the CEL envelope {dialect:\"cel\",source:\"record.owner\"}, a notify title \"Case {{ record.name }}\", and a query placeholder {current_user_id} in a CRUD filter operand all PASS"
20112011
],
20122012
"acceptance": [
@@ -2023,9 +2023,9 @@
20232023
"evidence": "one line per arm"
20242024
},
20252025
{
2026-
"clause": "the same bodies at PUT /meta/flow → 422 INVALID_METADATA and nothing stored",
2026+
"clause": "at PUT /api/v1/meta/flow the door refuses what it judges — 422 INVALID_METADATA with a located issue, and nothing stored — for the single-brace value and text tokens, the $-prefixed bound name, the undeclared builtin node config key and value, the dangling or repeated edge, an undeclared `retry` key under a `try_catch` node (`retry: {maxRetry: 3}`, the flow-shaped twin of the job arm) and a `runAs: \"system\"` flow that a code-declared `authRequired: false` endpoint names (issue at `runAs`). The two CEL root-scope arms — `record.x` in a flow no entrance hands a record, and `user.id` — answer 200 and are stored: this door does not judge root scope, by design, and `os validate` (acceptance[1]) refuses them. The job and the endpoint themselves are code-only types (PUT /meta/job and /meta/api answer 403 NOT_CREATABLE), so they are not PUT arms",
20272027
"oracle": "api",
2028-
"verify": "status + read-back 404",
2028+
"verify": "status + code per arm, then GET the same name: a 422 arm reads back 404, a root-scope arm 200",
20292029
"evidence": "per-arm lines"
20302030
},
20312031
{
@@ -2055,6 +2055,12 @@
20552055
"date": "2026-10-16",
20562056
"change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it",
20572057
"ref": "#23879"
2058+
},
2059+
{
2060+
"revision": 2,
2061+
"date": "2026-10-19",
2062+
"change": "acceptance[2] narrowed to what the PUT door refuses (QA run #24545 acceptance[2] fail, disposition stale-spec; parked on #24579 §1; QA run #24558 flagged the same clause's \"PUT 422\" as too broad). #24545: the runtime PUT gate \"deliberately stands down on the CEL root-scope judgment (whole-stack, owned by os validate — which still refuses both arms, so negative clauses hold)\", by rulings 5791822697 (item 3) and 6104584601 (letter B) as packages/lint/src/flow-cel-root-scope.ts#perWriteSnapshotEntrance records, and the item's own pin validate-expressions.flow-cel-root.test.ts asserts the stand-down. So the record.x and user.id arms now expect 200 and a stored row at PUT. The job arm and the endpoint arm are not PUT /meta/flow bodies — job and api are code-only types, 403 NOT_CREATABLE (#24558) — so the clause names the flow-side twins the door does refuse: a try_catch node's retry.maxRetry, and the runAs: \"system\" flow a code-declared anonymous endpoint names (422 at runAs, #24545). steps[1] and the title follow; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3",
2063+
"ref": "#24622"
20582064
}
20592065
]
20602066
},

0 commit comments

Comments
 (0)