From ab3cb02ca15131a9ca087a49a1672c02073e7fcb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:08:16 +0000 Subject: [PATCH 01/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20A=20=E2=80=94=20three=20records-forms=20pin=20over-claims?= =?UTF-8?q?=20narrowed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit conditional-rules-grid drops grid-file-upload.spec.ts and its stale record (seat ruling) and names the unpinned Product cell; master-detail-atomic-save narrows master-detail.spec.ts to what it asserts carrier-neutrally; field-type-constraints stops citing summary-rollup.spec.ts for invoice.total. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../areas/records-forms.json | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/qa/platform-checklist/areas/records-forms.json b/docs/qa/platform-checklist/areas/records-forms.json index e20ed3a680a..f0e5e686a7c 100644 --- a/docs/qa/platform-checklist/areas/records-forms.json +++ b/docs/qa/platform-checklist/areas/records-forms.json @@ -930,7 +930,7 @@ "title": "Grid-level conditional rules: row-scoped requiredWhen and parent-scoped readonlyWhen in the inline line-item grid", "since": "v16", "status": "active", - "revision": 7, + "revision": 8, "priority": "P1", "surface": "browser", "personas": [ @@ -971,13 +971,13 @@ { "clause": "parent-scoped readonlyWhen re-evaluates live against the header record: setting status to paid locks the three cells, reverting unlocks them — without a page reload", "oracle": "dom", - "verify": "after screenshots at each state, assert cell editability (pinned by objectui e2e/live/grid-parent-rules.spec.ts)", + "verify": "after screenshots at each state, assert the editability of all three cells. objectui e2e/live/grid-parent-rules.spec.ts pins Qty and Unit Price only (disabled at paid, enabled at draft, on the New Invoice dialog's first line); the Product cell carries the same readonlyWhen and no pin asserts it, so read it by hand", "evidence": "lock/unlock screenshots" }, { "clause": "the receipt upload cell stores a real managed file: the API re-read of the line carries the sys_file reference and the file is retrievable", "oracle": "api", - "verify": "GET the line post-save; the receipt field holds the file id, not an inline blob (ADR-0104 stored form; pinned by objectui e2e/live/grid-file-upload.spec.ts)", + "verify": "GET the line post-save; the receipt field holds the file id, not an inline blob (ADR-0104 stored form). No pin covers this clause: objectui e2e/live/grid-file-upload.spec.ts, cited here until revision 8, asserts only the receipt the outgoing batch carries; it never re-reads the line or fetches the file", "evidence": "line read + fetched file" }, { @@ -997,16 +997,7 @@ ], "automated": { "kind": "e2e", - "ref": "objectui: e2e/live/grid-conditional-rules.spec.ts (acceptance[0]'s inline-flag half ONLY — on the New Invoice dialog's first line, Description carries no required flag at Qty 2, is flagged at Qty 100 and clears once filled; the spec adds no second row and never saves, so neither the unflagged sibling row nor the blocked save is pinned), e2e/live/grid-parent-rules.spec.ts, e2e/live/grid-file-upload.spec.ts (stale at the pin, see automated.stale). No pin covers acceptance[1] or acceptance[4]", - "stale": { - "since": "2026-10-19", - "observedIn": "#24598", - "ref": "#24579 §2", - "partial": "objectui: e2e/live/grid-file-upload.spec.ts ONLY — grid-conditional-rules.spec.ts and grid-parent-rules.spec.ts passed", - "why": "RED AT THE PIN, AS A STALE SPEC — not a product defect. Tier 1 run #24598 at the sweep's console pin 4016370af3c9: grid-file-upload.spec.ts failed; the other two passed. Its 'Line Items' text locator also matches the master-detail dialog's screen-reader-only description (\"Enter the record and its line items, then save.\", objectui packages/plugin-form/src/ModalForm.tsx), so Playwright's strict mode refuses the locator before the form is driven (round-1 record #24572). Re-read at the shipped pin 12dc7b47c340: the spec's bytes and that description are unchanged, so it is still stale there.", - "runnerRule": "Cite grid-conditional-rules.spec.ts for acceptance[0]'s inline flag and grid-parent-rules.spec.ts for acceptance[2] as before. Do NOT cite grid-file-upload.spec.ts or score its failure as this item's FAIL: drive acceptance[3] by hand, with every clause no passing spec covers.", - "ownedBy": "objectui — re-pointing grid-file-upload.spec.ts at the current surface is objectui's half, recorded on wave anchor #24579 §2; this repository reports it and does not edit the spec" - } + "ref": "objectui: e2e/live/grid-conditional-rules.spec.ts (acceptance[0]'s inline-flag half ONLY — on the New Invoice dialog's first line, Description carries no required flag at Qty 2, is flagged at Qty 100 and clears once filled; the spec adds no second row and never saves, so neither the unflagged sibling row nor the blocked save is pinned), e2e/live/grid-parent-rules.spec.ts (acceptance[2] for Qty and Unit Price ONLY — on the New Invoice dialog's first line, with Qty filled, both inputs are enabled at status draft, disabled at paid with the typed quantity kept, and enabled again at draft; it never asserts the Product cell, which declares the same parent-scoped readonlyWhen). No pin covers acceptance[1], acceptance[3] or acceptance[4]. Dropped at revision 8: e2e/live/grid-file-upload.spec.ts, which uploads a file into the first line's Receipt cell and asserts only that the submitted /api/v1/batch carries a receipt with a name and an http(s) url; it never re-reads the saved line or fetches the file, so even green it would score no clause of this item (seat ruling 6281811723). Its stale-spec repair stays on objectstack-ai/objectui#13104 for the items it serves" }, "source": [ "examples/app-showcase/src/data/objects/invoice.object.ts (row/parent-scoped rules on the line object; ADR-0036 / #1581)", @@ -1055,6 +1046,12 @@ "date": "2026-10-20", "change": "automated.ref narrowed per clause — §2 theme \"pins that cover no full clause\" of wave anchor #24579 (18.0 sweep), one of the leftovers round 6 (#24697) named. Tier 1 run #24598 at the sweep's console pin 4016370af3c9: grid-conditional-rules.spec.ts passed, but it flags the Description cell on one row and never saves, so #24598 scored acceptance[0] not-run (round 1's QA run #24572 had scored it pass on that spec). The ref now says the spec claims acceptance[0]'s inline-flag half only, and that no pin covers acceptance[1] or [4]; QA run #24616 drove acceptance[1], [3] and [4] by hand. The spec is byte-identical at the shipped pin 12dc7b47c340. grid-parent-rules.spec.ts and grid-file-upload.spec.ts stay cited as they were, and the automated.stale record (grid-file-upload.spec.ts) is unchanged. No clause changed", "ref": "#24723" + }, + { + "revision": 8, + "date": "2026-10-20", + "change": "automated.ref, acceptance[2].verify and acceptance[3].verify narrowed, and automated.stale removed — the seat ruling 6281811723 (on #24723) and round 8's finding (i) for wave anchor #24579 (18.0 sweep; round 8's report 6281776167). Tier 1 run #24598 at the sweep's console pin 4016370af3c9 ran grid-file-upload.spec.ts red as a stale spec (cause from QA run #24572). Even green it asserts only the receipt the outgoing /api/v1/batch carries and never re-reads the line or fetches the file, so it scores no clause here: it is dropped from the ref and named there, and the stale record, which named only it, goes with it. grid-parent-rules.spec.ts asserts that Qty and Unit Price lock at paid and unlock at draft, and never the Product cell that the clause's 'three cells' include (#24598 scored acceptance[2] pass on it): acceptance[2].verify and the ref now say so. QA run #24616 drove acceptance[1], [3] and [4] by hand. Both specs are byte-identical at 4016370af3c9 and at the shipped pin 12dc7b47c340. No clause changed", + "ref": "#PENDING-24579R9" } ] }, @@ -1181,7 +1178,7 @@ "title": "Master + line items save as one atomic batch, with server-side roll-up", "since": "v16", "status": "active", - "revision": 5, + "revision": 6, "priority": "P1", "surface": "browser", "personas": [ @@ -1210,7 +1207,7 @@ { "clause": "the happy-path save lands master + children in ONE atomic batch request (not N sequential writes), with the child ops referencing the parent", "oracle": "network", - "verify": "the save issues a single batch call whose payload contains the parent and both line ops (pinned by objectui e2e/live/master-detail.spec.ts: 'Create submits the populated parent in one atomic batch' / 'includes the child op referencing the parent')", + "verify": "the save issues a single batch call whose payload contains the parent and both line ops. objectui e2e/live/master-detail.spec.ts pins the clause carrier-neutrally, not on this invoice: on the showcase 'New Project + Tasks' page (showcase_project_workspace), 'Create submits the populated parent in one atomic batch' asserts that the first POST /api/v1/batch the save sends opens with the populated showcase_project op, and 'Create with a task line includes the child op referencing the parent' asserts that the same batch carries one showcase_task op whose project is {$ref: 0}. It stages one child through the per-row form, not two lines in this item's invoice grid, and it reads the first batch rather than counting them, so read this run's two-line invoice payload from the network trace", "evidence": "the batch request payload" }, { @@ -1254,7 +1251,7 @@ ], "automated": { "kind": "e2e", - "ref": "objectui: e2e/live/master-detail.spec.ts, e2e/live/form-view-subforms.spec.ts. Dropped at revision 5: e2e/live/summary-rollup.spec.ts, which rolls showcase_task's estimate_hours up into showcase_project (total_estimate as a SUM, task_count as a COUNT) through a direct POST /api/v1/batch, reading both back after that create and again after a child delete. It never opens the invoice form and never reads invoice.total, the roll-up acceptance[2] scores, so it asserts no clause of this item (Tier 1 run #24598 scored acceptance[2] not-run on it for that carrier mismatch)", + "ref": "objectui: e2e/live/master-detail.spec.ts (acceptance[0], carrier-neutrally: the showcase 'New Project + Tasks' page, one showcase_task child staged through the per-row form, not this item's invoice grid with two lines), e2e/live/form-view-subforms.spec.ts. Dropped at revision 5: e2e/live/summary-rollup.spec.ts, which rolls showcase_task's estimate_hours up into showcase_project (total_estimate as a SUM, task_count as a COUNT) through a direct POST /api/v1/batch, reading both back after that create and again after a child delete. It never opens the invoice form and never reads invoice.total, the roll-up acceptance[2] scores, so it asserts no clause of this item (Tier 1 run #24598 scored acceptance[2] not-run on it for that carrier mismatch)", "stale": { "since": "2026-10-19", "observedIn": "#24598", @@ -1300,6 +1297,12 @@ "date": "2026-10-20", "change": "automated.ref and acceptance[2].verify corrected — §2 theme \"pins that cover no full clause\" of wave anchor #24579 (18.0 sweep), one of the leftovers round 6 (#24697) named. Tier 1 run #24598 at the sweep's console pin 4016370af3c9: summary-rollup.spec.ts passed 2/2, but it rolls showcase_task up into showcase_project through a direct batch and never reads invoice.total, so #24598 scored acceptance[2] not-run on it (round 1's QA run #24572 had scored acceptance[2] pass on it). It asserts no clause of this item, so it is dropped from the ref and named there, and acceptance[2].verify no longer says it pins the clause. The spec is byte-identical at the shipped pin 12dc7b47c340. QA run #24616 drove the invoice.total roll-up by hand. master-detail.spec.ts and form-view-subforms.spec.ts stay cited, and the automated.stale record (form-view-subforms.spec.ts) is unchanged. No clause text changed", "ref": "#24723" + }, + { + "revision": 6, + "date": "2026-10-20", + "change": "acceptance[0].verify and automated.ref narrowed to what master-detail.spec.ts asserts — round 8's finding (iii) for wave anchor #24579 (18.0 sweep; round 8's report 6281776167, carried by the seat's ACCEPT 6281811723). The spec drives showcase_project_workspace ('New Project + Tasks') with one task child staged through the per-row form, not the invoice grid with two lines that steps[1] and [2] drive. Tier 1 run #24598 at the sweep's console pin 4016370af3c9 ran it 2/2 green and scored acceptance[0] pass on it. The clause names no carrier (master and children in one atomic batch, the child ops referencing the parent), and the spec's two tests assert exactly that on their own carrier: the first batch the save sends opens with the populated parent op and carries the child op whose project is {$ref: 0}. So, under round 6's theme-B rule, a pin that asserts a full clause is kept and narrowed, not dropped. The spec is byte-identical at 4016370af3c9 and at the shipped pin 12dc7b47c340. No clause changed", + "ref": "#PENDING-24579R9" } ] }, @@ -3672,7 +3675,7 @@ "title": "Per-type CONSTRAINT enforcement on the write path (not just widget render): length/range/option/reference/computed limits, and where the platform deliberately does NOT enforce", "since": "v15", "status": "active", - "revision": 1, + "revision": 2, "priority": "P1", "surface": "mixed", "personas": [ @@ -3685,7 +3688,7 @@ "showcase_invoice (invoice.object.ts): status select {draft,sent,paid,void} required; account lookup with lookupFilters status!=churned; total summary(sum showcase_invoice_line.amount) — the summary carrier the zoo lacks" ], "knownGaps": [ - "precision/scale is DECLARED but NOT enforced on the write path — record-validator.ts validateOne's number branch checks only min/max/finite, no runtime reads field.scale/precision for rounding (grep clean across objectql/rest/runtime), and the SQL driver stores number/currency/percent as table.float (REAL affinity), not DECIMAL(p,s) (sql-driver.ts createColumn ~7354-7368). A currency value with more decimals than `scale` is stored verbatim, unrounded. Record it as a gap; do NOT tick 'scale enforced'.", + "precision/scale is DECLARED but NOT enforced on the write path — record-validator.ts validateOne's number branch checks only min/max/finite, no runtime reads field.scale/precision for rounding (grep clean across objectql/rest/runtime), and the SQL driver stores number/currency/percent as table.float (REAL affinity), not DECIMAL(p,s) (packages/drivers/driver-sql/src/sql-driver.ts#createColumn). A currency value with more decimals than `scale` is stored verbatim, unrounded. Record it as a gap; do NOT tick 'scale enforced'.", "autonumberFormat TOKEN expansion ({0000}/{YYYY}/{MM}/{DD}/{YYYYMMDD}/{field}, per-rendered-prefix scope+reset) has NO showcase fixture — no showcase object declares autonumberFormat (f_autonumber uses the default bare 4-width global counter). Token expansion is pinned instead by packages/spec/src/data/autonumber-format.test.ts + packages/drivers/driver-sql/src/sql-driver-autonumber.test.ts; only server-assignment + client-value-ignored is driveable on the zoo.", "the #4441 reference gate is EXISTENCE-only and deliberately unscoped (engine.ts assertReferencesResolve) — an id that exists but lies outside the field's lookupFilters/dependsOn scope is accepted; scope enforcement is client-only (drilled in records-forms.cascading-multilevel-and-clear).", "summary is a runtime-MAINTAINED cache, not a write-rejected readonly field — a caller-supplied initial total is a SUPPORTED import path and is kept, then self-heals to the child aggregate on the next child write (rule-validator.ts RUNTIME_OWNED_FIELD_TYPES note, #6014). Only `formula` is strictly read-only-on-write; do NOT assert 'summary rejects direct writes'." @@ -3773,7 +3776,7 @@ { "clause": "formula is read-only/computed: a direct write to f_formula is ignored and the read equals f_number*f_percent/100 (42*75/100 = 31.5); summary is a runtime-MAINTAINED cache (invoice.total = Σ line.amount server-side) and is NOT write-rejected — a caller's initial total is a supported import path that self-heals on the next child write", "oracle": "api", - "verify": "GET f_formula after a direct write shows 31.5 (write ignored); GET showcase_invoice.total equals the seeded line sum (objectui e2e/live/summary-rollup.spec.ts). The formula/summary distinction: rule-validator.ts note (formula computed-on-read; summary maintained cache, deliberately NOT in RUNTIME_OWNED)", + "verify": "GET f_formula after a direct write shows 31.5 (write ignored); GET showcase_invoice.total equals the seeded line sum. No pin reads invoice.total: objectui e2e/live/summary-rollup.spec.ts, cited here until revision 2, asserts a server roll-up on another carrier (showcase_project's total_estimate and task_count over showcase_task, written through a direct /api/v1/batch) and never reads showcase_invoice.total. The formula/summary distinction: rule-validator.ts note (formula computed-on-read; summary maintained cache, deliberately NOT in RUNTIME_OWNED)", "evidence": "the formula re-read + the invoice total re-read" } ], @@ -3809,6 +3812,12 @@ "date": "2026-08-08", "change": "initial — drills the field-type-matrix's shallow 'reject invalid' clause into per-type CONSTRAINT enforcement on the write path (length reject-not-truncate, numeric range, option server-boundary on two carriers, multiselect array shape, dangling-reference gate + its unscoped boundary, autonumber server-assignment, formula read-only) and records the deliberate non-enforcement gaps (scale/precision, autonumberFormat tokens, summary maintained-not-rejected)", "ref": "claude/platform-test-checklist-ocwugl" + }, + { + "revision": 2, + "date": "2026-10-20", + "change": "acceptance[7].verify corrected — round 8's carried finding for wave anchor #24579 (18.0 sweep; round 8's report 6281776167, out_of_scope_findings[1], carried by the seat's ACCEPT 6281811723). It cited objectui e2e/live/summary-rollup.spec.ts for showcase_invoice.total, which that spec never reads: it rolls showcase_task up into showcase_project (byte-identical at the sweep's console pin 4016370af3c9 and at the shipped pin 12dc7b47c340). Tier 1 run #24598 scored acceptance[7] not-run (its summary half unpinned), and round 1's QA run #24572 scored the item pass on its API pins. The verify now says that no pin reads invoice.total. The spec was never in automated.ref, which names API pins only, so the ref is unchanged. Beside it, fixtures.knownGaps[0]'s line citation 'createColumn ~7354-7368', a tilde range no gate reads, became the sql-driver.ts#createColumn anchor that its own text already named. No clause changed", + "ref": "#PENDING-24579R9" } ] }, From bbac45a1616d33aa67b2c854001d088cd81be4bc Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:13:03 +0000 Subject: [PATCH 02/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20access-security=20comma-range=20line=20cit?= =?UTF-8?q?ations=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit record-view-read-audit anchors read-audit.ts#buildRow; share-link-landing-page names its SharedRecordPage branches in prose (objectui, shipped pin). Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../areas/access-security.json | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index f4bdda31952..42061e66c8c 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -3052,7 +3052,7 @@ "title": "Opt-in record-view auditing writes `read` rows for exactly the opted-in objects' detail reads, batched off the request path — stock boot audits nothing, excluded names refuse loudly, values never copied", "since": "v17", "status": "active", - "revision": 2, + "revision": 3, "priority": "P2", "surface": "api", "personas": [ @@ -3091,7 +3091,7 @@ "evidence": "log line + the ledger rows before/after each read" }, { - "clause": "the row records WHO/WHICH/WHEN and nothing else: action 'read', user_id = M, object_name/record_id correct, old_value AND new_value both null (the afterFind hook sees PRE-MASK plaintext, so copying values would mint a plaintext copy of exactly what FLS withholds — read-audit.ts,516-521), and created_at is the VIEW instant, not the flush instant", + "clause": "the row records WHO/WHICH/WHEN and nothing else: action 'read', user_id = M, object_name/record_id correct, old_value AND new_value both null (the afterFind hook sees PRE-MASK plaintext, so copying values would mint a plaintext copy of exactly what FLS withholds — packages/plugins/plugin-audit/src/read-audit.ts#buildRow writes both as null, for the reason the file header's section 'The row records NO field values, and that is load-bearing' gives), and created_at is the VIEW instant, not the flush instant", "oracle": "api", "verify": "field-by-field read of the landed row; created_at within the read's wall-clock window, not the flush's", "evidence": "the row + the recorded clocks" @@ -3155,6 +3155,12 @@ "date": "2026-10-17", "change": "re-measured on main c91af8ed6 (checklist-accuracy finding from #23878): the stock leg's install-line grep was vacuous on a default boot, because the line logs at INFO and os dev defaults to warn, so steps[0], the fixture and clause 0's verify now boot at OS_LOG_LEVEL=info with an INFO-line positive control. The stock specimen GET /data/showcase_contact/ID is refused to a baseline member at the object gate (403), so the zero proved nothing either; the step now reads a showcase_account detail (200). knownGaps[0] gains the scripted scratch-copy recipe for the configured half, and steps 1 and 3 name X = showcase_account and the un-opted showcase_project. Re-run: stock boot at info (649 INFO lines), plain member detail reads of showcase_project, showcase_task and showcase_account all 200, action 'read' rows 0, no install line. Configured scratch copy: 'Plugin superseded: com.objectstack.audit' WARN, the sys_job exclusion WARN and 'AuditPlugin: record-view auditing installed on 1 object(s) — showcase_account'; member M's account detail read → 1 row (action read, user_id M, object_name showcase_account, record_id correct, old_value and new_value null, created_at 00:15:23.489Z inside the 23.385–23.497 read window, about 4 s before the flush read); the list read and the showcase_project detail read left the count at 1; the admin's detail read made it 2", "ref": "#24036" + }, + { + "revision": 3, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[2].clause cited lines 516-521 of read-audit.ts in the comma-range spelling, the second range of the two-range list 45397edf53 authored (55-75 and 516-521). At that commit lines 516-521 were the audit row's old_value / new_value nulls; at this base they hold a docblock, and the nulls sit in the buildRow closure of installReadAuditWriter. The clause now anchors read-audit.ts#buildRow and names the header section that gives the reason in prose. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, @@ -3163,7 +3169,7 @@ "title": "The /s/:token share-link landing page renders the resolved record minus redacted fields, gates on password, and refuses dead links with designed states — never a blank page or a raw error", "since": "v16", "status": "active", - "revision": 3, + "revision": 4, "priority": "P2", "surface": "browser", "personas": [ @@ -3179,7 +3185,7 @@ ], "knownGaps": [ "automated.ref lives ENTIRELY in the objectui repo — from this checkout it is neither runnable nor pin-evidenced (the RUNNER standing fact): drive the item by hand in the browser, or run the pin in an objectui checkout and name the revision", - "the ai_conversations transcript branch (SharedRecordPage.tsx,190-234 — messages fetch + ChatbotEnhanced readOnly) is ai_conversations-only (Cloud/EE service-ai) — the same knownGap split the API item records for /:token/messages; not runnable on open-framework showcase", + "the ai_conversations transcript branch (objectui SharedRecordPage.tsx: the SharedRecordPage component's ai_conversations branch, with its messages-fetch effect and the ChatbotEnhanced readOnly transcript) is ai_conversations-only (Cloud/EE service-ai) — the same knownGap split the API item records for /:token/messages; not runnable on open-framework showcase", "FIXED, regression row, expected PASS (objectui#11649): the page no longer folds every 401 into the password prompt. Measured at objectui 1fb1ced36243 (the pin this row was written at), again at daeb77fc84dd (#23878) and at f8267df93aba (this repo's .objectui-sha when revision 3 was written; re-read it at whatever pin the run boots): SharedRecordPage.tsx reads a 401 by the body's error.code through shared-record-shape.ts resolveGateOf — NEEDS_PASSWORD and WRONG_PASSWORD open the password prompt, SIGN_IN_REQUIRED opens the sign-in gate, and any other code shows the server's message, not a prompt — so a signed_in-audience link opened anonymously renders the dedicated 'Sign in required' state, never 'Password required'. acceptance[3] now asserts that state (QA run #23163 saw it live at objectstack 36b2889c). The objectui pins are apps/console/src/pages/SharedRecordPage-11649.test.tsx ('shows the sign-in path back to this link, and no password prompt') and shared-record-shape.test.ts ('reads each 401 code as its gate'), objectui-repo-only like knownGaps[0]" ] }, @@ -3201,13 +3207,13 @@ { "clause": "the password gate renders as designed and never leaks early: 401 → the 'Password required' prompt; wrong password → re-prompt with 'Wrong password.'; correct password → the record renders — and NO 401 response body carries the record", "oracle": "network", - "verify": "the three round-trips (SharedRecordPage.tsx,143-176): two 401s with record-free bodies, then the 200 render; drive the input with native setter + events, not coordinate typing", + "verify": "the three round-trips (objectui SharedRecordPage.tsx: the component's password-gate branch, gate === 'password'): two 401s with record-free bodies, then the 200 render; drive the input with native setter + events, not coordinate typing", "evidence": "the three network traces + screenshots of prompt and render" }, { "clause": "dead links refuse with designed, non-leaking states: revoked and expired render 'This link has expired or was revoked.' (410), a garbage token renders 'This link is invalid or no longer available.' (404) — never a blank page, a spinner that never settles, or a raw stack/JSON error, and no record data in any refusal body", "oracle": "screenshot", - "verify": "each terminal state's screenshot shows the designed message (SharedRecordPage.tsx,178-186); the paired network bodies are record-free", + "verify": "each terminal state's screenshot shows the designed message (objectui SharedRecordPage.tsx: the component's error branch, which renders the message fetchResolve sets for a 404 or a 410); the paired network bodies are record-free", "evidence": "screenshots + the 404/410 bodies" }, { @@ -3249,7 +3255,7 @@ }, "source": [ "objectui apps/console/src/App.tsx (the /s/:token route, mounted outside the authenticated shell)", - "objectui apps/console/src/pages/SharedRecordPage.tsx (status folds, password form, error states, generic record render + hidden-fields notice, ai_conversations branch,190-234)", + "objectui apps/console/src/pages/SharedRecordPage.tsx (status folds, password form, error states, generic record render + hidden-fields notice, ai_conversations branch)", "objectui apps/console/src/pages/shared-record-shape.ts (normalizeResolvedShare — both envelopes, the #3983 rename)", "cross-ref access-security.share-link-capability-tokens — the API half: mint/resolve/redaction/password/audience/revoke semantics and the #9308 showcase_client_brief fixture are asserted THERE; this item asserts only what the console renders of them", "#9308 (the stock fixture), objectstack#3983 (the enveloped-branch rename regression the notice clause guards)" @@ -3272,6 +3278,12 @@ "date": "2026-10-16", "change": "knownGaps[2] stopped naming objectui 1fb1ced36243 as 'still this repo's .objectui-sha' (#23878 checklist-accuracy finding). The pin moved to daeb77fc84dd and then to f8267df93aba; at f8267df93aba SharedRecordPage.tsx still reads a 401 by its code through shared-record-shape.ts resolveGateOf, renders the 'Sign in required' state for SIGN_IN_REQUIRED, and both objectui pins (SharedRecordPage-11649.test.tsx, shared-record-shape.test.ts) are present. The revision 2 history row stays as written: it was true at its pin. Wording only, no re-run owed", "ref": "#24036" + }, + { + "revision": 4, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.knownGaps[1], acceptance[1].verify, acceptance[2].verify and source[1] cited objectui SharedRecordPage.tsx by the line ranges 190-234 (twice), 143-176 and 178-186 in the comma-range spelling (authored in 45397edf53). At the objectui pin that commit shipped, 9602dc820450, those lines were the ai_conversations branch, the password form and the error state; at the shipped pin 12dc7b47c340 all three have moved down, below a sign-in gate and a reworked fetchResolve, and the password branch now reads gate === 'password'. Each now names its branch of the SharedRecordPage component. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, From f4607491ba5137feea51519dc87bb68532018951 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:15:02 +0000 Subject: [PATCH 03/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20ai=20comma-range=20line=20citations=20re-p?= =?UTF-8?q?ointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui, in prose read at the shipped pin. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- docs/qa/platform-checklist/areas/ai.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/qa/platform-checklist/areas/ai.json b/docs/qa/platform-checklist/areas/ai.json index 13efad9260f..8bda1089def 100644 --- a/docs/qa/platform-checklist/areas/ai.json +++ b/docs/qa/platform-checklist/areas/ai.json @@ -631,7 +631,7 @@ "title": "Console AI affordances gate on the access-filtered agent catalog: an agent-less boot hides FAB / chat dock / ⌘⇧I / top-bar link and redirects a stale /ai bookmark without flash — and the ungated bare system/ai-approvals route degrades honestly: one 501 read stops the poll, and the error replaces the empty queue (objectui#11736)", "since": "v16", "status": "active", - "revision": 4, + "revision": 5, "priority": "P2", "surface": "browser", "personas": ["admin (form sign-in — the pending-actions poll sends the COOKIE half only, credentials:'include' with no bearer header, so an injected-token session reads as anonymous there)"], @@ -705,7 +705,7 @@ ], "traps": ["hydration-race", "stale-console-bundle"], "source": [ - "objectui packages/app-shell/src/hooks/useAiSurface.ts,71-88 (the ONE signal: access-filtered GET /ai/agents, per-seat rationale, isLoading latch for the route guard; do-NOT-simplify-to-discovery warning)", + "objectui packages/app-shell/src/hooks/useAiSurface.ts, its useAiSurfaceEnabled hook (the ONE signal: access-filtered GET /ai/agents, per-seat rationale, isLoading latch for the route guard; do-NOT-simplify-to-discovery warning)", "objectui packages/app-shell/src/layout/ConsoleLayout.tsx (FAB + chat dock + ⌘⇧I all gated on showChatbot/dockEnabled)", "objectui packages/app-shell/src/layout/AppHeader.tsx (top-bar AI entry gated on the same hook) + console/home/HomeLayout.tsx (Home CTAs)", "objectui packages/app-shell/src/console/ConsoleShell.tsx (RequireAiSurface — waits for resolve, splash-preserving redirect, objectui#6507)", @@ -718,7 +718,8 @@ { "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, cross-angle hit 1+4): the console-side AI gating had no coverage — the catalog-signal design (useAiSurfaceEnabled) hides FAB/dock/⌘⇧I/header/Home affordances and no-flash-redirects /ai on an agent-less boot, while SystemHubPage's 'AI Approvals' card is built ungated and its page polls the dead /ai/pending-actions endpoint every 5s (501) rendering a fake empty queue beside the error alert. Authored as a NEW browser sibling of ai.open-edition-honest-degradation (which keeps the API half) rather than extending it, so neither surface double-covers the other; the two K2 defect clauses are expected-fail probes, the defect row itself is the sweep's FOLLOW-UPS entry", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-05", "change": "clause 4, steps 6-7, negative 3, the title and the source re-pointed (stale, #21782 VF4). objectui 9eea12a2b (objectui#10507, fixing objectui#3743) removed SystemHubPage and its 'AI Approvals' card before 17.6.0, so K2's card half is moot. The clause now asserts that no console surface advertises the entry (verifier's wording). The route half of K2 remains: system/ai-approvals is still registered ungated (AppContent systemRoutes), so steps 6-7 reach it by URL and clause 6 keeps its expected-fail scoring. Negative 3 names clause 6 only. Re-read at objectui 9dfaca6543: unchanged", "ref": "#21797" }, { "revision": 3, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21782 parked on #22017 (row 9). A2's entitled side was blocked(fixture) as the clause prescribed. Disposition: recorded knownGap. The side cannot be reached in the open framework by design (service-ai is Cloud/Enterprise). The knownGap names the environment it needs, says CI lacks it, and reclassifies the verdict blocked(environment); A2's clause follows. It also names the objectui hook pins as mechanism-only", "ref": "#22017" }, - { "revision": 4, "date": "2026-10-13", "change": "acceptance[5] (clause and verify) flipped from expected-fail K2 to the positive contract, with steps[6] and [7], negative[2], the title and source[4] and [5] (stale spec, #23163 C5; parked on #23121, carried by #23169). objectui#11736 made the poll follow its last answer (a refused read stops it, a transient one backs off within a ceiling) and made the inbox draw its empty state only when the read answered. QA run #23163 read one 501, no re-arm, and no empty state under the alert, at objectstack 36b2889c with objectui 1fb1ced36243. Re-read from objectui source at that pin, still this repo's .objectui-sha, including the two pins now named in the clause", "ref": "#23169" } + { "revision": 4, "date": "2026-10-13", "change": "acceptance[5] (clause and verify) flipped from expected-fail K2 to the positive contract, with steps[6] and [7], negative[2], the title and source[4] and [5] (stale spec, #23163 C5; parked on #23121, carried by #23169). objectui#11736 made the poll follow its last answer (a refused read stops it, a transient one backs off within a ceiling) and made the inbox draw its empty state only when the read answered. QA run #23163 read one 501, no re-arm, and no empty state under the alert, at objectstack 36b2889c with objectui 1fb1ced36243. Re-read from objectui source at that pin, still this repo's .objectui-sha, including the two pins now named in the clause", "ref": "#23169" }, + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[0] cited lines 71-88 of objectui useAiSurface.ts in the comma-range spelling, the second range of the list 45397edf53 authored (9-40 and 71-88). At the objectui pin that commit shipped, 9602dc820450, and still at the shipped pin 12dc7b47c340, those lines are the useAiSurfaceEnabled hook, so source[0] now names it. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From 08c688e2814e5a3782f96b4846017ecc85f1d4f2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:15:02 +0000 Subject: [PATCH 04/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20attachments-storage=20comma-range=20line?= =?UTF-8?q?=20citations=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui, in prose read at the shipped pin. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../areas/attachments-storage.json | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/qa/platform-checklist/areas/attachments-storage.json b/docs/qa/platform-checklist/areas/attachments-storage.json index 3d1de7b3e6d..3dc20cee586 100644 --- a/docs/qa/platform-checklist/areas/attachments-storage.json +++ b/docs/qa/platform-checklist/areas/attachments-storage.json @@ -28,7 +28,7 @@ "call": "PUT /api/v1/meta/object/qa_vault?package=com.objectstack.qa.attachments", "body": { "name": "qa_vault", "label": "QA Vault", "sharingModel": "private", "enable": { "files": true }, "fields": { "name": { "type": "text", "label": "Name", "required": true } } }, "expect": "2xx. This is THE object the area was missing: private OWD (owner-only) AND attachments-enabled, so a member who is not the owner genuinely cannot read the parent and the 403 deny side becomes provable.", - "source": "`sharingModel` is a TOP-LEVEL object key, enum ['private','public_read','public_read_write','controlled_by_parent'] (packages/spec/src/data/object.zod.ts#legacy; ADR-0090 D4 — legacy aliases removed). `enable.files` is the #2727 attachments opt-in, default false (object.zod.ts). `?package=` is read as `query.package` and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts,319)" + "source": "`sharingModel` is a TOP-LEVEL object key, enum ['private','public_read','public_read_write','controlled_by_parent'] (packages/spec/src/data/object.zod.ts#legacy; ADR-0090 D4 — legacy aliases removed). `enable.files` is the #2727 attachments opt-in, default false (object.zod.ts). `?package=` is read as `query.package` and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts#handleMetadataRequest, its PUT /metadata/:type/:name save branch, through packages/rest/src/rest-server.ts#metaItemPackageBinding)" }, { "step": 3, @@ -134,7 +134,7 @@ }, "qa-media-constraints": { "title": "Scratch object qa_media carrying FIELD-level accept/maxSize (plus an extension-only accept field)", - "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.", + "why": "The showcase declares accept/maxSize ONLY on action params (examples/app-showcase/src/ui/actions/index.ts#ActionParamGalleryAction, its p_cover and p_attachments params — 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.", "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", "app": "showcase", "requires": [ @@ -154,7 +154,7 @@ "call": "PUT /api/v1/meta/object/qa_media?package=com.objectstack.qa.media", "body": { "name": "qa_media", "label": "QA Media", "sharingModel": "public_read_write", "fields": { "name": { "type": "text", "label": "Name", "required": true }, "poster": { "type": "image", "label": "Poster", "accept": ["image/png", "image/jpeg"], "maxSize": 1048576 }, "doc": { "type": "file", "label": "Doc", "accept": [".pdf"] } } }, "expect": "2xx. `poster` is the MIME-entry + maxSize probe; `doc` (accept = ['.pdf'] ONLY, no maxSize) is the extension-entry probe whose dotless-filename hole is a documented boundary of the enforcement. `enable.files` is deliberately ABSENT: field-owned files ride file-reference-lifecycle.ts (activeFileFields keys on file-class field types), not the #2727 sys_attachment opt-in gate, so the object needs no attachments enablement.", - "source": "accept/maxSize are declared FieldSchema keys since ADR-0104 D3 wave 2 (packages/spec/src/data/field.zod.ts#shape — 'Offered to the file picker AND enforced on write'); authoring-call shape identical to qa-scratch-authz step 2 (meta.ts,319 for ?package=); file-class field set is FILE_REFERENCE_TYPES = image/file/avatar/video/audio (packages/spec/src/data/field-value.zod.ts)" + "source": "accept/maxSize are declared FieldSchema keys since ADR-0104 D3 wave 2 (packages/spec/src/data/field.zod.ts#shape — 'Offered to the file picker AND enforced on write'); authoring-call shape identical to qa-scratch-authz step 2 (packages/runtime/src/domains/meta.ts#handleMetadataRequest for ?package=); file-class field set is FILE_REFERENCE_TYPES = image/file/avatar/video/audio (packages/spec/src/data/field-value.zod.ts)" } ], "teardown": "DELETE /api/v1/packages/com.objectstack.qa.media — or discard the isolated file DB, the cheaper path an isolated boot makes free.", @@ -892,7 +892,7 @@ "title": "A field's declared accept/maxSize is re-enforced SERVER-SIDE on record write — the control the client widget check explicitly is not — with the declared missing-metadata and dotless-extension holes scored as documented boundaries", "since": "v17", "status": "active", - "revision": 2, + "revision": 3, "priority": "P1", "surface": "api", "personas": ["seeded admin (admin@objectos.ai) — the check is a declaration constraint, not an authz gate: it binds every caller identically, so no restricted persona is needed"], @@ -900,7 +900,7 @@ "app": "showcase", "requires": [ "the qa_media scratch object with field-level accept/maxSize (see provisioning) — no stock showcase object declares either", - "the storage service live at the default base — presign/complete is how the probe sys_file rows are minted, and their mime_type/size are the DECLARED values the check reads (storage-routes.ts,255)", + "the storage service live at the default base — presign/complete is how the probe sys_file rows are minted, and their mime_type/size are the DECLARED values the check reads (packages/services/service-storage/src/storage-routes.ts#registerStorageFamily: its POST /storage/upload/presigned handler persists the pending sys_file row with the declared mimeType and size)", "a system-write channel to CLEAR mime_type and size on one committed sys_file row for the missing-metadata clause — the presign door refuses a body without mimeType/size (400 INVALID_REQUEST, storage-routes.ts), so a metadata-less row cannot be minted through the API; without the system write that one clause is blocked(fixture)" ], "provisioning": { @@ -908,7 +908,7 @@ "why": "every clause of this item runs against qa_media.poster (MIME accept + maxSize) and qa_media.doc (extension-only accept). Without the recipe the ENTIRE item is blocked(fixture): the showcase's only accept/maxSize declarations sit on action params, which never reach this seam." }, "knownGaps": [ - "FIXTURE GAP (why the recipe exists): the showcase declares accept/maxSize only on ACTION PARAMS (examples/app-showcase/src/ui/actions/index.ts,337) — that lane feeds the dialog widget and the ADR-0059 Confirm-while-uploading guard pinned by records-forms.upload-guard-blocks-confirm, and never reaches assertFileConstraints, which fires on OBJECT-FIELD references at record write. No showcase object field carries either key, so on stock seeds this item cannot run at all. Landing one constrained field in the showcase seeds would retire the qa-media-constraints recipe.", + "FIXTURE GAP (why the recipe exists): the showcase declares accept/maxSize only on ACTION PARAMS (examples/app-showcase/src/ui/actions/index.ts#ActionParamGalleryAction, its p_cover and p_attachments params) — that lane feeds the dialog widget and the ADR-0059 Confirm-while-uploading guard pinned by records-forms.upload-guard-blocks-confirm, and never reaches assertFileConstraints, which fires on OBJECT-FIELD references at record write. No showcase object field carries either key, so on stock seeds this item cannot run at all. Landing one constrained field in the showcase seeds would retire the qa-media-constraints recipe.", "CONTENT-SNIFFING BOUNDARY (record so runs do not score it as a leak): enforcement is DECLARATION-based, never content-based. sys_file.mime_type is taken verbatim from the client's own request body on both upload doors — presigned (storage-routes.ts destructure, persisted, even echoed back as the upload content-type header) and chunked — and nothing on the upload path sniffs magic bytes (no file-type/sniffing code exists in service-storage; measured by search, only fs.readdir withFileTypes matches). A caller may therefore upload arbitrary bytes while declaring image/png and pass every accept test. That is the boundary of what the platform claims; a run demonstrating it records a documented-boundary observation, never a FAIL of this item.", "WIRE-ENVELOPE — MEASURED, the source analysis this row used to carry is superseded: FileConstraintError now declares `status: 400` beside its registered `code: 'ERR_FILE_CONSTRAINT'` (packages/services/service-storage/src/file-reference-lifecycle.ts, the same ADR-0112 shape as FileFieldBulkWriteError), so the REST declared-status passthrough answers 400 ERR_FILE_CONSTRAINT with the bounded message in the body — the message names the field and the constraint ('File type … is not permitted by the accept list declared for 'poster' (image/png, image/jpeg)', 'File exceeds the maximum size declared for 'poster' (2097152 bytes > 1048576 bytes)'), measured on main c91af8ed6. It is no longer a sanitized 500, and since #23932 closed rest no longer logs a declared client refusal as '[REST] Unhandled error' — the info-level server log carries no line for it at all. Consequence for scoring: the enforcement clauses still pass on the NO-ROW oracle, and clause 3 scores the wire answer" ] @@ -983,11 +983,12 @@ "packages/services/service-storage/src/storage-routes.ts#mime_type (presigned) and (chunked) — mime_type/size persisted VERBATIM from the client body: the declaration-based boundary in knownGaps", "packages/spec/src/api/error-code-ledger.zod.ts#status (ERR_FILE_CONSTRAINT registered) vs file-reference-lifecycle.ts (no status declared) vs packages/types/src/data-error-classification.ts#classifyDataError classifyDataError (no branch, declared-status passthrough skipped, UNCLASSIFIED_FAULT terminal) — the clause-2 wire analysis; file-reference-lifecycle.ts (FileFieldBulkWriteError's `status: 400` note is the in-module precedent for what a 4xx exit requires)", "packages/services/service-storage/CHANGELOG.md 17.0.0-rc.0 (changeset fe67e34, ADR-0104 D3 wave 2 PR-5a) — grounds since: v17", - "records-forms.upload-guard-blocks-confirm owns the CLIENT half (ADR-0059 dialog guard over ACTION-PARAM accept/maxSize, examples/app-showcase/src/ui/actions/index.ts,337). Cross-reference, do not duplicate — that item never touches this record-write seam" + "records-forms.upload-guard-blocks-confirm owns the CLIENT half (ADR-0059 dialog guard over ACTION-PARAM accept/maxSize, examples/app-showcase/src/ui/actions/index.ts#ActionParamGalleryAction). Cross-reference, do not duplicate — that item never touches this record-write seam" ], "history": [ { "revision": 1, "date": "2026-08-20", "change": "new item from the scoped scan-functionality sweep (扫描功能): the server-side re-enforcement of field accept/maxSize had NO coverage on either lane — the only pinned guard is the client dialog's (records-forms.upload-guard-blocks-confirm), which the enforcement source itself calls 'a convenience rather than a control'. Authored with the qa-media-constraints recipe (no stock showcase field declares either key), the two source-documented holes (missing metadata, dotless-name vs extension-only accept) as documented-boundary passes, the declaration-based content boundary recorded so runs do not score sniffing absence as a leak, and the per-source wire-envelope analysis (ERR_FILE_CONSTRAINT ledgered but status-less → sanitized 500 expected) carried as a knownGap for the run to measure rather than rediscover", "ref": "claude/new-session-0pv25p" }, - { "revision": 2, "date": "2026-10-16", "change": "clause 3 and knownGaps WIRE-ENVELOPE expected, per an unmeasured source reading, the sanitized 500 INTERNAL_ERROR with the prose only in the server log, and told the next run to revise the clause if a 4xx appeared (#23878 checklist-accuracy finding). It did: re-measured on main c91af8ed6 with the qa-media-constraints recipe, the accept probe and the size probe both answer 400 ERR_FILE_CONSTRAINT with the field-naming message in the body (FileConstraintError now declares status 400), the compliant control answers 201, and the info-level log carries no line for the refusal (#23932 closed). The clause's oracle moves from log to api and scores status, code and the named field; the knownGap records the measured envelope", "ref": "#24036" } + { "revision": 2, "date": "2026-10-16", "change": "clause 3 and knownGaps WIRE-ENVELOPE expected, per an unmeasured source reading, the sanitized 500 INTERNAL_ERROR with the prose only in the server log, and told the next run to revise the clause if a 4xx appeared (#23878 checklist-accuracy finding). It did: re-measured on main c91af8ed6 with the qa-media-constraints recipe, the accept probe and the size probe both answer 400 ERR_FILE_CONSTRAINT with the field-naming message in the body (FileConstraintError now declares status 400), the compliant control answers 201, and the info-level log carries no line for the refusal (#23932 closed). The clause's oracle moves from log to api and scores status, code and the named field; the knownGap records the measured envelope", "ref": "#24036" }, + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.requires[1] cited line 255 of storage-routes.ts, and fixtures.knownGaps[0] and source[5] line 337 of the showcase actions index.ts, in the comma-range spelling (authored in 8d74a57487 as the lists 241-243 and 255, and 334 and 337). At that commit line 255 was the mime_type of the pending sys_file row the presigned-upload route writes, and line 337 the accept/maxSize of the action gallery's p_attachments param; at this base both have moved. requires[1] now anchors storage-routes.ts#registerStorageFamily, whose POST /storage/upload/presigned handler writes that row, and knownGaps[0] and source[5] anchor index.ts#ActionParamGalleryAction. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From c3352f7e1b0efdf46ca1386975af041c5bdb2f70 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:15:02 +0000 Subject: [PATCH 05/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20automation=20comma-range=20line=20citation?= =?UTF-8?q?s=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui, in prose read at the shipped pin. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../platform-checklist/areas/automation.json | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/qa/platform-checklist/areas/automation.json b/docs/qa/platform-checklist/areas/automation.json index 5a4d78ffc48..25290c7c280 100644 --- a/docs/qa/platform-checklist/areas/automation.json +++ b/docs/qa/platform-checklist/areas/automation.json @@ -38,7 +38,7 @@ "edges": [] }, "expect": "2xx. The definition is deliberately AUTHORABLE-but-unexecutable: FlowSchema declares `nodes: z.array(FlowNodeSchema)` with no `.min(1)` and no refinement requiring a `start` member (packages/spec/src/automation/flow.zod.ts), and nothing rejects a start-less flow at publish, so this lands. It is the engine that refuses it at DISPATCH — `flow.nodes.find(n => n.type === 'start')` misses and execute() returns { success:false, code:'FLOW_NO_START_NODE' } (packages/services/service-automation/src/engine.ts). ⚠️ If a publish-time structural check lands later this step will start 4xx-ing — that is a FINDING about where the refusal moved, not a rotted recipe.", - "source": "flow is NOT in the org-overlay-allowed set (RUNNER.md's overlay fact — view/dashboard/report/translation/email_template only), so the `?package=` route is required exactly as qa-scratch-authz uses it for objects; `?package=` is read as query.package and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts,319)" + "source": "flow is NOT in the org-overlay-allowed set (RUNNER.md's overlay fact — view/dashboard/report/translation/email_template only), so the `?package=` route is required exactly as qa-scratch-authz uses it for objects; `?package=` is read as query.package and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts#handleMetadataRequest, its PUT /metadata/:type/:name save branch, through packages/rest/src/rest-server.ts#metaItemPackageBinding)" }, { "step": 3, @@ -1642,7 +1642,7 @@ "title": "Disabling a packaged flow that packaged callers invoke as a subflow is refused 409 DELETE_RESTRICTED naming every caller; the refused attempt writes no ledger row; enabling the subflow itself is never guarded", "since": "v17", "status": "active", - "revision": 4, + "revision": 5, "priority": "P1", "surface": "api", "personas": [ @@ -1713,7 +1713,7 @@ "packages/services/service-automation/src/engine.ts#packagedSubflowCallers (packagedSubflowCallers — definition scan at disable time, subflow AND map via config.flowName, non-packaged and self skipped), (the guard, before the durable write; the thrown {code:'DELETE_RESTRICTED', status:409, subflowCallers})", "packages/spec/src/api/errors.zod.ts#DELETE_RESTRICTED (DELETE_RESTRICTED — standard 409 catalog member, no new code minted; its DELETE_ prefix fits per the #10243 ruling quoted at the throw site)", "packages/services/service-automation/src/flow-activation-ledger.test.ts#engine (the engine-level pins: names every caller, map counts, non-packaged and self do not guard, enable never guarded, no-callers lands)", - "examples/app-showcase/src/automation/flows/index.ts,707,795,816,1322,1339 (the three stock caller→child pairs)", + "examples/app-showcase/src/automation/flows/index.ts#TaskDoneNotifyOwnerFlow + examples/app-showcase/src/automation/flows/index.ts#ProjectClosureFlow + examples/app-showcase/src/automation/flows/index.ts#ReleaseSignoffFlow (the three stock caller→child pairs: each caller's subflow or map node names its child by config.flowName — showcase_notify_owner, showcase_closure_signoff and showcase_one_task_signoff)", "#12438 (sweep) · Epic #12150", "cross-ref: automation.packaged-flow-disable-durable (what a disable that LANDS must do); automation.setup-packaged-automation-board (the refusal rendered in the UI)" ], @@ -1726,7 +1726,8 @@ }, { "revision": 2, "date": "2026-10-02", "change": "retired clause 5's expected-fail note and re-ordered step 6. The remedy sequence now holds (36d043b #20724, 0d9349f #20759): on 17.6.0 the caller's disable then the child's retry both answer 200 and the ledger reads active=false. Step 6's caller-first enable is refused by design since 679f95e (#20711, 409 RESOURCE_CONFLICT naming the disabled subflow), so the step enables the child first and clause 4 is scoped to a child's enable. Measured by the 17.6.0 release-verification run", "ref": "#21330" }, { "revision": 3, "date": "2026-10-16", "change": "the 'still armed' probe patched a showcase_task to done without saying how to get there (#23878 automation slice finding 2, re-measured on main c91af8ed6): showcase_task requires `project` (a create without it answers 400 VALIDATION_FAILED 'Project is required'), and task_status_flow allows status→done only from in_review (a PATCH from the default backlog answers 400 invalid_transition). A create with project and status 'in_review' answers 201 (create is not transition-checked) and the PATCH to done answers 200, firing the record-change flows. Step 4 now creates the task with project and status 'in_review' first; on that path showcase_task_done_notify_owner ran and completed", "ref": "#24036" }, - { "revision": 4, "date": "2026-10-19", "change": "acceptance[0].clause quotes the remedy the engine writes — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-subflow-disable-refusal acceptance[0]; wave anchor #24579 §3): the remedy names the calling flow, so a substring match on the generic quote fails although the meaning is identical. Re-derived at base 9a7838edf5 (packages/services/service-automation/src/engine.ts, the subflow-caller refusal: 'disable the calling flow 'NAME' first' … ' — or leave this one armed.')", "ref": "#24649" } + { "revision": 4, "date": "2026-10-19", "change": "acceptance[0].clause quotes the remedy the engine writes — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-subflow-disable-refusal acceptance[0]; wave anchor #24579 §3): the remedy names the calling flow, so a substring match on the generic quote fails although the meaning is identical. Re-derived at base 9a7838edf5 (packages/services/service-automation/src/engine.ts, the subflow-caller refusal: 'disable the calling flow 'NAME' first' … ' — or leave this one armed.')", "ref": "#24649" }, + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 707, 795, 816, 1322 and 1339 of the showcase flows index.ts in the comma-range spelling (authored in e0abc386a4 as the list 678 to 1339). At that commit those lines were the names and child flowName values of the three stock caller flows; at this base all of them have moved. source[4] now anchors the three callers, index.ts#TaskDoneNotifyOwnerFlow, #ProjectClosureFlow and #ReleaseSignoffFlow, and names each child in prose. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { @@ -1734,7 +1735,7 @@ "title": "POST /automation/:name/clone: whole-definition copy mutating exactly name/label/status, protection envelope dropped, no ancestry, draft-but-armed (double-fire notice verbatim), 409/404/400 refusal arms — and the honest clause: the clone must survive a restart and reach Studio", "since": "v17", "status": "active", - "revision": 4, + "revision": 5, "priority": "P1", "surface": "api", "personas": [ @@ -1780,7 +1781,7 @@ { "clause": "the refusal arms answer their own status+code: same/taken name → 409 RESOURCE_CONFLICT with the shadow-rationale message suggesting a free name; unknown source → 404 RESOURCE_NOT_FOUND; an illegal machine name → 400 (the definition goes through registerFlow's own validation, one policy not two)", "oracle": "api", - "verify": "step 2's remaining arms: the 409 message explains WHY same-name clones are refused (engine keys flows by bare name — silent order-dependent shadowing, flowCloneNameTakenMessage flow-clone.ts) and suggests '_copy'; 404 for the unknown source; 400 for 'Bad-Name!' (FlowSchema name regex ^[a-z_][a-z0-9_]*$, flow.zod.ts). Codes pinned at automation-flow-clone.test.ts,439", + "verify": "step 2's remaining arms: the 409 message explains WHY same-name clones are refused (engine keys flows by bare name — silent order-dependent shadowing, flowCloneNameTakenMessage flow-clone.ts) and suggests '_copy'; 404 for the unknown source; 400 for 'Bad-Name!' (FlowSchema name regex ^[a-z_][a-z0-9_]*$, flow.zod.ts). Codes pinned in packages/runtime/src/domains/automation-flow-clone.test.ts#RESOURCE_CONFLICT and packages/runtime/src/domains/automation-flow-clone.test.ts#RESOURCE_NOT_FOUND (its same-name 409 cases and its unknown-source 404 case)", "evidence": "the three bodies (status + code + message)" }, { @@ -1832,7 +1833,8 @@ }, { "revision": 2, "date": "2026-10-02", "change": "clause 7's expected-fail note now names only the reachability half. The durability half was fixed by cb4c31d (#20907, with #20761): on 17.6.0 the clone survives a cold restart, reads back with its edited label and still fires (release-verification run). The reachability half still fails — no Studio surface lists a package-less flow — and is now filed as #21332 instead of resting on the #12438 sweep", "ref": "#21330" }, { "revision": 3, "date": "2026-10-17", "change": "clause 6's reachability EXPECTED FAIL is stale (checklist-accuracy finding, automation slice report on #23878): objectui#11553 gave Studio an org scope whose Automations rail lists package-less flows, and #21332 closed as a duplicate. The verify now asserts the clone is listed and opens at /_console/studio/~org/automations, steps[7] drives it after the restart, and the objectui source line names the org scope and its pin. Re-run on main c91af8ed6 with the console at objectui f8267df93aba, file DB: POST …/showcase_urgent_task_alert/clone {name qa_urgent_alert_clone, label} → 200 status draft; the Organization flows rail listed 'QA urgent alert clone' and opened it (Trigger: Record created or updated · showcase_task, Enabled, no lock banner); after a cold restart over the same DB the GET answered 200, the rail listed and opened it again, and one urgent task create added one run to the clone (0 → 1) and one to the base (1 → 2); teardown DELETE → deleted true", "ref": "#24036" }, - { "revision": 4, "date": "2026-10-19", "change": "acceptance[1] (clause, verify) counts the dropped keys the clone really drops — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-clone-contract acceptance[1]; wave anchor #24579 §3): FLOW_CLONE_DROPPED_KEYS is 10, not 9, since packages/runtime/src/flow-clone.ts appends 'protection' (#23120, ADR-0010 §3.5) to the 2 read decorations and 7 protection fields. Re-derived at base 9a7838edf5", "ref": "#24649" } + { "revision": 4, "date": "2026-10-19", "change": "acceptance[1] (clause, verify) counts the dropped keys the clone really drops — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-clone-contract acceptance[1]; wave anchor #24579 §3): FLOW_CLONE_DROPPED_KEYS is 10, not 9, since packages/runtime/src/flow-clone.ts appends 'protection' (#23120, ADR-0010 §3.5) to the 2 read decorations and 7 protection fields. Re-derived at base 9a7838edf5", "ref": "#24649" }, + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[3].verify cited line 439 of automation-flow-clone.test.ts in the comma-range spelling (authored in e0abc386a4 as the list 368-401 and 439). Those lines are unchanged at this base: the same-name 409 cases and the unknown-source 404 assertion. The verify now anchors the two codes those cases assert, automation-flow-clone.test.ts#RESOURCE_CONFLICT and #RESOURCE_NOT_FOUND. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { @@ -1840,7 +1842,7 @@ "title": "The Setup packaged-automation page: reachable from Setup nav, lists packaged flows + packaged actions, toggle persists, clone on flow rows only, no lineage surface, server refusals verbatim in role=alert", "since": "v17", "status": "active", - "revision": 4, + "revision": 5, "priority": "P1", "surface": "browser", "personas": [ @@ -1911,7 +1913,7 @@ { "clause": "the clone dialog requires BOTH machine name and label before submit is possible, and a server-refused name surfaces legibly: the illegal-name 400 renders in the dialog's alert — record exactly what text arrives, because the per-field details[] are dropped client-side", "oracle": "dom", - "verify": "the submit control is disabled until both fields are non-empty (cloneNameValid, PackagedAutomationPage.tsx,529 — so the 'required' 400s of the API item are unreachable from this dialog); submitting 'Bad-Name!' round-trips the server 400 and the dialog alert (role=alert) shows the message actionErrorDetail extracted — details[] never reach the DOM, so if the rendered sentence does not state the ^[a-z_][a-z0-9_]*$ constraint legibly, record what DID render as the finding rather than inventing a pass. A legal clone then shows the server's post-clone notice verbatim", + "verify": "the submit control is disabled until both fields are non-empty (cloneNameValid, which disables the clone dialog's submit button in objectui PackagedAutomationPage.tsx — so the 'required' 400s of the API item are unreachable from this dialog); submitting 'Bad-Name!' round-trips the server 400 and the dialog alert (role=alert) shows the message actionErrorDetail extracted — details[] never reach the DOM, so if the rendered sentence does not state the ^[a-z_][a-z0-9_]*$ constraint legibly, record what DID render as the finding rather than inventing a pass. A legal clone then shows the server's post-clone notice verbatim", "evidence": "dialog screenshots: disabled submit, the 400 alert text, the post-clone notice" }, { @@ -1938,7 +1940,7 @@ }, "source": [ "docs/adr/0126-packaged-metadata-customization-model.md §7.4 (the Setup surface: on/off + clone, authoring stays in Studio; ⛔ no drift/ancestry surface)", - "objectui packages/app-shell/src/views/setup/PackagedAutomationPage.tsx (529 clone-dialog validation,516 role=alert refusal rendering) + PackagedActionsSection.tsx (header: ⛔ no clone on actions) + packagedFlows.ts (isPackagedFlowItem + runtime-spine join)", + "objectui packages/app-shell/src/views/setup/PackagedAutomationPage.tsx (the clone dialog's validation — cloneNameValid, which disables its submit button — and its role=alert rendering of clone.refusal) + PackagedActionsSection.tsx (header: ⛔ no clone on actions) + packagedFlows.ts (isPackagedFlowItem + runtime-spine join)", "objectui packages/app-shell/src/services/builtinComponents.tsx (registerAppComponent ref 'automation:packaged') + views/ComponentNavView.tsx (ref resolution, no gate) + views/setup/PackagedAutomationPage.navContribution.test.tsx (ref→URL resolution — the mocked half of the nav clause)", "objectui packages/core/src/actions/actionErrorDetail.ts (error → error.message → message; details[] dropped)", "packages/platform-objects/src/apps/setup-nav.contributions.ts#nav_packaged_automation (nav_packaged_automation → componentRef 'automation:packaged', landed by #12457; the entry's comment records why it lives in platform-objects, not service-automation) + setup-packaged-automation-nav.test.ts (the framework-half pin)", @@ -1972,6 +1974,12 @@ "date": "2026-10-19", "change": "steps[2], steps[3] and acceptance[1].clause corrected — checklist-accuracy findings of the 18.0 QA sweep (QA run #24545, automation.setup-packaged-automation-board steps[1] and acceptance[1] / steps[3]; wave anchor #24579 §3). The fallback URL was spelled with the app name where the sidebar lands on the package-id path, and \"every switch reads On\" did not exempt showcase_approver_bindings, authored status 'obsolete'. Re-derived at base 9a7838edf5: the engine reports a flow enabled: false when its status is obsolete (getFlowRuntimeStates, service-automation engine.ts)", "ref": "#24649" + }, + { + "revision": 5, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[6].verify and source[1] cited objectui PackagedAutomationPage.tsx by the lines 529 and 516 in the comma-range spelling (authored in e0abc386a4; source[1]'s list also left a bare 529). At objectui 9602dc820450, the file's latest commit when the item was authored, 529 was the clone dialog's submit button disabled by cloneNameValid and 516 its role=alert rendering of clone.refusal; at the shipped pin 12dc7b47c340 both have moved. Each now names that code of the PackagedAutomationPage component. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, From 6e069b73b174f92ea78369e56b2aa3cea5506e52 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:09 +0000 Subject: [PATCH 06/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20cli=20comma-range=20line=20citations=20re-?= =?UTF-8?q?pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- docs/qa/platform-checklist/areas/cli.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/qa/platform-checklist/areas/cli.json b/docs/qa/platform-checklist/areas/cli.json index f5d45a286b3..c226a5a006c 100644 --- a/docs/qa/platform-checklist/areas/cli.json +++ b/docs/qa/platform-checklist/areas/cli.json @@ -1691,7 +1691,7 @@ "title": "autoMigrate off|safe: a dev boot self-heals ONLY the safe-categorized drift and reports each applied op, `off` (the driver default) and NODE_ENV=production never touch the schema, and a duplicates-blocked tighten is never auto-applied", "since": "v15", "status": "active", - "revision": 3, + "revision": 4, "priority": "P1", "surface": "cli", "personas": ["operator (local shell)"], @@ -1776,13 +1776,14 @@ "packages/drivers/driver-sql/src/sql-driver.ts#SqlDriverConfig (SqlDriverConfig.autoMigrate docblock: non-destructive alters only), (default 'off'), (reconcileAndWarnDrift — the managed+safe gate, the production ignore warning verbatim, safe-only applyMigrationEntries allowDestructive:false, per-op auto-reconciled info line, post-reconcile re-detect, warn-once loop)", "packages/drivers/driver-sql/src/schema-drift.ts#tightenNullSafeOnly (tightenNullSafeOnly: clean probe → safe, duplicates → blocked with a row report, old index left in place; ADR-0120 D4)", "packages/runtime/src/dev-auto-migrate.ts#devAutoMigrateConfig (the ONE dev self-heal decision since #21733: a dev boot and a driver whose contract declares autoMigrate) + packages/runtime/src/standalone-stack.ts#createStandaloneStack (its default datasource reads it) + packages/cli/src/utils/storage-driver.ts#resolveStorageDefinition (the config-load fallback spreads it per kind) + packages/cli/src/utils/telemetry-datasource.ts#provisionTelemetryDatasource (the telemetry sibling, never self-healed on a one-shot boot)", - "packages/drivers/driver-sql/src/sql-driver-schema-drift.test.ts#driver + sql-driver-unique-tenancy.test.ts + sql-driver-index-drift.test.ts,322-342 (the pins: off-warns / safe-applies / clean-probe tighten / duplicates block)", + "packages/drivers/driver-sql/src/sql-driver-schema-drift.test.ts#driver + sql-driver-unique-tenancy.test.ts + sql-driver-index-drift.test.ts, its describe block \"dev auto-reconcile (autoMigrate: 'safe')\" (the pins: off-warns / safe-applies / clean-probe tighten / duplicates block)", "sibling items: cli.dev-boot-contract (the boot this rides), cli.migrate-plan-apply-json (the deliberate apply path — the ONLY door for destructive diffs; cross-referenced, not re-proven)" ], "history": [ { "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, angle 2): the autoMigrate off|safe policy had no coverage although it is the one path that mutates a dev database at boot. Grounded verify-first, correcting the register's sketch on two points: (1) 'safe' is the LOOSEN-only subset (relax NOT NULL, widen varchar, index ops, clean-probe tighten) — not 'additive' diffs; (2) the register's sql-driver.ts/4652-4654 cites the config/field declarations, but the enforcement lives in reconcileAndWarnDrift with the managed-mode gate, the production force-off warning, and allowDestructive:false — all now pinned as clauses. The dev-injection arm (storage-driver.ts / serve.ts, 'safe' only when isDev) was found while grounding and added as its own clause so a keyless dev boot's self-heal is not misread as a driver default. enumSource pins SqlAutoMigrateSchema expect 2", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-17", "change": "fixture and steps re-pointed (checklist-accuracy finding, #23878 close-out): a config-declared datasource named `default` is refused by defineStack, `required: true` no longer makes a NOT NULL column (storage.notNull, ADR-0113), and relax_not_null is needs_confirm, so the step-0 drift the safe leg relied on was never auto-appliable. The fixture now names a datasource routed by datasourceMapping default:true; step 0 stages one drift per category (storage.notNull relax = needs_confirm, a planted legacy platform-wide unique index = safe, a removed field = destructive); the steps read a schema dump instead of `os migrate plan`, which composes no driver for a config-declared primary and says its plan is PARTIAL; the safe variant lists the real safe ops; clauses 0, 1 and 3's verify follow. No clause's ruling changed. Re-run on main c91af8ed6 on a minimal scratch stack: datasource named default → build exit 2 with the reserved-name refusal; qa_main + mapping built. off and omitted boots each warned all three drifts and left the dump byte-identical; `os migrate plan` (also with --database-url) reported 'Examined 0 managed table(s)' and a PARTIAL plan. safe boot: '[schema-drift] auto-reconciled replace_unique_index on qa_thing.code', the legacy qa_thing_code_unique gone from the dump, the relax and orphan warnings still printed; the second safe boot printed no reconcile line. NODE_ENV=production with safe: the named ignore warning verbatim, all three warnings, dump unchanged. Keyless os dev over a planted legacy index: auto-reconciled replace_unique_index; non-dev os start over a re-planted one: the warning only, the index kept. Duplicates leg on the pin: driver-sql sql-driver-unique-tenancy.test.ts (incl. 'auto-tightens at boot under autoMigrate: safe when the probe is clean' and 'BLOCKS the tightening on duplicate NULL-organization rows') + sql-driver-schema-drift.test.ts, 38 passed", "ref": "#24036" }, - { "revision": 3, "date": "2026-10-19", "change": "steps[4], acceptance[5] (clause, verify) and source[3] re-pointed to the injection site that exists — checklist-accuracy finding of the 18.0 QA sweep (QA run #24551, cli.dev-automigrate-policy acceptance[5] / steps[4]; wave anchor #24579 §3): the cited storage-driver.ts `isDev ? { autoMigrate: 'safe' } : {}` and serve.ts telemetry branch moved. Re-derived at base 9a7838edf5: since #21733 the decision lives in packages/runtime/src/dev-auto-migrate.ts (devAutoMigrateConfig), read by createStandaloneStack's default datasource, resolveStorageDefinition's fallback and the telemetry sibling. The run found the behaviour matching the clause; the clause now names the one decision and the three readers", "ref": "#24649" } + { "revision": 3, "date": "2026-10-19", "change": "steps[4], acceptance[5] (clause, verify) and source[3] re-pointed to the injection site that exists — checklist-accuracy finding of the 18.0 QA sweep (QA run #24551, cli.dev-automigrate-policy acceptance[5] / steps[4]; wave anchor #24579 §3): the cited storage-driver.ts `isDev ? { autoMigrate: 'safe' } : {}` and serve.ts telemetry branch moved. Re-derived at base 9a7838edf5: since #21733 the decision lives in packages/runtime/src/dev-auto-migrate.ts (devAutoMigrateConfig), read by createStandaloneStack's default datasource, resolveStorageDefinition's fallback and the telemetry sibling. The run found the behaviour matching the clause; the clause now names the one decision and the three readers", "ref": "#24649" }, + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 322-342 of sql-driver-index-drift.test.ts in the comma-range spelling (authored in 45397edf53 as the list 112-113 and 322-342). Those lines are unchanged at this base: the describe block \"dev auto-reconcile (autoMigrate: 'safe')\", which source[4] now names. A test file declares no symbol worth anchoring, so the block is named in prose. The count of passed tests that history[1] records after a file name is not a citation, and that row is a dated record, so it is left. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From 11342884cb8b736f33873e2678131733a95cc39e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:09 +0000 Subject: [PATCH 07/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20identity-auth=20comma-range=20line=20citat?= =?UTF-8?q?ions=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../areas/identity-auth.json | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/docs/qa/platform-checklist/areas/identity-auth.json b/docs/qa/platform-checklist/areas/identity-auth.json index d36214ba119..da7a84c6c95 100644 --- a/docs/qa/platform-checklist/areas/identity-auth.json +++ b/docs/qa/platform-checklist/areas/identity-auth.json @@ -1245,7 +1245,7 @@ "title": "Admin CSV identity import: password-policy auto/temporary drive per-row credentials, imported users sign in, non-admins denied", "since": "v17", "status": "active", - "revision": 2, + "revision": 3, "priority": "P2", "surface": "mixed", "personas": ["platform admin (running the import)", "an imported user (signing in afterwards)", "a non-admin (forger)"], @@ -1258,7 +1258,7 @@ ], "knownGaps": [ "observing the `auto` INVITE path needs a transport to capture the invitation; with the dev log transport it is observable, otherwise the invite-vs-fallback split is blocked(fixture). The one-time passwords (auto-fallback + all of temporary) are returned ONLY in the response — the result step must reveal them; they are never persisted", - "the `auto` policy's TEMPORARY-FALLBACK branch is UNREACHABLE on `objectstack dev` (run #7663) — do not score it as a missing behaviour and do not re-derive this next sweep. `auto` falls back only when a row is neither email- nor SMS-deliverable (admin-import-users.ts), and on dev neither can be made false: service-email / service-sms always register (a log transport is the no-provider fallback, service-sms/src/sms-plugin.ts,169), so isEmailServiceAvailable() is a bare 'is a service wired?' check (auth-manager.ts) and returns true; and isPhoneOtpDeliverable() (auth-manager.ts) only returns false for an unconfigured transport when NODE_ENV === 'production', which `objectstack dev` rules out (cli/src/commands/dev.ts spawns with NODE_ENV='development'; serve.ts sets it under --dev). So every email row takes the invite path, and a phone-only row without the phoneNumber plugin fails PHONE_NOT_ENABLED before any plan is chosen. To exercise the fallback, boot WITHOUT an email service (or with NODE_ENV=production + an unconfigured SMS transport) — otherwise score the fallback via the `temporary` policy, which forces the same credential path for every row" + "the `auto` policy's TEMPORARY-FALLBACK branch is UNREACHABLE on `objectstack dev` (run #7663) — do not score it as a missing behaviour and do not re-derive this next sweep. `auto` falls back only when a row is neither email- nor SMS-deliverable (admin-import-users.ts), and on dev neither can be made false: service-email / service-sms always register (a log transport is the no-provider fallback: packages/services/service-sms/src/sms-plugin.ts#resolveInitialTransport answers LogSmsTransport, and init logs 'no provider configured'), so isEmailServiceAvailable() is a bare 'is a service wired?' check (auth-manager.ts) and returns true; and isPhoneOtpDeliverable() (auth-manager.ts) only returns false for an unconfigured transport when NODE_ENV === 'production', which `objectstack dev` rules out (cli/src/commands/dev.ts spawns with NODE_ENV='development'; serve.ts sets it under --dev). So every email row takes the invite path, and a phone-only row without the phoneNumber plugin fails PHONE_NOT_ENABLED before any plan is chosen. To exercise the fallback, boot WITHOUT an email service (or with NODE_ENV=production + an unconfigured SMS transport) — otherwise score the fallback via the `temporary` policy, which forces the same credential path for every row" ] }, "steps": [ @@ -1324,11 +1324,12 @@ "source": [ "objectui packages/app-shell/src/views/identityImport.ts (IdentityPasswordPolicy 'auto'|'none'|'invite'|'temporary'; wraps ImportWizard onto POST /api/v1/auth/admin/import-users; ≤500-row batches; one-time passwords response-only, never persisted; upsert idempotent on email/phone)", "packages/plugins/plugin-auth/src/admin-user-endpoints.ts#explicit (POST /api/v1/auth/admin/import-users — platform-admin-gated login-capable account creation; explicit-password/generatePassword resolution)", - "packages/plugins/plugin-auth/src/admin-import-users.ts#plan (the `auto` per-row plan: invite where email- or SMS-deliverable, temporary only otherwise) + auth-manager.ts,4074 (isEmailServiceAvailable / isPhoneOtpDeliverable — the two gates that decide it)" + "packages/plugins/plugin-auth/src/admin-import-users.ts#plan (the `auto` per-row plan: invite where email- or SMS-deliverable, temporary only otherwise) + packages/plugins/plugin-auth/src/auth-manager.ts#isEmailServiceAvailable + packages/plugins/plugin-auth/src/auth-manager.ts#isPhoneOtpDeliverable (the two gates that decide it)" ], "history": [ { "revision": 1, "date": "2026-08-08", "change": "new item: admin CSV identity import with password-policy matrix (auto/temporary/invite/none), imported-user sign-in, upsert idempotency, response-only one-time passwords, non-admin denied, grounded in objectui identityImport.ts + admin-user-endpoints.ts (PENDING-GAPS §G)", "ref": "claude/platform-test-checklist-ocwugl" }, - { "revision": 2, "date": "2026-08-11", "change": "from run #7663: recorded the fixture note that the `auto` policy's temporary-fallback branch cannot occur on `objectstack dev` — both transports always register (log fallback) and dev pins NODE_ENV='development', so neither deliverability gate can be made false and every row takes the invite path. The clause now says score the invite half and record the fallback half as not-exercised-by-fixture rather than as a defect, and names the boot that WOULD exercise it. Recorded so the next sweep does not re-derive it", "ref": "#7740" } + { "revision": 2, "date": "2026-08-11", "change": "from run #7663: recorded the fixture note that the `auto` policy's temporary-fallback branch cannot occur on `objectstack dev` — both transports always register (log fallback) and dev pins NODE_ENV='development', so neither deliverability gate can be made false and every row takes the invite path. The clause now says score the invite half and record the fallback half as not-exercised-by-fixture rather than as a defect, and names the boot that WOULD exercise it. Recorded so the next sweep does not re-derive it", "ref": "#7740" }, + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.knownGaps[1] cited line 169 of sms-plugin.ts and source[2] line 4074 of auth-manager.ts in the comma-range spelling (authored in 3bb9340974 as the lists 149 and 169, and 4054 and 4074). At that commit 149 and 169 were the LogSmsTransport fallback in resolveInitialTransport and its 'no provider configured' log in init, and 4054 and 4074 were isEmailServiceAvailable and isPhoneOtpDeliverable; at this base all four have moved. knownGaps[1] now anchors sms-plugin.ts#resolveInitialTransport, and source[2] anchors auth-manager.ts#isEmailServiceAvailable and #isPhoneOtpDeliverable, the two gates its words already name. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { @@ -1517,7 +1518,7 @@ "title": "Backup codes: revealed once at enable, spendable exactly once at the sign-in challenge, and regeneration kills the prior set — and the navigable regenerate surface reveals the new set in a one-shot dialog", "since": "v16", "status": "active", - "revision": 3, + "revision": 4, "priority": "P1", "surface": "api", "personas": ["a user with a VERIFIED enrollment (run identity-auth.two-factor-verify-to-activate's path first)", "the same user at the sign-in challenge spending a code"], @@ -1564,7 +1565,7 @@ "evidence": "the two traces" }, { - "clause": "regeneration invalidates the prior set wholesale: after generate-backup-codes, an UNSPENT code from the old set is refused and a code from the new set works — exactly what the regenerate dialog's own copy promises ('Previous backup codes are now invalid', sys-two-factor.object.ts,120)", + "clause": "regeneration invalidates the prior set wholesale: after generate-backup-codes, an UNSPENT code from the old set is refused and a code from the new set works — exactly what the regenerate dialog's own copy promises ('Previous backup codes are now invalid': the resultDialog of the regenerate_backup_codes action, packages/platform-objects/src/identity/sys-two-factor.object.ts#regenerate_backup_codes)", "oracle": "api", "verify": "the old-unspent-code refusal + the new-code 200, both at fresh challenges after the regenerate 200", "evidence": "the regenerate response shape + the two spend traces" @@ -1608,6 +1609,12 @@ "date": "2026-10-17", "change": "steps[8] and acceptance[5].verify cite the regenerate by its index (checklist-accuracy finding of the identity-auth slice report on #23878 (6216631966)): they said 'step-5 regenerate', but the regenerate is steps[4]. Wording only", "ref": "#24036" + }, + { + "revision": 4, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[3].clause cited line 120 of sys-two-factor.object.ts in the comma-range spelling (authored in 8d74a57487 as the list 113 and 120). At that commit 120 was the resultDialog description of the regenerate_backup_codes action, the quoted copy; at this base it has moved. The clause now anchors that action by its name, sys-two-factor.object.ts#regenerate_backup_codes. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, @@ -1703,7 +1710,7 @@ "title": "Zero-user first-run: the /setup owner wizard serves even under OS_DISABLE_SIGNUP, creates the owner + names the personal org through a full-document exit, and every bootstrap bypass closes the moment an owner exists", "since": "v16", "status": "active", - "revision": 2, + "revision": 3, "priority": "P1", "surface": "mixed", "personas": ["anonymous visitor on a zero-user boot (the would-be owner)", "the created owner (post-bootstrap)", "a second anonymous visitor (post-bootstrap forger)"], @@ -1735,7 +1742,7 @@ { "clause": "bootstrap-status is public and truthful on both sides: the zero-user boot answers {hasOwner:false} to an unauthenticated GET, and after the wizard completes the same call answers {hasOwner:true}", "oracle": "api", - "verify": "GET /api/v1/auth/bootstrap-status with no credentials, before and after; the route is ledgered and mounted ahead of the auth wall (auth-plugin.ts,1936-1949)", + "verify": "GET /api/v1/auth/bootstrap-status with no credentials, before and after; the route is ledgered and mounted ahead of the auth wall (packages/plugins/plugin-auth/src/auth-plugin.ts#registerAuthRoutes: its ADR-0069 D5 network-gating middleware lets /config and /bootstrap-status through)", "evidence": "the two bootstrap-status responses" }, { @@ -1784,11 +1791,12 @@ "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (GET /api/v1/auth/bootstrap-status = auth.bootstrapStatus, objectstack-mount — re-pointed #18104: bootstrapStatus is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/plugins/plugin-auth/src/auth-manager.ts#isBootstrapCreation (the bypass's contract comment) + (the before-hook: isBootstrapCreation flips disableSignUp for this request — [#11767] fixed the inert probe) + (isBootstrapCreation: human rows, fail-closed on a full page)", "packages/plugins/plugin-auth/src/audience-posture.ts#isHumanUserRow (isHumanUserRow) + (decideAudienceAdmission isBootstrap arm) + (undeclared audience ⇒ invite_only, maintainer ruling 2026-08-24)", - "packages/cli/src/commands/dev.ts,339 (seed-admin defaults ON — why a zero-user boot needs --no-seed-admin)" + "packages/cli/src/commands/dev.ts#seedAdmin (seed-admin defaults ON — why a zero-user boot needs --no-seed-admin)" ], "history": [ { "revision": 1, "date": "2026-08-30", "change": "authored in the 2026-08-30 coverage sweep ([x2] hit, angles 1+4): the zero-user first-run wizard had no item. Encodes the public bootstrap-status door, the deliberate disableSignUp + audience-gate bypass scoped to the zero-user state, the full-document exit hazard (objectui#4181), the rename-not-create org contract, both closed-door contrasts, and /setup's two meanings (objectui#2794); recorded the rows-vs-humans divergence between the two bootstrap probes as observe-and-record", "ref": "#sweep-2026-08-30" }, - { "revision": 2, "date": "2026-10-17", "change": "steps[7] and acceptance[4] (verify, evidence) corrected (checklist-accuracy finding of the identity-auth slice report on #23878 (6216631966)). On the OS_DISABLE_SIGNUP boot an uninvited forge is refused first by the audience gate (403 SELF_REGISTRATION_CLOSED, invite_only), so door 1 — the re-enforced toggle — was never reached by the step's anonymous visitor; only an invited address reaches it, answering 400 EMAIL_PASSWORD_SIGN_UP_DISABLED. The step adds the owner's invitation and the clause names which address proves which door. Not loosened: every forged sign-up after the owner exists must still be refused with no row written", "ref": "#24036" } + { "revision": 2, "date": "2026-10-17", "change": "steps[7] and acceptance[4] (verify, evidence) corrected (checklist-accuracy finding of the identity-auth slice report on #23878 (6216631966)). On the OS_DISABLE_SIGNUP boot an uninvited forge is refused first by the audience gate (403 SELF_REGISTRATION_CLOSED, invite_only), so door 1 — the re-enforced toggle — was never reached by the step's anonymous visitor; only an invited address reaches it, answering 400 EMAIL_PASSWORD_SIGN_UP_DISABLED. The step adds the owner's invitation and the clause names which address proves which door. Not loosened: every forged sign-up after the owner exists must still be refused with no row written", "ref": "#24036" }, + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 1936-1949 of auth-plugin.ts and source[6] line 339 of the cli dev.ts in the comma-range spelling (authored in 45397edf53 as the lists 1895 and 1936-1949, and 141-142 and 339). At that commit 1936-1949 were the ADR-0069 D5 network-gating middleware in registerAuthRoutes that lets /config and /bootstrap-status through, and 339 was the seedAdmin default; at this base both have moved. acceptance[0].verify now anchors auth-plugin.ts#registerAuthRoutes and source[6] anchors dev.ts#seedAdmin. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { @@ -1796,7 +1804,7 @@ "title": "Self-signup gate: the default audience posture (invite_only) refuses at the server with a LOUD code, a pending invitation carves through, and OS_DISABLE_SIGNUP bounces the UI AND the endpoint — the console offers the register form only to a visitor the server would admit (an invitation redirect, or a deployment with no owner) and explains the by-invitation rule to everyone else; the form is never the gate", "since": "v17", "status": "active", - "revision": 5, + "revision": 6, "priority": "P1", "surface": "mixed", "personas": ["anonymous uninvited registrant", "an invited email's registrant", "org admin (mints the invitation)", "env owner (sets OS_DISABLE_SIGNUP)"], @@ -1862,8 +1870,8 @@ "under stock invite_only on a deployment with an owner, a generic 'Sign up' link on the login page, or the register form on /register for a visitor who did not come from an invitation, is a FAIL: that is the pre-objectui#11691 shape, which offered the form and then refused the finished form with 403 SELF_REGISTRATION_CLOSED. Equally, no form for an /accept-invitation/ID redirect, or on a deployment with no owner yet, strands the people the carve-out and the bootstrap exist to admit — FAIL" ], "variants": [ - "invite_only (stock default; refuse SELF_REGISTRATION_CLOSED, invitation carve-out admits — audience-posture.ts,398-402)", - "email_domain (allowlisted address admitted + granted the declared set; off-list refused EMAIL_DOMAIN_NOT_ALLOWED; matching rules pinned — last-@, case-insensitive, exact entry, no subdomain implication, +tag irrelevant, audience-posture.ts,411-421) — blocked(fixture) without a config boot", + "invite_only (stock default; refuse SELF_REGISTRATION_CLOSED, invitation carve-out admits — packages/plugins/plugin-auth/src/audience-posture.ts#decideAudienceAdmission, whose pending-invitation branch admits before the posture switch)", + "email_domain (allowlisted address admitted + granted the declared set; off-list refused EMAIL_DOMAIN_NOT_ALLOWED; matching rules pinned — last-@, case-insensitive, exact entry, no subdomain implication, +tag irrelevant: packages/plugins/plugin-auth/src/audience-posture.ts#emailDomainAllowed, which the email_domain case of packages/plugins/plugin-auth/src/audience-posture.ts#decideAudienceAdmission asks) — blocked(fixture) without a config boot", "open (admitted + granted selfRegistrationPermissionSet; verification forced on unless the deployment declares it off — the loop is email-verification-loop's) — blocked(fixture) without a config boot", "OS_DISABLE_SIGNUP=true env (UI bounce + server refusal; env > config; OS_AUTH_SIGNUP_ENABLED inverts and wins over it)", "ssoOnlyMode (forces disableSignUp true — surface covered by identity-auth.sso-enforced-first-paint; here only the config-resolution fact)" @@ -1874,8 +1882,8 @@ "packages/plugins/plugin-auth/src/audience-posture.ts#resolveAudience (the single owner of audience admission: resolveAudience default invite_only; decideAudienceAdmission — operator/provider exempt, bootstrap admit, invitation carve-out, posture semantics; SELF_REGISTRATION_CLOSED / EMAIL_DOMAIN_NOT_ALLOWED; pinned domain rules in the module doc)", "packages/plugins/plugin-auth/src/auth-manager.ts#readDisableSignUpEnv (readDisableSignUpEnv: OS_AUTH_SIGNUP_ENABLED wins, then OS_DISABLE_SIGNUP) + (effective disableSignUp: ssoOnly forces true, else env ?? config) + (the sign-up route raises the audience refusal BEFORE the anti-enumeration shield — measured swallow documented in place) +,5040 (getPublicConfig: disableSignUp NOT forced by posture, features.audiencePosture advertised)", "packages/spec/src/system/auth-config.zod.ts#AUDIENCE_POSTURES (AUDIENCE_POSTURES const — invite_only/email_domain/open, the named enum backing posture z.enum) + (AudienceConfigSchema on AuthConfigSchema — the stack-config door; the auth settings namespace is the second door, through the console and the OS_AUTH_AUDIENCE_* env overrides)", - "objectui apps/console/src/pages/auth/RegisterPage.tsx,69-88 (probe /auth/config, bounce to /login when disableSignUp; server-side gate named as the source of truth in its own header)", - "objectui apps/console/src/pages/auth/LoginPage.tsx,136,298 (signUpDisabled from /auth/config; registerUrl withheld when disabled)", + "objectui apps/console/src/pages/auth/RegisterPage.tsx (the RegisterPage component's getAuthConfig probe, and its effect that bounces to /login when decideSignUpOffer answers 'closed', which is disableSignUp; server-side gate named as the source of truth in its own header)", + "objectui apps/console/src/pages/auth/LoginPage.tsx (the LoginPage component passes registerUrl to LoginFormCard only once the /auth/config read is known and decideSignUpOffer answers 'form', so never under disableSignUp; the signUpDisabled state it used to keep is gone)", "objectui packages/app-shell/src/console/auth/signUpOffer.ts (decideSignUpOffer: form / by-invitation / closed / pending from disableSignUp, features.audiencePosture, the invitation redirect and the bootstrap probe — the one decision the console's /login and /register and the package's DefaultLoginPage / DefaultRegisterPage share, objectui#11691 / objectui#11705) + apps/console/src/pages/auth/RegisterPage.tsx (the register-by-invitation notice) + apps/console/src/pages/auth/__tests__/signUpFollowsPosture-11691.test.tsx (the objectui-side pins)" ], "history": [ @@ -1888,6 +1896,12 @@ "date": "2026-10-19", "change": "steps[0] corrected — a checklist-accuracy finding of the 18.0 QA sweep (QA run #24538, identity-auth.self-signup-gate; wave anchor #24579 §3): the step quoted the by-invitation notice as 'Self-registration is not open on this environment…'; the pinned console (objectui 4016370a, RegisterPage.tsx) renders '…not open on this system…'. The step no longer pins the sentence; the data-testid and the absent form are the oracle. No clause changed", "ref": "#24632" + }, + { + "revision": 6, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). variants[0] and variants[1] cited lines 398-402 and 411-421 of audience-posture.ts, and source[3] and source[4] objectui RegisterPage.tsx 69-88 and LoginPage.tsx 136 and 298, in the comma-range spelling (authored in 45397edf53). At that commit the audience-posture lines were decideAudienceAdmission's pending-invitation branch and its email_domain case; at this base both have moved, and the variants now anchor audience-posture.ts#decideAudienceAdmission and #emailDomainAllowed. At the objectui pin 45397edf53 shipped, 9602dc820450, the RegisterPage lines were its getAuthConfig probe that bounced to /login on disableSignUp, and the LoginPage lines its signUpDisabled state and the registerUrl it withheld. At the shipped pin 12dc7b47c340 both pages decide through decideSignUpOffer, whose 'closed' answer is disableSignUp, and the signUpDisabled state is gone; source[3] and source[4] now say so. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, @@ -1896,7 +1910,7 @@ "title": "Email verification loop: a challenged sign-up lands a captured verification mail, unverified sign-in is refused EMAIL_NOT_VERIFIED server-side, the link admits, resend works — and the default boot never challenges", "since": "v16", "status": "active", - "revision": 4, + "revision": 5, "priority": "P2", "surface": "mixed", "personas": ["a fresh registrant (unverified, then verified)", "admin (reads state)", "env owner (configures the verification boot)"], @@ -1914,7 +1928,7 @@ }, "steps": [ "on the verification boot, sign up a fresh admissible address: the console routes to /verify-email-prompt after sign-up (RegisterPage header contract) and the verification mail is sent via template auth.verify_email — capture the link/token from its sys_email row (admin GET /api/v1/data/sys_email; the LogTransport line carries no link) (sendVerificationEmail, auth-manager.ts: template failures THROW into the log rather than silently dropping)", - "attempt POST /api/v1/auth/sign-in/email for the unverified user: capture the refusal carrying EMAIL_NOT_VERIFIED, and in the browser confirm the login page redirects that error into /verify-email-prompt (LoginPage.tsx,346,360)", + "attempt POST /api/v1/auth/sign-in/email for the unverified user: capture the refusal carrying EMAIL_NOT_VERIFIED, and in the browser confirm the login page redirects that error into /verify-email-prompt (objectui LoginPage.tsx: the onError of its LoginFormCard)", "resend from the prompt page (useAuth().sendVerificationEmail → POST /api/v1/auth/send-verification-email, ledgered auth-route-ledger.ts) and capture the second mail from its own, newer sys_email row", "follow the captured link: the console's /verify-email consumes ?token= via GET /api/v1/auth/verify-email?token=… — better-auth serves the route as GET ONLY (a POST answers 404, objectui#11633), and sent WITHOUT callbackURL it answers JSON ({status: true, user: null} once the token verifies — no user object, 401 {code, message} for a garbage or expired one) instead of a 302, which is how the SPA keeps the post-verify UX (VerifyEmailPage.tsx; ledger row GET /api/v1/auth/verify-email) — and renders the success state", "sign in again with the same credentials: admitted; get-session identifies the user", @@ -1975,14 +1989,15 @@ "objectui apps/console/src/App.tsx (/verify-email + /verify-email-prompt routes)", "objectui apps/console/src/pages/auth/VerifyEmailPage.tsx (consumes ?token= via GET with no callbackURL, which answers JSON so the SPA controls the post-verify UX; better-auth serves no POST variant — it answers 404, objectui#11633)", "objectui apps/console/src/pages/auth/VerifyEmailPromptPage.tsx (shown after sign-up or an EMAIL_NOT_VERIFIED-blocked sign-in; resend via useAuth().sendVerificationEmail)", - "objectui apps/console/src/pages/auth/LoginPage.tsx,346,360 (EMAIL_NOT_VERIFIED → /verify-email-prompt redirect + the named error copy)", + "objectui apps/console/src/pages/auth/LoginPage.tsx (the onError of its LoginFormCard: EMAIL_NOT_VERIFIED → /verify-email-prompt redirect) + objectui packages/app-shell/src/console/auth/signInRefusalMessages.ts (signInRefusalMessages: the named error copy, which moved there from LoginPage.tsx)", "packages/plugins/plugin-email/src/transports/index.ts (the dev `log` capture transport — same harness as identity-auth.self-service-password-reset)" ], "history": [ { "revision": 1, "date": "2026-08-30", "change": "authored in the 2026-08-30 coverage sweep (angle 4): the verification loop (challenge, capture, verify, resend, default-never-challenges) had no item. Grounded the #11739 posture-forces-verification invariant and its advertised mirror, the console's three surfaces (/verify-email POST-variant consumption, /verify-email-prompt resend, LoginPage's EMAIL_NOT_VERIFIED redirect), and the admissibility precondition the audience wall adds to the fixture", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-09-28", "change": "restated the forced-verification wording to the shipped rule: email_domain always forces verification on; open forces it on unless the deployment declares it off (OS_AUTH_REQUIRE_EMAIL_VERIFICATION=false, or emailAndPassword.requireEmailVerification: false in the stack config); a false stored only through the settings console is refused under open. The (b) fixture, clause 6, the mirror negative and two source notes said every permitting posture forces it; the negative now names the open opt-out boot, which advertises false correctly, as not a FAIL. Steps, oracles and the other clauses are unchanged", "ref": "#20413" }, { "revision": 3, "date": "2026-10-13", "change": "steps[3], acceptance[2].clause and source[4] name the GET verify-email the console uses (stale step, #23166 C2; parked on #23121, carried by #23169). POST /api/v1/auth/verify-email answers 404 — better-auth serves the route as GET only — and the console's VerifyEmailPage calls GET ?token= without a callbackURL, which answers JSON (objectui#11633, at 1fb1ced36243, still this repo's .objectui-sha). The route ledger already books only the GET row. QA run #23166 verified through GET and passed", "ref": "#23169" }, - { "revision": 4, "date": "2026-10-17", "change": "fixtures.requires[2], knownGaps[1], steps[0], [2] and [3] and acceptance[1].verify, [2].clause and [3].verify re-pointed (checklist-accuracy findings of the identity-auth slice report on #23878 (6216631966)). Three premises had moved: the dev transport logs no body or link, so the mail is captured from its sys_email row; verify-email answers {status: true, user: null}, so the step and clause no longer imply a user object; and a consumed token presented for an already-verified user answers a silent 200, so clause 3's 'or the first's already-consumed state is reported loudly' described a refusal that never happens — the resend is now proven by verifying with the resent token first. Not loosened: the resent mail must still carry a token that verifies", "ref": "#24036" } + { "revision": 4, "date": "2026-10-17", "change": "fixtures.requires[2], knownGaps[1], steps[0], [2] and [3] and acceptance[1].verify, [2].clause and [3].verify re-pointed (checklist-accuracy findings of the identity-auth slice report on #23878 (6216631966)). Three premises had moved: the dev transport logs no body or link, so the mail is captured from its sys_email row; verify-email answers {status: true, user: null}, so the step and clause no longer imply a user object; and a consumed token presented for an already-verified user answers a silent 200, so clause 3's 'or the first's already-consumed state is reported loudly' described a refusal that never happens — the resend is now proven by verifying with the resent token first. Not loosened: the resent mail must still carry a token that verifies", "ref": "#24036" }, + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). steps[1] and source[6] cited objectui LoginPage.tsx 346 and 360 in the comma-range spelling (authored in 45397edf53 as the list 339, 346 and 360). At the objectui pin that commit shipped, 9602dc820450, those lines were the onError redirect of EMAIL_NOT_VERIFIED to /verify-email-prompt and the named error copy; at the shipped pin 12dc7b47c340 the redirect sits in the onError of LoginPage.tsx's LoginFormCard, and the copy moved to app-shell's signInRefusalMessages. Both now say so. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From 5c3ee1ff373df570cd78718cbcf1dc1d893274e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:10 +0000 Subject: [PATCH 08/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20platform-core=20comma-range=20line=20citat?= =?UTF-8?q?ions=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- docs/qa/platform-checklist/areas/platform-core.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/qa/platform-checklist/areas/platform-core.json b/docs/qa/platform-checklist/areas/platform-core.json index 7fefa25f2cd..06f86f221a3 100644 --- a/docs/qa/platform-checklist/areas/platform-core.json +++ b/docs/qa/platform-checklist/areas/platform-core.json @@ -2162,7 +2162,7 @@ "title": "Docs portal render: /docs lists the installed corpus, a doc body renders with working intra-corpus links, a flat-doc URL redirects to its canonical in-book path, the per-app index scopes to one package, and a lesser persona's rendered tree equals the API's pruned subset — never a blank region", "since": "v16", "status": "active", - "revision": 2, + "revision": 3, "priority": "P1", "surface": "browser", "personas": [ @@ -2233,7 +2233,7 @@ ], "traps": ["hydration-race", "auth-state-leak", "stale-console-bundle", "wrong-persona"], "source": [ - "objectui apps/console/src/App.tsx (/docs → DocsLayout with index/:slug/:slug/:name children) + AppContent.tsx,176-185 (app-scoped /apps/:packageId/docs — AppDocsIndex + the same DocsLayout children)", + "objectui apps/console/src/App.tsx (/docs → DocsLayout with index/:slug/:slug/:name children) + AppContent.tsx, its systemRoutes (app-scoped /apps/:packageId/docs — AppDocsIndex + the same DocsLayout children)", "objectui apps/console/src/pages/{DocsLayout,DocsIndex,DocsSlug,BookSidebar,AppDocsIndex}.tsx (DocsSlug: a non-book segment is a flat doc name, redirected to /docs//)", "objectui apps/console/src/pages/doc-groups.ts (grouping by namespace prefix — the package is derived from the doc name, ADR-0046)", "objectui packages/app-shell/src/layout/AppHeader.tsx (the Help & Documentation menu: 'All documentation' → /docs for every persona, plus a contextual \"This app's docs\" entry when the current app ships docs) + packages/app-shell/src/console/home/HomeLayout.tsx (/home deliberately omits the sidebar). UnifiedSidebar's home navigation also lists Documentation, but it renders only inside ConsoleLayout, which sets the app context, so it is not the entry this item scores", @@ -2252,6 +2252,12 @@ "date": "2026-10-05", "change": "clause 5, step 5 and the member persona re-pointed (assertion defect, #21782 VF4). The clause sought the Documentation entry in a /home sidebar that no persona has: HomeLayout deliberately omits the sidebar, and UnifiedSidebar's home navigation renders only inside ConsoleLayout, which forces the app context. The entry every persona has is the top-bar Help menu → All documentation → /docs (AppHeader). The verifier's wording is used for the clause. The member persona now reads invite + sign-up, because the stock auth posture is invite_only. Re-read at objectui 9dfaca6543: unchanged from the run's 2e818d0b51ec", "ref": "#21797" + }, + { + "revision": 3, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[0] cited lines 176-185 of objectui apps/console AppContent.tsx in the comma-range spelling (authored in 45397edf53 as the list 35-41 and 176-185). At the objectui pin that commit shipped, 9602dc820450, those lines were the app-scoped docs route (DocsLayout with its index, :slug and :slug/:name children); at the shipped pin 12dc7b47c340 that route sits further down in the same file's systemRoutes, which source[0] now names. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, From d4154880ada7e5aa85b4f84feddc44da4cc0a024 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:10 +0000 Subject: [PATCH 09/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20records-forms=20comma-range=20line=20citat?= =?UTF-8?q?ions=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../areas/records-forms.json | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/docs/qa/platform-checklist/areas/records-forms.json b/docs/qa/platform-checklist/areas/records-forms.json index f0e5e686a7c..f4bec5ebb83 100644 --- a/docs/qa/platform-checklist/areas/records-forms.json +++ b/docs/qa/platform-checklist/areas/records-forms.json @@ -4165,7 +4165,7 @@ "title": "Field-level `unique` on the write path: colliding writes refused 409 UNIQUE_VIOLATION on both driver families, NULL-distinct, organization-scoped by default, whole-batch refusal, autonumber resync converges", "since": "v17", "status": "active", - "revision": 3, + "revision": 4, "priority": "P1", "surface": "api", "personas": [ @@ -4208,13 +4208,13 @@ { "clause": "the update paths are constrained too: an update onto a taken value is refused and the row keeps its old value; a row never collides with ITSELF (an update leaving the unique field alone passes)", "oracle": "api", - "verify": "the PATCH refusal + the unchanged re-read; the self-update 2xx (pins memory-unique-constraint.test.ts,141)", + "verify": "the PATCH refusal + the unchanged re-read; the self-update 2xx (pins: packages/drivers/driver-memory/src/memory-unique-constraint.test.ts, the cases 'update onto a taken value is refused and the row keeps its old value' and 'a row does not collide with ITSELF — an update that leaves the unique field alone passes')", "evidence": "both responses + the re-read" }, { "clause": "updateMany refuses the WHOLE batch BEFORE mutating anything — a predicate update stamping one value onto two rows leaves zero rows changed, never a half-applied batch", "oracle": "api", - "verify": "post-refusal re-reads of every matched row are byte-identical to before (memory-driver.ts,627-631 'Prepare and CHECK every row before mutating any of them'; pin). If no REST surface reaches updateMany on the boot under test, score from the pin and record the substitution", + "verify": "post-refusal re-reads of every matched row are byte-identical to before (packages/drivers/driver-memory/src/memory-driver.ts#updateMany 'Prepare and CHECK every row before mutating any of them'; pin). If no REST surface reaches updateMany on the boot under test, score from the pin and record the substitution", "evidence": "the refusal + full before/after row reads" }, { @@ -4269,6 +4269,12 @@ "date": "2026-10-16", "change": "acceptance[0] (clause, verify) re-pointed (checklist-accuracy finding of QA run #23949, wave #23878): on the SQLite leg the object-naming sentences are in the envelope's developerMessage, and the user-facing `error` is the generic 'A record with this value already exists' — #23949 read them so. The clause now reads the naming where it lives. Not loosened: the object must still be named, no driver text may appear in either field, and nothing may be written", "ref": "#24036" + }, + { + "revision": 4, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[2].verify cited line 141 of memory-unique-constraint.test.ts and acceptance[3].verify lines 627-631 of memory-driver.ts in the comma-range spelling (authored in 45397edf53 as the lists 135 and 141, and 611 and 627-631). Lines 135 and 141 are unchanged at this base: the cases 'update onto a taken value is refused and the row keeps its old value' and 'a row does not collide with ITSELF — an update that leaves the unique field alone passes', which acceptance[2].verify now names. Lines 627-631 held findOne even at that commit; the comment the verify quotes, 'Prepare and CHECK every row before mutating any of them', sat in updateMany then and does now, so acceptance[3].verify anchors memory-driver.ts#updateMany. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, @@ -4277,7 +4283,7 @@ "title": "deleteBehavior matrix: set_null clears / member-removes, master_detail cascades, restrict answers 409 DELETE_RESTRICTED with the cascade remedy, required-FK set_null escalates to restrict", "since": "v15", "status": "active", - "revision": 1, + "revision": 2, "priority": "P1", "surface": "api", "personas": [ @@ -4369,7 +4375,7 @@ "source": [ "packages/spec/src/data/field.zod.ts#deleteBehavior (deleteBehavior inline enum; #9689 parse rejection, #9784 default materialization)", "packages/objectql/src/engine.ts#required (defaults, coercion + [cascade-delete] log, required-FK escalation incl. #9688 multi-value deferral), (DELETE_RESTRICTED envelope, #12166 count disclosure, cascade recursion)", - "examples/app-showcase/src/data/objects/invoice.object.ts,184; contact.object.ts; field-zoo.object.ts; expense-report.object.ts (the four stock arms)" + "examples/app-showcase/src/data/objects/invoice.object.ts#InvoiceLine (its invoice master_detail, deleteBehavior 'cascade') + examples/app-showcase/src/data/objects/invoice.object.ts#Invoice (its required account lookup, the required-FK escalation); contact.object.ts; field-zoo.object.ts; expense-report.object.ts (the four stock arms)" ], "history": [ { @@ -4377,6 +4383,12 @@ "date": "2026-08-30", "change": "initial — sweep gap (spec-enums angle): all three deleteBehavior members plus the escalation/coercion seams were enforced and pinned engine-side but never driven over HTTP by any item. Register corrected against source: restrict is NOT fixture-blocked on stock seeds — invoice.account (required lookup) reaches the same DELETE_RESTRICTED refusal via the #9688 escalation, so only the authored-restrict spelling needs a scratch child", "ref": "#sweep-2026-08-30" + }, + { + "revision": 2, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[2] cited line 184 of the showcase invoice.object.ts in the comma-range spelling (authored in 45397edf53 as the list 69-71 and 184). At that commit 184 was deleteBehavior 'cascade' on the invoice line's invoice master_detail, and 69-71 the invoice's required account lookup, the required-FK escalation arm fixtures.requires names; at this base both have moved. source[2] now anchors invoice.object.ts#InvoiceLine and #Invoice. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, @@ -4475,7 +4487,7 @@ "title": "Per-field trackHistory: a tracked edit lands the ADR-0052 §5b old→new timeline summary with display values, an untracked edit does not, and object-level enable.trackHistory gates the History tab and derived history op both ways", "since": "v15", "status": "active", - "revision": 3, + "revision": 4, "priority": "P1", "surface": "mixed", "personas": [ @@ -4485,7 +4497,7 @@ "app": "showcase", "requires": [ "showcase_account: enable.trackHistory:true (account.object.ts) + per-field trackHistory on industry/status — the BOTH-halves fixture", - "showcase_task: per-field trackHistory on status/priority (task.object.ts,60) with NO object-level enable block — the natural negative for the tab/op gating" + "showcase_task: per-field trackHistory on status/priority (examples/app-showcase/src/data/objects/task.object.ts#Task: its status and priority fields declare trackHistory) with NO object-level enable block — the natural negative for the tab/op gating" ], "knownGaps": [ "no showcase object declares trackHistory:true on a REFERENCE field, so the referenced-record-title rendering (clause 5) is a unit-pin verdict (audit-lookup-summary.test.ts) unless a scratch tracked lookup is authored — record which the verdict rests on" @@ -4557,7 +4569,7 @@ "packages/plugins/plugin-audit/src/audit-writers.ts#planTrackedLookupReads (planTrackedLookupReads), (renderTrackedChangeSummary — ADR-0052 §5b, #7230/#7289 localization), (zero-reads-by-default plan)", "packages/spec/src/data/object.zod.ts#trackHistory (history derives from get ∧ trackHistory), (opt-in default false); packages/spec/src/data/api-derivation.ts", "objectui: packages/app-shell/src/views/RecordDetailView.tsx (History tab three-precondition gate)", - "examples/app-showcase/src/data/objects/account.object.ts (the deliberate both-halves fixture + its comment ruling the tab gate), task.object.ts,60" + "examples/app-showcase/src/data/objects/account.object.ts (the deliberate both-halves fixture + its comment ruling the tab gate), examples/app-showcase/src/data/objects/task.object.ts#Task (its status and priority fields declare trackHistory)" ], "history": [ { @@ -4577,6 +4589,12 @@ "date": "2026-10-20", "change": "automated.stale added — §2 theme \"objectui live e2e is not green at its own pin\" of wave anchor #24579 (18.0 sweep). Tier 1 run #24598 at the sweep's console pin 4016370af3c9: record-history-display.spec.ts skipped (it runs only against app-todo, on the stale premise that the showcase has no enable.trackHistory object; QA runs #24572 / #24616); the two plugin-audit pins passed and stay cited. Re-read at the shipped pin 12dc7b47c340: byte-identical, still skips. No clause changed", "ref": "#24697" + }, + { + "revision": 4, + "date": "2026-10-20", + "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.requires[1] and source[3] cited line 60 of the showcase task.object.ts in the comma-range spelling (authored in 45397edf53 as the list 49 and 60). At that commit 49 and 60 were the trackHistory flags of the task's status and priority fields; at this base both have moved by a line. Both citations now anchor task.object.ts#Task and name the two fields. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", + "ref": "#PENDING-24579R9" } ] }, From 78bae3d619d23f3d7dfa66b76b2a99f413ea50d2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:10 +0000 Subject: [PATCH 10/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20search=20comma-range=20line=20citations=20?= =?UTF-8?q?re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- docs/qa/platform-checklist/areas/search.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/qa/platform-checklist/areas/search.json b/docs/qa/platform-checklist/areas/search.json index b95a04b9d71..af5cae661eb 100644 --- a/docs/qa/platform-checklist/areas/search.json +++ b/docs/qa/platform-checklist/areas/search.json @@ -586,7 +586,7 @@ "title": "The ⌘K palette is a NAVIGATOR beyond record search: the active app's nav corpus renders grouped (Objects/Dashboards/Pages/Reports), Enter navigates each type, app-switch and theme commands dispatch for real, and visibility-gated / inactive entries stay absent", "since": "v15", "status": "active", - "revision": 3, + "revision": 4, "priority": "P2", "surface": "browser", "personas": ["seeded admin (admin@objectos.ai)"], @@ -626,7 +626,7 @@ { "clause": "the nav corpus renders grouped by TYPE from the active app's flattened navigation: object/dashboard/page/report leaves each under their own heading, nested nav groups flattened to leaves, no other app's items mixed in", "oracle": "dom", - "verify": "post-screenshot DOM shows the four headings with the showcase fixtures under the right ones (flattenNavigation + the per-type CommandGroup blocks, CommandPalette.tsx,391-402); a grouped leaf (e.g. a nested showcase nav child) is present as a flat entry", + "verify": "post-screenshot DOM shows the four headings with the showcase fixtures under the right ones (objectui CommandPalette.tsx: its flattenNavigation function, and the CommandPalette component's per-type CommandGroup blocks); a grouped leaf (e.g. a nested showcase nav child) is present as a flat entry", "evidence": "the grouped-palette screenshot + heading/entry DOM" }, { @@ -671,13 +671,14 @@ "source": [ "objectui packages/app-shell/src/chrome/CommandPalette.tsx (the palette's declared scope: 'quick navigation across apps, objects, dashboards, pages, reports, and global actions'), (flattened nav corpus + evaluateVisibility filter + searchable-object whitelist), (the four per-type CommandGroups, onSelect → navigate(resolveHref…)), (Switch app, active !== false, current marker), (theme commands via setTheme), (Open full search → /search), (flattenNavigation leaves-only)", "objectui packages/app-shell/src/context/CommandPaletteProvider.tsx (the shared open path — covered by search.console-global-search clause 1, cross-referenced not re-proven)", - "examples/app-showcase/src/ui/apps/index.ts,50-65,92-95,102-105 (the fixture: page/object/dashboard/report nav declarations, nested groups)", + "examples/app-showcase/src/ui/apps/index.ts#ShowcaseApp (the fixture: its navigation's page/object/dashboard/report declarations — the grp_data object leaves, and grp_analytics's command-center page, dashboards and reports — inside nested groups)", "search.console-global-search (the sibling item owning the record-search half of the same palette: GET /api/v1/search hits, grouping #3371, recents, RLS parity, /search page — the boundary both items keep so neither double-covers)" ], "history": [ { "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, angle 1), authored as a SIBLING of search.console-global-search rather than an extension — writer's call per the register: that item's identity is the GET /api/v1/search record path (hits, grouping, RLS, recents, /search page) and already carries seven clauses, while the palette's other half — the client-side nav corpus (objects/dashboards/pages/reports groups from the active app's navigation), per-type Enter navigation, app switching, theme dispatch, and the evaluateVisibility gate — was wholly uncovered and is a different mechanism (app metadata + client filter, no server search). Grounded in CommandPalette.tsx; the gate-hidden side is blocked(fixture) on stock seeds because no showcase nav item declares a visibility expression and app metadata is not runtime-writable", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21782 parked on #22017 (row 5). A5 was blocked(fixture): no stock nav item carries a visibility predicate. Disposition: fixture recipe. The knownGap now spells the smallest fixture: two nav leaves with visible 'false' and 'true' added in a scratch copy of the showcase, authored from source and not yet run-proven. A5 named `visibleOn`, which a nav item refuses as a near-miss of `visible` (NAV_ITEM_ALIASES in packages/spec/src/ui/app.zod.ts), so the clause names `visible` only; step 8 points at the recipe", "ref": "#22017" }, - { "revision": 3, "date": "2026-10-13", "change": "knownGaps[0] records that the visibility-predicate fixture recipe is run-proven (knownGaps update, #23163 A4; parked on #23121, carried by #23169). QA run #23163 drove the scratch-copy recipe — two grp_data leaves with visible 'false' and 'true' — at objectstack 36b2889c with objectui 1fb1ced36243, and the palette honoured the predicate on both sides. The recipe text is unchanged; without the scratch copy the hidden side still scores blocked(fixture)", "ref": "#23169" } + { "revision": 3, "date": "2026-10-13", "change": "knownGaps[0] records that the visibility-predicate fixture recipe is run-proven (knownGaps update, #23163 A4; parked on #23121, carried by #23169). QA run #23163 drove the scratch-copy recipe — two grp_data leaves with visible 'false' and 'true' — at objectstack 36b2889c with objectui 1fb1ced36243, and the palette honoured the predicate on both sides. The recipe text is unchanged; without the scratch copy the hidden side still scores blocked(fixture)", "ref": "#23169" }, + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 391-402 of objectui CommandPalette.tsx and source[2] lines 50-65, 92-95 and 102-105 of the showcase apps index.ts in the comma-range spelling (authored in 45397edf53 as the lists 255-328 and 391-402, and 30-40 to 102-105). At the objectui pin that commit shipped, 9602dc820450, 391-402 was the flattenNavigation function and 255-328 the per-type CommandGroup blocks; at the shipped pin 12dc7b47c340 both have moved, and acceptance[0].verify now names them. The apps index.ts lines are unchanged at this base: the ShowcaseApp navigation's object leaves (grp_data), its command-center page and dashboards and its reports (grp_analytics), and the pages above them. source[2] now anchors index.ts#ShowcaseApp. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From 347186527d40b6cf75edc6b200c5ba92b8f6e9ac Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:18:10 +0000 Subject: [PATCH 11/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20pa?= =?UTF-8?q?rt=20B=20=E2=80=94=20studio-authoring=20comma-range=20line=20ci?= =?UTF-8?q?tations=20re-pointed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each comma-range citation names the code its line range pointed at, as a file#symbol anchor or, for objectui and test files, in prose. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../platform-checklist/areas/studio-authoring.json | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/qa/platform-checklist/areas/studio-authoring.json b/docs/qa/platform-checklist/areas/studio-authoring.json index 28ff00d21eb..3e295d31680 100644 --- a/docs/qa/platform-checklist/areas/studio-authoring.json +++ b/docs/qa/platform-checklist/areas/studio-authoring.json @@ -589,7 +589,7 @@ "title": "The metadata type registry gates runtime writes: allowEnvironmentOverlay=false kinds refuse overlay (403 not_overridable), allowRuntimeCreate=false kinds refuse creation — both sides", "since": "v16", "status": "active", - "revision": 3, + "revision": 4, "priority": "P1", "surface": "api", "personas": ["admin"], @@ -662,12 +662,13 @@ "packages/metadata-protocol/src/protocol.ts#isRuntimeCreateAllowed (isRuntimeCreateAllowed — the write-gate authority)", "ADR-0005 (metadata customization opt-in), ADR-0049 (enforce-or-remove — the job rationale)", "packages/spec/src/api/protocol.zod.ts#overrideSource (overrideSource registry|env — how GET /meta reports an OS_METADATA_WRITABLE-granted override, the read that made the #7637 correction checkable)", - "objectui packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx, 1311-1323 (the artifact-backed heuristic behind the read-only banner; cross-linked to objectui#4308)" + "objectui packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (its isArtifactItem test, the artifact-backed heuristic behind the read-only banner; cross-linked to objectui#4308)" ], "history": [ { "revision": 1, "date": "2026-08-07", "change": "new item: both sides of the registry's runtime-write gates (not_overridable / not_creatable vs accepted overlay / accepted create), variants sampled straight from DEFAULT_METADATA_TYPE_REGISTRY and pinned to the overlay-precedence suite", "ref": "claude/platform-test-checklist-ocwugl" }, { "revision": 2, "date": "2026-08-11", "change": "recorded two notes from run #7695 — (a) the CORRECTION to run #7637: with OS_METADATA_WRITABLE=permission the Studio read-only badge clears and the editor is fully writable (GET /meta reports overrideSource:'env'), so the earlier 'badge asserts a lock the server is not applying' observation does not reproduce and must not be acted on as written; (b) the route note that a metadata-API-authored flow opens read-only in Studio (ResourceEditPage's artifact-backed heuristic + flow's allowOrgOverride:false) — correct for this kind, with the polarity-reversed defect filed at objectui#4308. Notes only; no clause, variant or oracle changed", "ref": "#7753" }, - { "revision": 3, "date": "2026-10-16", "change": "variants[1] corrected (checklist-accuracy finding 1 of QA run #23942, wave #23878). The field variant still read 'create open', but DEFAULT_METADATA_TYPE_REGISTRY has declared field allowRuntimeCreate:false since #7893 (a standalone field row reached no object's fields), so its create side is locked like job's and answers 403 NOT_CREATABLE. The variant now states the expectation the registry declares; step[0] already tells the runner to read the flags first", "ref": "#24036" } + { "revision": 3, "date": "2026-10-16", "change": "variants[1] corrected (checklist-accuracy finding 1 of QA run #23942, wave #23878). The field variant still read 'create open', but DEFAULT_METADATA_TYPE_REGISTRY has declared field allowRuntimeCreate:false since #7893 (a standalone field row reached no object's fields), so its create side is locked like job's and answers 403 NOT_CREATABLE. The variant now states the expectation the registry declares; step[0] already tells the runner to read the flags first", "ref": "#24036" }, + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 1311-1323 of objectui ResourceEditPage.tsx in the comma-range spelling, written with a space (authored in 3bb9340974 as the list 951-955 and 1311-1323). At the objectui pin that commit shipped, 6314e87f2d49, 1311-1323 was the isArtifactItem test; at the shipped pin 12dc7b47c340 it has moved and also excludes provenance 'org'. source[5] now names isArtifactItem. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { @@ -1357,7 +1358,7 @@ "title": "The metadata governance sweep: GET /meta/diagnostics reports every STORED item failing spec validation with located errors, refuses outages and bad spellings loudly instead of answering '0 problems', and the Studio diagnostics page + directory tile badges paint the same numbers", "since": "v16", "status": "active", - "revision": 5, + "revision": 6, "priority": "P2", "surface": "mixed", "personas": ["admin (the governance surface is Studio's)"], @@ -1452,7 +1453,7 @@ "packages/metadata-protocol/src/protocol.ts#getMetaDiagnostics (getMetaDiagnostics: registry-derived type set filtered to registered schemas; reuses the _diagnostics read decoration; stats { count, locked, packages } computed in the same sweep 'so the Studio directory page can render tile counts and a package filter in one round-trip'; 503 outage rethrown #8855 / ADR-0110 D3; 400 unrecognised-spelling rethrown #8924; warnings 'reserved for a future lint layer')", "packages/metadata-protocol/src/metadata-diagnostics.ts#computeMetadataDiagnostics (computeMetadataDiagnostics — errors only, undefined = no opinion for schema-less types; zodIssuesToMetadataIssues names union branches #5598 so Studio has a path to highlight)", "packages/spec/src/api/protocol.zod.ts#GetMetaDiagnosticsResponseSchema (GetMetaDiagnosticsResponseSchema — entries[].diagnostics is the canonical MetadataValidationResultSchema the save path's 422 also speaks)", - "objectui packages/app-shell/src/views/metadata-admin/DiagnosticsPage.tsx (groups by type descending, per-row deep link..//, severity tabs, the summary badge, the clean Empty state, the loadFailed banner) + useMetadata.ts (useGlobalDiagnostics: strict error count vs warn-only count, counts/locked/packages from stats, older-server catch degrades to empty-not-fatal) + DirectoryPage.tsx,242-254 (package-scoped sweep drives tile badges; diagnostics link only when total > 0) + console/AppContent.tsx,982 (the metadata/_diagnostics route)", + "objectui packages/app-shell/src/views/metadata-admin/DiagnosticsPage.tsx (groups by type descending, per-row deep link..//, severity tabs, the summary badge, the clean Empty state, the loadFailed banner) + useMetadata.ts (useGlobalDiagnostics: strict error count vs warn-only count, counts/locked/packages from stats, older-server catch degrades to empty-not-fatal) + DirectoryPage.tsx (MetadataDirectoryPage: the package-scoped useGlobalDiagnostics sweep drives tile badges; the diagnostics link renders only when diagSummary.total > 0) + console/AppContent.tsx (the AppContent component's metadata/_diagnostics route)", "studio-authoring.authoring-validation-not-persisted (why stock stores are clean — the save-time gate; also the known spurious _diagnostics banner on the DESIGNER, which is that item's business, not this sweep's)" ], "history": [ @@ -1460,7 +1461,8 @@ { "revision": 2, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21784 parked on #22017 (row 17). A7 was blocked(fixture): an invalid stored row cannot be planted, because every authoring door validates at save. Disposition: recorded knownGap. The leg cannot be reached on a stock environment by design. The knownGap now names the environment it needs (a store already holding a stale row), says no CI job builds one, and points at the producer-level pin as mechanism-only. No clause changed", "ref": "#22017" }, { "revision": 3, "date": "2026-10-13", "change": "acceptance[1].verify compares stats.locked against the served envelope lock (stale spec, #23166 A1; parked on #23121, carried by #23169). getMetaDiagnostics counts an item as locked when its read envelope reports a lock other than 'none' — the same derivation getMetaItem publishes (#21694) — not when its declared _lock is set. QA run #23166 compared against the envelope lock and passed. Read from source at 6d7f4df3c (protocol.ts getMetaDiagnostics docblock and loop). The A6 row of the same run, the unplantable invalid stored row, is already recorded in full in knownGaps[0] and needs no edit", "ref": "#23169" }, { "revision": 4, "date": "2026-10-16", "change": "acceptance[1].verify names the read that carries the envelope lock (checklist-accuracy finding 2 of QA run #23942, wave #23878). It told the runner to compare stats.locked against the lock GET /api/v1/meta/TYPE/NAME publishes, but that default read is the cached arm and carries no `lock` by design; the envelope lock is on GET /api/v1/meta/TYPE/NAME/layers, which is where #23942 read it (object 107, view 0, flow 32 locked, matching stats). The comparison itself is unchanged", "ref": "#24036" }, - { "revision": 5, "date": "2026-10-19", "change": "fixtures.knownGaps[0], steps[6], steps[8] and acceptance[6] (clause, verify) corrected from QA run #24604 (18.0 sweep round 2, ba4afcc2), the round-2 §3 note that knownGaps[0] is wrong. The invalid stored row is plantable in-run on an isolated scratch file DB: save a valid view through the door with ?package=, rewrite its sys_metadata.metadata, and the next sweep lists it — the run scored acceptance[6] pass that way, deep link and badge included. The directory always repairs ?package= to a project package, so the red button is judged per package scope; rootless union-parent entries may ride beside the located leaf. Wave anchor #24579 round 2 §3 (6272314386)", "ref": "#24671" } + { "revision": 5, "date": "2026-10-19", "change": "fixtures.knownGaps[0], steps[6], steps[8] and acceptance[6] (clause, verify) corrected from QA run #24604 (18.0 sweep round 2, ba4afcc2), the round-2 §3 note that knownGaps[0] is wrong. The invalid stored row is plantable in-run on an isolated scratch file DB: save a valid view through the door with ?package=, rewrite its sys_metadata.metadata, and the next sweep lists it — the run scored acceptance[6] pass that way, deep link and badge included. The directory always repairs ?package= to a project package, so the red button is judged per package scope; rootless union-parent entries may ride beside the located leaf. Wave anchor #24579 round 2 §3 (6272314386)", "ref": "#24671" }, + { "revision": 6, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 242-254 of objectui DirectoryPage.tsx and line 982 of app-shell's console AppContent.tsx in the comma-range spelling (authored in 45397edf53 as the lists 133-158 and 242-254, and 882 and 982). At the objectui pin that commit shipped, 9602dc820450, 242-254 was the diagnostics link that renders only when diagSummary.total is above 0, 133-158 the package-scoped useGlobalDiagnostics sweep, and 982 the nested metadata route block that holds _diagnostics; at the shipped pin 12dc7b47c340 all have moved. source[5] now names the MetadataDirectoryPage component's sweep and link, and the AppContent component's metadata/_diagnostics route. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } ] }, { From a5a72cf7f9670aa4dbdd001401186326188ec0bd Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:32:00 +0000 Subject: [PATCH 12/12] =?UTF-8?q?docs(qa):=2018.0=20sweep=20round=209=20?= =?UTF-8?q?=E2=80=94=20fill=20the=20history=20refs=20with=20the=20pull=20r?= =?UTF-8?q?equest=20number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exactly the 23 placeholder history refs change, and nothing else. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../qa/platform-checklist/areas/access-security.json | 4 ++-- docs/qa/platform-checklist/areas/ai.json | 2 +- .../areas/attachments-storage.json | 2 +- docs/qa/platform-checklist/areas/automation.json | 6 +++--- docs/qa/platform-checklist/areas/cli.json | 2 +- docs/qa/platform-checklist/areas/identity-auth.json | 10 +++++----- docs/qa/platform-checklist/areas/platform-core.json | 2 +- docs/qa/platform-checklist/areas/records-forms.json | 12 ++++++------ docs/qa/platform-checklist/areas/search.json | 2 +- .../platform-checklist/areas/studio-authoring.json | 4 ++-- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index 42061e66c8c..a375d41037b 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -3160,7 +3160,7 @@ "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[2].clause cited lines 516-521 of read-audit.ts in the comma-range spelling, the second range of the two-range list 45397edf53 authored (55-75 and 516-521). At that commit lines 516-521 were the audit row's old_value / new_value nulls; at this base they hold a docblock, and the nulls sit in the buildRow closure of installReadAuditWriter. The clause now anchors read-audit.ts#buildRow and names the header section that gives the reason in prose. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -3283,7 +3283,7 @@ "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.knownGaps[1], acceptance[1].verify, acceptance[2].verify and source[1] cited objectui SharedRecordPage.tsx by the line ranges 190-234 (twice), 143-176 and 178-186 in the comma-range spelling (authored in 45397edf53). At the objectui pin that commit shipped, 9602dc820450, those lines were the ai_conversations branch, the password form and the error state; at the shipped pin 12dc7b47c340 all three have moved down, below a sign-in gate and a reworked fetchResolve, and the password branch now reads gate === 'password'. Each now names its branch of the SharedRecordPage component. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, diff --git a/docs/qa/platform-checklist/areas/ai.json b/docs/qa/platform-checklist/areas/ai.json index 8bda1089def..225af5026a8 100644 --- a/docs/qa/platform-checklist/areas/ai.json +++ b/docs/qa/platform-checklist/areas/ai.json @@ -719,7 +719,7 @@ { "revision": 2, "date": "2026-10-05", "change": "clause 4, steps 6-7, negative 3, the title and the source re-pointed (stale, #21782 VF4). objectui 9eea12a2b (objectui#10507, fixing objectui#3743) removed SystemHubPage and its 'AI Approvals' card before 17.6.0, so K2's card half is moot. The clause now asserts that no console surface advertises the entry (verifier's wording). The route half of K2 remains: system/ai-approvals is still registered ungated (AppContent systemRoutes), so steps 6-7 reach it by URL and clause 6 keeps its expected-fail scoring. Negative 3 names clause 6 only. Re-read at objectui 9dfaca6543: unchanged", "ref": "#21797" }, { "revision": 3, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21782 parked on #22017 (row 9). A2's entitled side was blocked(fixture) as the clause prescribed. Disposition: recorded knownGap. The side cannot be reached in the open framework by design (service-ai is Cloud/Enterprise). The knownGap names the environment it needs, says CI lacks it, and reclassifies the verdict blocked(environment); A2's clause follows. It also names the objectui hook pins as mechanism-only", "ref": "#22017" }, { "revision": 4, "date": "2026-10-13", "change": "acceptance[5] (clause and verify) flipped from expected-fail K2 to the positive contract, with steps[6] and [7], negative[2], the title and source[4] and [5] (stale spec, #23163 C5; parked on #23121, carried by #23169). objectui#11736 made the poll follow its last answer (a refused read stops it, a transient one backs off within a ceiling) and made the inbox draw its empty state only when the read answered. QA run #23163 read one 501, no re-arm, and no empty state under the alert, at objectstack 36b2889c with objectui 1fb1ced36243. Re-read from objectui source at that pin, still this repo's .objectui-sha, including the two pins now named in the clause", "ref": "#23169" }, - { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[0] cited lines 71-88 of objectui useAiSurface.ts in the comma-range spelling, the second range of the list 45397edf53 authored (9-40 and 71-88). At the objectui pin that commit shipped, 9602dc820450, and still at the shipped pin 12dc7b47c340, those lines are the useAiSurfaceEnabled hook, so source[0] now names it. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[0] cited lines 71-88 of objectui useAiSurface.ts in the comma-range spelling, the second range of the list 45397edf53 authored (9-40 and 71-88). At the objectui pin that commit shipped, 9602dc820450, and still at the shipped pin 12dc7b47c340, those lines are the useAiSurfaceEnabled hook, so source[0] now names it. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { diff --git a/docs/qa/platform-checklist/areas/attachments-storage.json b/docs/qa/platform-checklist/areas/attachments-storage.json index 3dc20cee586..71c995ac3ef 100644 --- a/docs/qa/platform-checklist/areas/attachments-storage.json +++ b/docs/qa/platform-checklist/areas/attachments-storage.json @@ -988,7 +988,7 @@ "history": [ { "revision": 1, "date": "2026-08-20", "change": "new item from the scoped scan-functionality sweep (扫描功能): the server-side re-enforcement of field accept/maxSize had NO coverage on either lane — the only pinned guard is the client dialog's (records-forms.upload-guard-blocks-confirm), which the enforcement source itself calls 'a convenience rather than a control'. Authored with the qa-media-constraints recipe (no stock showcase field declares either key), the two source-documented holes (missing metadata, dotless-name vs extension-only accept) as documented-boundary passes, the declaration-based content boundary recorded so runs do not score sniffing absence as a leak, and the per-source wire-envelope analysis (ERR_FILE_CONSTRAINT ledgered but status-less → sanitized 500 expected) carried as a knownGap for the run to measure rather than rediscover", "ref": "claude/new-session-0pv25p" }, { "revision": 2, "date": "2026-10-16", "change": "clause 3 and knownGaps WIRE-ENVELOPE expected, per an unmeasured source reading, the sanitized 500 INTERNAL_ERROR with the prose only in the server log, and told the next run to revise the clause if a 4xx appeared (#23878 checklist-accuracy finding). It did: re-measured on main c91af8ed6 with the qa-media-constraints recipe, the accept probe and the size probe both answer 400 ERR_FILE_CONSTRAINT with the field-naming message in the body (FileConstraintError now declares status 400), the compliant control answers 201, and the info-level log carries no line for the refusal (#23932 closed). The clause's oracle moves from log to api and scores status, code and the named field; the knownGap records the measured envelope", "ref": "#24036" }, - { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.requires[1] cited line 255 of storage-routes.ts, and fixtures.knownGaps[0] and source[5] line 337 of the showcase actions index.ts, in the comma-range spelling (authored in 8d74a57487 as the lists 241-243 and 255, and 334 and 337). At that commit line 255 was the mime_type of the pending sys_file row the presigned-upload route writes, and line 337 the accept/maxSize of the action gallery's p_attachments param; at this base both have moved. requires[1] now anchors storage-routes.ts#registerStorageFamily, whose POST /storage/upload/presigned handler writes that row, and knownGaps[0] and source[5] anchor index.ts#ActionParamGalleryAction. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.requires[1] cited line 255 of storage-routes.ts, and fixtures.knownGaps[0] and source[5] line 337 of the showcase actions index.ts, in the comma-range spelling (authored in 8d74a57487 as the lists 241-243 and 255, and 334 and 337). At that commit line 255 was the mime_type of the pending sys_file row the presigned-upload route writes, and line 337 the accept/maxSize of the action gallery's p_attachments param; at this base both have moved. requires[1] now anchors storage-routes.ts#registerStorageFamily, whose POST /storage/upload/presigned handler writes that row, and knownGaps[0] and source[5] anchor index.ts#ActionParamGalleryAction. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { diff --git a/docs/qa/platform-checklist/areas/automation.json b/docs/qa/platform-checklist/areas/automation.json index 25290c7c280..91a9bacc3e0 100644 --- a/docs/qa/platform-checklist/areas/automation.json +++ b/docs/qa/platform-checklist/areas/automation.json @@ -1727,7 +1727,7 @@ { "revision": 2, "date": "2026-10-02", "change": "retired clause 5's expected-fail note and re-ordered step 6. The remedy sequence now holds (36d043b #20724, 0d9349f #20759): on 17.6.0 the caller's disable then the child's retry both answer 200 and the ledger reads active=false. Step 6's caller-first enable is refused by design since 679f95e (#20711, 409 RESOURCE_CONFLICT naming the disabled subflow), so the step enables the child first and clause 4 is scoped to a child's enable. Measured by the 17.6.0 release-verification run", "ref": "#21330" }, { "revision": 3, "date": "2026-10-16", "change": "the 'still armed' probe patched a showcase_task to done without saying how to get there (#23878 automation slice finding 2, re-measured on main c91af8ed6): showcase_task requires `project` (a create without it answers 400 VALIDATION_FAILED 'Project is required'), and task_status_flow allows status→done only from in_review (a PATCH from the default backlog answers 400 invalid_transition). A create with project and status 'in_review' answers 201 (create is not transition-checked) and the PATCH to done answers 200, firing the record-change flows. Step 4 now creates the task with project and status 'in_review' first; on that path showcase_task_done_notify_owner ran and completed", "ref": "#24036" }, { "revision": 4, "date": "2026-10-19", "change": "acceptance[0].clause quotes the remedy the engine writes — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-subflow-disable-refusal acceptance[0]; wave anchor #24579 §3): the remedy names the calling flow, so a substring match on the generic quote fails although the meaning is identical. Re-derived at base 9a7838edf5 (packages/services/service-automation/src/engine.ts, the subflow-caller refusal: 'disable the calling flow 'NAME' first' … ' — or leave this one armed.')", "ref": "#24649" }, - { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 707, 795, 816, 1322 and 1339 of the showcase flows index.ts in the comma-range spelling (authored in e0abc386a4 as the list 678 to 1339). At that commit those lines were the names and child flowName values of the three stock caller flows; at this base all of them have moved. source[4] now anchors the three callers, index.ts#TaskDoneNotifyOwnerFlow, #ProjectClosureFlow and #ReleaseSignoffFlow, and names each child in prose. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 707, 795, 816, 1322 and 1339 of the showcase flows index.ts in the comma-range spelling (authored in e0abc386a4 as the list 678 to 1339). At that commit those lines were the names and child flowName values of the three stock caller flows; at this base all of them have moved. source[4] now anchors the three callers, index.ts#TaskDoneNotifyOwnerFlow, #ProjectClosureFlow and #ReleaseSignoffFlow, and names each child in prose. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { @@ -1834,7 +1834,7 @@ { "revision": 2, "date": "2026-10-02", "change": "clause 7's expected-fail note now names only the reachability half. The durability half was fixed by cb4c31d (#20907, with #20761): on 17.6.0 the clone survives a cold restart, reads back with its edited label and still fires (release-verification run). The reachability half still fails — no Studio surface lists a package-less flow — and is now filed as #21332 instead of resting on the #12438 sweep", "ref": "#21330" }, { "revision": 3, "date": "2026-10-17", "change": "clause 6's reachability EXPECTED FAIL is stale (checklist-accuracy finding, automation slice report on #23878): objectui#11553 gave Studio an org scope whose Automations rail lists package-less flows, and #21332 closed as a duplicate. The verify now asserts the clone is listed and opens at /_console/studio/~org/automations, steps[7] drives it after the restart, and the objectui source line names the org scope and its pin. Re-run on main c91af8ed6 with the console at objectui f8267df93aba, file DB: POST …/showcase_urgent_task_alert/clone {name qa_urgent_alert_clone, label} → 200 status draft; the Organization flows rail listed 'QA urgent alert clone' and opened it (Trigger: Record created or updated · showcase_task, Enabled, no lock banner); after a cold restart over the same DB the GET answered 200, the rail listed and opened it again, and one urgent task create added one run to the clone (0 → 1) and one to the base (1 → 2); teardown DELETE → deleted true", "ref": "#24036" }, { "revision": 4, "date": "2026-10-19", "change": "acceptance[1] (clause, verify) counts the dropped keys the clone really drops — checklist-accuracy finding of the 18.0 QA sweep (QA run #24545, automation.packaged-flow-clone-contract acceptance[1]; wave anchor #24579 §3): FLOW_CLONE_DROPPED_KEYS is 10, not 9, since packages/runtime/src/flow-clone.ts appends 'protection' (#23120, ADR-0010 §3.5) to the 2 read decorations and 7 protection fields. Re-derived at base 9a7838edf5", "ref": "#24649" }, - { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[3].verify cited line 439 of automation-flow-clone.test.ts in the comma-range spelling (authored in e0abc386a4 as the list 368-401 and 439). Those lines are unchanged at this base: the same-name 409 cases and the unknown-source 404 assertion. The verify now anchors the two codes those cases assert, automation-flow-clone.test.ts#RESOURCE_CONFLICT and #RESOURCE_NOT_FOUND. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[3].verify cited line 439 of automation-flow-clone.test.ts in the comma-range spelling (authored in e0abc386a4 as the list 368-401 and 439). Those lines are unchanged at this base: the same-name 409 cases and the unknown-source 404 assertion. The verify now anchors the two codes those cases assert, automation-flow-clone.test.ts#RESOURCE_CONFLICT and #RESOURCE_NOT_FOUND. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { @@ -1979,7 +1979,7 @@ "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[6].verify and source[1] cited objectui PackagedAutomationPage.tsx by the lines 529 and 516 in the comma-range spelling (authored in e0abc386a4; source[1]'s list also left a bare 529). At objectui 9602dc820450, the file's latest commit when the item was authored, 529 was the clone dialog's submit button disabled by cloneNameValid and 516 its role=alert rendering of clone.refusal; at the shipped pin 12dc7b47c340 both have moved. Each now names that code of the PackagedAutomationPage component. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, diff --git a/docs/qa/platform-checklist/areas/cli.json b/docs/qa/platform-checklist/areas/cli.json index c226a5a006c..e053a167d66 100644 --- a/docs/qa/platform-checklist/areas/cli.json +++ b/docs/qa/platform-checklist/areas/cli.json @@ -1783,7 +1783,7 @@ { "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, angle 2): the autoMigrate off|safe policy had no coverage although it is the one path that mutates a dev database at boot. Grounded verify-first, correcting the register's sketch on two points: (1) 'safe' is the LOOSEN-only subset (relax NOT NULL, widen varchar, index ops, clean-probe tighten) — not 'additive' diffs; (2) the register's sql-driver.ts/4652-4654 cites the config/field declarations, but the enforcement lives in reconcileAndWarnDrift with the managed-mode gate, the production force-off warning, and allowDestructive:false — all now pinned as clauses. The dev-injection arm (storage-driver.ts / serve.ts, 'safe' only when isDev) was found while grounding and added as its own clause so a keyless dev boot's self-heal is not misread as a driver default. enumSource pins SqlAutoMigrateSchema expect 2", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-17", "change": "fixture and steps re-pointed (checklist-accuracy finding, #23878 close-out): a config-declared datasource named `default` is refused by defineStack, `required: true` no longer makes a NOT NULL column (storage.notNull, ADR-0113), and relax_not_null is needs_confirm, so the step-0 drift the safe leg relied on was never auto-appliable. The fixture now names a datasource routed by datasourceMapping default:true; step 0 stages one drift per category (storage.notNull relax = needs_confirm, a planted legacy platform-wide unique index = safe, a removed field = destructive); the steps read a schema dump instead of `os migrate plan`, which composes no driver for a config-declared primary and says its plan is PARTIAL; the safe variant lists the real safe ops; clauses 0, 1 and 3's verify follow. No clause's ruling changed. Re-run on main c91af8ed6 on a minimal scratch stack: datasource named default → build exit 2 with the reserved-name refusal; qa_main + mapping built. off and omitted boots each warned all three drifts and left the dump byte-identical; `os migrate plan` (also with --database-url) reported 'Examined 0 managed table(s)' and a PARTIAL plan. safe boot: '[schema-drift] auto-reconciled replace_unique_index on qa_thing.code', the legacy qa_thing_code_unique gone from the dump, the relax and orphan warnings still printed; the second safe boot printed no reconcile line. NODE_ENV=production with safe: the named ignore warning verbatim, all three warnings, dump unchanged. Keyless os dev over a planted legacy index: auto-reconciled replace_unique_index; non-dev os start over a re-planted one: the warning only, the index kept. Duplicates leg on the pin: driver-sql sql-driver-unique-tenancy.test.ts (incl. 'auto-tightens at boot under autoMigrate: safe when the probe is clean' and 'BLOCKS the tightening on duplicate NULL-organization rows') + sql-driver-schema-drift.test.ts, 38 passed", "ref": "#24036" }, { "revision": 3, "date": "2026-10-19", "change": "steps[4], acceptance[5] (clause, verify) and source[3] re-pointed to the injection site that exists — checklist-accuracy finding of the 18.0 QA sweep (QA run #24551, cli.dev-automigrate-policy acceptance[5] / steps[4]; wave anchor #24579 §3): the cited storage-driver.ts `isDev ? { autoMigrate: 'safe' } : {}` and serve.ts telemetry branch moved. Re-derived at base 9a7838edf5: since #21733 the decision lives in packages/runtime/src/dev-auto-migrate.ts (devAutoMigrateConfig), read by createStandaloneStack's default datasource, resolveStorageDefinition's fallback and the telemetry sibling. The run found the behaviour matching the clause; the clause now names the one decision and the three readers", "ref": "#24649" }, - { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 322-342 of sql-driver-index-drift.test.ts in the comma-range spelling (authored in 45397edf53 as the list 112-113 and 322-342). Those lines are unchanged at this base: the describe block \"dev auto-reconcile (autoMigrate: 'safe')\", which source[4] now names. A test file declares no symbol worth anchoring, so the block is named in prose. The count of passed tests that history[1] records after a file name is not a citation, and that row is a dated record, so it is left. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[4] cited lines 322-342 of sql-driver-index-drift.test.ts in the comma-range spelling (authored in 45397edf53 as the list 112-113 and 322-342). Those lines are unchanged at this base: the describe block \"dev auto-reconcile (autoMigrate: 'safe')\", which source[4] now names. A test file declares no symbol worth anchoring, so the block is named in prose. The count of passed tests that history[1] records after a file name is not a citation, and that row is a dated record, so it is left. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { diff --git a/docs/qa/platform-checklist/areas/identity-auth.json b/docs/qa/platform-checklist/areas/identity-auth.json index da7a84c6c95..180a63decc6 100644 --- a/docs/qa/platform-checklist/areas/identity-auth.json +++ b/docs/qa/platform-checklist/areas/identity-auth.json @@ -1329,7 +1329,7 @@ "history": [ { "revision": 1, "date": "2026-08-08", "change": "new item: admin CSV identity import with password-policy matrix (auto/temporary/invite/none), imported-user sign-in, upsert idempotency, response-only one-time passwords, non-admin denied, grounded in objectui identityImport.ts + admin-user-endpoints.ts (PENDING-GAPS §G)", "ref": "claude/platform-test-checklist-ocwugl" }, { "revision": 2, "date": "2026-08-11", "change": "from run #7663: recorded the fixture note that the `auto` policy's temporary-fallback branch cannot occur on `objectstack dev` — both transports always register (log fallback) and dev pins NODE_ENV='development', so neither deliverability gate can be made false and every row takes the invite path. The clause now says score the invite half and record the fallback half as not-exercised-by-fixture rather than as a defect, and names the boot that WOULD exercise it. Recorded so the next sweep does not re-derive it", "ref": "#7740" }, - { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.knownGaps[1] cited line 169 of sms-plugin.ts and source[2] line 4074 of auth-manager.ts in the comma-range spelling (authored in 3bb9340974 as the lists 149 and 169, and 4054 and 4074). At that commit 149 and 169 were the LogSmsTransport fallback in resolveInitialTransport and its 'no provider configured' log in init, and 4054 and 4074 were isEmailServiceAvailable and isPhoneOtpDeliverable; at this base all four have moved. knownGaps[1] now anchors sms-plugin.ts#resolveInitialTransport, and source[2] anchors auth-manager.ts#isEmailServiceAvailable and #isPhoneOtpDeliverable, the two gates its words already name. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.knownGaps[1] cited line 169 of sms-plugin.ts and source[2] line 4074 of auth-manager.ts in the comma-range spelling (authored in 3bb9340974 as the lists 149 and 169, and 4054 and 4074). At that commit 149 and 169 were the LogSmsTransport fallback in resolveInitialTransport and its 'no provider configured' log in init, and 4054 and 4074 were isEmailServiceAvailable and isPhoneOtpDeliverable; at this base all four have moved. knownGaps[1] now anchors sms-plugin.ts#resolveInitialTransport, and source[2] anchors auth-manager.ts#isEmailServiceAvailable and #isPhoneOtpDeliverable, the two gates its words already name. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { @@ -1614,7 +1614,7 @@ "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[3].clause cited line 120 of sys-two-factor.object.ts in the comma-range spelling (authored in 8d74a57487 as the list 113 and 120). At that commit 120 was the resultDialog description of the regenerate_backup_codes action, the quoted copy; at this base it has moved. The clause now anchors that action by its name, sys-two-factor.object.ts#regenerate_backup_codes. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -1796,7 +1796,7 @@ "history": [ { "revision": 1, "date": "2026-08-30", "change": "authored in the 2026-08-30 coverage sweep ([x2] hit, angles 1+4): the zero-user first-run wizard had no item. Encodes the public bootstrap-status door, the deliberate disableSignUp + audience-gate bypass scoped to the zero-user state, the full-document exit hazard (objectui#4181), the rename-not-create org contract, both closed-door contrasts, and /setup's two meanings (objectui#2794); recorded the rows-vs-humans divergence between the two bootstrap probes as observe-and-record", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-17", "change": "steps[7] and acceptance[4] (verify, evidence) corrected (checklist-accuracy finding of the identity-auth slice report on #23878 (6216631966)). On the OS_DISABLE_SIGNUP boot an uninvited forge is refused first by the audience gate (403 SELF_REGISTRATION_CLOSED, invite_only), so door 1 — the re-enforced toggle — was never reached by the step's anonymous visitor; only an invited address reaches it, answering 400 EMAIL_PASSWORD_SIGN_UP_DISABLED. The step adds the owner's invitation and the clause names which address proves which door. Not loosened: every forged sign-up after the owner exists must still be refused with no row written", "ref": "#24036" }, - { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 1936-1949 of auth-plugin.ts and source[6] line 339 of the cli dev.ts in the comma-range spelling (authored in 45397edf53 as the lists 1895 and 1936-1949, and 141-142 and 339). At that commit 1936-1949 were the ADR-0069 D5 network-gating middleware in registerAuthRoutes that lets /config and /bootstrap-status through, and 339 was the seedAdmin default; at this base both have moved. acceptance[0].verify now anchors auth-plugin.ts#registerAuthRoutes and source[6] anchors dev.ts#seedAdmin. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 1936-1949 of auth-plugin.ts and source[6] line 339 of the cli dev.ts in the comma-range spelling (authored in 45397edf53 as the lists 1895 and 1936-1949, and 141-142 and 339). At that commit 1936-1949 were the ADR-0069 D5 network-gating middleware in registerAuthRoutes that lets /config and /bootstrap-status through, and 339 was the seedAdmin default; at this base both have moved. acceptance[0].verify now anchors auth-plugin.ts#registerAuthRoutes and source[6] anchors dev.ts#seedAdmin. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { @@ -1901,7 +1901,7 @@ "revision": 6, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). variants[0] and variants[1] cited lines 398-402 and 411-421 of audience-posture.ts, and source[3] and source[4] objectui RegisterPage.tsx 69-88 and LoginPage.tsx 136 and 298, in the comma-range spelling (authored in 45397edf53). At that commit the audience-posture lines were decideAudienceAdmission's pending-invitation branch and its email_domain case; at this base both have moved, and the variants now anchor audience-posture.ts#decideAudienceAdmission and #emailDomainAllowed. At the objectui pin 45397edf53 shipped, 9602dc820450, the RegisterPage lines were its getAuthConfig probe that bounced to /login on disableSignUp, and the LoginPage lines its signUpDisabled state and the registerUrl it withheld. At the shipped pin 12dc7b47c340 both pages decide through decideSignUpOffer, whose 'closed' answer is disableSignUp, and the signUpDisabled state is gone; source[3] and source[4] now say so. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -1997,7 +1997,7 @@ { "revision": 2, "date": "2026-09-28", "change": "restated the forced-verification wording to the shipped rule: email_domain always forces verification on; open forces it on unless the deployment declares it off (OS_AUTH_REQUIRE_EMAIL_VERIFICATION=false, or emailAndPassword.requireEmailVerification: false in the stack config); a false stored only through the settings console is refused under open. The (b) fixture, clause 6, the mirror negative and two source notes said every permitting posture forces it; the negative now names the open opt-out boot, which advertises false correctly, as not a FAIL. Steps, oracles and the other clauses are unchanged", "ref": "#20413" }, { "revision": 3, "date": "2026-10-13", "change": "steps[3], acceptance[2].clause and source[4] name the GET verify-email the console uses (stale step, #23166 C2; parked on #23121, carried by #23169). POST /api/v1/auth/verify-email answers 404 — better-auth serves the route as GET only — and the console's VerifyEmailPage calls GET ?token= without a callbackURL, which answers JSON (objectui#11633, at 1fb1ced36243, still this repo's .objectui-sha). The route ledger already books only the GET row. QA run #23166 verified through GET and passed", "ref": "#23169" }, { "revision": 4, "date": "2026-10-17", "change": "fixtures.requires[2], knownGaps[1], steps[0], [2] and [3] and acceptance[1].verify, [2].clause and [3].verify re-pointed (checklist-accuracy findings of the identity-auth slice report on #23878 (6216631966)). Three premises had moved: the dev transport logs no body or link, so the mail is captured from its sys_email row; verify-email answers {status: true, user: null}, so the step and clause no longer imply a user object; and a consumed token presented for an already-verified user answers a silent 200, so clause 3's 'or the first's already-consumed state is reported loudly' described a refusal that never happens — the resend is now proven by verifying with the resent token first. Not loosened: the resent mail must still carry a token that verifies", "ref": "#24036" }, - { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). steps[1] and source[6] cited objectui LoginPage.tsx 346 and 360 in the comma-range spelling (authored in 45397edf53 as the list 339, 346 and 360). At the objectui pin that commit shipped, 9602dc820450, those lines were the onError redirect of EMAIL_NOT_VERIFIED to /verify-email-prompt and the named error copy; at the shipped pin 12dc7b47c340 the redirect sits in the onError of LoginPage.tsx's LoginFormCard, and the copy moved to app-shell's signInRefusalMessages. Both now say so. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 5, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). steps[1] and source[6] cited objectui LoginPage.tsx 346 and 360 in the comma-range spelling (authored in 45397edf53 as the list 339, 346 and 360). At the objectui pin that commit shipped, 9602dc820450, those lines were the onError redirect of EMAIL_NOT_VERIFIED to /verify-email-prompt and the named error copy; at the shipped pin 12dc7b47c340 the redirect sits in the onError of LoginPage.tsx's LoginFormCard, and the copy moved to app-shell's signInRefusalMessages. Both now say so. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { diff --git a/docs/qa/platform-checklist/areas/platform-core.json b/docs/qa/platform-checklist/areas/platform-core.json index 06f86f221a3..e011d2a52ed 100644 --- a/docs/qa/platform-checklist/areas/platform-core.json +++ b/docs/qa/platform-checklist/areas/platform-core.json @@ -2257,7 +2257,7 @@ "revision": 3, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[0] cited lines 176-185 of objectui apps/console AppContent.tsx in the comma-range spelling (authored in 45397edf53 as the list 35-41 and 176-185). At the objectui pin that commit shipped, 9602dc820450, those lines were the app-scoped docs route (DocsLayout with its index, :slug and :slug/:name children); at the shipped pin 12dc7b47c340 that route sits further down in the same file's systemRoutes, which source[0] now names. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, diff --git a/docs/qa/platform-checklist/areas/records-forms.json b/docs/qa/platform-checklist/areas/records-forms.json index f4bec5ebb83..05ffdc3eb62 100644 --- a/docs/qa/platform-checklist/areas/records-forms.json +++ b/docs/qa/platform-checklist/areas/records-forms.json @@ -1051,7 +1051,7 @@ "revision": 8, "date": "2026-10-20", "change": "automated.ref, acceptance[2].verify and acceptance[3].verify narrowed, and automated.stale removed — the seat ruling 6281811723 (on #24723) and round 8's finding (i) for wave anchor #24579 (18.0 sweep; round 8's report 6281776167). Tier 1 run #24598 at the sweep's console pin 4016370af3c9 ran grid-file-upload.spec.ts red as a stale spec (cause from QA run #24572). Even green it asserts only the receipt the outgoing /api/v1/batch carries and never re-reads the line or fetches the file, so it scores no clause here: it is dropped from the ref and named there, and the stale record, which named only it, goes with it. grid-parent-rules.spec.ts asserts that Qty and Unit Price lock at paid and unlock at draft, and never the Product cell that the clause's 'three cells' include (#24598 scored acceptance[2] pass on it): acceptance[2].verify and the ref now say so. QA run #24616 drove acceptance[1], [3] and [4] by hand. Both specs are byte-identical at 4016370af3c9 and at the shipped pin 12dc7b47c340. No clause changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -1302,7 +1302,7 @@ "revision": 6, "date": "2026-10-20", "change": "acceptance[0].verify and automated.ref narrowed to what master-detail.spec.ts asserts — round 8's finding (iii) for wave anchor #24579 (18.0 sweep; round 8's report 6281776167, carried by the seat's ACCEPT 6281811723). The spec drives showcase_project_workspace ('New Project + Tasks') with one task child staged through the per-row form, not the invoice grid with two lines that steps[1] and [2] drive. Tier 1 run #24598 at the sweep's console pin 4016370af3c9 ran it 2/2 green and scored acceptance[0] pass on it. The clause names no carrier (master and children in one atomic batch, the child ops referencing the parent), and the spec's two tests assert exactly that on their own carrier: the first batch the save sends opens with the populated parent op and carries the child op whose project is {$ref: 0}. So, under round 6's theme-B rule, a pin that asserts a full clause is kept and narrowed, not dropped. The spec is byte-identical at 4016370af3c9 and at the shipped pin 12dc7b47c340. No clause changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -3817,7 +3817,7 @@ "revision": 2, "date": "2026-10-20", "change": "acceptance[7].verify corrected — round 8's carried finding for wave anchor #24579 (18.0 sweep; round 8's report 6281776167, out_of_scope_findings[1], carried by the seat's ACCEPT 6281811723). It cited objectui e2e/live/summary-rollup.spec.ts for showcase_invoice.total, which that spec never reads: it rolls showcase_task up into showcase_project (byte-identical at the sweep's console pin 4016370af3c9 and at the shipped pin 12dc7b47c340). Tier 1 run #24598 scored acceptance[7] not-run (its summary half unpinned), and round 1's QA run #24572 scored the item pass on its API pins. The verify now says that no pin reads invoice.total. The spec was never in automated.ref, which names API pins only, so the ref is unchanged. Beside it, fixtures.knownGaps[0]'s line citation 'createColumn ~7354-7368', a tilde range no gate reads, became the sql-driver.ts#createColumn anchor that its own text already named. No clause changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -4274,7 +4274,7 @@ "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[2].verify cited line 141 of memory-unique-constraint.test.ts and acceptance[3].verify lines 627-631 of memory-driver.ts in the comma-range spelling (authored in 45397edf53 as the lists 135 and 141, and 611 and 627-631). Lines 135 and 141 are unchanged at this base: the cases 'update onto a taken value is refused and the row keeps its old value' and 'a row does not collide with ITSELF — an update that leaves the unique field alone passes', which acceptance[2].verify now names. Lines 627-631 held findOne even at that commit; the comment the verify quotes, 'Prepare and CHECK every row before mutating any of them', sat in updateMany then and does now, so acceptance[3].verify anchors memory-driver.ts#updateMany. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -4388,7 +4388,7 @@ "revision": 2, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[2] cited line 184 of the showcase invoice.object.ts in the comma-range spelling (authored in 45397edf53 as the list 69-71 and 184). At that commit 184 was deleteBehavior 'cascade' on the invoice line's invoice master_detail, and 69-71 the invoice's required account lookup, the required-FK escalation arm fixtures.requires names; at this base both have moved. source[2] now anchors invoice.object.ts#InvoiceLine and #Invoice. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, @@ -4594,7 +4594,7 @@ "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). fixtures.requires[1] and source[3] cited line 60 of the showcase task.object.ts in the comma-range spelling (authored in 45397edf53 as the list 49 and 60). At that commit 49 and 60 were the trackHistory flags of the task's status and priority fields; at this base both have moved by a line. Both citations now anchor task.object.ts#Task and name the two fields. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", - "ref": "#PENDING-24579R9" + "ref": "#24752" } ] }, diff --git a/docs/qa/platform-checklist/areas/search.json b/docs/qa/platform-checklist/areas/search.json index af5cae661eb..4c7b09102b6 100644 --- a/docs/qa/platform-checklist/areas/search.json +++ b/docs/qa/platform-checklist/areas/search.json @@ -678,7 +678,7 @@ { "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, angle 1), authored as a SIBLING of search.console-global-search rather than an extension — writer's call per the register: that item's identity is the GET /api/v1/search record path (hits, grouping, RLS, recents, /search page) and already carries seven clauses, while the palette's other half — the client-side nav corpus (objects/dashboards/pages/reports groups from the active app's navigation), per-type Enter navigation, app switching, theme dispatch, and the evaluateVisibility gate — was wholly uncovered and is a different mechanism (app metadata + client filter, no server search). Grounded in CommandPalette.tsx; the gate-hidden side is blocked(fixture) on stock seeds because no showcase nav item declares a visibility expression and app metadata is not runtime-writable", "ref": "#sweep-2026-08-30" }, { "revision": 2, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21782 parked on #22017 (row 5). A5 was blocked(fixture): no stock nav item carries a visibility predicate. Disposition: fixture recipe. The knownGap now spells the smallest fixture: two nav leaves with visible 'false' and 'true' added in a scratch copy of the showcase, authored from source and not yet run-proven. A5 named `visibleOn`, which a nav item refuses as a near-miss of `visible` (NAV_ITEM_ALIASES in packages/spec/src/ui/app.zod.ts), so the clause names `visible` only; step 8 points at the recipe", "ref": "#22017" }, { "revision": 3, "date": "2026-10-13", "change": "knownGaps[0] records that the visibility-predicate fixture recipe is run-proven (knownGaps update, #23163 A4; parked on #23121, carried by #23169). QA run #23163 drove the scratch-copy recipe — two grp_data leaves with visible 'false' and 'true' — at objectstack 36b2889c with objectui 1fb1ced36243, and the palette honoured the predicate on both sides. The recipe text is unchanged; without the scratch copy the hidden side still scores blocked(fixture)", "ref": "#23169" }, - { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 391-402 of objectui CommandPalette.tsx and source[2] lines 50-65, 92-95 and 102-105 of the showcase apps index.ts in the comma-range spelling (authored in 45397edf53 as the lists 255-328 and 391-402, and 30-40 to 102-105). At the objectui pin that commit shipped, 9602dc820450, 391-402 was the flattenNavigation function and 255-328 the per-type CommandGroup blocks; at the shipped pin 12dc7b47c340 both have moved, and acceptance[0].verify now names them. The apps index.ts lines are unchanged at this base: the ShowcaseApp navigation's object leaves (grp_data), its command-center page and dashboards and its reports (grp_analytics), and the pages above them. source[2] now anchors index.ts#ShowcaseApp. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). acceptance[0].verify cited lines 391-402 of objectui CommandPalette.tsx and source[2] lines 50-65, 92-95 and 102-105 of the showcase apps index.ts in the comma-range spelling (authored in 45397edf53 as the lists 255-328 and 391-402, and 30-40 to 102-105). At the objectui pin that commit shipped, 9602dc820450, 391-402 was the flattenNavigation function and 255-328 the per-type CommandGroup blocks; at the shipped pin 12dc7b47c340 both have moved, and acceptance[0].verify now names them. The apps index.ts lines are unchanged at this base: the ShowcaseApp navigation's object leaves (grp_data), its command-center page and dashboards and its reports (grp_analytics), and the pages above them. source[2] now anchors index.ts#ShowcaseApp. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { diff --git a/docs/qa/platform-checklist/areas/studio-authoring.json b/docs/qa/platform-checklist/areas/studio-authoring.json index 3e295d31680..cf4f7573a52 100644 --- a/docs/qa/platform-checklist/areas/studio-authoring.json +++ b/docs/qa/platform-checklist/areas/studio-authoring.json @@ -668,7 +668,7 @@ { "revision": 1, "date": "2026-08-07", "change": "new item: both sides of the registry's runtime-write gates (not_overridable / not_creatable vs accepted overlay / accepted create), variants sampled straight from DEFAULT_METADATA_TYPE_REGISTRY and pinned to the overlay-precedence suite", "ref": "claude/platform-test-checklist-ocwugl" }, { "revision": 2, "date": "2026-08-11", "change": "recorded two notes from run #7695 — (a) the CORRECTION to run #7637: with OS_METADATA_WRITABLE=permission the Studio read-only badge clears and the editor is fully writable (GET /meta reports overrideSource:'env'), so the earlier 'badge asserts a lock the server is not applying' observation does not reproduce and must not be acted on as written; (b) the route note that a metadata-API-authored flow opens read-only in Studio (ResourceEditPage's artifact-backed heuristic + flow's allowOrgOverride:false) — correct for this kind, with the polarity-reversed defect filed at objectui#4308. Notes only; no clause, variant or oracle changed", "ref": "#7753" }, { "revision": 3, "date": "2026-10-16", "change": "variants[1] corrected (checklist-accuracy finding 1 of QA run #23942, wave #23878). The field variant still read 'create open', but DEFAULT_METADATA_TYPE_REGISTRY has declared field allowRuntimeCreate:false since #7893 (a standalone field row reached no object's fields), so its create side is locked like job's and answers 403 NOT_CREATABLE. The variant now states the expectation the registry declares; step[0] already tells the runner to read the flags first", "ref": "#24036" }, - { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 1311-1323 of objectui ResourceEditPage.tsx in the comma-range spelling, written with a space (authored in 3bb9340974 as the list 951-955 and 1311-1323). At the objectui pin that commit shipped, 6314e87f2d49, 1311-1323 was the isArtifactItem test; at the shipped pin 12dc7b47c340 it has moved and also excludes provenance 'org'. source[5] now names isArtifactItem. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 4, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 1311-1323 of objectui ResourceEditPage.tsx in the comma-range spelling, written with a space (authored in 3bb9340974 as the list 951-955 and 1311-1323). At the objectui pin that commit shipped, 6314e87f2d49, 1311-1323 was the isArtifactItem test; at the shipped pin 12dc7b47c340 it has moved and also excludes provenance 'org'. source[5] now names isArtifactItem. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, { @@ -1462,7 +1462,7 @@ { "revision": 3, "date": "2026-10-13", "change": "acceptance[1].verify compares stats.locked against the served envelope lock (stale spec, #23166 A1; parked on #23121, carried by #23169). getMetaDiagnostics counts an item as locked when its read envelope reports a lock other than 'none' — the same derivation getMetaItem publishes (#21694) — not when its declared _lock is set. QA run #23166 compared against the envelope lock and passed. Read from source at 6d7f4df3c (protocol.ts getMetaDiagnostics docblock and loop). The A6 row of the same run, the unplantable invalid stored row, is already recorded in full in knownGaps[0] and needs no edit", "ref": "#23169" }, { "revision": 4, "date": "2026-10-16", "change": "acceptance[1].verify names the read that carries the envelope lock (checklist-accuracy finding 2 of QA run #23942, wave #23878). It told the runner to compare stats.locked against the lock GET /api/v1/meta/TYPE/NAME publishes, but that default read is the cached arm and carries no `lock` by design; the envelope lock is on GET /api/v1/meta/TYPE/NAME/layers, which is where #23942 read it (object 107, view 0, flow 32 locked, matching stats). The comparison itself is unchanged", "ref": "#24036" }, { "revision": 5, "date": "2026-10-19", "change": "fixtures.knownGaps[0], steps[6], steps[8] and acceptance[6] (clause, verify) corrected from QA run #24604 (18.0 sweep round 2, ba4afcc2), the round-2 §3 note that knownGaps[0] is wrong. The invalid stored row is plantable in-run on an isolated scratch file DB: save a valid view through the door with ?package=, rewrite its sys_metadata.metadata, and the next sweep lists it — the run scored acceptance[6] pass that way, deep link and badge included. The directory always repairs ?package= to a project package, so the red button is judged per package scope; rootless union-parent entries may ride beside the located leaf. Wave anchor #24579 round 2 §3 (6272314386)", "ref": "#24671" }, - { "revision": 6, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 242-254 of objectui DirectoryPage.tsx and line 982 of app-shell's console AppContent.tsx in the comma-range spelling (authored in 45397edf53 as the lists 133-158 and 242-254, and 882 and 982). At the objectui pin that commit shipped, 9602dc820450, 242-254 was the diagnostics link that renders only when diagSummary.total is above 0, 133-158 the package-scoped useGlobalDiagnostics sweep, and 982 the nested metadata route block that holds _diagnostics; at the shipped pin 12dc7b47c340 all have moved. source[5] now names the MetadataDirectoryPage component's sweep and link, and the AppContent component's metadata/_diagnostics route. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#PENDING-24579R9" } + { "revision": 6, "date": "2026-10-20", "change": "line citations re-pointed — the comma-range spelling that round 7 of wave anchor #24579 named (18.0 sweep; round 7's report 6281433885, out_of_scope_findings[1]). source[5] cited lines 242-254 of objectui DirectoryPage.tsx and line 982 of app-shell's console AppContent.tsx in the comma-range spelling (authored in 45397edf53 as the lists 133-158 and 242-254, and 882 and 982). At the objectui pin that commit shipped, 9602dc820450, 242-254 was the diagnostics link that renders only when diagSummary.total is above 0, 133-158 the package-scoped useGlobalDiagnostics sweep, and 982 the nested metadata route block that holds _diagnostics; at the shipped pin 12dc7b47c340 all have moved. source[5] now names the MetadataDirectoryPage component's sweep and link, and the AppContent component's metadata/_diagnostics route. objectui is read at the shipped pin 12dc7b47c340 and cited in prose, because no objectui anchor resolves in this gate. The spelling is what #13786's strip left when it removed only the first range of a ':A,B' list, and the line-citation limb reads only the colon spellings, so no gate caught it. Where the surrounding words still describe the range the strip removed, the new citation names that code too. No clause's assertion changed", "ref": "#24752" } ] }, {