Repository navigation
QA run · records-forms (38/44) · ba4afcc2 · 2026-10-19 · 34 PASS / 2 PARTIAL / 2 FAIL / 0 BLOCKED / 6 NOT-RUN #24616
Description
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's5b14b7f3, 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-sha4016370af3c9c9dafec2bc5299afd8e8079701b8, built withpnpm objectui:build(deps--concurrency=2);packages/console/dist/.objectui-shastamp 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 build10m20s, 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-matrixnegative[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_foundfor 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 pagetop=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.donewith filterdone 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 viewshowcase_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/batchatomic 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/batchatomic: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_comment201 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/notificationsunread 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+bulktotal=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) > 0with 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_logrequest; task detail (App wireframe … - records-forms.field-history-tracking rev1 · acceptance[3] · pass ·
/api/v1/auth/me/permissions: showcase_account apiOperations includehistory; 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/objectqlvitest `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 requesttop=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 sentsort=due_datefirst); 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
projectquick- … - 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.exampleIf-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 searchGET /data/sys_user?…&search=zzqqnomatchand 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)
- Canonical showcase boot (stock seed); sign in as admin@objectos.ai through the form.
- In a fresh browser context open
/_console/apps/com.example.showcase/showcase_invoice/record/INV-1003-ID/edit(INV-1003 is seededstatus: paid;GET /api/v1/data/showcase_invoice?filter=[["name","=","INV-1003"]]gives the id). Do not touch the header. - Wait ≥ 10 s; read the first
tbody trof the Line Items grid: the product lookup button, Qtyinput[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}}.
- Expected (invoice.object.ts: product/quantity/unit_price
- 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
totalroll-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. (Theamountcomment 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.) - Mechanism (objectui 4016370a,
packages/plugin-form/src/MasterDetailForm.tsx,MasterDetailLines):parentRecordis scraped from the header DOM on mount and on timers at 120/360/800 ms plusinput/changeevents. The header's edit-mode load (schema fetch → record load → RHF reset) fires no input event, so when it finishes after 800 msparentstays{}andparent.status == 'paid'evaluates false.
- Self-check: state read from the
disabledDOM 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.
- Open
/_console/apps/com.example.showcase/showcase_project/record/WEBSITE-RELAUNCH-ID?tab=related(any project with tasks). - In the "Tasks" related list, open a row's menu:
getByRole('row').filter({hasText:'Design system'}).getByRole('button',{name:'Row actions'})→ menuitem "Log Time". - 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.tsxrunRowAction retargets the row action by puttingobjectName: childObject/recordIdon the action DEF and calls the page's sharedexecute;packages/core/src/actions/ActionRunner.tsexecuteForm reads the id and object only fromthis.context(the parent page: record = the project, objectName = showcase_project) and deliberately ignoresaction.objectName(objectui#4292).crossesObjectBoundary('showcase_task.form','showcase_project')→ true → bare/forms/:name. So everytype:'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— PASSrecords-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— PASSrecords-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-RUNrecords-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— PARTIALrecords-forms.gantt-interactions— PASS (changed: was PARTIAL)records-forms.kanban-drag-persistence— NOT-RUNrecords-forms.form-dirty-guard— PASS (changed: was PARTIAL)records-forms.named-import-mapping— NOT-RUNrecords-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-RUNrecords-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— PASSrecords-forms.cascading-multilevel-and-clear— PASS (changed: was PARTIAL)records-forms.encrypted-field-behavior— PASSrecords-forms.field-group-visible-when— PASSrecords-forms.field-unique-enforcement— PASSrecords-forms.delete-behavior-matrix— PASSrecords-forms.record-clone-contract— PASSrecords-forms.field-history-tracking— PASS (changed: was PARTIAL)records-forms.import-transform-matrix— NOT-RUNrecords-forms.predicate-relationship-traversal— PASS (changed: was PARTIAL)records-forms.script-action-hook-refusal-toast— NOT-RUNrecords-forms.write-time-option-and-element-shape-judgement— PASSrecords-forms.write-answer-advisories-rollback-and-tree-delete— PASSrecords-forms.comment-reactions-and-edit-stamps— PASSrecords-forms.v18-semantic-defaults— PASS (changed: was PARTIAL)records-forms.field-type-matrixstays PARTIAL: acceptance[1] is blocked(fixture) —summaryis not on the field zoo andautonumberisreadonly: true(objectui drops readonly fields from edit forms by design); 47 of 49 variants pass.records-forms.validation-rule-type-matrixstays PARTIAL (B class, see Scope).records-forms.conditional-rules-gridnegative[1] FAIL confirmed by an independent rule-7 verifier (8 of 9 fresh loads unlocked; not an authorization bypass).records-forms.action-location-matrixacceptance[2] / negative[2] FAIL (record_related dispatch leg of atype: formaction); A4 half (a) blocked(fixture) per its knownGap, judged on half (b).
Product defects (extraction)
records-forms.conditional-rules-gridnegative[1] → product defect in objectui (packages/plugin-form/src/MasterDetailForm.tsxtimer-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-matrixacceptance[2] / negative[2] → product defect in objectui (RelatedRecordActionsBridge.tsxretargets the action def,ActionRunner.executeFormreads only the page context). Card drafted and handed to the dispatching session (same scope reason).- Server half of the grid finding (framework / showcase metadata):
amounton a paid invoice's line has noreadonlyWhenand is not recomputed server-side, soPATCH /api/v1/data/showcase_invoice_line/ID {"amount":1}rewrites the paid invoice'stotal— residual of closed Parent-scopedreadonlyWhenis 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)
records-forms.upload-guard-blocks-confirm— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.kanban-drag-persistence— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.named-import-mapping— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.saved-view-management— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.import-transform-matrix— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.script-action-hook-refusal-toast— NOT-RUN, Tier 3 deferred by the 18.0 sweep plan (carried from QA run · records-forms (30/44) · 5b14b7f3 · 2026-10-19 · 11 PASS / 19 PARTIAL / 0 FAIL / 0 BLOCKED / 14 NOT-RUN #24572)records-forms.validation-rule-type-matrixnegative[0] — blocked(fixture): an unevaluable CEL validation cannot be authored through any door (fixture outside the brief's B list; stays parked) — B class, 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
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 19, 2026
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)
amount, an edit produces a line whose quantity and amount disagree, and the total is wrong.done == "maybe"on a boolean). A saved view can be published that can never run.showcase_task.chart) renders without the view-tab bar and toolbar, so no switcher is reachable from it.f_repeaterembedded 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.HookConditionError(hook 的condition求不出值时:全局 fail loud —— 抛错并中断该次操作(方案 B 已拍板;Blocked-by #4770) #4775) answers500 {"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, conditionrecord.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.author_namestores 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.type:'form'action placed atrecord_relatedopens 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).redirect=with the previous user'suf__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.Checklist-accuracy findings / fixture gaps
For the wave anchor #24579 (not extracted).
summaryhas no zoo carrier (knownGap already says so for the API clause), andautonumberisreadonly: trueand is deliberately filtered out of create AND edit forms by objectui (autoLayout.filterCreateModeFieldsdrops 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".PATCH f_secret "sk-plain-123"answered 200 on a stockos devboot (a crypto provider is present) and reads back masked.showcase_inquiryalso requiresmessage; a createMany with only name+email answers 400 "Message is required". Addmessageto the recipe.dropdownuserFilters chips ARE allowed on object list views (showcaseproject.view.tsships them on All Projects); onlyelement: 'tabs'is suppressed (verified: ignored with a console warning). Scope the negative to tabs.PUT /api/v1/meta/view/showcase_task.donewithfilter: [{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 notINVALID_FILTER: the body names the field and says the filter was not applied.amountnull (amount is client-computed and stored as sent), so the invoice total ignores it. Stage it withamounttoo, or through the grid.role: admininvitation creates the membership asmember, and the invitation stayspending. The persona holdsorg_admin(and the tier gate opens) only afterPOST /api/v1/auth/organization/accept-invitation {invitationId}as that user. Add the accept step to the recipe wherever a non-member role is needed.object-view-import-buttonthat Tasks shows.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.record.name.startsWith('qa-…')) isolates every scratch variant without disturbing other writes; for fail-closed,record.name.startsWith('qa-fc') && int(record.name) > 0gives 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.contributorposition (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.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 tocontributorprovides one. fixtures say "fresh bootpnpm dev -- --fresh"; canonical file-DB boot works too.?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/recalcwith top-level_selectedIds(notparams._selectedIds); the run dialog shows "N / 55 processed" and takes ~15 s.sys_notificationtopiccollab.mention;GET /api/v1/notifications→ unreadCount), not objectuiuseMentionNotifications(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 carryingactivityMilestones[].type— the live open-vocabulary probe (acceptance[8]) is runnable (scratch objects get console routes/_console/apps/showcase_app/OBJ/record/ID).$filter=with OData text is refused (INVALID_FILTER, must be JSON); usefilter=JSON.data-testid=lookup-trigger-contact(before it islookup-trigger-gated, "Select Account first"); chosen values show as chips above the trigger, the trigger text stays "Select…".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 explicitactionNames(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 pinexamples/app-showcase/test/record-action-location-hosts.test.ts(9/9) covers the host declarations and could be named inautomated.refas the framework half.?tab=related, badge 28 = 26 contacts + 2 Field Zoo rows), page size 5 → "Page 1 of 6"; the console spells the paramstop/skip/filter(no$), so acceptance[0]/negative[0]'s "$top" readstopon 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.$filter/$orderby; the console sendsfilter=andsort=-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]).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 (requiredprojectthat quick-create cannot fill, objectui#12291) with the date pre-filled — not a quick-create dialog.If-Match; the inline dialog's buttons are "Cancel / Overwrite anyway / Reload latest" (steps say Reload / Overwrite).Create new "Zeta", the form opens blank) — an observation, not a clause.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
objectstack-fleet commentedon Oct 19, 2026
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)
[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:summaryis not on the zoo (knownGap — no carrier on the form) andautonumber(f_autonumber,readonly: true) is deliberately dropped from create/edit forms by objectuiautoLayout.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.reference_not_foundfor f_lookup (POST and PATCH on Specimen — Minimal), f_lookups (one bad id in array), f_master_detail, f_tree; no row landed."••••••••"; the create/patch response bodies also mask.records-forms.list-view-capabilities (rev 3)
GET …showcase_task?populate=project&top=50&select=…), in_progress filtered (export requests carryfilter=[["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 rowbackground-color: rgba(37, 99, 235, 0.08), Specimen — Minimal and qa row none).GET /api/v1/data/showcase_account?top=50&search=huaning&select=…→ 200[华宁科技]total 1; directGET …showcase_account?search=huaningreproduces it.top=50(50 ids), Next pagetop=50&skip=50(8 ids); union 58, distinct 58 = API total 58; no unpaged fetch.…&sort=-estimate_hours→ 200; rows 60,40,30,24,20,18,16,16,12,8 (descending); rendered without error.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.qa_task_export{showcase_task: allowRead, allowExport} bound to admin. Display popover footer lists exactly Export as CSV / XLSX / JSON; each firesGET /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).POST /api/v1/apps/showcase/recalc {"_selectedIds":[3 ids]}→ 200 summary selected 3 / acted 3; Mark Done → THREEPOST /api/v1/actions/showcase_task/showcase_mark_done {"recordId":…}→ 200 each.POST /api/v1/apps/showcase/recalc {"recordId":…}; Quick View opened the Component Gallery modal.showcase_task.donewith filterdone 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.userFilters {element:'tabs', tabs:[QA High]}to the object viewshowcase_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.view-type-gallery (rev 1)
GET /api/v1/data/showcase_task?top=100(counts and estimate_hours sums identical; values reflect this run's recalc on 3 tasks).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.GET /api/v1/data/showcase_business_unit; no pageerror.records-forms.conditional-rules-header (rev 2)
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.)PATCH {"tax_rate":99}200 → re-read tax_rate 8 (stripped). Control: same PATCH shape on draft INV-1004 persisted (5), then restored.[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-grid (rev 4)
POST /api/v1/batchatomic 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.{"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.{"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 theparentbinding stays{}. Repro rule below.records-forms.cascading-options (rev 3)
?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].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.GET /api/v1/data/showcase_contact?top=50&filter=["account","=","uLAv4e5GNPKbwKdO"]→ 26; after switching to Contoso…filter=["account","=","K3tY6LQBJDQDPc7-"]→ 2.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.master-detail-atomic-save (rev 3)
POST /api/v1/batchatomic:true with the invoice create + 2 line creates referencing{"$ref":0}.records-forms.action-param-widgets (rev 2)
INPUT-TYPE-FILE-ACCEPT-IMAGE(no multiple); p_attachmentsinput[type=file] accept="application/pdf,image/*" multiple>.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.import-wizard-encoding-and-hints (rev 6)
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.gantt-interactions rev4
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 positionPATCH {"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.form-dirty-guard rev3
?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)https://initech.example, updated_at unchanged (byte-identical); after Update: websitehttps://initech.example/saved-qa2, updated_at 15:08:20records-forms.record-discussion-mentions rev3
POST /api/v1/data/sys_comment201 id 81214553-…;GET sys_comment filter thread_id=showcase_account:L-O5F-zQM733EAA0 sort created_atreturns it with body "QA2 hello @Mei Phone (demo) please review", mentions ["usr_showcase_phone_demo"]/api/v1/notificationsunread 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 clearedqa_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 …POST sys_comment {thread_id:"qa_nofeeds:QhJUILpRyhA4nwqn"}→ 403 FEEDS_DISABLED, thread read 0 rowsrecords-forms.bulk-select-all-matching rev3
?top=50&search=QA+bulktotal=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)GET ?top=500&skip=0&search=QA+bulk→ n=55; aggregate POST/api/v1/apps/showcase/recalccarried_selectedIdslen 55 (55 unique) → 200; server flow logshowcase_recalc_estimates … selected=55 acted=55; direct API count for search = 55Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Comment 3 — untrimmed round-2 per-clause evidence (part 2 of 2).
records-forms.object-hook-lifecycle rev5
INFO [hook 'showcase_audit_task_completion'] task completed: Build homepageWARN [hook 'showcase_warn_over_budget'] project over budget: Data Platform (650000 / 600000){"error":"qa scratch abort on insert"}; filtered count 0 before and after (repeated on a fresh boot: "qa-abort-2" → 400)ERROR [hook] handler failed (onError=log; suppressing) {"hook":"qa_tolerate_update",…}record.name.startsWith('qa-fc') && int(record.name) > 0with onError:'log': POST "qa-fc-abc" → refused (row count 0), logHookConditionError: 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 generic500 {"error":"Internal server error","code":"INTERNAL_ERROR"}with[REST] Unhandled error— see suspected defectsqa_prio_10 … priority-10 ran(14:50:03.365) thenqa_prio_90 … priority-90 ran(14:50:03.383)records-forms.cascading-multilevel-and-clear rev3
{"country":"us","province":null,…}GET showcase_contact?filter=["account","=","q81MWvDmgCZEDWzE"]total 26; picked Noah Bell (chip shown); account→Contoso → Noah Bell chip cleared, candidatesfilter=["account","=","MN-nXAbtK5JcYfPU"]total 2 (Carl Fox, Cara Ito)reference_not_foundrecords-forms.field-history-tracking rev1
Updated Account "Hooli"(no per-field summary); tracked industry PATCH beside it →Industry: Technology → Finance; Discussion timeline renders the same two summariesGET sys_audit_logrequest; task detail (App wireframes) has no tablist, no "History" text, zero sys_audit_log requests/api/v1/auth/me/permissions: showcase_account apiOperations includehistory; showcase_task's do notrecords-forms.predicate-relationship-traversal rev3
{field:'_record', code:'rule_violation', message:'This account has churned — reactivate it before invoicing.'}(= authored message); filtered count 0packages/objectqlvitestsrc/engine-predicate-relationship.test.ts45/45 passed at ba4afcc (system-authority related read, accept/refuse on the real write path)records-forms.v18-semantic-defaults rev1
/api/v1/meta/view/showcase_task.default) with 66 rows: data requesttop=50, 50 tbody rows, "Rows per page 50", "Page 1 of 2", "66 records" (same on view/grid)Tier-1-pin items (round 1 NOT-RUN), every clause driven by hand — RUNNER option (a)
records-forms.related-list-server-pagination rev4
GET /data/showcase_contact?…&top=5&skip=0&filter=["account","=","S_ifFwiLdRpvXgSe"], page 2top=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 astop)top=100id set — disjoint, nothing skippedselect=id,name,status,total,issued_on— matches invoice.object.ts relatedListTitle 'Invoices' / relatedListColumns [name,status,total,issued_on]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.
records-forms.adhoc-filter-sort-builder rev3
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 excludedsort=-due_date(A→Z sentsort=due_datefirst); 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)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_progressfilter=[["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)?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 → samefilter=["priority","equals","urgent"], same 2 rowsfilter=[["status","equals","in_progress"]]— the valueless row was dropped, not sent as [title, =, '']records-forms.calendar-interactions rev2
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)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)projectquick-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-14records-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.
PATCH website=https://a-wins.exampleIf-Match 15:07:53.269Z → 200 (updated_at → 15:38:35.326Z); B's form savePATCH {"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)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)PATCH {"billing_email":"ap@globex.example","annual_revenue":43000000}with If-Match = read updated_at 15:38:39.720Z → 200; re-read shows both valuesrecords-forms.grid-personalization rev4
list-state:ADMINID:showcase_task= perView["showcase_task.grid"].columnState.widths.assignee 357 and cachegrid-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 nopinnedcolumn)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 leftrecords-forms.lookup-picker-create-new rev3
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 Zoof_lookup(Field.lookup('showcase_account') bare) zero-hit →Create new "zzqqnomatch"POST /data/showcase_business_unit {"name":"Zeta",…}→ 201 id -yOzpmpSJuL7T-vy; the parent form's Parent Unit then shows "Zeta"; parent savePOST {"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)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 serverf_user(Field.user → sys_user directory) zero-hit "zzqqnomatch" → server searchGET /data/sys_user?…&search=zzqqnomatchand popover "No records found" with NO button / create-new affordance (screenshot)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.
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"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"{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)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"Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Extracted: #24619 · records-forms.conditional-rules-grid · negative[1] (server half: paid invoice line
amount/totalwritable)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
objectstack-fleet commentedon Oct 19, 2026
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 (theExtracted:/Parked-on:lines on this record), and its partial coverage gaps and not-run handover are parked on #24579.Generated by Claude Code