Skip to content

QA run · records-forms (38/44) · ba4afcc2 · 2026-10-19 · 34 PASS / 2 PARTIAL / 2 FAIL / 0 BLOCKED / 6 NOT-RUN #24616

Closed

Description

@objectstack-fleet

Round 2 of the 18.0 release sweep for records-forms: re-judges on ba4afcc2 the clauses round 1 (#24572, subject 5b14b7f3) left unjudged and that this environment can drive (A class); every other verdict is carried forward from #24572 below. Supersedes #24572 under checklist-test SKILL §5. Wave anchor: #24579.

Environment fingerprint

  • framework ba4afcc2391922a86678bf5e47b1a0e4d2c87ff1 (pinned; one commit after round 1's 5b14b7f3, a release-script fix — git diff 5b14b7f3 ba4afcc2 -- docs/qa/platform-checklist/ is empty, so every item revision is unchanged and carried verdicts stay revision-valid)
  • console .objectui-sha 4016370af3c9c9dafec2bc5299afd8e8079701b8, built with pnpm objectui:build (deps --concurrency=2); packages/console/dist/.objectui-sha stamp equals the pin
  • app: showcase, canonical boot OS_PORT=PORT pnpm -C examples/app-showcase exec objectstack dev --ui --seed-admin -p PORT -d file:/tmp/qa2/LABEL/ITEM.db; own port + file DB per runner/item; scratch app copies for metadata-writing items; seed --seed-admin + showcase seed
  • browser: Playwright, executablePath /opt/pw-browsers/chromium, one context per runner, form sign-in
  • timestamps 2026-10-19: environment prep 14:12–14:44 UTC (cold tree: install 39 s, pnpm build 10m20s, console build ~25 min); testing 14:45–15:42 UTC (+ rule-7 verifier 15:40–15:46 UTC)
  • execution: three browser runner sub-agents in parallel (≤ 3 browser contexts machine-wide, one per runner), each on its own ports and file DB (:47531, :47541, :47561); metadata-writing items booted from scratch app copies; an independent rule-7 verifier re-derived conditional-rules-grid negative[1] on :47592

Scope

  • selector records-forms — 44 items (resolver-runnable set; planned/blocked items as in QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572). Revisions per item are those recorded in QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572 (unchanged at ba4afcc).
  • Re-judged this round (A class):
    • records-forms.field-type-matrix — acceptance[1], negative[0]–[2]
    • records-forms.list-view-capabilities — acceptance[0], [2]–[9], negative[0]–[2]
    • records-forms.view-type-gallery — acceptance[0]–[4], negative[0], [1]
    • records-forms.conditional-rules-header — acceptance[1]–[5], negative[0]–[2]
    • records-forms.conditional-rules-grid — acceptance[1], [3], [4], negative[0], [1]
    • records-forms.cascading-options — acceptance[0], [2]–[4], negative[0], [1]
    • records-forms.master-detail-atomic-save — acceptance[1], [3]–[5], negative[0], [1]
    • records-forms.action-param-widgets — acceptance[0], [1], [3], negative[0], [1]
    • records-forms.import-wizard-encoding-and-hints — acceptance[3], negative[0], [1]
    • records-forms.gantt-interactions — acceptance[0], [3], negative[0]
    • records-forms.form-dirty-guard — acceptance[0], [1], negative[0]
    • records-forms.record-discussion-mentions — acceptance[0]–[4], [7], [8], negative[0]–[2], [4], [5]
    • records-forms.bulk-select-all-matching — acceptance[0], [1], [4], negative[0]–[2]
    • records-forms.object-hook-lifecycle — acceptance[1]–[9], negative[0]–[4]
    • records-forms.cascading-multilevel-and-clear — acceptance[0], [2]–[5], negative[0]–[2]
    • records-forms.field-history-tracking — acceptance[1]–[3], negative[0]–[3]
    • records-forms.predicate-relationship-traversal — acceptance[0]–[2], negative[0]–[2]
    • records-forms.v18-semantic-defaults — acceptance[1]–[3]
    • records-forms.related-list-server-pagination — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.action-location-matrix — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.adhoc-filter-sort-builder — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.calendar-interactions — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.concurrent-edit-conflict — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.grid-personalization — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.lookup-picker-create-new — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
    • records-forms.import-job-undo-cancel — every clause — round 1 NOT-RUN (Tier 1 pin covers no full clause); driven by hand in the browser + API (RUNNER option (a))
  • Not driven (B class — no fixture in this environment; stays parked on qa(checklist): 18.0 release sweep anchor at 5b14b7f3 — re-point 5 red-row clauses + the wave's checklist-accuracy findings, fixture gaps and not-run handover (18 records) #24579 §4):
    • records-forms.validation-rule-type-matrix negative[0] — blocked(fixture): an unevaluable CEL validation cannot be authored through any door (fixture outside the brief's B list; stays parked)

Round-2 per-clause verdicts (ba4afcc)

Each line: item revN · clause · verdict · text oracle evidence, trimmed to one line for the body cap — the untrimmed evidence is in comments 2–3 on this record.

records-forms.field-type-matrix (rev 3)

  • records-forms.field-type-matrix rev3 · acceptance[1] · blocked(fixture) · 47/49 variants PASS with their dedicated widget on the Specimen — Full edit form (DOM after screenshot, per [data-field]): …
  • records-forms.field-type-matrix rev3 · negative[0] · pass · POST /api/v1/data/showcase_field_zoo {name, f_master_detail:VALID, f_select:"not-a-value"} → 400 VALIDATION_FAILED fields[{field:f_select, …
  • records-forms.field-type-matrix rev3 · negative[1] · pass · fabricated ids refused 400 VALIDATION_FAILED code reference_not_found for f_lookup (POST and PATCH on Specimen — Minimal), f_lookups (on …
  • records-forms.field-type-matrix rev3 · negative[2] · pass · wrote f_password "Hunter2-plain" and f_secret "sk-plain-123" (PATCH 200 on stock boot); every read (single GET, list GET, select=f_passwor …

records-forms.list-view-capabilities (rev 3)

  • records-forms.list-view-capabilities rev3 · acceptance[0] · pass · one artifact per variant captured: default grid (screenshot + GET …showcase_task?populate=project&top=50&select=…), in_progress f …
  • records-forms.list-view-capabilities rev3 · acceptance[2] · pass · typing 'huaning' on Accounts issued GET /api/v1/data/showcase_account?top=50&search=huaning&select=… → 200 [华宁科技] total 1; dire …
  • records-forms.list-view-capabilities rev3 · acceptance[3] · pass · Inquiries (58 rows after staging): page 1 top=50 (50 ids), Next page top=50&skip=50 (8 ids); union 58, distinct 58 = API total …
  • records-forms.list-view-capabilities rev3 · acceptance[4] · pass · Task List view requests …&sort=-estimate_hours → 200; rows 60,40,30,24,20,18,16,16,12,8 (descending); rendered without error.
  • records-forms.list-view-capabilities rev3 · acceptance[5] · pass · Grid view, Content backlog estimate 12→13 via cell edit + "Save All (1)": `PATCH /api/v1/data/showcase_task/mBz559k4jR3ZUFDg {"esti …
  • records-forms.list-view-capabilities rev3 · acceptance[6] · pass · grant provisioned: runtime set qa_task_export {showcase_task: allowRead, allowExport} bound to admin. Display popover footer list …
  • records-forms.list-view-capabilities rev3 · acceptance[7] · pass · Display → Layout dropdown offers exactly Grid, Kanban, Gallery, Calendar, Timeline, Gantt (no map/chart); each switch re-rendered t …
  • records-forms.list-view-capabilities rev3 · acceptance[8] · pass · 3 selected: Recalculate Selection → ONE POST /api/v1/apps/showcase/recalc {"_selectedIds":[3 ids]} → 200 summary selected 3 / act …
  • records-forms.list-view-capabilities rev3 · acceptance[9] · pass · legacy_row_actions row menu = Reopen, Reassign…, Quick View (once), Recalculate Estimate; Recalculate Estimate dispatched `POST /ap …
  • records-forms.list-view-capabilities rev3 · negative[0] · pass · overlay on showcase_task.done with filter done equals "maybe" (accepted at authoring): grid request `…filter=[["done","equals","m …
  • records-forms.list-view-capabilities rev3 · negative[1] · pass · overlay adding userFilters {element:'tabs', tabs:[QA High]} to the object view showcase_task.done: the QA High tab never renders …
  • records-forms.list-view-capabilities rev3 · negative[2] · pass · all three exports of the filtered view hold only the 2 in_progress rows (table has 10).

records-forms.view-type-gallery (rev 1)

  • records-forms.view-type-gallery rev1 · acceptance[0] · pass · one screenshot each, real structure observed: Grid (table, 10 rows), Board (5 status columns with cards + Σ estimate), Cards (10 cards), …
  • records-forms.view-type-gallery rev1 · acceptance[1] · pass · board columns BACKLOG 2/Σ16, TO DO 2/Σ108, IN PROGRESS 2/Σ100, IN REVIEW 2/Σ54, DONE 2/Σ40 = client-side group of `GET /api/v1/data/show …
  • records-forms.view-type-gallery rev1 · acceptance[2] · pass · calendar request is a due_date window; Audit current IA on Oct 1 (due 2026-10-01), App wireframes Oct 13 (2026-10-13), Design system Oct …
  • records-forms.view-type-gallery rev1 · acceptance[3] · pass · map: 10 markers vs 10 tasks with a location (API); chart: `POST /api/v1/analytics/dataset/query {"datasetName":"showcase_task_metrics", …
  • records-forms.view-type-gallery rev1 · acceptance[4] · pass · tree after expanding: Acme Corporation → (Product & Engineering → Frontend Guild → Design Systems; Platform), (Go-To-Market → Sales → En …
  • records-forms.view-type-gallery rev1 · negative[0] · pass · no variant rendered as a plain grid.
  • records-forms.view-type-gallery rev1 · negative[1] · pass · chart is multi-bucket (5 statuses × 4 priorities, 8 non-empty bars), not a single datapoint.

records-forms.conditional-rules-header (rev 2)

  • records-forms.conditional-rules-header rev2 · acceptance[1] · pass · POST /api/v1/data/showcase_invoice {name:"qa-rf1-sent-noissue", account, status:"sent"} → 400 VALIDATION_FAILED fields[{field:i …
  • records-forms.conditional-rules-header rev2 · acceptance[2] · pass · INV-1003 (paid) tax_rate 8 → PATCH {"tax_rate":99} 200 → re-read tax_rate 8 (stripped). Control: same PATCH shape on draft INV- …
  • records-forms.conditional-rules-header rev2 · acceptance[3] · pass · INV-1002 draft edit form: no [data-field=paid_on]; INV-1003 paid form: paid_on present with required marker; tax_rate renders a …
  • records-forms.conditional-rules-header rev2 · acceptance[4] · pass · invoice list (2 fresh loads): INV-1003 menu = Edit (disabled), Submit for Sign-off, Generate PDF — no Delete; INV-1002 menu = Edi …
  • records-forms.conditional-rules-header rev2 · acceptance[5] · pass · form leg: INV-1002 status → Sent marks issued_on required; Save shows "Issued On is required" and issues no write (2 fresh loads; …
  • records-forms.conditional-rules-header rev2 · negative[0] · pass · the direct 'sent' POST without issued_on was refused (A1).
  • records-forms.conditional-rules-header rev2 · negative[1] · pass · tax_rate 99 did not persist (A2).
  • records-forms.conditional-rules-header rev2 · negative[2] · pass · no Delete affordance on the paid row (A4).

records-forms.conditional-rules-grid (rev 4)

  • records-forms.conditional-rules-grid rev4 · acceptance[1] · pass · POST /api/v1/batch atomic with line update {description:"",quantity:120} → 400 VALIDATION_FAILED fields[{field:description, code: …
  • records-forms.conditional-rules-grid rev4 · acceptance[3] · pass · uploaded receipt-qa.pdf into line 1's receipt cell: presigned → PUT → complete (fileId fcba01a0…), Save sent `{"receipt":"fcba01a0- …
  • records-forms.conditional-rules-grid rev4 · acceptance[4] · pass · INV-1002 with lines at positions 0 and 1 (second line staged at position 1 per fixtures): grid save sent ONE batch with only line 0 …
  • records-forms.conditional-rules-grid rev4 · negative[0] · pass · client: qty 120 + empty description flags the row-0 cell ("Description is required", aria-invalid) and not row 1; the batch it sends …
  • records-forms.conditional-rules-grid rev4 · negative[1] · FAIL · on a freshly loaded STORED paid invoice (INV-1003) the parent-scoped readonlyWhen does not apply: product/quantity/unit_price cel …

records-forms.cascading-options (rev 3)

  • records-forms.cascading-options rev3 · acceptance[0] · pass · New Cascading Select (?form=new): province reads "Select country first" until a country is chosen; cn → options [Zhejiang, Guangdong]; …
  • records-forms.cascading-options rev3 · acceptance[2] · pass · org_admin persona (invited role admin + accepted): tier options [Standard, Restricted (admin only)] in the form; `POST {tier:"restricted …
  • records-forms.cascading-options rev3 · acceptance[3] · pass · New Invoice: contact trigger disabled "Select Account first" before an account; after Northwind the picker requested `GET /api/v1/data/s …
  • records-forms.cascading-options rev3 · acceptance[4] · pass · form create sent POST /api/v1/data/showcase_cascade {"tier":"standard","name":"qa-rf1-form-cn-zj","country":"cn","province":"zj"}; API …
  • records-forms.cascading-options rev3 · negative[0] · pass · POST country cn + province ca → 400 VALIDATION_FAILED fields[{field:province, code:invalid_option}].
  • records-forms.cascading-options rev3 · negative[1] · pass · plain member's direct tier='restricted' POST refused 400 invalid_option (picker also hid it).

records-forms.master-detail-atomic-save (rev 3)

  • records-forms.master-detail-atomic-save rev3 · acceptance[1] · pass · New Invoice os-qa-rf1-md1 (Northwind, draft), line 1 Widget A (auto-filled "Standard widget"/29.99) qty 4, line 2 Consulting Hou …
  • records-forms.master-detail-atomic-save rev3 · acceptance[3] · pass · total 419.96 after atomic create (=119.96+300); add Gadget X line via edit form (batch create) → 518.96; remove that line (batch …
  • records-forms.master-detail-atomic-save rev3 · acceptance[4] · pass · New Invoice os-qa-rf1-md-bad with line 2 lacking product: one batch → 400 VALIDATION_FAILED {field:product, code:required}; form …
  • records-forms.master-detail-atomic-save rev3 · acceptance[5] · pass · amount cell (data-computed) recomputed live without save: qty 3 → 89.97, qty 4 → 119.96; saved line reads amount 119.96 = 4 × 29 …
  • records-forms.master-detail-atomic-save rev3 · negative[0] · pass · after the failed save neither the master nor the valid sibling line exists (API reads above).
  • records-forms.master-detail-atomic-save rev3 · negative[1] · pass · create issued exactly ONE write: POST /api/v1/batch atomic:true with the invoice create + 2 line creates referencing `{"$ref":0} …

records-forms.action-param-widgets (rev 2)

  • records-forms.action-param-widgets rev2 · acceptance[0] · pass · dialog from Specimen — Full row menu (screenshot first): p_text→input[text] (required *), p_richtext→RichTextField textarea, p_priori …
  • records-forms.action-param-widgets rev2 · acceptance[1] · pass · DOM attributes: p_cover INPUT-TYPE-FILE-ACCEPT-IMAGE (no multiple); p_attachments `input[type=file] accept="application/pdf,image/* …
  • records-forms.action-param-widgets rev2 · acceptance[3] · pass · UI: Confirm with empty Title shows "Title is required" and no dispatch (2 opens); API: `POST /api/v1/actions/showcase_field_zoo/showc …
  • records-forms.action-param-widgets rev2 · negative[0] · pass · no maxSize DOM attribute was claimed; an actual 6.0 MB PNG into p_cover was refused client-side ('"big.png" exceeds max size (5.0 MB)') …
  • records-forms.action-param-widgets rev2 · negative[1] · pass · malformed bags refused before the body: p_priority "urgent-bogus" → 400 'Invalid option: expected one of "low"|"normal"|"high"'; undecl …

records-forms.import-wizard-encoding-and-hints (rev 6)

  • records-forms.import-wizard-encoding-and-hints rev6 · acceptance[3] · pass · Contacts → overflow "…" → Import; uploaded a GBK-encoded CSV (2 rows, CJK name/company/title); auto-mapped 4 columns; Imp …
  • records-forms.import-wizard-encoding-and-hints rev6 · negative[0] · pass · the wired wizard's preview of the GBK file rendered 张三QA导入 / 华宁科技 / 工程师 etc. (screenshot), no mojibake.
  • records-forms.import-wizard-encoding-and-hints rev6 · negative[1] · pass · success report matched by the API read (2 rows found).

records-forms.gantt-interactions rev4

  • records-forms.gantt-interactions rev4 · acceptance[0] · pass · drag of "Design system" bar (+2 days, Day mode) → `PATCH /api/v1/data/showcase_task/D8EVuZQQwd7AwhKR {"start_date":"2026-10-09","end_da …
  • records-forms.gantt-interactions rev4 · acceptance[3] · pass · server veto: Mei (contributor, own-row RLS) opened gantt, task kgkRGuoycf8DTNXZ reassigned away underneath her, her drag sent `PATCH {" …
  • records-forms.gantt-interactions rev4 · negative[0] · pass · successful drag landed a 200 PATCH and persisted; the 4xx drag did not keep its new position (snap-back + rollback toast)

records-forms.form-dirty-guard rev3

  • records-forms.form-dirty-guard rev3 · acceptance[0] · pass · Edit Account modal (?form=Sc8UxP41F6TCIjQK): clean form — X / Escape / backdrop / Cancel all closed with no prompt; dirty form (website …
  • records-forms.form-dirty-guard rev3 · acceptance[1] · pass · after Discard: API website https://initech.example, updated_at unchanged (byte-identical); after Update: website `https://initech.examp …
  • records-forms.form-dirty-guard rev3 · negative[0] · pass · no accidental close lost a dirty edit without prompt; no prompt on any pristine-form close

records-forms.record-discussion-mentions rev3

  • records-forms.record-discussion-mentions rev3 · acceptance[0] · pass · UI post on Globex → POST /api/v1/data/sys_comment 201 id 81214553-…; `GET sys_comment filter thread_id=showcase_account:L-O5F …
  • records-forms.record-discussion-mentions rev3 · acceptance[1] · pass · client-minted id in POST body == server id; row count of the comment sampled 13× across post (incl. optimistic frame) = 1 every …
  • records-forms.record-discussion-mentions rev3 · acceptance[2] · pass · feed after an attributable PATCH (industry) and a later comment reads oldest-first: comment 15:15:45 → "Industry: Technology → …
  • records-forms.record-discussion-mentions rev3 · acceptance[3] · pass · Mei: /api/v1/notifications unread 0 → 1 (collab.mention "Dev Admin mentioned you", actionUrl /showcase_account/L-O5F-zQM733 …
  • records-forms.record-discussion-mentions rev3 · acceptance[4] · pass · Ada (non-mentioned): server notifications unchanged (only the pre-existing approval.requested, unread 1); bell panel lists only …
  • records-forms.record-discussion-mentions rev3 · acceptance[7] · pass · Globex: All Activity 3 rows (2 comments + 1 field change); Comments Only 2 (both comments); Field Changes 1 (Industry change); …
  • records-forms.record-discussion-mentions rev3 · acceptance[8] · pass · live milestone channel (not the pin): qa_milestone record, stage→won wrote sys_activity type qa_custom_kind "QA milestone rea …
  • records-forms.record-discussion-mentions rev3 · negative[0] · pass · no dupe/phantom (see acceptance[1])
  • records-forms.record-discussion-mentions rev3 · negative[1] · pass · mention notification reached Mei only; Ada and the author got none
  • records-forms.record-discussion-mentions rev3 · negative[2] · pass · qa_nofeeds record detail: no Discussion panel, no comment box, zero sys_comment requests (control qa_milestone: panel + sys_comme …
  • records-forms.record-discussion-mentions rev3 · negative[4] · pass · both FEEDS_DISABLED refusals measured WITH controls: create on enabled parent 201; re-thread of comment 8k3S1yjSsTTdhU3c onto qa_ …
  • records-forms.record-discussion-mentions rev3 · negative[5] · pass · no mode showed another mode's type (created/updated → field_change by the objectui map); custom type present in 'all', absent onl …

records-forms.bulk-select-all-matching rev3

  • records-forms.bulk-select-all-matching rev3 · acceptance[0] · pass · bulk_actions view, quick search "QA bulk": find ?top=50&search=QA+bulk total=55 n=50; with ONE row ticked no banner; with the w …
  • records-forms.bulk-select-all-matching rev3 · acceptance[1] · pass · after "Select all 55 matching" ("All 55 matching records are selected."), dispatch fanned out `GET ?top=500&skip=0&search=QA+bulk …
  • records-forms.bulk-select-all-matching rev3 · acceptance[4] · pass (weak, single datapoint) · collected 55 ≤ HARD_CAP 5000; a > 5000 match set was not provisioned, so the truncation branch was not e …
  • records-forms.bulk-select-all-matching rev3 · negative[0] · pass · dispatched set 55 > rendered page 50
  • records-forms.bulk-select-all-matching rev3 · negative[1] · pass · banner 55 == filtered API count 55
  • records-forms.bulk-select-all-matching rev3 · negative[2] · pass · Clear: 0 checked row boxes (50 before), header checkbox unchecked, bulk bar/selection text gone (screenshot: plain list, no bar)

records-forms.object-hook-lifecycle rev5

  • records-forms.object-hook-lifecycle rev5 · acceptance[1] · pass · (stock :47541; 5 showcase hooks "Registered hook" in boot log) POST task title " os-qa-rf2 " → re-read "os-qa-rf2"; PATCH " os-q …
  • records-forms.object-hook-lifecycle rev5 · acceptance[2] · pass · PATCH Build homepage {done:true} → log INFO [hook 'showcase_audit_task_completion'] task completed: Build homepage
  • records-forms.object-hook-lifecycle rev5 · acceptance[3] · pass · PATCH App wireframes {priority:high} (done already true) → 200, settle 5 s, no "task completed: App wireframes" line (only lines in …
  • records-forms.object-hook-lifecycle rev5 · acceptance[4] · pass · PATCH Data Platform {spent:650000} → WARN [hook 'showcase_warn_over_budget'] project over budget: Data Platform (650000 / 600000)
  • records-forms.object-hook-lifecycle rev5 · acceptance[5] · pass · spent-only PATCH fired with budget read from storage (line above); Website Relaunch {spent:70000} → 200 and no warn line
  • records-forms.object-hook-lifecycle rev5 · acceptance[6] · pass · (scratch :47542) qa_abort_insert (beforeInsert, throws, onError abort): POST inquiry "qa-abort-1" → 400 `{"error":"qa scratch abort …
  • records-forms.object-hook-lifecycle rev5 · acceptance[7] · pass · qa_tolerate_update (async afterUpdate, throws, onError log): PATCH message → 200, re-read "after-tolerate"; log `ERROR [hook] handle …
  • records-forms.object-hook-lifecycle rev5 · acceptance[8] · pass (envelope note) · qa_failclosed condition record.name.startsWith('qa-fc') && int(record.name) > 0 with onError:'log': POST "qa-fc-ab …
  • records-forms.object-hook-lifecycle rev5 · acceptance[9] · pass · qa_prio_90 and qa_prio_10 (afterInsert, declared 90 first): one POST "qa-prio-1" logged qa_prio_10 … priority-10 ran (14:50:03.365 …
  • records-forms.object-hook-lifecycle rev5 · negative[0] · pass · throwing beforeInsert abort left 0 rows
  • records-forms.object-hook-lifecycle rev5 · negative[1] · pass · async onError:'log' failure did not roll back the PATCH
  • records-forms.object-hook-lifecycle rev5 · negative[2] · pass · real transition emitted the audit line
  • records-forms.object-hook-lifecycle rev5 · negative[3] · pass · no audit on the non-transition edit
  • records-forms.object-hook-lifecycle rev5 · negative[4] · pass · unevaluable condition aborted the write (not skipped, not softened by onError:'log')

records-forms.cascading-multilevel-and-clear rev3

  • records-forms.cascading-multilevel-and-clear rev3 · acceptance[0] · pass · New Cascading Select modal: province options @china = [Zhejiang, Guangdong]; picked Zhejiang; switch to United States → pro …
  • records-forms.cascading-multilevel-and-clear rev3 · acceptance[2] · pass (gap confirmed) · POST {cn,zj} 201 → PATCH {country:'us'} only → 200; GET → country us, province zj (stale child retained)
  • records-forms.cascading-multilevel-and-clear rev3 · acceptance[3] · pass · New Invoice: account=Northwind → contact candidates GET showcase_contact?filter=["account","=","q81MWvDmgCZEDWzE"] total …
  • records-forms.cascading-multilevel-and-clear rev3 · acceptance[4] · pass (gap confirmed) · POST invoice {account:Contoso, contact:Noah Bell (Northwind)} → 201; fabricated contact id → 400 `reference …
  • records-forms.cascading-multilevel-and-clear rev3 · acceptance[5] · pass · re-read {cn,zj} row verbatim; invoice QA2-twin {Northwind, Noah Bell} re-reads account/contact verbatim
  • records-forms.cascading-multilevel-and-clear rev3 · negative[0] · pass · PATCH {country:'us', province:'zj'} (child in payload) → 400 invalid_option, row unchanged {cn,zj}
  • records-forms.cascading-multilevel-and-clear rev3 · negative[1] · pass · POST {cn, ca} → 400 invalid_option on province
  • records-forms.cascading-multilevel-and-clear rev3 · negative[2] · pass · both gaps recorded as client-only (stale-child PATCH 200; cross-account contact 201) — not ticked as server enforcement

records-forms.field-history-tracking rev1

  • records-forms.field-history-tracking rev1 · acceptance[1] · pass · Hooli website-only PATCH → sys_activity summary Updated Account "Hooli" (no per-field summary); tracked industry PATCH beside it …
  • records-forms.field-history-tracking rev1 · acceptance[2] · pass · account detail tabs [Details, Invoices, Projects, Related, History] and one GET sys_audit_log request; task detail (App wireframe …
  • records-forms.field-history-tracking rev1 · acceptance[3] · pass · /api/v1/auth/me/permissions: showcase_account apiOperations include history; showcase_task's do not
  • records-forms.field-history-tracking rev1 · negative[0] · pass · untracked edit produced no old→new tracked summary in sys_activity / timeline (the History TAB, fed by sys_audit_log, does show "Webs …
  • records-forms.field-history-tracking rev1 · negative[1] · pass · no History tab on task detail (and no audit fetch)
  • records-forms.field-history-tracking rev1 · negative[2] · pass · select rendered labels "Technology → Finance", not values
  • records-forms.field-history-tracking rev1 · negative[3] · pass · guard honored — crud-roundtrip clause 5 not re-scored here

records-forms.predicate-relationship-traversal rev3

  • records-forms.predicate-relationship-traversal rev3 · acceptance[0] · pass · POST invoice account=Contoso (active) → 201, filtered read returns it, no validation error
  • records-forms.predicate-relationship-traversal rev3 · acceptance[1] · pass · POST account=Umbrella Health (churned) → 400 VALIDATION_FAILED, fields[0] `{field:'_record', code:'rule_violation', messa …
  • records-forms.predicate-relationship-traversal rev3 · acceptance[2] · pass · PATCH existing invoice {account: Wonka Brands (churned)} → 400 same envelope; re-read account still Contoso
  • records-forms.predicate-relationship-traversal rev3 · negative[0] · pass · churned create refused
  • records-forms.predicate-relationship-traversal rev3 · negative[1] · pass · no "could not be evaluated" fault on any readable-parent case
  • records-forms.predicate-relationship-traversal rev3 · negative[2] · pass (engine pin, same basis as acceptance[3]) · no stock persona lacks parent read; packages/objectql vitest `src/engine-predic …

records-forms.v18-semantic-defaults rev1

  • records-forms.v18-semantic-defaults rev1 · acceptance[1] · pass · task default view (no pagination.pageSize in /api/v1/meta/view/showcase_task.default) with 66 rows: data request top=50, 50 tbod …
  • records-forms.v18-semantic-defaults rev1 · acceptance[2] · pass · editInline omitted on the view: Mei (contributor, allowEdit true) — "Edit inline" switch offered in the Display popover, toggling it …
  • records-forms.v18-semantic-defaults rev1 · acceptance[3] · pass · New on showcase_field_zoo (59 fields) / showcase_task (25 fields): desktop 1440×900 → centered bounded dialog (1024 wide, field_zoo …

Tier-1-pin items (round 1 NOT-RUN), every clause driven by hand — RUNNER option (a)

records-forms.related-list-server-pagination rev4

  • related-list-server-pagination rev4 · acceptance[0] · pass · manual browser: Related tab Contacts page-1 GET /data/showcase_contact?…&top=5&skip=0&filter=["account","=","S_ifFwiLdRpvXgSe"], page 2 …
  • related-list-server-pagination rev4 · acceptance[1] · pass · pager "Page 1 of 6" → "Page 6 of 6" (5/page, server total 26 in every response); page-1 ids (5, via identical API query) + pages 2–6 ids …
  • related-list-server-pagination rev4 · acceptance[2] · pass · stock Account detail (no authored page) screenshot shows derived tabs Details | Invoices 1 | Projects 2 | Related 28 | History; Projects …
  • related-list-server-pagination rev4 · acceptance[3] · pass · Invoices tab label "Invoices", headers Invoice Number | Status | Total | Issued On (+Actions), request `select=id,name,status,total,issue …
  • related-list-server-pagination rev4 · acceptance[4] · pass · clicking "Prospect 06" in the Contacts related list navigated to /showcase_contact/record/3SA4DwbDVtVBYlP7 (h1 "Prospect 06"); GET /api/v …
  • related-list-server-pagination rev4 · acceptance[5] · pass · contributor (session = qa-contrib): Northwind detail tabs Details|Invoices|Projects 2|Related 2|History, Related tab holds only the two F …
  • related-list-server-pagination rev4 · negative[0] · pass · no child-list request without a top bound among all captured detail-page requests
  • related-list-server-pagination rev4 · negative[1] · pass · pager total 26 == API filtered total 26
  • related-list-server-pagination rev4 · negative[2] · pass · no Contacts section for contributor AND server 403 (both ends hold)

records-forms.action-location-matrix rev11

(framework-side cite: examples/app-showcase test/record-action-location-hosts.test.ts — 9/9 pass, vitest --maxWorkers=1; it pins the host page declarations only, the verdicts below are from the browse …
Placement matrix observed (rendered vs declared): list_toolbar = Reassign… · list_item (row ⋯) = Mark Done(not-done only)/Reopen(done only)/Reassign…/Quick View (+host Edit/Delete) · record_header (Ta …

  • action-location-matrix rev11 · acceptance[0] · pass · all six hosted surfaces rendered ≥1 declared action (matrix above, each surface screenshotted after settle)
  • action-location-matrix rev11 · acceptance[1] · pass · zero extra placements: Open Docs / Recalculate Selection appear only under the title-bar ⋯, never on the title bar or list toolbar; Log Time abs …
  • action-location-matrix rev11 · acceptance[2] · FAIL · 5 of 6 legs dispatched for real: toolbar Reassign… (row selected) → POST /actions/showcase_task/showcase_bulk_reassign {recordId} → wizard "Reas …
  • action-location-matrix rev11 · acceptance[3] · pass · not-done "Ingest pipeline": row menu has Mark Done, title bar has Mark Done; done "Audit current IA": row menu has Reopen and no Mark Done, titl …
  • action-location-matrix rev11 · acceptance[4] · pass · half (a) blocked(fixture) per knownGaps[2] (no packaged locations-less specimen); half (b): "New Task" (showcase_new_task, locations: []) on non …
  • action-location-matrix rev11 · negative[0] · pass · no undeclared placement in the matrix
  • action-location-matrix rev11 · negative[1] · pass · Recalculate Selection not on the list toolbar
  • action-location-matrix rev11 · negative[2] · FAIL · record_related Log Time opens the create form instead of the declared edit form for the row (see Repro rules) — not a list view, but the wrong tar …

records-forms.adhoc-filter-sort-builder rev3

  • adhoc-filter-sort-builder rev3 · acceptance[0] · pass · manual browser on view showcase_task.in_progress: FilterBuilder Priority Equals High AND Estimate (h) Greater than 4 → `GET /data/showcase_tas …
  • adhoc-filter-sort-builder rev3 · acceptance[1] · pass · SortBuilder Due Date Z→A → same request gains sort=-due_date (A→Z sent sort=due_date first); returned single row ordered trivially (single …
  • adhoc-filter-sort-builder rev3 · acceptance[2] · pass · sidebar Projects → sidebar Tasks (URL /showcase_task, no query) → In Progress: the URL is rebuilt with uf__filter/uf__sort/uf__search, the re- …
  • adhoc-filter-sort-builder rev3 · acceptance[3] · pass · A's row user_id = fGjkBff5… and cache key list-state:fGjkBff5…:showcase_task; Log out → form sign-in as qa-mgr (get-session = qa-mgr) in the S …
  • adhoc-filter-sort-builder rev3 · acceptance[4] · pass · interface page showcase_task_workbench: Status dropdown In Progress + In Review → URL ?uf_status=in_progress%2Cin_review, request filter ["o …
  • adhoc-filter-sort-builder rev3 · negative[0] · pass · merge, not replace (request carries the status node; no out-of-view row returned)
  • adhoc-filter-sort-builder rev3 · negative[1] · pass · bare object list showcase_task: no quick-filter chips (screenshot), URL carries only the reserved uf__filter / uf__sort / uf__search
  • adhoc-filter-sort-builder rev3 · negative[2] · pass · second account saw none of A's toolbar filter via the cache (see acceptance[3]); observation recorded under defects-suspected about the post-log …
  • adhoc-filter-sort-builder rev3 · negative[3] · pass · an incomplete row (Title Equals '') was persisted in the preference (value.perView…conditions[0].value "") and the console showed "Filter, 1 act …

records-forms.calendar-interactions rev2

  • calendar-interactions rev2 · acceptance[0] · pass · manual browser, view showcase_task.calendar (month): native drag of "Design system" Wed 21 → Fri 23 issued `PATCH /api/v1/data/showcase_task/xjg8K …
  • calendar-interactions rev2 · acceptance[1] · pass · contributor persona (task_own_rows: assignee == own email) loaded the calendar with "Content backlog" (assigned to them, Tue 27, draggable=true); …
  • calendar-interactions rev2 · acceptance[2] · pass · Month → Week (Oct 18–24: Warehouse schema on Thu 22, Design system on Fri 23, all-day row) → Day (Thu Oct 22: Warehouse schema); API reads: Wareho …
  • calendar-interactions rev2 · acceptance[3] · pass · click on empty Wed Oct 14 → URL ?form=new, "Create Task" dialog with Due Date pre-filled 10/14/2026 (showcase_task has a required project quick- …
  • calendar-interactions rev2 · negative[0] · pass · the successful drag landed a 200 PATCH; the failed one (404) did not keep the new day
  • calendar-interactions rev2 · negative[1] · pass · the failed reschedule surfaced an error toast (not a silent snap-back)

records-forms.concurrent-edit-conflict rev3

Two independent admin sessions under the one-browser-context limit: session B = the browser (form sign-in), session A = a separate API sign-in (its own bearer session) writing with an explicit If-Matc …

  • concurrent-edit-conflict rev3 · acceptance[0] · pass · B opened the modal Edit form holding updated_at 15:07:53.269Z; A PATCH website=https://a-wins.example If-Match 15:07:53.269Z → 200 (updated_a …
  • concurrent-edit-conflict rev3 · acceptance[1] · pass · modal form: alertdialog "Save conflict … Their save: 10/19/2026, 3:38:35 PM" with Keep editing / Overwrite; inline edit: dialog "This record wa …
  • concurrent-edit-conflict rev3 · acceptance[2] · pass · inline stale save (B billing_email=b3-inline… vs A's a3-inline…) → 409 → "Reload latest": zero further showcase_account writes captured, the pa …
  • concurrent-edit-conflict rev3 · acceptance[3] · pass · modal "Overwrite" → PATCH {"website":"https://b-stale.example"} with If-Match = 15:38:35.326Z (the 409's currentVersion) → 200; final re-read …
  • concurrent-edit-conflict rev3 · acceptance[4] · pass · inline session on the detail: edited Billing Email (details body) + Annual Revenue (header highlight) → one Save bar (1 Save button) → exactly …
  • concurrent-edit-conflict rev3 · acceptance[5] · pass · stale inline PATCH (If-Match 15:39:38.357Z vs current 15:39:50.555Z, and again 15:40:44.806Z vs 15:41:05.118Z) → 409 CONCURRENT_UPDATE + the in …
  • concurrent-edit-conflict rev3 · negative[0] · pass · no silent last-write-wins on either surface (409 every stale save)
  • concurrent-edit-conflict rev3 · negative[1] · pass · one PATCH, two changed keys only
  • concurrent-edit-conflict rev3 · negative[2] · pass · every form and inline save carried If-Match

records-forms.grid-personalization rev4

  • grid-personalization rev4 · acceptance[0] · pass · manual browser, view showcase_task.grid: dragging the Assignee header's col-resize handle +120 px took Assignee 239 → 369 px; storage `list-state:A …
  • grid-personalization rev4 · acceptance[1] · pass · Display → Density cycles Compact → Comfortable → Spacious; Compact = 41 px rows, Spacious = 56 px rows (stored rowHeight "tall"); after reload the …
  • grid-personalization rev4 · acceptance[2] · pass · Display → Group → Status: headers Backlog 3 · To Do 2 · In Progress 2 · In Review 2 · Done 2, one server query per group (`filter=["and",["status", …
  • grid-personalization rev4 · acceptance[3] · pass · post-reload screenshot: urgent rows (PII access review) red-100, high rows amber-100, medium rows blue-100, low row (Content backlog) slate-100 — m …
  • grid-personalization rev4 · acceptance[4] · pass · server row sys_user_preference key ui.list.showcase_task, user_id = admin id, value.perView["showcase_task.grid"] = {columnState:{widths:{assignee: …
  • grid-personalization rev4 · negative[0] · pass · every personalization survived reload (widths, density, row colours)
  • grid-personalization rev4 · negative[1] · pass · group counts == API counts

records-forms.lookup-picker-create-new rev3

  • lookup-picker-create-new rev3 · acceptance[0] · pass · manual browser, New Business Unit → Parent Unit picker, typed "Zeta" → popover "No options found" + button Create new "Zeta"; clicking it sta …
  • lookup-picker-create-new rev3 · acceptance[1] · pass · child create POST /data/showcase_business_unit {"name":"Zeta",…} → 201 id -yOzpmpSJuL7T-vy; the parent form's Parent Unit then shows "Zeta"; …
  • lookup-picker-create-new rev3 · acceptance[2] · pass · open → GET /data/showcase_business_unit?populate=parent&top=50; typing "Zeta" / "Plat" (150 ms/keystroke) → exactly one request per settled t …
  • lookup-picker-create-new rev3 · acceptance[3] · pass · Field Zoo f_user (Field.user → sys_user directory) zero-hit "zzqqnomatch" → server search GET /data/sys_user?…&search=zzqqnomatch and popov …
  • lookup-picker-create-new rev3 · negative[0] · pass · no create-new on the sys_user directory reference
  • lookup-picker-create-new rev3 · negative[1] · pass · every term went to the server (search= param), none filtered client-side
  • lookup-picker-create-new rev3 · negative[2] · pass · parent holds the created child's real id

records-forms.import-job-undo-cancel rev4

Option (a): the gated objectui console spec (import-console-undo.spec.ts, needs a scratch qa_lead object) was NOT run; the clauses were driven by hand — console Import wizard in the browser + the API …

  • import-job-undo-cancel rev4 · acceptance[0] · pass · API: POST /api/v1/data/showcase_contact/import/jobs {format:"csv", 12 QAIMPU- rows} → 201 pending; GET /data/import/jobs/imp_mvffn5jj0tfvxopw …
  • import-job-undo-cancel rev4 · acceptance[1] · pass · API marker counts QAIMPU-: pre 0 / post-import 12 / post-undo 0 (undo → deleted 12, restored 0, failed 0); all-contacts total 32 → 44 → 32. Brows …
  • import-job-undo-cancel rev4 · acceptance[2] · pass · 3000-row CSV (each row name/email/company + account "Northwind"), cancel POSTed at processed 200 → {success:true}; job ends status "cancelled", …
  • import-job-undo-cancel rev4 · acceptance[3] · pass · GET /api/v1/data/import/jobs → {jobs:[…]}: fresh job {jobId, undoable:true, createdAt, completedAt, …} with revertedAt absent; after undo the s …
  • import-job-undo-cancel rev4 · negative[0] · pass · undo removed exactly the imported set (12/12, 3/3, 600/600), no collateral rows
  • import-job-undo-cancel rev4 · negative[1] · pass · cancelled partial is whole rows only
  • import-job-undo-cancel rev4 · negative[2] · pass · no verdict here rests on a skipped spec — the spec was not run at all and is not cited as evidence

Reproduction rules (fails)

records-forms.conditional-rules-grid · negative[1] — stored paid invoice loads with editable locked cells (client lock race)

  1. Canonical showcase boot (stock seed); sign in as admin@objectos.ai through the form.
  2. In a fresh browser context open /_console/apps/com.example.showcase/showcase_invoice/record/INV-1003-ID/edit (INV-1003 is seeded status: paid; GET /api/v1/data/showcase_invoice?filter=[["name","=","INV-1003"]] gives the id). Do not touch the header.
  3. Wait ≥ 10 s; read the first tbody tr of the Line Items grid: the product lookup button, Qty input[type=number] and Unit Price input.
    • Expected (invoice.object.ts: product/quantity/unit_price readonlyWhen: parent.status == 'paid'): all three disabled, as they are after a live flip to Paid.
    • Actual: all three enabled in 6 of 7 fresh loads (sampled at 3, 6 and 10 s; one load came up locked). Typing 7 into Qty is accepted and Save sends POST /api/v1/batch … {"object":"showcase_invoice_line","action":"update","id":LINE,"data":{"quantity":7,"amount":349.93}}.
  4. Server consequence: the server's readonlyWhen strip keeps quantity 6 but stores the client-computed amount (349.93 = 7 × 49.99, but 6 × 49.99 = 299.94), and the invoice total roll-up becomes 349.93. Same thing over the API alone: POST /api/v1/batch {"operations":[{"object":"showcase_invoice_line","action":"update","id":INV-1003-LINE,"data":{"quantity":9,"amount":449.91}}],"atomic":true} → 200, line reads quantity 6 / amount 449.91, invoice total 449.91. (The amount comment in invoice.object.ts says the client-sent value is stored as-is, so this half is the documented trust model; the client lock race is what exposes it.)
  5. Mechanism (objectui 4016370a, packages/plugin-form/src/MasterDetailForm.tsx, MasterDetailLines): parentRecord is scraped from the header DOM on mount and on timers at 120/360/800 ms plus input/change events. The header's edit-mode load (schema fetch → record load → RHF reset) fires no input event, so when it finishes after 800 ms parent stays {} and parent.status == 'paid' evaluates false.
  • Self-check: state read from the disabled DOM property after a screenshot, no interaction before sampling; the typed value actually reached the batch (not a driver artifact); stamp equals pin, mechanism confirmed in the pinned source; hydration-race ruled out by sampling up to 10 s. Test data restored (line amount PATCHed back to 299.94, total 299.94).

records-forms.action-location-matrix · acceptance[2] (record_related dispatch leg) + negative[2]

Boot: stock showcase (objectstack dev --ui --seed-admin), console stamp 4016370a == pin. Sign in admin@objectos.ai / admin123.

  1. Open /_console/apps/com.example.showcase/showcase_project/record/WEBSITE-RELAUNCH-ID?tab=related (any project with tasks).
  2. In the "Tasks" related list, open a row's menu: getByRole('row').filter({hasText:'Design system'}).getByRole('button',{name:'Row actions'}) → menuitem "Log Time".
  3. Expected: the declared form view opens for THAT task — /_console/forms/showcase_task.form?recordId=TASK-ID&recordObject=showcase_task, prefilled (which is exactly what the same action does from the Task Detail quick-actions bar / title bar: /_console/forms/showcase_task.form?recordId=NszgRYReCy-v3CLH&recordObject=showcase_task, Title "SEO migration plan" prefilled).
    Actual: navigates to bare /_console/forms/showcase_task.form — an empty CREATE form (Title empty, Project "Select…", Status "Select an option"); no GET of the clicked task is issued. Reproduced on 3 fresh loads with 3 rows (Design system, Content backlog, Build homepage).
    Mechanism (objectui @ 4016370a): packages/app-shell/src/views/RelatedRecordActionsBridge.tsx runRowAction retargets the row action by putting objectName: childObject / recordId on the action DEF and calls the page's shared execute; packages/core/src/actions/ActionRunner.ts executeForm reads the id and object only from this.context (the parent page: record = the project, objectName = showcase_project) and deliberately ignores action.objectName (objectui#4292). crossesObjectBoundary('showcase_task.form','showcase_project') → true → bare /forms/:name. So every type:'form' action placed at record_related opens a create form instead of the clicked row's edit form.
    Self-check: ref-targeted role clicks (no coordinates); the same Log Time action dispatched from record_section on a fresh Task Detail load carried recordId correctly; hydration ruled out (row list rendered and screenshotted before the click); stale bundle ruled out (dist stamp == .objectui-sha, mechanism read from the same sha's source).

Carried forward from #24572 (verdicts valid for 5b14b7f3, same item revisions)

Carried-forward: #24572 · records-forms.crud-roundtrip · PASS
Carried-forward: #24572 · records-forms.field-type-matrix · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.list-view-capabilities · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.view-type-gallery · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.form-view-gallery · PASS
Carried-forward: #24572 · records-forms.conditional-rules-header · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.conditional-rules-grid · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.cascading-options · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.master-detail-atomic-save · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.related-list-server-pagination · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.action-param-widgets · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.upload-guard-blocks-confirm · NOT-RUN
Carried-forward: #24572 · records-forms.import-wizard-encoding-and-hints · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.action-location-matrix · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.validation-rule-type-matrix · PARTIAL
Carried-forward: #24572 · records-forms.gantt-interactions · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.kanban-drag-persistence · NOT-RUN
Carried-forward: #24572 · records-forms.form-dirty-guard · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.named-import-mapping · NOT-RUN
Carried-forward: #24572 · records-forms.adhoc-filter-sort-builder · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.calendar-interactions · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.concurrent-edit-conflict · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.record-discussion-mentions · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.grid-personalization · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.saved-view-management · NOT-RUN
Carried-forward: #24572 · records-forms.bulk-select-all-matching · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.lookup-picker-create-new · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.import-job-undo-cancel · NOT-RUN at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.object-hook-lifecycle · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.field-type-constraints · PASS
Carried-forward: #24572 · records-forms.cascading-multilevel-and-clear · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.encrypted-field-behavior · PASS
Carried-forward: #24572 · records-forms.field-group-visible-when · PASS
Carried-forward: #24572 · records-forms.field-unique-enforcement · PASS
Carried-forward: #24572 · records-forms.delete-behavior-matrix · PASS
Carried-forward: #24572 · records-forms.record-clone-contract · PASS
Carried-forward: #24572 · records-forms.field-history-tracking · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.import-transform-matrix · NOT-RUN
Carried-forward: #24572 · records-forms.predicate-relationship-traversal · PARTIAL at 5b14b7f3 for every clause except those re-judged above
Carried-forward: #24572 · records-forms.script-action-hook-refusal-toast · NOT-RUN
Carried-forward: #24572 · records-forms.write-time-option-and-element-shape-judgement · PASS
Carried-forward: #24572 · records-forms.write-answer-advisories-rollback-and-tree-delete · PASS
Carried-forward: #24572 · records-forms.comment-reactions-and-edit-stamps · PASS
Carried-forward: #24572 · records-forms.v18-semantic-defaults · PARTIAL at 5b14b7f3 for every clause except those re-judged above

FAIL items carried forward keep their round-1 disposition and extraction lines on #24572 (re-point rows on #24579 §1, defect cards as listed there).

Derived item verdicts (round-2 clauses + carried clauses)

  • records-forms.crud-roundtrip — PASS
  • records-forms.field-type-matrix — PARTIAL (re-judged clauses added; unchanged)
  • records-forms.list-view-capabilities — PASS (changed: was PARTIAL)
  • records-forms.view-type-gallery — PASS (changed: was PARTIAL)
  • records-forms.form-view-gallery — PASS
  • records-forms.conditional-rules-header — PASS (changed: was PARTIAL)
  • records-forms.conditional-rules-grid — FAIL (changed: was PARTIAL)
  • records-forms.cascading-options — PASS (changed: was PARTIAL)
  • records-forms.master-detail-atomic-save — PASS (changed: was PARTIAL)
  • records-forms.related-list-server-pagination — PASS (changed: was NOT-RUN)
  • records-forms.action-param-widgets — PASS (changed: was PARTIAL)
  • records-forms.upload-guard-blocks-confirm — NOT-RUN
  • records-forms.import-wizard-encoding-and-hints — PASS (changed: was PARTIAL)
  • records-forms.action-location-matrix — FAIL (changed: was NOT-RUN)
  • records-forms.validation-rule-type-matrix — PARTIAL
  • records-forms.gantt-interactions — PASS (changed: was PARTIAL)
  • records-forms.kanban-drag-persistence — NOT-RUN
  • records-forms.form-dirty-guard — PASS (changed: was PARTIAL)
  • records-forms.named-import-mapping — NOT-RUN
  • records-forms.adhoc-filter-sort-builder — PASS (changed: was NOT-RUN)
  • records-forms.calendar-interactions — PASS (changed: was NOT-RUN)
  • records-forms.concurrent-edit-conflict — PASS (changed: was NOT-RUN)
  • records-forms.record-discussion-mentions — PASS (changed: was PARTIAL)
  • records-forms.grid-personalization — PASS (changed: was NOT-RUN)
  • records-forms.saved-view-management — NOT-RUN
  • records-forms.bulk-select-all-matching — PASS (changed: was PARTIAL)
  • records-forms.lookup-picker-create-new — PASS (changed: was NOT-RUN)
  • records-forms.import-job-undo-cancel — PASS (changed: was NOT-RUN)
  • records-forms.object-hook-lifecycle — PASS (changed: was PARTIAL)
  • records-forms.field-type-constraints — PASS
  • records-forms.cascading-multilevel-and-clear — PASS (changed: was PARTIAL)
  • records-forms.encrypted-field-behavior — PASS
  • records-forms.field-group-visible-when — PASS
  • records-forms.field-unique-enforcement — PASS
  • records-forms.delete-behavior-matrix — PASS
  • records-forms.record-clone-contract — PASS
  • records-forms.field-history-tracking — PASS (changed: was PARTIAL)
  • records-forms.import-transform-matrix — NOT-RUN
  • records-forms.predicate-relationship-traversal — PASS (changed: was PARTIAL)
  • records-forms.script-action-hook-refusal-toast — NOT-RUN
  • records-forms.write-time-option-and-element-shape-judgement — PASS
  • records-forms.write-answer-advisories-rollback-and-tree-delete — PASS
  • records-forms.comment-reactions-and-edit-stamps — PASS
  • records-forms.v18-semantic-defaults — PASS (changed: was PARTIAL)
  • records-forms.field-type-matrix stays PARTIAL: acceptance[1] is blocked(fixture) — summary is not on the field zoo and autonumber is readonly: true (objectui drops readonly fields from edit forms by design); 47 of 49 variants pass.
  • records-forms.validation-rule-type-matrix stays PARTIAL (B class, see Scope).
  • records-forms.conditional-rules-grid negative[1] FAIL confirmed by an independent rule-7 verifier (8 of 9 fresh loads unlocked; not an authorization bypass).
  • records-forms.action-location-matrix acceptance[2] / negative[2] FAIL (record_related dispatch leg of a type: form action); A4 half (a) blocked(fixture) per its knownGap, judged on half (b).

Product defects (extraction)

  • records-forms.conditional-rules-grid negative[1] → product defect in objectui (packages/plugin-form/src/MasterDetailForm.tsx timer-bounded header scrape). Card drafted and handed to the dispatching session: this session's GitHub scope is objectstack-ai/objectstack only, so no objectui write was made here.
  • records-forms.action-location-matrix acceptance[2] / negative[2] → product defect in objectui (RelatedRecordActionsBridge.tsx retargets the action def, ActionRunner.executeForm reads only the page context). Card drafted and handed to the dispatching session (same scope reason).
  • Server half of the grid finding (framework / showcase metadata): amount on a paid invoice's line has no readonlyWhen and is not recomputed server-side, so PATCH /api/v1/data/showcase_invoice_line/ID {"amount":1} rewrites the paid invoice's total — residual of closed Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889; extracted with the other framework-side observations, see the Extracted: line in the close-out comment.
  • Runner-reported low-severity observations and the full checklist-accuracy / fixture-gap list: comment 1 on this record (body cap).

Checklist-accuracy findings / fixture gaps

In comment 1 on this record (moved for the 60 KB body cap).

Handover (not judged on ba4afcc)


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Comment 1 — checklist-accuracy findings / fixture gaps and runner-reported low-severity observations (moved out of the body for the 60 KB cap). For the wave anchor #24579, not extracted.

    Product observations (runner-reported, not clause fails)

    • conditional-rules-grid negative[1] (FAIL above): objectui MasterDetailLines reads the parent record through fixed timers, so a stored paid invoice often loads with editable lines. Combined with the server's trust in client amount, an edit produces a line whose quantity and amount disagree, and the total is wrong.
    • (observation, low) Author-time view validation accepts a filter value that every query then refuses (done == "maybe" on a boolean). A saved view can be published that can never run.
    • (observation, low) Gantt places tasks with null start_date/end_date (Evidence collection, Content backlog) as zero-length milestones on today's date (10/19 → 10/19), which invents dates.
    • (observation, low) The Chart named view (showcase_task.chart) renders without the view-tab bar and toolbar, so no switcher is reachable from it.
    • (observation, low) The zoo's f_repeater embedded grid shows only the # column for rows [{label,qty},…]. No data columns are derived when the repeater declares no item schema, so the values are not visible on the edit form.
    • (low) Hook condition fail-closed surfaces as an unhandled 500: a write refused by HookConditionError (hook 的 condition 求不出值时:全局 fail loud —— 抛错并中断该次操作(方案 B 已拍板;Blocked-by #4770) #4775) answers 500 {"error":"Internal server error","code":"INTERNAL_ERROR"} and the server logs [REST] Unhandled error: HookConditionError …. Repro (scratch copy only): add a hook on showcase_inquiry, event beforeInsert, condition record.name.startsWith('qa-fc') && int(record.name) > 0; POST /api/v1/data/showcase_inquiry {"name":"qa-fc-abc","email":"a@b.co","message":"m"} → 500 (expected a deliberate refusal status, not an internal error); row not written (correct). Reproduced 3× over two boots. Write semantics are correct; only the envelope is generic.
    • (low, observation) A sys_comment created over REST without author_name stores author_id (correct) but the Discussion feed renders its author as "Unknown" (POST /api/v1/data/sys_comment {thread_id, body} as admin → feed row "Unknown"). Only the console UI path sends author_name.
    • (observation) A mentioned member who cannot read sys_comment on the record gets a deep link to a feed that says "You don't have permission to view comments on this record" (Mei on Globex). This may be by design (comment access follows record grants).
    • objectui (console 4016370a): a type:'form' action placed at record_related opens a blank CREATE form instead of the clicked row's edit form (RelatedRecordActionsBridge sets objectName/recordId on the action def; ActionRunner.executeForm reads only the page context and so sees a cross-object boundary). Repro above. Severity: P2 functional (wrong target mode, no data loss).
    • objectui, observation (not scored, possibly by design): after "Log out" the login URL carries redirect= with the previous user's uf__filter/uf__sort; a different account signing in on that same page lands on the list WITH the previous user's toolbar filter applied ("Filter, 2 active"). URL-borne, not the per-user cache, and the filter values are visible in the URL anyway — worth a maintainer look given the item's "a filter value can be sensitive" rationale.
    • cosmetic: the routed form page heading shows the raw FormView name "showcase_task.form".

    Checklist-accuracy findings / fixture gaps

    For the wave anchor #24579 (not extracted).

    • field-type-matrix acceptance[1]: "each of the 49 FieldTypeSchema members renders … on the Specimen — Full form" cannot hold on stock: summary has no zoo carrier (knownGap already says so for the API clause), and autonumber is readonly: true and is deliberately filtered out of create AND edit forms by objectui (autoLayout.filterCreateModeFields drops schema-readonly fields); it renders read-only only on the record detail page. Re-scope to "47 variants on the edit form + autonumber on the detail page + summary on its carriers".
    • field-type-matrix knownGaps[2] is stale on this boot: PATCH f_secret "sk-plain-123" answered 200 on a stock os dev boot (a crypto provider is present) and reads back masked.
    • list-view-capabilities step 5: showcase_inquiry also requires message; a createMany with only name+email answers 400 "Message is required". Add message to the recipe.
    • list-view-capabilities negative[1]: too broad. Since the ADR-0047 amendment, dropdown userFilters chips ARE allowed on object list views (showcase project.view.ts ships them on All Projects); only element: 'tabs' is suppressed (verified: ignored with a console warning). Scope the negative to tabs.
    • list-view-capabilities step 7: the visualization switcher is Display → Layout (a dropdown inside the Display popover), not a toolbar control.
    • list-view-capabilities negative[0]: no stock view has a refused filter. The working fixture is an overlay PUT /api/v1/meta/view/showcase_task.done with filter: [{field:'done', operator:'equals', value:'maybe'}]: accepted at authoring, refused at query. A filter on a missing field is refused at authoring (list-view-field-unknown), so it cannot be used. The refusal code is not INVALID_FILTER: the body names the field and says the filter was not applied.
    • conditional-rules-grid fixture note confirmed: INV-1002 ships one line; staging a second line over the data API (position 1) leaves its amount null (amount is client-computed and stored as sent), so the invoice total ignores it. Stage it with amount too, or through the grid.
    • cascading-options / RUNNER "invite, then sign up" recipe: sign-up with a pending role: admin invitation creates the membership as member, and the invitation stays pending. The persona holds org_admin (and the tier gate opens) only after POST /api/v1/auth/organization/accept-invitation {invitationId} as that user. Add the accept step to the recipe wherever a non-member role is needed.
    • import-wizard step 3: on Contacts the Import entry is in the header's overflow "…" menu (the long object description pushes it out of the toolbar). It is not the object-view-import-button that Tasks shows.
    • view-type-gallery: the map's base style (https://demotiles.maplibre.org/style.json) is unreachable from the sandbox. Markers still render and the client shows its own degrade banner. Record this as environment, not product.
    • action-param-widgets: the p_richtext helpText says "Renders the rich-text editor, not a plain textarea", but at the pin RichTextField is textarea-based by design (the field-type-matrix step already says so). The fixture copy contradicts the widget.
    • object-hook-lifecycle: the scratch-hook recipe is now run-proven — a scratch app copy with hooks gated by a name-prefix CEL condition on showcase_inquiry (record.name.startsWith('qa-…')) isolates every scratch variant without disturbing other writes; for fail-closed, record.name.startsWith('qa-fc') && int(record.name) > 0 gives a gate that faults only for the probe rows. Worth recording in fixtures. acceptance[8].verify says "returns a HookConditionError-class refusal": the wire answer is a generic 500 INTERNAL_ERROR (class visible only in the server log) — the clause should state the expected status/envelope.
    • gantt-interactions: acceptance[3] (server veto) is runnable on stock with no lockField: bind a member to the contributor position (POST /api/v1/data/sys_user_position), open the gantt as that member, reassign one of their tasks away via API, then drag it → 404 → snap-back + "Save failed — the change was rolled back". Steps[4] could name this recipe. Seed tasks with null dates render as milestones at today.
    • v18-semantic-defaults: knownGaps[0] (pinned objectui does not build) is stale — the console at 4016370a is built and served. acceptance[2] "inline edit is offered" means the "Edit inline" SWITCH is offered (in the Display/view-settings popover at desktop width, data-testid=toolbar-inline-edit-toggle); edit mode itself is session state and starts OFF (objectui ObjectView docblock), so a run looking for editable cells on load sees none. Neither stock persona is an updater on showcase_task; binding Mei to contributor provides one. fixtures say "fresh boot pnpm dev -- --fresh"; canonical file-DB boot works too.
    • bulk-select-all-matching: the global header search opens the command palette (?palette=1), not the list quick search; the list search is [data-testid=search-icon-button] → [data-testid=search-popover] input. The aggregate dispatch posts to /api/v1/apps/showcase/recalc with top-level _selectedIds (not params._selectedIds); the run dialog shows "N / 55 processed" and takes ~15 s.
    • field-history-tracking: negative[0] should name its surface — the History tab is sys_audit_log (compliance audit, not per-field-gated) and DOES render "Website: old → new" for the untracked field; the per-field opt-in governs only the sys_activity summary / Discussion timeline. sys_activity.metadata also carries raw old/new for untracked fields by design. The task detail page has no tablist at all, so "no History tab" is best corroborated by the absent sys_audit_log fetch.
    • record-discussion-mentions: the bell is SERVER-backed (plugin-audit writes sys_notification topic collab.mention; GET /api/v1/notifications → unreadCount), not objectui useMentionNotifications (exported but unused by the console); source[2] and acceptance[3]/[4] verify should cite the server path. No sys_comment refetch follows a post within ~6 s, so steps[3] "after the feed refetch" needs a reload. The mentioned member (Mei) lands on the record but sees "You don't have permission to view comments on this record". The qa-feeds-disabled recipe also works for a second scratch object carrying activityMilestones[].type — the live open-vocabulary probe (acceptance[8]) is runnable (scratch objects get console routes /_console/apps/showcase_app/OBJ/record/ID).
    • predicate-relationship-traversal: list $filter= with OData text is refused (INVALID_FILTER, must be JSON); use filter= JSON.
    • cascading-multilevel-and-clear: after an account is picked, the contact trigger is data-testid=lookup-trigger-contact (before it is lookup-trigger-gated, "Select Account first"); chosen values show as chips above the trigger, the trigger text stays "Select…".
    • action-location-matrix steps[3] says log_time opens a "form dialog on showcase_task.form"; at console 4016370a a type:'form' action navigates to the routed page /_console/forms/showcase_task.form?recordId=…&recordObject=showcase_task (page heading shows the raw view name "showcase_task.form"), not a dialog. The record_section quick-actions bar renders only its node's explicit actionNames (mark_done, log_time, archive) — showcase_recalc_estimate also declares record_section but is not in that bar, which is correct, not a missing placement. framework pin examples/app-showcase/test/record-action-location-hosts.test.ts (9/9) covers the host declarations and could be named in automated.ref as the framework half.
    • related-list-server-pagination: Contacts is not its own tab — it is a section of the "Related" tab (?tab=related, badge 28 = 26 contacts + 2 Field Zoo rows), page size 5 → "Page 1 of 6"; the console spells the params top/skip/filter (no $), so acceptance[0]/negative[0]'s "$top" reads top on the wire. Personas: qa-contrib/qa-mgr were minted with the invite+sign-up+sys_user_position recipe (search:qa-contributor-bound-member, positions contributor / manager) — knownGaps[0]'s "blocked(fixture) on a single-user boot" is stale; the recipe works on stock.
    • adhoc-filter-sort-builder: acceptance[0]/[1] name $filter/$orderby; the console sends filter= and sort=-due_date (acceptance[2] already notes the $-less spelling). The stock seed makes the merged filter return one row, so acceptance[1]'s row-order oracle is single-datapoint; a condition pair that leaves ≥2 rows (e.g. estimate_hours > 4 alone on in_progress) would make it observable. FilterBuilder "Add filter" persists an incomplete row immediately (good material for negative[3]).
    • calendar-interactions steps[3]: "drive as a persona lacking edit" cannot produce the optimistic move — a no-edit persona (auditor.demo) gets draggable=false, so nothing drags. Working recipe: a contributor-bound member (task_own_rows) loads the calendar with a task assigned to them; admin reassigns the row away server-side; the drag then PATCHes → 404 RECORD_NOT_FOUND → revert + error toast. steps[5]/acceptance[3]: on showcase_task the empty-day click hands off to the FULL create form (required project that quick-create cannot fill, objectui#12291) with the date pre-filled — not a quick-create dialog.
    • concurrent-edit-conflict: with a one-browser-context budget, session A can be a separate API sign-in writing with If-Match; the inline dialog's buttons are "Cancel / Overwrite anyway / Reload latest" (steps say Reload / Overwrite).
    • grid-personalization: the console's density control offers Compact / Comfortable / Spacious (stored as rowHeight "compact" … "tall"), not the five modes steps[1] lists. Clicking Display → "Add group field" immediately adds a default "Title" group before a field is chosen.
    • lookup-picker-create-new: the stacked create form does NOT pre-fill the typed term into Name (the affordance is labelled Create new "Zeta", the form opens blank) — an observation, not a clause.
    • import-job-undo-cancel: a hand-driven console route exists without the gated spec — Import → Preview → tick "Import in the background (runs as an undoable job)" → History → "Undo import". The Undo uses a native window.confirm; Playwright dismisses native dialogs by default, which makes Undo a silent no-op (automation-input trap) — accept the dialog. steps[1] repeats its poll/results clause twice. showcase_contact's list has no Import button (showcase_task does).

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Comment 2 — untrimmed round-2 per-clause evidence (part 1 of 2).

    Round-2 per-clause verdicts (ba4afcc)

    Each line: item revN · clause · verdict · text oracle evidence.

    records-forms.field-type-matrix (rev 3)

    • records-forms.field-type-matrix rev3 · acceptance[1] · blocked(fixture) · 47/49 variants PASS with their dedicated widget on the Specimen — Full edit form (DOM after screenshot, per [data-field]): text→input[text]; textarea→textarea; email/url/phone→input[email|url|tel]; password/secret→input[password]+reveal button; markdown/html/richtext/code→textarea-based dedicated widgets (by design per step 3); number/currency→input[number] (currency with $ adornment); percent/slider/progress→slider; date/datetime→date-picker (input+calendar button); time→input[time]; boolean/toggle→switch; select→combobox; multiselect→chip group; radio→radiogroup; checkboxes→checkbox group; tags→chip input; lookup/master_detail/tree/user (f_user,f_users,f_owner)→record picker (search + browse-all); image/avatar→upload button; file/video/audio→dropzone input[file]; formula→read-only group (315); composite/record/json→JSON editor (field:object); repeater→embedded grid with Add line; location→"latitude, longitude" LocationField input; address→structured street/city/state/zip/country inputs; color→input[color]+hex; rating→stars; signature→canvas+Clear; qrcode→QRCodeField input; vector→read-only vector display. Residue: summary is not on the zoo (knownGap — no carrier on the form) and autonumber (f_autonumber, readonly: true) is deliberately dropped from create/edit forms by objectui autoLayout.filterCreateModeFields (renders read-only "0001" on the record DETAIL page instead). The clause as written ("each of the 49 … on the Specimen — Full form") cannot be satisfied by the stock fixture → checklist finding, not a product fail.
    • records-forms.field-type-matrix rev3 · negative[0] · pass · POST /api/v1/data/showcase_field_zoo {name, f_master_detail:VALID, f_select:"not-a-value"} → 400 VALIDATION_FAILED fields[{field:f_select, code:invalid_option, options:[low,medium,high]}]; zoo count 2→2.
    • records-forms.field-type-matrix rev3 · negative[1] · pass · fabricated ids refused 400 VALIDATION_FAILED code reference_not_found for f_lookup (POST and PATCH on Specimen — Minimal), f_lookups (one bad id in array), f_master_detail, f_tree; no row landed.
    • records-forms.field-type-matrix rev3 · negative[2] · pass · wrote f_password "Hunter2-plain" and f_secret "sk-plain-123" (PATCH 200 on stock boot); every read (single GET, list GET, select=f_password,f_secret, search) returns "••••••••"; the create/patch response bodies also mask.

    records-forms.list-view-capabilities (rev 3)

    • records-forms.list-view-capabilities rev3 · acceptance[0] · pass · one artifact per variant captured: default grid (screenshot + GET …showcase_task?populate=project&top=50&select=…), in_progress filtered (export requests carry filter=[["status","equals","in_progress"]]), quick-search, tabular sort, paging, inline edit, export ×3, visualization switcher ×6, bulk per-record + aggregate, legacy row actions, zoo conditional formatting (Specimen — Full row background-color: rgba(37, 99, 235, 0.08), Specimen — Minimal and qa row none).
    • records-forms.list-view-capabilities rev3 · acceptance[2] · pass · typing 'huaning' on Accounts issued GET /api/v1/data/showcase_account?top=50&search=huaning&select=… → 200 [华宁科技] total 1; direct GET …showcase_account?search=huaning reproduces it.
    • records-forms.list-view-capabilities rev3 · acceptance[3] · pass · Inquiries (58 rows after staging): page 1 top=50 (50 ids), Next page top=50&skip=50 (8 ids); union 58, distinct 58 = API total 58; no unpaged fetch.
    • records-forms.list-view-capabilities rev3 · acceptance[4] · pass · Task List view requests …&sort=-estimate_hours → 200; rows 60,40,30,24,20,18,16,16,12,8 (descending); rendered without error.
    • records-forms.list-view-capabilities rev3 · acceptance[5] · pass · Grid view, Content backlog estimate 12→13 via cell edit + "Save All (1)": PATCH /api/v1/data/showcase_task/mBz559k4jR3ZUFDg {"estimate_hours":13}; post-reload row shows 13; full-row API diff before/after = estimate_hours, updated_at, updated_by only.
    • records-forms.list-view-capabilities rev3 · acceptance[6] · pass · grant provisioned: runtime set qa_task_export {showcase_task: allowRead, allowExport} bound to admin. Display popover footer lists exactly Export as CSV / XLSX / JSON; each fires GET /api/v1/data/showcase_task/export?format=F&fields=…&filter=[["status","equals","in_progress"]]; all three files contain exactly Ingest pipeline + Build homepage (2 rows).
    • records-forms.list-view-capabilities rev3 · acceptance[7] · pass · Display → Layout dropdown offers exactly Grid, Kanban, Gallery, Calendar, Timeline, Gantt (no map/chart); each switch re-rendered the task records (10/10 titles on grid/kanban/gallery/timeline/gantt; calendar month view shows the October-dated tasks).
    • records-forms.list-view-capabilities rev3 · acceptance[8] · pass · 3 selected: Recalculate Selection → ONE POST /api/v1/apps/showcase/recalc {"_selectedIds":[3 ids]} → 200 summary selected 3 / acted 3; Mark Done → THREE POST /api/v1/actions/showcase_task/showcase_mark_done {"recordId":…} → 200 each.
    • records-forms.list-view-capabilities rev3 · acceptance[9] · pass · legacy_row_actions row menu = Reopen, Reassign…, Quick View (once), Recalculate Estimate; Recalculate Estimate dispatched POST /api/v1/apps/showcase/recalc {"recordId":…}; Quick View opened the Component Gallery modal.
    • records-forms.list-view-capabilities rev3 · negative[0] · pass · overlay on showcase_task.done with filter done equals "maybe" (accepted at authoring): grid request …filter=[["done","equals","maybe"]] → 400; grid shows 0 rows and "This view's query was rejected … Retry" (2 fresh loads) — honest symptom, never unfiltered rows. Overlay reverted.
    • records-forms.list-view-capabilities rev3 · negative[1] · pass · overlay adding userFilters {element:'tabs', tabs:[QA High]} to the object view showcase_task.done: the QA High tab never renders (2 loads) and the console warns "defines userFilters (element: "tabs"), which are ignored on an object list view". (See findings: dropdown chips ARE allowed on object views.)
    • records-forms.list-view-capabilities rev3 · negative[2] · pass · all three exports of the filtered view hold only the 2 in_progress rows (table has 10).

    records-forms.view-type-gallery (rev 1)

    • records-forms.view-type-gallery rev1 · acceptance[0] · pass · one screenshot each, real structure observed: Grid (table, 10 rows), Board (5 status columns with cards + Σ estimate), Cards (10 cards), Calendar (month grid, tasks on dates), Activity Timeline (dated vertical feed), Schedule/Gantt (task list + bars + Today line), Work Locations/Map (MapLibre canvas + 10 📍 markers; base tiles from demotiles.maplibre.org blocked by sandbox egress — the client shows its own "Map failed to load … markers below are still listed" banner), Hours by Status/Chart (bar SVG), Organization Chart/tree (nested rows). None fell back to grid.
    • records-forms.view-type-gallery rev1 · acceptance[1] · pass · board columns BACKLOG 2/Σ16, TO DO 2/Σ108, IN PROGRESS 2/Σ100, IN REVIEW 2/Σ54, DONE 2/Σ40 = client-side group of GET /api/v1/data/showcase_task?top=100 (counts and estimate_hours sums identical; values reflect this run's recalc on 3 tasks).
    • records-forms.view-type-gallery rev1 · acceptance[2] · pass · calendar request is a due_date window; Audit current IA on Oct 1 (due 2026-10-01), App wireframes Oct 13 (2026-10-13), Design system Oct 21, Warehouse schema Oct 22 — match API due_date; timeline: Ingest pipeline 9/9/2026, Warehouse schema 9/24/2026 = API created_at; gantt bars Warehouse schema 9/27→10/22 and Design system 10/7→10/21 = API start/end, progress shaded (90% / 80%).
    • records-forms.view-type-gallery rev1 · acceptance[3] · pass · map: 10 markers vs 10 tasks with a location (API); chart: POST /api/v1/analytics/dataset/query {"datasetName":"showcase_task_metrics", dimensions:[status,priority], measures:[est_hours]} and an SVG with 8 plotted bars across 5 status buckets.
    • records-forms.view-type-gallery rev1 · acceptance[4] · pass · tree after expanding: Acme Corporation → (Product & Engineering → Frontend Guild → Design Systems; Platform), (Go-To-Market → Sales → Enterprise Sales; Marketing) with indent 0/20/40/60px — identical to parent refs from GET /api/v1/data/showcase_business_unit; no pageerror.
    • records-forms.view-type-gallery rev1 · negative[0] · pass · no variant rendered as a plain grid.
    • records-forms.view-type-gallery rev1 · negative[1] · pass · chart is multi-bucket (5 statuses × 4 priorities, 8 non-empty bars), not a single datapoint.

    records-forms.conditional-rules-header (rev 2)

    • records-forms.conditional-rules-header rev2 · acceptance[1] · pass · POST /api/v1/data/showcase_invoice {name:"qa-rf1-sent-noissue", account, status:"sent"} → 400 VALIDATION_FAILED fields[{field:issued_on, code:required}]; filtered count 0. (paid without paid_on → 400 paid_on required; sent with issued_on → 201.)
    • records-forms.conditional-rules-header rev2 · acceptance[2] · pass · INV-1003 (paid) tax_rate 8 → PATCH {"tax_rate":99} 200 → re-read tax_rate 8 (stripped). Control: same PATCH shape on draft INV-1004 persisted (5), then restored.
    • records-forms.conditional-rules-header rev2 · acceptance[3] · pass · INV-1002 draft edit form: no [data-field=paid_on]; INV-1003 paid form: paid_on present with required marker; tax_rate renders as read-only group on paid, input[number] on draft.
    • records-forms.conditional-rules-header rev2 · acceptance[4] · pass · invoice list (2 fresh loads): INV-1003 menu = Edit (disabled), Submit for Sign-off, Generate PDF — no Delete; INV-1002 menu = Edit, Delete, Submit for Sign-off, Generate PDF.
    • records-forms.conditional-rules-header rev2 · acceptance[5] · pass · form leg: INV-1002 status → Sent marks issued_on required; Save shows "Issued On is required" and issues no write (2 fresh loads; server re-read still draft/null); API leg refuses the same shape (A1); field the client locks (tax_rate on paid) is the field the server strips (A2).
    • records-forms.conditional-rules-header rev2 · negative[0] · pass · the direct 'sent' POST without issued_on was refused (A1).
    • records-forms.conditional-rules-header rev2 · negative[1] · pass · tax_rate 99 did not persist (A2).
    • records-forms.conditional-rules-header rev2 · negative[2] · pass · no Delete affordance on the paid row (A4).

    records-forms.conditional-rules-grid (rev 4)

    • records-forms.conditional-rules-grid rev4 · acceptance[1] · pass · POST /api/v1/batch atomic with line update {description:"",quantity:120} → 400 VALIDATION_FAILED fields[{field:description, code:required}] (also with the header update in the same batch, which did not land: tax_rate stayed 0); batch of create(valid sibling)+create(qty 120, no description) → 400, neither line created; single POST → 400; INV-1002 line read byte-identical before/after.
    • records-forms.conditional-rules-grid rev4 · acceptance[3] · pass · uploaded receipt-qa.pdf into line 1's receipt cell: presigned → PUT → complete (fileId fcba01a0…), Save sent {"receipt":"fcba01a0-caff-4e32-9942-5628050319b6"} in the batch; GET …/showcase_invoice_line/OamZxL71eMBQEJIN → receipt {id, name, size 45, mimeType application/pdf, url /api/v1/storage/files/ID}; fetching that URL returns 200 application/pdf, bytes identical to the upload; sys_file row exists.
    • records-forms.conditional-rules-grid rev4 · acceptance[4] · pass · INV-1002 with lines at positions 0 and 1 (second line staged at position 1 per fixtures): grid save sent ONE batch with only line 0's dirty fields {description, quantity:120, amount:11880}; API diff: line 0 changed (description/quantity/amount/updated_*), line 1 (position 1) BYTE-IDENTICAL; reopening the form shows qty 120.
    • records-forms.conditional-rules-grid rev4 · negative[0] · pass · client: qty 120 + empty description flags the row-0 cell ("Description is required", aria-invalid) and not row 1; the batch it sends is refused 400 and lines stay byte-identical (by-design send, per acceptance[0] note); server: every direct shape refused (A1).
    • records-forms.conditional-rules-grid rev4 · negative[1] · FAIL · on a freshly loaded STORED paid invoice (INV-1003) the parent-scoped readonlyWhen does not apply: product/quantity/unit_price cells are enabled (6 of 7 fresh loads, sampled at 3/6/10 s), typing into Qty works and Save sends {"quantity":7,"amount":349.93} for the line. Live flip draft→Paid (unsaved) locks the cells and →Sent/Draft unlocks them (that half holds). Root cause at objectui 4016370a: MasterDetailLines (packages/plugin-form/src/MasterDetailForm.tsx) scrapes the header only at mount and at 120/360/800 ms timers plus input/change events; when the header record loads later than 800 ms the parent binding stays {}. Repro rule below.

    records-forms.cascading-options (rev 3)

    • records-forms.cascading-options rev3 · acceptance[0] · pass · New Cascading Select (?form=new): province reads "Select country first" until a country is chosen; cn → options [Zhejiang, Guangdong]; picked Zhejiang; switching to United States cleared province ("Select an option") and offered [California, Texas].
    • records-forms.cascading-options rev3 · acceptance[2] · pass · org_admin persona (invited role admin + accepted): tier options [Standard, Restricted (admin only)] in the form; POST {tier:"restricted"} as that persona → 201, re-read tier restricted. Plain member: options [Standard] only; direct POST tier restricted → 400 invalid_option (twice); member standard control → 201. Seeded admin (org_owner) also sees only Standard and is refused — predicate as authored.
    • records-forms.cascading-options rev3 · acceptance[3] · pass · New Invoice: contact trigger disabled "Select Account first" before an account; after Northwind the picker requested GET /api/v1/data/showcase_contact?top=50&filter=["account","=","uLAv4e5GNPKbwKdO"] → 26; after switching to Contoso …filter=["account","=","K3tY6LQBJDQDPc7-"] → 2.
    • records-forms.cascading-options rev3 · acceptance[4] · pass · form create sent POST /api/v1/data/showcase_cascade {"tier":"standard","name":"qa-rf1-form-cn-zj","country":"cn","province":"zj"}; API re-read returns country cn, province zj (also API-created qa-rf1-zj re-reads verbatim).
    • records-forms.cascading-options rev3 · negative[0] · pass · POST country cn + province ca → 400 VALIDATION_FAILED fields[{field:province, code:invalid_option}].
    • records-forms.cascading-options rev3 · negative[1] · pass · plain member's direct tier='restricted' POST refused 400 invalid_option (picker also hid it).

    records-forms.master-detail-atomic-save (rev 3)

    • records-forms.master-detail-atomic-save rev3 · acceptance[1] · pass · New Invoice os-qa-rf1-md1 (Northwind, draft), line 1 Widget A (auto-filled "Standard widget"/29.99) qty 4, line 2 Consulting Hour (auto-filled "Professional services, per hour"/150) qty 2; API re-read: invoice K6xWpnORdyKg4c66 name/account/status as entered; lines position 0/1 with product ids, auto-filled description/unit_price, quantity 4/2, amount 119.96/300.
    • records-forms.master-detail-atomic-save rev3 · acceptance[3] · pass · total 419.96 after atomic create (=119.96+300); add Gadget X line via edit form (batch create) → 518.96; remove that line (batch delete) → 419.96; each equals Σ line amounts read back.
    • records-forms.master-detail-atomic-save rev3 · acceptance[4] · pass · New Invoice os-qa-rf1-md-bad with line 2 lacking product: one batch → 400 VALIDATION_FAILED {field:product, code:required}; form shows "Product is required"; filtered GET for the name → 0 invoices; total line count unchanged (8→8); no line carries a phantom parent.
    • records-forms.master-detail-atomic-save rev3 · acceptance[5] · pass · amount cell (data-computed) recomputed live without save: qty 3 → 89.97, qty 4 → 119.96; saved line reads amount 119.96 = 4 × 29.99 and the roll-up uses it.
    • records-forms.master-detail-atomic-save rev3 · negative[0] · pass · after the failed save neither the master nor the valid sibling line exists (API reads above).
    • records-forms.master-detail-atomic-save rev3 · negative[1] · pass · create issued exactly ONE write: POST /api/v1/batch atomic:true with the invoice create + 2 line creates referencing {"$ref":0}.

    records-forms.action-param-widgets (rev 2)

    • records-forms.action-param-widgets rev2 · acceptance[0] · pass · dialog from Specimen — Full row menu (screenshot first): p_text→input[text] (required *), p_richtext→RichTextField textarea, p_priority→combobox (select-trigger-p_priority, default Normal), p_date→date-picker, p_account→record picker (lookup-trigger-p_account + browse-all), p_assignee→record picker (lookup-trigger-p_assignee), p_color→input[color]+hex (#7C3AED default), p_reference→read-only empty-value "—" (autonumber, server-assigned), p_cover→image upload, p_attachments→file dropzone.
    • records-forms.action-param-widgets rev2 · acceptance[1] · pass · DOM attributes: p_cover INPUT-TYPE-FILE-ACCEPT-IMAGE (no multiple); p_attachments input[type=file] accept="application/pdf,image/*" multiple>.
    • records-forms.action-param-widgets rev2 · acceptance[3] · pass · UI: Confirm with empty Title shows "Title is required" and no dispatch (2 opens); API: POST /api/v1/actions/showcase_field_zoo/showcase_action_param_gallery/ID {"params":{"p_priority":"high"}} → 400 VALIDATION_ERROR 'Action param "p_text" is required' (no echo). Conformant UI confirm → POST … {"recordId":…,"params":{"p_priority":"high","p_color":"#7C3AED","p_text":"qa-rf1 conformant"}} → 200 echo received [p_priority,p_color,p_text,recordId,objectName].
    • records-forms.action-param-widgets rev2 · negative[0] · pass · no maxSize DOM attribute was claimed; an actual 6.0 MB PNG into p_cover was refused client-side ('"big.png" exceeds max size (5.0 MB)') with no storage request.
    • records-forms.action-param-widgets rev2 · negative[1] · pass · malformed bags refused before the body: p_priority "urgent-bogus" → 400 'Invalid option: expected one of "low"|"normal"|"high"'; undeclared p_evil → 400 'Unknown action param "p_evil"'; no echo returned.

    records-forms.import-wizard-encoding-and-hints (rev 6)

    • records-forms.import-wizard-encoding-and-hints rev6 · acceptance[3] · pass · Contacts → overflow "…" → Import; uploaded a GBK-encoded CSV (2 rows, CJK name/company/title); auto-mapped 4 columns; Import 2 Rows → POST /api/v1/data/showcase_contact/import {"format":"json","rows":[{"name":"张三QA导入",…},{"name":"李四QA导入",…}],"writeMode":"insert",…}; "Import Complete 2 created"; GET …showcase_contact?filter=[["email","startswith","qa-rf1-imp"]] → 2 rows, names/company/title decoded intact.
    • records-forms.import-wizard-encoding-and-hints rev6 · negative[0] · pass · the wired wizard's preview of the GBK file rendered 张三QA导入 / 华宁科技 / 工程师 etc. (screenshot), no mojibake.
    • records-forms.import-wizard-encoding-and-hints rev6 · negative[1] · pass · success report matched by the API read (2 rows found).

    records-forms.gantt-interactions rev4

    • records-forms.gantt-interactions rev4 · acceptance[0] · pass · drag of "Design system" bar (+2 days, Day mode) → PATCH /api/v1/data/showcase_task/D8EVuZQQwd7AwhKR {"start_date":"2026-10-09","end_date":"2026-10-23"} → 200; API re-read 2026-10-09/2026-10-23 (was 10-07/10-21); after reload task list reads "10/9 → 10/23" and bar re-renders at new position
    • records-forms.gantt-interactions rev4 · acceptance[3] · pass · server veto: Mei (contributor, own-row RLS) opened gantt, task kgkRGuoycf8DTNXZ reassigned away underneath her, her drag sent PATCH {"start_date":"2026-10-23","end_date":"2026-11-02"} → 404 RECORD_NOT_FOUND; bar box x=1550 mid-drag → 1330 immediately after drop and settled (snapped back), toast "Save failed — the change was rolled back"; admin re-read dates unchanged 2026-10-21/2026-10-31. (Read-only Ada: gantt read-only, drag produced no request and no movement.)
    • records-forms.gantt-interactions rev4 · negative[0] · pass · successful drag landed a 200 PATCH and persisted; the 4xx drag did not keep its new position (snap-back + rollback toast)

    records-forms.form-dirty-guard rev3

    • records-forms.form-dirty-guard rev3 · acceptance[0] · pass · Edit Account modal (?form=Sc8UxP41F6TCIjQK): clean form — X / Escape / backdrop / Cancel all closed with no prompt; dirty form (website typed) — X, Escape and backdrop each raised "Discard changes?" (screenshot: alert over blurred form, Keep editing / Discard), "Keep editing" kept the typed value; dirty + footer Cancel closed with no prompt and server row unchanged (updated_at 14:46:53.784Z)
    • records-forms.form-dirty-guard rev3 · acceptance[1] · pass · after Discard: API website https://initech.example, updated_at unchanged (byte-identical); after Update: website https://initech.example/saved-qa2, updated_at 15:08:20
    • records-forms.form-dirty-guard rev3 · negative[0] · pass · no accidental close lost a dirty edit without prompt; no prompt on any pristine-form close

    records-forms.record-discussion-mentions rev3

    • records-forms.record-discussion-mentions rev3 · acceptance[0] · pass · UI post on Globex → POST /api/v1/data/sys_comment 201 id 81214553-…; GET sys_comment filter thread_id=showcase_account:L-O5F-zQM733EAA0 sort created_at returns it with body "QA2 hello @Mei Phone (demo) please review", mentions ["usr_showcase_phone_demo"]
    • records-forms.record-discussion-mentions rev3 · acceptance[1] · pass · client-minted id in POST body == server id; row count of the comment sampled 13× across post (incl. optimistic frame) = 1 every sample; after reload (server fetch) still exactly 1 row. Note: no automatic sys_comment refetch was issued within ~6 s of the POST — reconcile observed across the reload
    • records-forms.record-discussion-mentions rev3 · acceptance[2] · pass · feed after an attributable PATCH (industry) and a later comment reads oldest-first: comment 15:15:45 → "Industry: Technology → Finance" (sys_activity 15:16:07) → second comment; feed count 3
    • records-forms.record-discussion-mentions rev3 · acceptance[3] · pass · Mei: /api/v1/notifications unread 0 → 1 (collab.mention "Dev Admin mentioned you", actionUrl /showcase_account/L-O5F-zQM733EAA0); bell badge "1" and panel item shown; clicking it navigated to the Globex record (heading "Globex"), server unreadCount → 0, read:true, badge cleared
    • records-forms.record-discussion-mentions rev3 · acceptance[4] · pass · Ada (non-mentioned): server notifications unchanged (only the pre-existing approval.requested, unread 1); bell panel lists only "Approval requested"
    • records-forms.record-discussion-mentions rev3 · acceptance[7] · pass · Globex: All Activity 3 rows (2 comments + 1 field change); Comments Only 2 (both comments); Field Changes 1 (Industry change); Tasks Only 0 (empty — record has no task-type rows); back to All 3. Options offered exactly the four spec modes
    • records-forms.record-discussion-mentions rev3 · acceptance[8] · pass · live milestone channel (not the pin): qa_milestone record, stage→won wrote sys_activity type qa_custom_kind "QA milestone reached: qa-ms-1"; it renders in All Activity, is absent from the three narrowing modes, and the console logs the named diagnostic [record:activity] rendered a sys_activity row with type "qa_custom_kind" through the generic "system" presentation …
    • records-forms.record-discussion-mentions rev3 · negative[0] · pass · no dupe/phantom (see acceptance[1])
    • records-forms.record-discussion-mentions rev3 · negative[1] · pass · mention notification reached Mei only; Ada and the author got none
    • records-forms.record-discussion-mentions rev3 · negative[2] · pass · qa_nofeeds record detail: no Discussion panel, no comment box, zero sys_comment requests (control qa_milestone: panel + sys_comment GET); server POST sys_comment {thread_id:"qa_nofeeds:QhJUILpRyhA4nwqn"} → 403 FEEDS_DISABLED, thread read 0 rows
    • records-forms.record-discussion-mentions rev3 · negative[4] · pass · both FEEDS_DISABLED refusals measured WITH controls: create on enabled parent 201; re-thread of comment 8k3S1yjSsTTdhU3c onto qa_nofeeds → 403 FEEDS_DISABLED with thread_id unchanged on re-read; body-edit control 200; re-thread to another enabled parent 200
    • records-forms.record-discussion-mentions rev3 · negative[5] · pass · no mode showed another mode's type (created/updated → field_change by the objectui map); custom type present in 'all', absent only from narrowing modes

    records-forms.bulk-select-all-matching rev3

    • records-forms.bulk-select-all-matching rev3 · acceptance[0] · pass · bulk_actions view, quick search "QA bulk": find ?top=50&search=QA+bulk total=55 n=50; with ONE row ticked no banner; with the whole page ticked banner "All 50 on this page are selected. Select all 55 matching" (55 = response total)
    • records-forms.bulk-select-all-matching rev3 · acceptance[1] · pass · after "Select all 55 matching" ("All 55 matching records are selected."), dispatch fanned out GET ?top=500&skip=0&search=QA+bulk → n=55; aggregate POST /api/v1/apps/showcase/recalc carried _selectedIds len 55 (55 unique) → 200; server flow log showcase_recalc_estimates … selected=55 acted=55; direct API count for search = 55
    • records-forms.bulk-select-all-matching rev3 · acceptance[4] · pass (weak, single datapoint) · collected 55 ≤ HARD_CAP 5000; a > 5000 match set was not provisioned, so the truncation branch was not exercised live
    • records-forms.bulk-select-all-matching rev3 · negative[0] · pass · dispatched set 55 > rendered page 50
    • records-forms.bulk-select-all-matching rev3 · negative[1] · pass · banner 55 == filtered API count 55
    • records-forms.bulk-select-all-matching rev3 · negative[2] · pass · Clear: 0 checked row boxes (50 before), header checkbox unchecked, bulk bar/selection text gone (screenshot: plain list, no bar)

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Comment 3 — untrimmed round-2 per-clause evidence (part 2 of 2).

    records-forms.object-hook-lifecycle rev5

    • records-forms.object-hook-lifecycle rev5 · acceptance[1] · pass · (stock :47541; 5 showcase hooks "Registered hook" in boot log) POST task title " os-qa-rf2 " → re-read "os-qa-rf2"; PATCH " os-qa-rf2-upd " → re-read "os-qa-rf2-upd"
    • records-forms.object-hook-lifecycle rev5 · acceptance[2] · pass · PATCH Build homepage {done:true} → log INFO [hook 'showcase_audit_task_completion'] task completed: Build homepage
    • records-forms.object-hook-lifecycle rev5 · acceptance[3] · pass · PATCH App wireframes {priority:high} (done already true) → 200, settle 5 s, no "task completed: App wireframes" line (only lines in log: Build homepage, Data Platform)
    • records-forms.object-hook-lifecycle rev5 · acceptance[4] · pass · PATCH Data Platform {spent:650000} → WARN [hook 'showcase_warn_over_budget'] project over budget: Data Platform (650000 / 600000)
    • records-forms.object-hook-lifecycle rev5 · acceptance[5] · pass · spent-only PATCH fired with budget read from storage (line above); Website Relaunch {spent:70000} → 200 and no warn line
    • records-forms.object-hook-lifecycle rev5 · acceptance[6] · pass · (scratch :47542) qa_abort_insert (beforeInsert, throws, onError abort): POST inquiry "qa-abort-1" → 400 {"error":"qa scratch abort on insert"}; filtered count 0 before and after (repeated on a fresh boot: "qa-abort-2" → 400)
    • records-forms.object-hook-lifecycle rev5 · acceptance[7] · pass · qa_tolerate_update (async afterUpdate, throws, onError log): PATCH message → 200, re-read "after-tolerate"; log ERROR [hook] handler failed (onError=log; suppressing) {"hook":"qa_tolerate_update",…}
    • records-forms.object-hook-lifecycle rev5 · acceptance[8] · pass (envelope note) · qa_failclosed condition record.name.startsWith('qa-fc') && int(record.name) > 0 with onError:'log': POST "qa-fc-abc" → refused (row count 0), log HookConditionError: Hook 'qa_failclosed' could not evaluate its condition (runtime: int() type error…) — operation aborted; body never ran; control insert with other name 201. Reproduced on a fresh boot (qa-fc-xyz, qa-fc-2). Wire envelope is a generic 500 {"error":"Internal server error","code":"INTERNAL_ERROR"} with [REST] Unhandled error — see suspected defects
    • records-forms.object-hook-lifecycle rev5 · acceptance[9] · pass · qa_prio_90 and qa_prio_10 (afterInsert, declared 90 first): one POST "qa-prio-1" logged qa_prio_10 … priority-10 ran (14:50:03.365) then qa_prio_90 … priority-90 ran (14:50:03.383)
    • records-forms.object-hook-lifecycle rev5 · negative[0] · pass · throwing beforeInsert abort left 0 rows
    • records-forms.object-hook-lifecycle rev5 · negative[1] · pass · async onError:'log' failure did not roll back the PATCH
    • records-forms.object-hook-lifecycle rev5 · negative[2] · pass · real transition emitted the audit line
    • records-forms.object-hook-lifecycle rev5 · negative[3] · pass · no audit on the non-transition edit
    • records-forms.object-hook-lifecycle rev5 · negative[4] · pass · unevaluable condition aborted the write (not skipped, not softened by onError:'log')

    records-forms.cascading-multilevel-and-clear rev3

    • records-forms.cascading-multilevel-and-clear rev3 · acceptance[0] · pass · New Cascading Select modal: province options @china = [Zhejiang, Guangdong]; picked Zhejiang; switch to United States → province trigger "Select an option" (cleared), options = [California, Texas]; submitted POST body {"country":"us","province":null,…}
    • records-forms.cascading-multilevel-and-clear rev3 · acceptance[2] · pass (gap confirmed) · POST {cn,zj} 201 → PATCH {country:'us'} only → 200; GET → country us, province zj (stale child retained)
    • records-forms.cascading-multilevel-and-clear rev3 · acceptance[3] · pass · New Invoice: account=Northwind → contact candidates GET showcase_contact?filter=["account","=","q81MWvDmgCZEDWzE"] total 26; picked Noah Bell (chip shown); account→Contoso → Noah Bell chip cleared, candidates filter=["account","=","MN-nXAbtK5JcYfPU"] total 2 (Carl Fox, Cara Ito)
    • records-forms.cascading-multilevel-and-clear rev3 · acceptance[4] · pass (gap confirmed) · POST invoice {account:Contoso, contact:Noah Bell (Northwind)} → 201; fabricated contact id → 400 reference_not_found
    • records-forms.cascading-multilevel-and-clear rev3 · acceptance[5] · pass · re-read {cn,zj} row verbatim; invoice QA2-twin {Northwind, Noah Bell} re-reads account/contact verbatim
    • records-forms.cascading-multilevel-and-clear rev3 · negative[0] · pass · PATCH {country:'us', province:'zj'} (child in payload) → 400 invalid_option, row unchanged {cn,zj}
    • records-forms.cascading-multilevel-and-clear rev3 · negative[1] · pass · POST {cn, ca} → 400 invalid_option on province
    • records-forms.cascading-multilevel-and-clear rev3 · negative[2] · pass · both gaps recorded as client-only (stale-child PATCH 200; cross-account contact 201) — not ticked as server enforcement

    records-forms.field-history-tracking rev1

    • records-forms.field-history-tracking rev1 · acceptance[1] · pass · Hooli website-only PATCH → sys_activity summary Updated Account "Hooli" (no per-field summary); tracked industry PATCH beside it → Industry: Technology → Finance; Discussion timeline renders the same two summaries
    • records-forms.field-history-tracking rev1 · acceptance[2] · pass · account detail tabs [Details, Invoices, Projects, Related, History] and one GET sys_audit_log request; task detail (App wireframes) has no tablist, no "History" text, zero sys_audit_log requests
    • records-forms.field-history-tracking rev1 · acceptance[3] · pass · /api/v1/auth/me/permissions: showcase_account apiOperations include history; showcase_task's do not
    • records-forms.field-history-tracking rev1 · negative[0] · pass · untracked edit produced no old→new tracked summary in sys_activity / timeline (the History TAB, fed by sys_audit_log, does show "Website: old → new" — that is the compliance audit, not per-field gated; see findings)
    • records-forms.field-history-tracking rev1 · negative[1] · pass · no History tab on task detail (and no audit fetch)
    • records-forms.field-history-tracking rev1 · negative[2] · pass · select rendered labels "Technology → Finance", not values
    • records-forms.field-history-tracking rev1 · negative[3] · pass · guard honored — crud-roundtrip clause 5 not re-scored here

    records-forms.predicate-relationship-traversal rev3

    • records-forms.predicate-relationship-traversal rev3 · acceptance[0] · pass · POST invoice account=Contoso (active) → 201, filtered read returns it, no validation error
    • records-forms.predicate-relationship-traversal rev3 · acceptance[1] · pass · POST account=Umbrella Health (churned) → 400 VALIDATION_FAILED, fields[0] {field:'_record', code:'rule_violation', message:'This account has churned — reactivate it before invoicing.'} (= authored message); filtered count 0
    • records-forms.predicate-relationship-traversal rev3 · acceptance[2] · pass · PATCH existing invoice {account: Wonka Brands (churned)} → 400 same envelope; re-read account still Contoso
    • records-forms.predicate-relationship-traversal rev3 · negative[0] · pass · churned create refused
    • records-forms.predicate-relationship-traversal rev3 · negative[1] · pass · no "could not be evaluated" fault on any readable-parent case
    • records-forms.predicate-relationship-traversal rev3 · negative[2] · pass (engine pin, same basis as acceptance[3]) · no stock persona lacks parent read; packages/objectql vitest src/engine-predicate-relationship.test.ts 45/45 passed at ba4afcc (system-authority related read, accept/refuse on the real write path)

    records-forms.v18-semantic-defaults rev1

    • records-forms.v18-semantic-defaults rev1 · acceptance[1] · pass · task default view (no pagination.pageSize in /api/v1/meta/view/showcase_task.default) with 66 rows: data request top=50, 50 tbody rows, "Rows per page 50", "Page 1 of 2", "66 records" (same on view/grid)
    • records-forms.v18-semantic-defaults rev1 · acceptance[2] · pass · editInline omitted on the view: Mei (contributor, allowEdit true) — "Edit inline" switch offered in the Display popover, toggling it made cells editable and a single click opened a Status editor; Ada (read-only, allowEdit false) — popover has no "Edit inline" entry
    • records-forms.v18-semantic-defaults rev1 · acceptance[3] · pass · New on showcase_field_zoo (59 fields) / showcase_task (25 fields): desktop 1440×900 → centered bounded dialog (1024 wide, field_zoo 810 tall); mobile 390×844 → dialog 390×844 full-screen

    Tier-1-pin items (round 1 NOT-RUN), every clause driven by hand — RUNNER option (a)

    records-forms.related-list-server-pagination rev4

    • related-list-server-pagination rev4 · acceptance[0] · pass · manual browser: Related tab Contacts page-1 GET /data/showcase_contact?…&top=5&skip=0&filter=["account","=","S_ifFwiLdRpvXgSe"], page 2 top=5&skip=5 (same filter), pages 3–6 skip=10/15/20/25; every child query on the detail page carries top (top=1 count probes for invoice/project/contact/field_zoo, top=5 lists) — no unbounded child fetch (console spells $top as top)
    • related-list-server-pagination rev4 · acceptance[1] · pass · pager "Page 1 of 6" → "Page 6 of 6" (5/page, server total 26 in every response); page-1 ids (5, via identical API query) + pages 2–6 ids (21, captured responses) = 26 unique, equal to the full top=100 id set — disjoint, nothing skipped
    • related-list-server-pagination rev4 · acceptance[2] · pass · stock Account detail (no authored page) screenshot shows derived tabs Details | Invoices 1 | Projects 2 | Related 28 | History; Projects tab renders the relationship-derived list (Project Name/Status/Health/Budget/End Date)
    • related-list-server-pagination rev4 · acceptance[3] · pass · Invoices tab label "Invoices", headers Invoice Number | Status | Total | Issued On (+Actions), request select=id,name,status,total,issued_on — matches invoice.object.ts relatedListTitle 'Invoices' / relatedListColumns [name,status,total,issued_on]
    • related-list-server-pagination rev4 · acceptance[4] · pass · clicking "Prospect 06" in the Contacts related list navigated to /showcase_contact/record/3SA4DwbDVtVBYlP7 (h1 "Prospect 06"); GET /api/v1/data/showcase_contact/3SA4DwbDVtVBYlP7 → name "Prospect 06", account S_ifFwiLdRpvXgSe
    • related-list-server-pagination rev4 · acceptance[5] · pass · contributor (session = qa-contrib): Northwind detail tabs Details|Invoices|Projects 2|Related 2|History, Related tab holds only the two Field Zoo lists, no Contacts section, and the console issued no showcase_contact request; forged GET /data/showcase_contact?$filter=[["account","=",Northwind]] → 403 PERMISSION_DENIED. manager (session = qa-mgr): Related 28, Contacts section with 5 Prospect rows; same query → 200, total 26
    • related-list-server-pagination rev4 · negative[0] · pass · no child-list request without a top bound among all captured detail-page requests
    • related-list-server-pagination rev4 · negative[1] · pass · pager total 26 == API filtered total 26
    • related-list-server-pagination rev4 · negative[2] · pass · no Contacts section for contributor AND server 403 (both ends hold)

    records-forms.action-location-matrix rev11

    (framework-side cite: examples/app-showcase test/record-action-location-hosts.test.ts — 9/9 pass, vitest --maxWorkers=1; it pins the host page declarations only, the verdicts below are from the browser)
    Placement matrix observed (rendered vs declared): list_toolbar = Reassign… · list_item (row ⋯) = Mark Done(not-done only)/Reopen(done only)/Reassign…/Quick View (+host Edit/Delete) · record_header (Task Detail title bar) = Mark Done(not-done only)/Log Time/Archive(disabled until done) · record_more (title-bar ⋯) = Open Docs/Recalculate Estimate/Recalculate Selection (+host Add to favorites/Share/Delete) · record_section (quick-actions bar) = Mark Done/Log Time/Archive (the node's actionNames list) · record_related (Project Detail ?tab=related → Tasks rows) = Edit/Mark Done|Reopen/Reassign…/Quick View/Log Time/Delete.

    • action-location-matrix rev11 · acceptance[0] · pass · all six hosted surfaces rendered ≥1 declared action (matrix above, each surface screenshotted after settle)
    • action-location-matrix rev11 · acceptance[1] · pass · zero extra placements: Open Docs / Recalculate Selection appear only under the title-bar ⋯, never on the title bar or list toolbar; Log Time absent from the showcase_task list-view row menu, present on related rows; list header ⋯ holds only host items
    • action-location-matrix rev11 · acceptance[2] · FAIL · 5 of 6 legs dispatched for real: toolbar Reassign… (row selected) → POST /actions/showcase_task/showcase_bulk_reassign {recordId} → wizard "Reassign Task" → POST …/runs/ID/resume {new_assignee} → toast 'Flow "Reassign Task" completed', re-read assignee = qa-reassign@example.com; row Quick View → modal "Component Gallery"; header Mark Done → POST /actions/showcase_task/showcase_mark_done → re-read done false→true; section Log Time → /_console/forms/showcase_task.form?recordId=NszgRYReCy-v3CLH&recordObject=showcase_task (edit form, prefilled); ⋯ Open Docs → new tab requesting https://objectstack.ai/; ⋯ Recalculate Selection → POST /api/v1/apps/showcase/recalc {recordId} → estimate_hours 16→88. BUT record_related leg: Log Time from a Tasks related-list row opens bare /_console/forms/showcase_task.form (blank CREATE form, no recordId) — not the edit form for the clicked row (reproduced 3× on fresh loads, 3 rows)
    • action-location-matrix rev11 · acceptance[3] · pass · not-done "Ingest pipeline": row menu has Mark Done, title bar has Mark Done; done "Audit current IA": row menu has Reopen and no Mark Done, title bar has Log Time/Archive and no Mark Done (fail-closed throw path not exercisable on stock — the stock expression is has()-guarded)
    • action-location-matrix rev11 · acceptance[4] · pass · half (a) blocked(fixture) per knownGaps[2] (no packaged locations-less specimen); half (b): "New Task" (showcase_new_task, locations: []) on none of the six surfaces (host "New" create buttons are not the action); Recalculate Selection under ⋯ and absent from the list toolbar
    • action-location-matrix rev11 · negative[0] · pass · no undeclared placement in the matrix
    • action-location-matrix rev11 · negative[1] · pass · Recalculate Selection not on the list toolbar
    • action-location-matrix rev11 · negative[2] · FAIL · record_related Log Time opens the create form instead of the declared edit form for the row (see Repro rules) — not a list view, but the wrong target mode

    records-forms.adhoc-filter-sort-builder rev3

    • adhoc-filter-sort-builder rev3 · acceptance[0] · pass · manual browser on view showcase_task.in_progress: FilterBuilder Priority Equals High AND Estimate (h) Greater than 4 → GET /data/showcase_task?…&filter=["and",[["status","equals","in_progress"]],["and",["priority","=","high"],["estimate_hours",">",4]]] (view rule + both toolbar conditions merged); rows = [Build homepage] (in_progress/high/40h) — the high in_review rows (Warehouse schema, Design system) stay excluded
    • adhoc-filter-sort-builder rev3 · acceptance[1] · pass · SortBuilder Due Date Z→A → same request gains sort=-due_date (A→Z sent sort=due_date first); returned single row ordered trivially (single-datapoint, so the server ordering was cross-checked with the view-filter-only request: sort=-due_date → Ingest pipeline 11-08, Build homepage 10-29; sort=due_date → reversed)
    • adhoc-filter-sort-builder rev3 · acceptance[2] · pass · sidebar Projects → sidebar Tasks (URL /showcase_task, no query) → In Progress: the URL is rebuilt with uf__filter/uf__sort/uf__search, the re-issued request is identical (search=homepage&sort=-due_date&filter=[merged]), FilterBuilder shows the two conditions ("Filter, 2 active"), SortBuilder "Due Date Z → A"; store = sys_user_preference ui.list.showcase_task row (user_id = admin id, value.perView["showcase_task.in_progress"].{filters,sort}) + localStorage list-state:ADMINID:showcase_task; search under list-filters:ADMINID:showcase_task:showcase_task.in_progress
    • adhoc-filter-sort-builder rev3 · acceptance[3] · pass · A's row user_id = fGjkBff5… and cache key list-state:fGjkBff5…:showcase_task; Log out → form sign-in as qa-mgr (get-session = qa-mgr) in the SAME browser context → /view/showcase_task.in_progress issues filter=[["status","equals","in_progress"]] only, Filter button "Filter" (0 active), no list-state key for A is readable (A's key was cleared on the user switch)
    • adhoc-filter-sort-builder rev3 · acceptance[4] · pass · interface page showcase_task_workbench: Status dropdown In Progress + In Review → URL ?uf_status=in_progress%2Cin_review, request filter ["or",[status=in_progress],[status=in_review]] → 4 rows; same URL in a fresh context → identical request + identical 4 rows. showcase_task_triage tab Urgent → ?uf__tab=urgent, fresh context → same filter=["priority","equals","urgent"], same 2 rows
    • adhoc-filter-sort-builder rev3 · negative[0] · pass · merge, not replace (request carries the status node; no out-of-view row returned)
    • adhoc-filter-sort-builder rev3 · negative[1] · pass · bare object list showcase_task: no quick-filter chips (screenshot), URL carries only the reserved uf__filter / uf__sort / uf__search
    • adhoc-filter-sort-builder rev3 · negative[2] · pass · second account saw none of A's toolbar filter via the cache (see acceptance[3]); observation recorded under defects-suspected about the post-logout redirect URL
    • adhoc-filter-sort-builder rev3 · negative[3] · pass · an incomplete row (Title Equals '') was persisted in the preference (value.perView…conditions[0].value "") and the console showed "Filter, 1 active", yet the data request carried only filter=[["status","equals","in_progress"]] — the valueless row was dropped, not sent as [title, =, '']

    records-forms.calendar-interactions rev2

    • calendar-interactions rev2 · acceptance[0] · pass · manual browser, view showcase_task.calendar (month): native drag of "Design system" Wed 21 → Fri 23 issued PATCH /api/v1/data/showcase_task/xjg8KMQ_SiJZyqgO {"due_date":"2026-10-23"} → 200; API re-read due_date 2026-10-23; fresh load renders the card in the Fri 23 cell (card box x = the "23" cell label x)
    • calendar-interactions rev2 · acceptance[1] · pass · contributor persona (task_own_rows: assignee == own email) loaded the calendar with "Content backlog" (assigned to them, Tue 27, draggable=true); admin then reassigned the row away server-side; drag → PATCH …/vShFjd-370lGjtK2 {"due_date":"2026-10-28"} → 404 RECORD_NOT_FOUND; the card sits back on Tue 27 and a red error toast "Record vShFjd-370lGjtK2 not found in showcase_task" shows; re-read due_date still 2026-10-27 (the optimistic frame itself was too short to capture at 150 ms — revert + toast is the oracle). Auditor (no edit) gets draggable=false — no drag at all, so the deny case is courtesy-gated client-side and 403s server-side (direct PATCH as auditor → 403 PERMISSION_DENIED)
    • calendar-interactions rev2 · acceptance[2] · pass · Month → Week (Oct 18–24: Warehouse schema on Thu 22, Design system on Fri 23, all-day row) → Day (Thu Oct 22: Warehouse schema); API reads: Warehouse schema due 2026-10-22, Design system 2026-10-23 — same records placed by due_date, no blank/grid fallback
    • calendar-interactions rev2 · acceptance[3] · pass · click on empty Wed Oct 14 → URL ?form=new, "Create Task" dialog with Due Date pre-filled 10/14/2026 (showcase_task has a required project quick-create cannot fill, so the calendar hands the day to the full create form, objectui#12291); fill title + project → POST /data/showcase_task {…"due_date":"2026-10-14","title":"QA calendar quick-create","project":"0Ua8kuNoMR4SQyTW"} → 201 id hJKJ6KI9FEMXoj-n; re-read due_date 2026-10-14
    • calendar-interactions rev2 · negative[0] · pass · the successful drag landed a 200 PATCH; the failed one (404) did not keep the new day
    • calendar-interactions rev2 · negative[1] · pass · the failed reschedule surfaced an error toast (not a silent snap-back)

    records-forms.concurrent-edit-conflict rev3

    Two independent admin sessions under the one-browser-context limit: session B = the browser (form sign-in), session A = a separate API sign-in (its own bearer session) writing with an explicit If-Match. Record: showcase_account Globex ft0ts6NM0g-NKfJO.

    • concurrent-edit-conflict rev3 · acceptance[0] · pass · B opened the modal Edit form holding updated_at 15:07:53.269Z; A PATCH website=https://a-wins.example If-Match 15:07:53.269Z → 200 (updated_at → 15:38:35.326Z); B's form save PATCH {"website":"https://b-stale.example"} If-Match 15:07:53.269Z → 409 code CONCURRENT_UPDATE, currentVersion 15:38:35.326Z (+currentRecord); independent re-read website = https://a-wins.example (A intact)
    • concurrent-edit-conflict rev3 · acceptance[1] · pass · modal form: alertdialog "Save conflict … Their save: 10/19/2026, 3:38:35 PM" with Keep editing / Overwrite; inline edit: dialog "This record was modified by someone else" showing YOUR EDIT vs CURRENT VALUE (racer's value + "Updated at 3:41:05 PM") with Cancel / Overwrite anyway / Reload latest — structured choice both ways, no raw error
    • concurrent-edit-conflict rev3 · acceptance[2] · pass · inline stale save (B billing_email=b3-inline… vs A's a3-inline…) → 409 → "Reload latest": zero further showcase_account writes captured, the page shows a3-inline@globex.example (b3 nowhere, edit inputs closed); API re-read billing_email = a3-inline@globex.example
    • concurrent-edit-conflict rev3 · acceptance[3] · pass · modal "Overwrite" → PATCH {"website":"https://b-stale.example"} with If-Match = 15:38:35.326Z (the 409's currentVersion) → 200; final re-read website = https://b-stale.example (one winner, B)
    • concurrent-edit-conflict rev3 · acceptance[4] · pass · inline session on the detail: edited Billing Email (details body) + Annual Revenue (header highlight) → one Save bar (1 Save button) → exactly ONE PATCH {"billing_email":"ap@globex.example","annual_revenue":43000000} with If-Match = read updated_at 15:38:39.720Z → 200; re-read shows both values
    • concurrent-edit-conflict rev3 · acceptance[5] · pass · stale inline PATCH (If-Match 15:39:38.357Z vs current 15:39:50.555Z, and again 15:40:44.806Z vs 15:41:05.118Z) → 409 CONCURRENT_UPDATE + the inline conflict dialog
    • concurrent-edit-conflict rev3 · negative[0] · pass · no silent last-write-wins on either surface (409 every stale save)
    • concurrent-edit-conflict rev3 · negative[1] · pass · one PATCH, two changed keys only
    • concurrent-edit-conflict rev3 · negative[2] · pass · every form and inline save carried If-Match

    records-forms.grid-personalization rev4

    • grid-personalization rev4 · acceptance[0] · pass · manual browser, view showcase_task.grid: dragging the Assignee header's col-resize handle +120 px took Assignee 239 → 369 px; storage list-state:ADMINID:showcase_task = perView["showcase_task.grid"].columnState.widths.assignee 357 and cache grid-columns-showcase_task = {"widths":{"assignee":357}}; after reload Assignee = 369 px again (all other widths identical). Reorder n/a (stock view sets no reorderableColumns); pin n/a (the stock task views declare no pinned column)
    • grid-personalization rev4 · acceptance[1] · pass · Display → Density cycles Compact → Comfortable → Spacious; Compact = 41 px rows, Spacious = 56 px rows (stored rowHeight "tall"); after reload the grid renders at 56 px and the panel reads Spacious (also verified for Compact on an earlier pass)
    • grid-personalization rev4 · acceptance[2] · pass · Display → Group → Status: headers Backlog 3 · To Do 2 · In Progress 2 · In Review 2 · Done 2, one server query per group (filter=["and",["status","=",…]]); direct per-status API totals backlog 3 / todo 2 / in_progress 2 / in_review 2 / done 2 — all equal; Group → Clear: 11 plain rows, no group header text left
    • grid-personalization rev4 · acceptance[3] · pass · post-reload screenshot: urgent rows (PII access review) red-100, high rows amber-100, medium rows blue-100, low row (Content backlog) slate-100 — matches rowColor {low slate, medium blue, high amber, urgent red} against the seeded priorities
    • grid-personalization rev4 · acceptance[4] · pass · server row sys_user_preference key ui.list.showcase_task, user_id = admin id, value.perView["showcase_task.grid"] = {columnState:{widths:{assignee:357}}, rowHeight:"tall"}; a FRESH browser context as admin restored Assignee 364 px / 56 px rows; qa-mgr in its own context sees the default layout (Assignee 267 px, 41 px rows) and holds no ui.list.showcase_task row (0 rows on its own read)
    • grid-personalization rev4 · negative[0] · pass · every personalization survived reload (widths, density, row colours)
    • grid-personalization rev4 · negative[1] · pass · group counts == API counts

    records-forms.lookup-picker-create-new rev3

    • lookup-picker-create-new rev3 · acceptance[0] · pass · manual browser, New Business Unit → Parent Unit picker, typed "Zeta" → popover "No options found" + button Create new "Zeta"; clicking it stacked the referenced object's full create form (Name*, Parent Unit, Type, Manager, Headcount). Default-on also seen on a lookup with NO allowCreate key: Field Zoo f_lookup (Field.lookup('showcase_account') bare) zero-hit → Create new "zzqqnomatch"
    • lookup-picker-create-new rev3 · acceptance[1] · pass · child create POST /data/showcase_business_unit {"name":"Zeta",…} → 201 id -yOzpmpSJuL7T-vy; the parent form's Parent Unit then shows "Zeta"; parent save POST {"name":"QA Child Unit","parent":"-yOzpmpSJuL7T-vy",…} → 201 mgh_Ml-KsI6qjBJl; API re-read mgh_Ml-KsI6qjBJl.parent = -yOzpmpSJuL7T-vy (the created row's real id)
    • lookup-picker-create-new rev3 · acceptance[2] · pass · open → GET /data/showcase_business_unit?populate=parent&top=50; typing "Zeta" / "Plat" (150 ms/keystroke) → exactly one request per settled term, …&search=Zeta / …&search=Plat, scoped to the referenced object; "Plat" returned Platform from the server
    • lookup-picker-create-new rev3 · acceptance[3] · pass · Field Zoo f_user (Field.user → sys_user directory) zero-hit "zzqqnomatch" → server search GET /data/sys_user?…&search=zzqqnomatch and popover "No records found" with NO button / create-new affordance (screenshot)
    • lookup-picker-create-new rev3 · negative[0] · pass · no create-new on the sys_user directory reference
    • lookup-picker-create-new rev3 · negative[1] · pass · every term went to the server (search= param), none filtered client-side
    • lookup-picker-create-new rev3 · negative[2] · pass · parent holds the created child's real id

    records-forms.import-job-undo-cancel rev4

    Option (a): the gated objectui console spec (import-console-undo.spec.ts, needs a scratch qa_lead object) was NOT run; the clauses were driven by hand — console Import wizard in the browser + the API half.

    • import-job-undo-cancel rev4 · acceptance[0] · pass · API: POST /api/v1/data/showcase_contact/import/jobs {format:"csv", 12 QAIMPU- rows} → 201 pending; GET /data/import/jobs/imp_mvffn5jj0tfvxopw → status succeeded, processed 12, created 12, undoable true; /results → 12 per-row entries {row, ok:true, action:"created", id}; job-list entry {jobId, undoable:true, createdAt, …} with NO revertedAt key. Browser: Task Import wizard → Preview → "Import in the background (runs as an undoable job)" → POST /data/showcase_task/import/jobs → polls /import/jobs/imp_mvffqo6z1koammi3 + /results → "Import Complete 3 created"; History tab lists it Succeeded 3/3 with "Undo import"
    • import-job-undo-cancel rev4 · acceptance[1] · pass · API marker counts QAIMPU-: pre 0 / post-import 12 / post-undo 0 (undo → deleted 12, restored 0, failed 0); all-contacts total 32 → 44 → 32. Browser: History → Undo import → native confirm "Undo this import? …" accepted → POST /data/import/jobs/imp_mvffqo6z1koammi3/undo → deleted 3; marker QAIMPJ- 3 → 0, the 3 QAIMPB- rows from an earlier synchronous import untouched, task total 17 → 14 (exactly the 3); row shows "Undone"
    • import-job-undo-cancel rev4 · acceptance[2] · pass · 3000-row CSV (each row name/email/company + account "Northwind"), cancel POSTed at processed 200 → {success:true}; job ends status "cancelled", processed 600 / created 600 / errors 0; 600 QAIMPC- rows committed, 0 torn (every row has name, matching email, company "QA Cancel"), 0 dangling FK (all account = S_ifFwiLdRpvXgSe Northwind); the cancelled job stays undoable and its undo deleted exactly 600 (marker back to 0, contact total back to 32)
    • import-job-undo-cancel rev4 · acceptance[3] · pass · GET /api/v1/data/import/jobs → {jobs:[…]}: fresh job {jobId, undoable:true, createdAt, completedAt, …} with revertedAt absent; after undo the same entry reads undoable:false + revertedAt "2026-10-19T15:52:10.532Z"
    • import-job-undo-cancel rev4 · negative[0] · pass · undo removed exactly the imported set (12/12, 3/3, 600/600), no collateral rows
    • import-job-undo-cancel rev4 · negative[1] · pass · cancelled partial is whole rows only
    • import-job-undo-cancel rev4 · negative[2] · pass · no verdict here rests on a skipped spec — the spec was not run at all and is not cited as evidence

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Extracted: #24619 · records-forms.conditional-rules-grid · negative[1] (server half: paid invoice line amount / total writable)
    Extracted: #24619 · records-forms.object-hook-lifecycle · acceptance[8] (envelope observation: HookConditionError answers 500 INTERNAL_ERROR)
    Handed-off: objectstack-ai/objectui · records-forms.conditional-rules-grid · negative[1] — product defect in objectui; card drafted and handed to the dispatching session, not filed from here (this session's GitHub scope is objectstack-ai/objectstack only)
    Handed-off: objectstack-ai/objectui · records-forms.action-location-matrix · acceptance[2] — product defect in objectui; card drafted and handed to the dispatching session, not filed from here (this session's GitHub scope is objectstack-ai/objectstack only)
    Parked-on: #24579 · this record's checklist-accuracy findings, fixture gaps and B-class parked clauses (wave anchor §2–§4)


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Extracted: objectstack-ai/objectui#13062 · records-forms.conditional-rules-grid · negative[1]
    Extracted: objectstack-ai/objectui#13063 · records-forms.action-location-matrix · acceptance[2]
    Extracted: objectstack-ai/objectui#13063 · records-forms.action-location-matrix · negative[2]

    Closed by: the 18.0 QA wave dispatch session session_01CfRDy7SuTfUqaTu2AEH2Hi, on the maintainer's instruction there on 2026-10-19, verbatim 「qa-run的卡片处理完的是不是可以关闭」. Closure complete (checklist-test §5): every FAIL in this record has a disposition (the Extracted: / Parked-on: lines on this record), and its partial coverage gaps and not-run handover are parked on #24579.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions