Skip to content

Commit 1f7239d

Browse files
committed
docs(qa): re-point five 18.0 sweep red-row clauses to the shipped contract
Five checklist clauses the 18.0 release sweep scored fail were each disposed as a stale spec or an assertion defect against a documented contract. Each item is re-pointed, bumps its revision to 2 and records the run that found it: - cli.organization-ownership-ceremony: acceptance[1]-[3] score the 18.0 release refusal and the drop gate; the withdrawn ceremony arms move to fixtures.knownGaps as not scored; automated.ref gains the release-refusal pin. - automation.flow-authoring-refusals-v18: acceptance[2] says what the PUT door refuses; the CEL root-scope arms expect 200. - api-backend.error-sentences-and-unique-violation-wire-code: acceptance[2] asserts the composite details shape. - access-security.share-link-combined-gates: acceptance[3] is open/refused parity between /messages and /resolve. - attachments-storage.chunked-upload-integrity: acceptance[3] expects progress 200 unless the expiry stamp is due; chunks number from 0. No product code, test or pin changes. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5a871e4 commit 1f7239d

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
@@ -3799,10 +3799,10 @@
37993799
},
38003800
{
38013801
"id": "access-security.share-link-combined-gates",
3802-
"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",
3802+
"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",
38033803
"since": "v18",
38043804
"status": "active",
3805-
"revision": 1,
3805+
"revision": 2,
38063806
"priority": "P2",
38073807
"surface": "api",
38083808
"personas": [
@@ -3841,9 +3841,9 @@
38413841
"evidence": "the bodies"
38423842
},
38433843
{
3844-
"clause": "/messages answers identically to /resolve on every call",
3844+
"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)",
38453845
"oracle": "api",
3846-
"verify": "status+code pairs",
3846+
"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",
38473847
"evidence": "the paired lines"
38483848
}
38493849
],
@@ -3865,6 +3865,12 @@
38653865
"date": "2026-10-16",
38663866
"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",
38673867
"ref": "#23879"
3868+
},
3869+
{
3870+
"revision": 2,
3871+
"date": "2026-10-19",
3872+
"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",
3873+
"ref": "#PR-PENDING"
38683874
}
38693875
]
38703876
}

‎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": "#PR-PENDING"
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": "#PR-PENDING"
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": "#PR-PENDING"
20582064
}
20592065
]
20602066
},

0 commit comments

Comments
 (0)