Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions docs/qa/platform-checklist/areas/records-forms.json
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
"title": "Create → read → update → delete a record through the console UI",
"since": "v15",
"status": "active",
"revision": 15,
"revision": 16,
"priority": "P0",
"surface": "browser",
"personas": [
Expand All @@ -213,7 +213,7 @@
"capture the create request/response (expect POST /api/v1/data/showcase_account). The payload also carries the select defaults of fields the step leaves untouched — sales_region:'amer' (its AMER option is default:true, examples/app-showcase/src/data/objects/account.object.ts) — so expect that key in the body you diff (QA run #24556)",
"re-read server-side: GET /api/v1/data/showcase_account?$filter=[[\"name\",\"=\",\"os-qa-<runid>\"]] — field-by-field vs the submitted payload",
"open the record detail; edit exactly one field (annual_revenue); submit it (an edit form's button reads 'Update'); capture the PATCH /api/v1/data/showcase_account/<id>; re-read the full row via GET /api/v1/data/showcase_account/<id>",
"open the record's History tab (screenshot first, then read entries)",
"read the record's field-change history on the record page's timeline stream, under its Changes chip (变更). Record page v3 draws no tab named History at any width (#27055). Where the stream sits depends on the record view's width (ui/packages/plugin-detail/src/synth/recordPageColumns.ts#recordPageTierFor), the window minus the console sidebar: at 760 px and wider it is resident (the Timeline column, or, while the reader's timeline switch is off, the Activity card at the foot of the related column); narrower, it is the Timeline tab. A 1440×900 window is a column tier whatever the sidebar does. Screenshot first, then read the change lines",
"clone the record: POST /api/v1/data/showcase_account/<id>/clone (optionally with {overrides:{name:'os-qa-<runid>-clone'}}); capture the 201 result (new id ≠ source, sourceId, record); re-read the clone via GET /api/v1/data/showcase_account/<new id>",
"RLS probe on clone: as a persona WITHOUT read on the source row (a permission-zoo persona, or a non-owner under owner-RLS), POST the same clone route and capture the refusal — expect 404 RECORD_NOT_FOUND, never a silent duplicate (record blocked(fixture) if no non-reading persona is bound on this boot)",
"delete via the row/detail action; confirm the dialog; re-read via the filtered GET. ⚠️ If clause 7's recipe gave the member an own-row invoice pointing at THIS account, the delete answers 409 DELETE_RESTRICTED: the invoice's account lookup is required, and the engine turns a required set_null into restrict (packages/objectql/src/engine.ts). Point that invoice at a seeded account instead (the recipe's step 5 says so)",
Expand Down Expand Up @@ -245,9 +245,9 @@
"evidence": "screenshots"
},
{
"clause": "record History reflects the create and the update with display values (option labels, localized dates, real actor), not raw audit payloads or phantom value→null rows",
"clause": "the record's field-change history (the record page's sys_audit_log read, shown as the timeline stream's Changes chip) reflects the create and the update with display values (option labels, localized dates, real actor), not raw audit payloads or phantom value→null rows",
"oracle": "dom",
"verify": "after a screenshot confirms the History tab rendered, read its entries — same contract ui/e2e/live/record-history-display.spec.ts pins on showcase_account, the showcase's enable.trackHistory object (its option labels, the localized Customer Since date and the resolved owner); it is a live Playwright spec in this checkout, run from ui/ with `pnpm test:e2e:live` against a backend on port 3000 and the console dev server on port 5180",
"verify": "after a screenshot confirms the Changes chip is selected on the account's timeline stream (steps[5]), read its change lines — same contract ui/e2e/live/record-history-display.spec.ts pins on showcase_account, the showcase's enable.trackHistory object, at 1440×900 (its option labels, the localized Customer Since date and the resolved owner). The page reads sys_audit_log only for an object whose enable.trackHistory is true (ui/packages/app-shell/src/views/RecordDetailView.tsx, historyEnabled), and the rows reach the stream as field_change items (ui/packages/plugin-detail/src/recordTimelineStream.ts#auditEntriesToFeedItems). The chip also lists the stream's sys_activity created/updated rows, so attribute a line to the audit read before scoring it. ⛔ Never look for a tab named History: record page v3 removed it at every width (#27055; buildDefaultPageSchema.test.ts asserts the default tabs carry neither Activity nor History), so its absence fails a working product. The spec is a live Playwright spec in this checkout, run from ui/ with `pnpm test:e2e:live` against a backend on port 3000 and the console dev server on port 5180",
"evidence": "screenshot + entries"
},
{
Expand Down Expand Up @@ -373,6 +373,12 @@
"date": "2026-10-28",
"change": "steps[0], steps[1], steps[4], acceptance[4].verify and one source line corrected. Checklist-accuracy findings of the 18.2.0 wave 2 (QA run #26481, priority:P0, at 756220c4; wave anchor #25807, slice B): the Accounts entry sits in the Data Model group, which the runner found collapsed; the form buttons read 'Create' and 'Update', not 'Save'; and acceptance[4].verify still cited the retired console pin cf153eb2e535 and an objectui blob, while the spec lives in this checkout at ui/e2e/live/record-history-display.spec.ts. Re-read at base fd246c22: examples/app-showcase/src/ui/apps/index.ts (grp_data 'Data Model', nav_accounts), ui/packages/plugin-form/src/ModalForm.tsx and DrawerForm.tsx (form.create 'Create', form.update 'Update'), ui/playwright.live.config.ts. No clause's assertion changed",
"ref": "#25807"
},
{
"revision": 16,
"date": "2026-10-29",
"change": "steps[5] and acceptance[4] (clause and verify) re-pointed from the History tab to the record page v3 surface, the same shape records-forms.field-history-tracking took at its revision 10 (#27492). Record page v3 (#27055) removed the History tab at every width, so a runner following the old step found no tab and scored a working product red or blocked. The step now reads the account's sys_audit_log field-change history under the timeline stream's Changes chip, located by width tier (recordPageTierFor), and the verify names the gate (RecordDetailView historyEnabled), the stream mapping (auditEntriesToFeedItems), the sys_activity rows the chip also lists, and the 1440×900 viewport the re-pointed live spec record-history-display.spec.ts uses. The clause's contract (display values, real actor, no raw payloads) is unchanged; no run verdict on it is invalidated beyond the surface it is read on",
"ref": "#27654"
}
]
},
Expand Down Expand Up @@ -3699,7 +3705,7 @@
"title": "Record edit undo: toast Undo / Ctrl+Z restores the prior value through the API and logs a revert; undo after a concurrent change must not silently clobber",
"since": "v16",
"status": "active",
"revision": 5,
"revision": 6,
"priority": "P2",
"surface": "browser",
"personas": [
Expand All @@ -3719,7 +3725,7 @@
"steps": [
"open a record; run the packaged undoable action (fixtures.requires[0]) on it; confirm the success toast shows an Undo button. An inline edit offers none by design",
"click Undo (or press Ctrl+Z); capture the resulting update; re-read the record over the API and confirm the prior value is restored",
"open the History/audit and confirm a revert entry was added (a forward write, not a silent rollback)",
"read the record's field-change history on the record page's timeline stream, under its Changes chip (变更). Record page v3 draws no tab named History at any width (#27055). Where the stream sits depends on the record view's width (ui/packages/plugin-detail/src/synth/recordPageColumns.ts#recordPageTierFor), the window minus the console sidebar: at 760 px and wider it is resident (the Timeline column, or, while the reader's timeline switch is off, the Activity card at the foot of the related column); narrower, it is the Timeline tab. A 1440×900 window is a column tier whatever the sidebar does. Also read sys_audit_log for the record over the API, and confirm a revert entry was added (a forward write, not a silent rollback)",
"press Ctrl+Shift+Z (redo); confirm the edited value is restored",
"CONCURRENT-CLOBBER probe: in session A make the undoable edit; in session B change the SAME field and save; back in A, click Undo",
"observe and FLAG whether A's undo carries an OCC guard or silently overwrites B's value"
Expand All @@ -3738,10 +3744,10 @@
"evidence": "screenshots of both paths"
},
{
"clause": "the revert is auditable: the History/audit gains a NEW entry for the undo (undo is a forward write, not a hidden state reset)",
"clause": "the revert is auditable: sys_audit_log gains a NEW entry for the undo (undo is a forward write, not a hidden state reset)",
"oracle": "api",
"verify": "after screenshot of the History tab, the audit/read shows the revert as its own update",
"evidence": "the History entries + audit read"
"verify": "the sys_audit_log read for the record shows the revert as its own update; screenshot the timeline stream's Changes chip showing it as a change line when the object's enable.trackHistory is true (the page reads sys_audit_log only then — ui/packages/app-shell/src/views/RecordDetailView.tsx, historyEnabled). ⛔ Never look for a tab named History: record page v3 removed it at every width (#27055), so its absence fails a working product",
"evidence": "the audit read + the Changes chip screenshot"
},
{
"clause": "CONCURRENT-CLOBBER (observe + flag): the undo path issues a bare dataSource.update with NO ifMatch, so an undo after a concurrent edit landed in between will overwrite it — verify the observed behavior and record a silent clobber as a finding, not a silent pass",
Expand Down Expand Up @@ -3798,6 +3804,12 @@
"date": "2026-10-28",
"change": "BLOCKED premise re-checked and kept (lead from slice B's report 6457925443). At base f2fdac5d, examples/ declares zero `undoable` keys and no packaged action in packages/ declares undoable: true, so the showcase still ships no undoable action; inline edits still push no Undo op (ActionRunner pushes only an action result's undo). fixtures.requires[0] says the reading is current on main, and knownGaps[1] records the re-check and the two undoable shapes the spec now accepts (operation 'update' with a patch, or type 'api'), either of which can be the lifting fixture. `blocked` unchanged. Wave anchor #25807, slice C. No clause changed",
"ref": "#25807"
},
{
"revision": 6,
"date": "2026-10-29",
"change": "steps[2] and acceptance[2] (clause, verify, evidence) re-pointed from the History tab to the record page v3 surface, the same shape records-forms.field-history-tracking took at its revision 10 (#27492). Record page v3 (#27055) removed the History tab at every width. The revert's oracle is now the record's sys_audit_log read over the API, with the timeline stream's Changes chip (located by width tier, recordPageTierFor) as the screenshot when the object tracks history. The clause's contract (the undo is a forward, audited write) is unchanged, and the item stays blocked(fixture)",
"ref": "#27654"
}
]
},
Expand Down
13 changes: 8 additions & 5 deletions examples/app-showcase/src/data/objects/account.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ export const Account = ObjectSchema.create({
// every surface, no per-page config.
highlightFields: ['status', 'industry', 'annual_revenue'],

// Show the record **History tab** (audit-trail UI). The console gates the tab
// on object-level `enable.trackHistory` (RecordDetailView) — audit *capture*
// is always on, but the tab is opt-in — so without this the tab never renders
// and the feature is undemonstrable. Paired with the per-field `trackHistory`
// on `industry` / `status` below so those changes get summarized diffs
// Show the record's field-change history (audit-trail UI). The console reads
// `sys_audit_log` for the record page only on object-level
// `enable.trackHistory` (RecordDetailView) and lists the rows as change lines
// under the timeline stream's Changes chip (record page v3 draws no tab
// named History). Audit *capture* is always on, but the display is opt-in,
// so without this the feature is undemonstrable. Paired with the per-field
// `trackHistory` on `industry` / `status` below so those changes get
// summarized diffs
// (display values, not raw ids; computed fields excluded — #2691/#3293).
enable: { trackHistory: true },

Expand Down
Loading