From 1f7239d71740f9955a96c8a72c903f0278d47c07 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 16:06:45 +0000 Subject: [PATCH 1/2] 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 --- .../areas/access-security.json | 14 +++-- .../platform-checklist/areas/api-backend.json | 12 +++-- .../areas/attachments-storage.json | 24 +++++---- .../platform-checklist/areas/automation.json | 16 ++++-- docs/qa/platform-checklist/areas/cli.json | 52 ++++++++++--------- 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index 6f7c9862b87..74494488c0f 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -3799,10 +3799,10 @@ }, { "id": "access-security.share-link-combined-gates", - "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", + "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", "since": "v18", "status": "active", - "revision": 1, + "revision": 2, "priority": "P2", "surface": "api", "personas": [ @@ -3841,9 +3841,9 @@ "evidence": "the bodies" }, { - "clause": "/messages answers identically to /resolve on every call", + "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)", "oracle": "api", - "verify": "status+code pairs", + "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", "evidence": "the paired lines" } ], @@ -3865,6 +3865,12 @@ "date": "2026-10-16", "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", "ref": "#23879" + }, + { + "revision": 2, + "date": "2026-10-19", + "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", + "ref": "#PR-PENDING" } ] } diff --git a/docs/qa/platform-checklist/areas/api-backend.json b/docs/qa/platform-checklist/areas/api-backend.json index 64dc8e2f722..1cd84b0f8b6 100644 --- a/docs/qa/platform-checklist/areas/api-backend.json +++ b/docs/qa/platform-checklist/areas/api-backend.json @@ -2823,7 +2823,7 @@ "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", "since": "v18", "status": "active", - "revision": 1, + "revision": 2, "priority": "P2", "surface": "api", "personas": [ @@ -2856,9 +2856,9 @@ "evidence": "the body" }, { - "clause": "the duplicate insert through the action door → 409 UNIQUE_VIOLATION with details naming the field", + "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)", "oracle": "api", - "verify": "status + code + details", + "verify": "status + error.code + the key set of error.details (exactly developerMessage and object) + details.object", "evidence": "the body" }, { @@ -2885,6 +2885,12 @@ "date": "2026-10-16", "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", "ref": "#23879" + }, + { + "revision": 2, + "date": "2026-10-19", + "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", + "ref": "#PR-PENDING" } ] } diff --git a/docs/qa/platform-checklist/areas/attachments-storage.json b/docs/qa/platform-checklist/areas/attachments-storage.json index a9e56435414..7666e86ddfa 100644 --- a/docs/qa/platform-checklist/areas/attachments-storage.json +++ b/docs/qa/platform-checklist/areas/attachments-storage.json @@ -1077,10 +1077,10 @@ }, { "id": "attachments-storage.chunked-upload-integrity", - "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", + "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", "since": "v18", "status": "active", - "revision": 1, + "revision": 2, "priority": "P2", "surface": "api", "personas": [ @@ -1093,10 +1093,10 @@ ] }, "steps": [ - "start a chunked upload of 3 chunks; PUT chunks 1 and 3; POST complete", - "PUT chunk 1 again; GET progress", - "PUT chunk 2; POST complete", - "start another, switch active organization (POST /api/v1/auth/organization/set-active) and PUT a chunk" + "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", + "PUT chunk 0 again; GET progress", + "PUT chunk 1; POST complete", + "start another, switch active organization (POST /api/v1/auth/organization/set-active), then PUT a chunk, POST complete and GET progress" ], "acceptance": [ { @@ -1106,7 +1106,7 @@ "evidence": "the vitest summary line per pin file, with the package name and the subject sha" }, { - "clause": "complete with a missing chunk → 409 RESOURCE_CONFLICT with details.missingChunks [2]; progress still in_progress", + "clause": "complete with a missing chunk → 409 RESOURCE_CONFLICT with details.missingChunks [1] (the chunk not sent, numbered from 0); progress still in_progress", "oracle": "api", "verify": "status + details + progress", "evidence": "answers" @@ -1118,9 +1118,9 @@ "evidence": "the progress body" }, { - "clause": "after the org switch chunk PUT / complete / progress → 409", + "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", "oracle": "api", - "verify": "status per call", + "verify": "status per call; for progress, also the session's expiresAt against the clock of the call", "evidence": "three lines" } ], @@ -1138,6 +1138,12 @@ "date": "2026-10-16", "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", "ref": "#23879" + }, + { + "revision": 2, + "date": "2026-10-19", + "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", + "ref": "#PR-PENDING" } ] } diff --git a/docs/qa/platform-checklist/areas/automation.json b/docs/qa/platform-checklist/areas/automation.json index ab9ee960c13..8e66c0c3565 100644 --- a/docs/qa/platform-checklist/areas/automation.json +++ b/docs/qa/platform-checklist/areas/automation.json @@ -1987,10 +1987,10 @@ }, { "id": "automation.flow-authoring-refusals-v18", - "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", + "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", "since": "v18", "status": "active", - "revision": 1, + "revision": 2, "priority": "P1", "surface": "cli", "personas": [ @@ -2006,7 +2006,7 @@ }, "steps": [ "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", - "PUT the same flow bodies to a fresh showcase boot at /api/v1/meta/flow/qa_ARM (scratch names)", + "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", "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" ], "acceptance": [ @@ -2023,9 +2023,9 @@ "evidence": "one line per arm" }, { - "clause": "the same bodies at PUT /meta/flow → 422 INVALID_METADATA and nothing stored", + "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", "oracle": "api", - "verify": "status + read-back 404", + "verify": "status + code per arm, then GET the same name: a 422 arm reads back 404, a root-scope arm 200", "evidence": "per-arm lines" }, { @@ -2055,6 +2055,12 @@ "date": "2026-10-16", "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", "ref": "#23879" + }, + { + "revision": 2, + "date": "2026-10-19", + "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", + "ref": "#PR-PENDING" } ] }, diff --git a/docs/qa/platform-checklist/areas/cli.json b/docs/qa/platform-checklist/areas/cli.json index 2a39e6e79bb..e6dd0a7131d 100644 --- a/docs/qa/platform-checklist/areas/cli.json +++ b/docs/qa/platform-checklist/areas/cli.json @@ -1832,10 +1832,10 @@ }, { "id": "cli.organization-ownership-ceremony", - "title": "The v18 upgrade ceremony `os migrate organization-ownership`: a bare run writes a plan and changes nothing, --apply demands a reviewed --plan-file (and --backup-taken), refuses a mismatched plan, an open SQLite holder (database-busy) and an unresolved dialect, checkpoints its steps, and `os migrate apply --allow-destructive` holds every organization_id drop until the ceremony marker is verified; then `os migrate comment-reactions --apply` converts reactions idempotently — end to end, plan → backup → apply → v18 boot", + "title": "`os migrate organization-ownership` in 18.0, which supports fresh installs only: plan and apply alike refuse NOT_IMPLEMENTED before reading anything and leave the database unchanged, and `os migrate apply --allow-destructive` still withholds every organization_id drop on a v17-shaped database; the ceremony class the refusal keeps underneath (plan, refusals, checkpoints, drop gate) and `os migrate comment-reactions --apply` stay pinned — the v17 → v18 ceremony itself ships in an 18.x release", "since": "v18", "status": "active", - "revision": 1, + "revision": 2, "priority": "P0", "surface": "cli", "personas": [ @@ -1846,46 +1846,42 @@ "requires": [ "a SCRATCH copy of examples/app-showcase (or a scaffolded blank app) for every planted-metadata step — never edit the shared fixtures; a file DB under /tmp/RUN/ for every boot", "a COPY of a v17-shaped SQLite DB (platform-core.v18-boot-refusals names how to get one) — never the original" + ], + "knownGaps": [ + "WITHDRAWN IN 18.0 and deliberately not scored here: the ceremony's own arms — the plan file a bare run writes, its plan-file-required / plan-*-mismatch / database-busy refusals, the sys_migration adr-0131-organization-ownership checkpoint a reviewed apply writes, and a migrated copy booting under v18 — are not clauses of this revision. QA run #24551: \"ruling records 6259608309 (item 1) and 6259698357 then cut 18.0 to fresh installs on the single posture, carried by .changeset/pre/15212-180-guards-fresh-single-only.md, the ADR-0131 release-scope note and organization-ownership.ts …\"; the registered command (packages/cli/src/commands/migrate/organization-ownership.ts#MigrateOrganizationOwnership) refuses before the ceremony runs. A runner scores none of these arms — neither `fail` (QA run #24551's reading of revision 1) nor `skipped` (QA run #24556's, c1/c2/c4): they are not on the item. The 18.x release that ships the upgrade path restores them as clauses in the revision that re-registers the ceremony; their revision-1 wording is in this file's git history", + "acceptance[3] scores the drop gate's exit code, `message` and `tables`, not its prose: that prose still prescribes `os migrate organization-ownership --out PLAN` and `--apply --plan-file PLAN`, which 18.0 refuses — a product defect tracked on #24567, not a fail of this clause" ] }, "steps": [ - "`os migrate organization-ownership` on the copy; read the plan file; checksum the DB before/after", - "`--apply` without --plan-file; with a plan for another DB; with the DB open in a second process", - "`--apply --plan-file PLAN --backup-taken`; read sys_migration row adr-0131-organization-ownership", - "`os migrate apply --allow-destructive` before and after the marker is verified", - "`os migrate comment-reactions --apply` twice", - "`os serve` on the migrated copy — it must boot (platform-core.v18-boot-refusals is the before-state)" + "`os migrate organization-ownership --database-url file:COPY` on the v17-shaped copy, plain and with `--json`; checksum the DB before and after, and list the working directory for organization-ownership-plan-*.json", + "`--apply` without --plan-file; `--apply --plan-file P --backup-taken` with P any path (18.0 writes no plan, and the refusal reads none); `--apply` with the DB held open by a second process; each with `--json` too", + "`os migrate apply --allow-destructive --yes --json` on the v17-shaped copy; checksum the DB before and after", + "`os migrate comment-reactions --apply` twice" ], "acceptance": [ { - "clause": "the ceremony's plan, refusals, checkpoints, drop gate and reactions conversion — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand)", + "clause": "the 18.0 release refusal of the registered command, and the ceremony class it keeps whole underneath (plan, refusals, checkpoints, drop gate, reactions conversion) — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand)", "oracle": "test", "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", "evidence": "the vitest summary line per pin file, with the package name and the subject sha" }, { - "clause": "the bare run writes organization-ownership-plan-*.json and the DB checksum is unchanged", + "clause": "a bare run (plan mode, plain or `--json`) is refused before it reads anything: exit 1 with NOT_IMPLEMENTED — `--json` answers {error: plan_refused, reason: upgrade-unavailable, code: NOT_IMPLEMENTED, detail}, the plain form prints the refusal with `(NOT_IMPLEMENTED)` — no organization-ownership-plan-*.json is written, and the DB checksum is unchanged", "oracle": "build", - "verify": "file + checksums", - "evidence": "plan name + checksums" + "verify": "exit code + the JSON object (or the printed refusal) per form + a directory listing + checksums before/after", + "evidence": "the refusal per form, the listing, the checksum pair" }, { - "clause": "--apply without a plan → plan-file-required; a mismatched plan → plan-*-mismatch; an open holder → database-busy (exit 1, nothing applied)", + "clause": "every --apply arm — no --plan-file, a --plan-file with --backup-taken, the DB held open by a second process — is refused the same way before reading anything: exit 1, `--json` {error: apply_refused, reason: upgrade-unavailable, code: NOT_IMPLEMENTED}; none answers the ceremony's own plan-file-required, plan-*-mismatch or database-busy, which nothing reaches in 18.0, and nothing is applied", "oracle": "build", - "verify": "exit code + reason per arm", + "verify": "exit code + error / reason / code per arm + checksums before/after", "evidence": "per-arm lines" }, { - "clause": "the reviewed apply checkpoints in sys_migration and the drop gate withholds organization_id drops until then", + "clause": "the drop gate still holds on a v17-shaped DB: `os migrate apply --allow-destructive` refuses every organization_id drop the ceremony owns — exit 1, `--json` message refused_organization_ownership_unmigrated with `tables` naming them — and applies nothing", "oracle": "build", - "verify": "sys_migration row + apply output", - "evidence": "excerpts" - }, - { - "clause": "the migrated copy boots under v18", - "oracle": "log", - "verify": "boot output reaches listening", - "evidence": "the line" + "verify": "exit code + the JSON message and tables + checksums before/after", + "evidence": "the excerpt and the checksum pair" } ], "negative": [ @@ -1896,10 +1892,12 @@ ], "automated": { "kind": "unit", - "ref": "packages/cli/src/commands/migrate/organization-ownership.apply-flags.test.ts + packages/cli/src/utils/organization-ownership-apply.test.ts + packages/cli/src/commands/migrate/organization-ownership.occupancy.integration.test.ts + packages/cli/src/commands/migrate/organization-ownership.dialect.test.ts + packages/cli/src/commands/migrate/apply-organization-ownership-gate.integration.test.ts + packages/cli/src/commands/migrate/comment-reactions.integration.test.ts + packages/cli/src/utils/organization-ownership-host-supplement.integration.test.ts" + "ref": "packages/cli/src/commands/migrate/organization-ownership.apply-flags.test.ts + packages/cli/src/utils/organization-ownership-apply.test.ts + packages/cli/src/commands/migrate/organization-ownership.occupancy.integration.test.ts + packages/cli/src/commands/migrate/organization-ownership.dialect.test.ts + packages/cli/src/commands/migrate/apply-organization-ownership-gate.integration.test.ts + packages/cli/src/commands/migrate/comment-reactions.integration.test.ts + packages/cli/src/utils/organization-ownership-host-supplement.integration.test.ts + packages/cli/src/commands/migrate/organization-ownership.release-refusal.test.ts" }, "source": [ "packages/cli/src/commands/migrate/organization-ownership.ts", + "packages/cli/src/commands/migrate/organization-ownership.ts#ORGANIZATION_OWNERSHIP_UPGRADE_UNAVAILABLE", + ".changeset/pre/15212-180-guards-fresh-single-only.md", "packages/spec/src/system/fate-supplement.zod.ts#OrganizationOwnershipSupplementSchema", "packages/cli/src/utils/organization-ownership-drop-gate.ts", "docs/adr/0131-total-organization-ownership-no-null-organization-id.md", @@ -1911,6 +1909,12 @@ "date": "2026-10-16", "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", "ref": "#23879" + }, + { + "revision": 2, + "date": "2026-10-19", + "change": "re-pointed to the 18.0 release refusal (QA run #24551 acceptance[1]–[4] fail, disposition stale-spec, RUNNER rule 7 agreeing; parked on #24579 §1). 18.0 was narrowed to fresh installs by ruling — #24551: \"ruling records 6259608309 (item 1) and 6259698357 then cut 18.0 to fresh installs on the single posture\" — and the registered `os migrate organization-ownership` refuses plan and apply alike with NOT_IMPLEMENTED before reading anything. acceptance[1] and [2] now score that refusal (no plan written, the DB unchanged, every apply arm refused the same way); acceptance[3] keeps the drop-gate half and drops the sys_migration checkpoint half; revision 1's acceptance[4] (the migrated copy boots) is removed. The ledger has no clause-level skip, so the ceremony's own arms are recorded in fixtures.knownGaps[0] as withdrawn and deliberately not scored, the shape knownGaps already carries for a half an item does not score. That is the one reading for both runs: a runner scores those arms neither `fail` (#24551, revision 1) nor `skipped` (QA run #24556, c1/c2/c4), and both runs captured the refusal each re-pointed clause now asserts. automated.ref gains organization-ownership.release-refusal.test.ts, the pin of the registered command (the other pins drive the ceremony class beneath it); acceptance[0], the title, the steps and source follow; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3", + "ref": "#PR-PENDING" } ] }, From d3ea1a46fd05f184d10491ff259011007387fcd4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 16:28:50 +0000 Subject: [PATCH 2/2] docs(qa): point the five new history rows at their pull request The rows were written before the pull request existed; this replaces their placeholder ref with its number and changes nothing else. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- docs/qa/platform-checklist/areas/access-security.json | 2 +- docs/qa/platform-checklist/areas/api-backend.json | 2 +- docs/qa/platform-checklist/areas/attachments-storage.json | 2 +- docs/qa/platform-checklist/areas/automation.json | 2 +- docs/qa/platform-checklist/areas/cli.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index 74494488c0f..2c079477be4 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -3870,7 +3870,7 @@ "revision": 2, "date": "2026-10-19", "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", - "ref": "#PR-PENDING" + "ref": "#24622" } ] } diff --git a/docs/qa/platform-checklist/areas/api-backend.json b/docs/qa/platform-checklist/areas/api-backend.json index 1cd84b0f8b6..31660299067 100644 --- a/docs/qa/platform-checklist/areas/api-backend.json +++ b/docs/qa/platform-checklist/areas/api-backend.json @@ -2890,7 +2890,7 @@ "revision": 2, "date": "2026-10-19", "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", - "ref": "#PR-PENDING" + "ref": "#24622" } ] } diff --git a/docs/qa/platform-checklist/areas/attachments-storage.json b/docs/qa/platform-checklist/areas/attachments-storage.json index 7666e86ddfa..d5c3fea69e7 100644 --- a/docs/qa/platform-checklist/areas/attachments-storage.json +++ b/docs/qa/platform-checklist/areas/attachments-storage.json @@ -1143,7 +1143,7 @@ "revision": 2, "date": "2026-10-19", "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", - "ref": "#PR-PENDING" + "ref": "#24622" } ] } diff --git a/docs/qa/platform-checklist/areas/automation.json b/docs/qa/platform-checklist/areas/automation.json index 8e66c0c3565..bd0fed61a69 100644 --- a/docs/qa/platform-checklist/areas/automation.json +++ b/docs/qa/platform-checklist/areas/automation.json @@ -2060,7 +2060,7 @@ "revision": 2, "date": "2026-10-19", "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", - "ref": "#PR-PENDING" + "ref": "#24622" } ] }, diff --git a/docs/qa/platform-checklist/areas/cli.json b/docs/qa/platform-checklist/areas/cli.json index e6dd0a7131d..4ac65e73ee4 100644 --- a/docs/qa/platform-checklist/areas/cli.json +++ b/docs/qa/platform-checklist/areas/cli.json @@ -1914,7 +1914,7 @@ "revision": 2, "date": "2026-10-19", "change": "re-pointed to the 18.0 release refusal (QA run #24551 acceptance[1]–[4] fail, disposition stale-spec, RUNNER rule 7 agreeing; parked on #24579 §1). 18.0 was narrowed to fresh installs by ruling — #24551: \"ruling records 6259608309 (item 1) and 6259698357 then cut 18.0 to fresh installs on the single posture\" — and the registered `os migrate organization-ownership` refuses plan and apply alike with NOT_IMPLEMENTED before reading anything. acceptance[1] and [2] now score that refusal (no plan written, the DB unchanged, every apply arm refused the same way); acceptance[3] keeps the drop-gate half and drops the sys_migration checkpoint half; revision 1's acceptance[4] (the migrated copy boots) is removed. The ledger has no clause-level skip, so the ceremony's own arms are recorded in fixtures.knownGaps[0] as withdrawn and deliberately not scored, the shape knownGaps already carries for a half an item does not score. That is the one reading for both runs: a runner scores those arms neither `fail` (#24551, revision 1) nor `skipped` (QA run #24556, c1/c2/c4), and both runs captured the refusal each re-pointed clause now asserts. automated.ref gains organization-ownership.release-refusal.test.ts, the pin of the registered command (the other pins drive the ceremony class beneath it); acceptance[0], the title, the steps and source follow; re-derived from main 5a871e4e41, where every source cited here is byte-identical to the run subject 5b14b7f3", - "ref": "#PR-PENDING" + "ref": "#24622" } ] },