Skip to content

Commit 3c2187f

Browse files
test(dogfood): pin five records-forms checklist items at the REST door (slice 2) (#26813)
<!-- claude-projects-attribution: {"github_login":"os-warren"} --> _Requested by **Warren** · [project thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8EZuqRp2sWT5mEbwB3fUdmh)_ Refs #26573 (items `action-param-widgets`, `cascading-multilevel-and-clear`, `cascading-options`, `conditional-rules-header`, `field-history-tracking`; slice 2) Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:records-forms 区按卡片顺序的下 5 个清单项,新增 5 个 dogfood 测试文件,在原样启动的 showcase 上经 REST 门断言它们的 api 条款,并把 5 项的 `automated.ref` 指向新钉测(revision 各加 1,history 引本卡)。 - 为什么改:18.2.0 Tier 1 扫描把这些 api 条款判为 PARTIAL(没有 oracle 层的钉测);钉在 HTTP 层后每次发版可直接复跑。 - 风险与回滚:只加测试和清单文字,不动产品代码、不加 CI 车道;新文件落在 dogfood 现有的 isolated 项目里。回滚即 revert 本 PR。 - 先看:`cascade-server-boundary.dogfood.test.ts`(两个 KNOWN GAP 按现状钉住:服务端哪天开始拦截就会变红,按条目自己的话应另开卡,而不是算通过);`field-history-tracking-activity.dogfood.test.ts`(未追踪字段的实测摘要是 #25787 通用框架,会写出字段标签 Website 但不写值)。 - 两分钟验证:先建依赖闭包,再 `pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/action-param-gallery-dispatch.dogfood.test.ts test/cascade-server-boundary.dogfood.test.ts test/cascade-role-gated-option.dogfood.test.ts test/invoice-conditional-rules-server.dogfood.test.ts test/field-history-tracking-activity.dogfood.test.ts`,预期 5 个文件 14 个用例全绿;`node scripts/check-platform-checklist.mjs` 预期 OK。 - 需要你做的:无,席位落地。 ## What changes Five new dogfood files, each booting the showcase as shipped through `@objectstack/verify` and driving its REST doors: | Item (rev → new) | Clauses now pinned over REST | Pin | |---|---|---| | `action-param-widgets` (4 → 5) | acceptance[2], negative[1], acceptance[3] server half | `action-param-gallery-dispatch.dogfood.test.ts`: the gallery action's body has no side effect and echoes `received`, so every refusal asserts the echo is absent (the body never ran); a bag missing only `p_text` is its own case | | `cascading-multilevel-and-clear` (8 → 9) | acceptance[2], [4], [5], negative[2] (plus negative[0]–[1] as the control) | `cascade-server-boundary.dogfood.test.ts`: the two recorded gaps pinned as they stand today | | `cascading-options` (6 → 7) | acceptance[2] persistence and server halves, acceptance[4], negative[1] | `cascade-role-gated-option.dogfood.test.ts`: a member graded `admin` (positions read back with `org_admin`) vs a plain member | | `conditional-rules-header` (5 → 6) | acceptance[1], acceptance[2] server half, acceptance[5] API half, negative[0]–[1] | `invoice-conditional-rules-server.dogfood.test.ts`: requiredWhen refusal and readonlyWhen strip on seeded `INV-1003` | | `field-history-tracking` (7 → 8) | acceptance[0], [1], [3], negative[0], [2] | `field-history-tracking-activity.dogfood.test.ts`: the sys_activity summary rows and `GET /auth/me/permissions` | Each item's `automated.ref` keeps the pins it already named and adds the new one with what it scores. One history row per item, citing #26573. No clause text, fixture, step or `knownGaps` line was edited (the claim's file surface). **Skipped, by the slice-2 order:** - `record-discussion-mentions`: waits on #26625 (the walled two-organization recipe). - `adhoc-filter-sort-builder`: next in card order, but every clause is a network/dom oracle; it needs Playwright, and the ruling adds no lane. - Browser legs inside the five items, left unpinned: `action-param-widgets` acceptance[0], [1], acceptance[3] dialog half, negative[0]; `cascading-multilevel-and-clear` acceptance[0], [3]; `cascading-options` acceptance[0], [3] and acceptance[2]'s "sees" half; `conditional-rules-header` acceptance[0], [2] client lock, [3], [4], negative[2]; `field-history-tracking` acceptance[2], negative[1]. `cascading-*` acceptance[1] stays on the objectui live spec and `field-history-tracking` acceptance[4] on its unit pin. ## Why The 18.2.0 release-candidate Tier 1 run scored these api clauses PARTIAL: no pin asserted them at the oracle's layer, so each sweep drove them by hand. The triage ruling allows ~5-item slices and no new CI lane; the new files fall under the dogfood package's existing `isolated` vitest project and run where the dogfood legs run today. ## Tests Measured answers the pins now hold (all first read live, then pinned exactly): - gallery dispatch: the conformant bag → `200` with the body's `received` echo; out-of-set `p_priority` + undeclared `bogus` → `400` naming both, no echo; only `p_text` missing → `400` naming `p_text`, no echo. - cascade: create `{cn, zj}` then PATCH `{country:'us'}` → `200`, re-read holds `province: 'zj'`; the same pair in the payload → `400` `province` / `invalid_option`. Invoice on Contoso with an existing Northwind contact → `201`, stored as sent; a fabricated contact → `400` `contact` / `reference_not_found`, nothing stored. - role gate: the graded member's `tier: 'restricted'` → `201`, re-reads; the plain member's → `400 VALIDATION_FAILED` `tier` / `invalid_option`, nothing stored; `tier: 'standard'` → `201`. - invoice: `status: 'sent'` without `issued_on` → `400` with exactly `[issued_on, required]`, nothing stored; draft and dated-sent → `201`. PATCH `tax_rate: 99` on paid `INV-1003` → `200`, re-read unchanged; the same PATCH on a draft persists. - history: PATCH industry retail → finance lands `summary: 'Industry: Retail → Finance'` (message key `fieldChanges`); a website-only PATCH lands `Updated Account (Success Overlay) "<name>": Website` (key `activityUpdatedFields`, no arrow, neither URL). `/auth/me/permissions` → `objects.showcase_account.apiOperations` contains `history`; `showcase_task`'s contains `get`, not `history`. <details><summary>Runs</summary> - Dependency closure on `8b276385` (the restarted branch): `pnpm exec turbo run build --filter='@objectstack/dogfood^...' --concurrency=2` under `os-verify-lock.sh`, held 8m34s. - First run of the five files: `Tests 11 passed | 3 failed (14)`, all three in the history file: `Object 'sys_activity' not found` (the showcase boot composes no audit plugin) and `apiOperations` read from the wrong key. Fixed by adding `AuditPlugin` and reading `objects.<name>.apiOperations`; the untracked-edit case was then re-pinned to the measured #25787 generic frame. - Commit head: the five files → `Test Files 5 passed (5)`, `Tests 14 passed (14)`; `pnpm typecheck` in `packages/qa/dogfood` (`tsc --noEmit`) → exit 0. - Final head `efe6101e` (after merging `origin/main` `c8583f80`, which brought #26797 and #26796: dogfood tests, the access-security area file and create-objectstack, none in this diff's pins' closure): the five files → `Test Files 5 passed (5)`, `Tests 14 passed (14)`, then the dogfood typecheck, one locked command, VERDICT command-exit 0. </details> No ablation was run: this diff adds tests and changes no behaviour they pin. Each refusal assertion has a same-door admitted control beside it, so none passes on a door that refuses everything. ## Acceptance notes - `field-history-tracking`: the showcase boot composes no audit plugin, so this file adds `AuditPlugin` the way `objectstack serve` composes it (as `activity-withheld-update.dogfood.test.ts` does). acceptance[1] says "no field-diff summary naming website"; the measured row is the #25787 generic frame, which names the changed field's label and never its values, so the pin asserts no old → new for website. The clause text was not reworded (outside the claim's surface). - `cascading-multilevel-and-clear` acceptance[2] and [4] are KNOWN GAP clauses: the pins assert today's 200/201, so new server enforcement turns them red, which by the item's own text is new enforcement to file, not a pass. - `cascading-options` acceptance[2]: the seeded admin is `org_owner`, which does not imply `org_admin`, so the admin persona is a signed-up member whose `sys_member` row is graded `admin`, read back from the resolved positions before any write. ## Verification - `node scripts/check-platform-checklist.mjs` → exit 0, `OK — 16 areas, 329 items (324 active, 1 planned)`, on the commit head and again on the final head. - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` → 55 commands on the tree of this PR's commit `38c2de88` (run before a message-only reword), each run and reconciled with `--ran`: `55 derived famil(ies) accounted for — 55 run, 0 NOT-MEASURED`, all exit 0. - CI families are read from this PR's check-runs, not re-run locally. `Dogfood Regression Gate` does not run on pull_request, so the local runs above are this PR's evidence for the new pins. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. (CI-owned run) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset — nothing publishes here (`@objectstack/dogfood` is private; `docs/qa/**` ships in no package), so `skip-changeset`; both declaration lines are filled in above. - [x] 6. `packages/spec` not touched. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the maintainer brief above is Chinese by the repo's communication rule). --- _Generated by [Claude Code](https://claude.ai/code/session_01JQwxbZ3oTCkvGGTMNd5XYU)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent f1cd529 commit 3c2187f

6 files changed

Lines changed: 521 additions & 10 deletions

‎docs/qa/platform-checklist/areas/records-forms.json‎

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@
848848
"title": "Header-level conditional rules: visibleWhen / requiredWhen / readonlyWhen on invoice fields, enforced on BOTH ends",
849849
"since": "v16",
850850
"status": "active",
851-
"revision": 5,
851+
"revision": 6,
852852
"priority": "P1",
853853
"surface": "mixed",
854854
"personas": [
@@ -924,7 +924,7 @@
924924
],
925925
"automated": {
926926
"kind": "e2e",
927-
"ref": "objectui: e2e/live/required-when-submit.spec.ts (acceptance[0]: a requiredWhen-required Issued On blocks submit with its field error) + e2e/live/field-conditional-rules.spec.ts (acceptance[0]'s required marker and acceptance[3], on the New Invoice dialog as Status flips: Issued On's required marker, and paid_on mounted, and required, only at paid). Neither pins acceptance[2]'s client lock: on that New dialog the spec asserts the OPPOSITE at paid, tax_rate enabled and no read-only field group, because the server exempts INSERT from readonlyWhen and the create form follows it (objectui#13436); the lock lives on an edit form of a paid invoice, which no pin drives. Both read the DOM through Playwright locators with no screenshot step: their wait for visibility is what stands in for the render-first order acceptance[0] and [3]'s dom oracle asks for, so a run citing them says so. No pin covers acceptance[1], [2], [4] or [5]; the row-action spec cited here until revision 3 was dropped (history, revision 3)"
927+
"ref": "objectui: e2e/live/required-when-submit.spec.ts (acceptance[0]: a requiredWhen-required Issued On blocks submit with its field error) + e2e/live/field-conditional-rules.spec.ts (acceptance[0]'s required marker and acceptance[3], on the New Invoice dialog as Status flips: Issued On's required marker, and paid_on mounted, and required, only at paid). Neither pins acceptance[2]'s client lock: on that New dialog the spec asserts the OPPOSITE at paid, tax_rate enabled and no read-only field group, because the server exempts INSERT from readonlyWhen and the create form follows it (objectui#13436); the lock lives on an edit form of a paid invoice, which no pin drives. Both read the DOM through Playwright locators with no screenshot step: their wait for visibility is what stands in for the render-first order acceptance[0] and [3]'s dom oracle asks for, so a run citing them says so. packages/qa/dogfood/test/invoice-conditional-rules-server.dogfood.test.ts, at the REST data door of the showcase as shipped, pins acceptance[1] and negative[0] (a sent invoice with no issued_on is 400 VALIDATION_FAILED with exactly issued_on required and nothing is stored; the draft twin and a dated sent invoice are 201), acceptance[2]'s server half and negative[1] (a tax_rate PATCH on the seeded paid INV-1003 answers 200 and the re-read is unchanged; the same PATCH on a draft persists) and acceptance[5]'s API half. No pin covers acceptance[2]'s client lock, acceptance[4] or negative[2]; the row-action spec cited here until revision 3 was dropped (history, revision 3)"
928928
},
929929
"source": [
930930
"examples/app-showcase/src/data/objects/invoice.object.ts#userActions (the B2 rules + userActions gating, with server-semantics comments)",
@@ -961,6 +961,12 @@
961961
"date": "2026-10-26",
962962
"change": "automated.ref, from Tier 1 run #25815 (6679644a, pin b41ed7f68956), re-read at ui/e2e/live/field-conditional-rules.spec.ts on main cc378e93. (1) It claimed the spec pins acceptance[2]'s client lock; at paid on the New dialog the spec asserts tax_rate enabled and no read-only group, since INSERT is exempt from readonlyWhen (objectui#13436), and no pin drives an edit form of a paid invoice, so acceptance[2] joins the unpinned list. (2) It says both pins read the DOM by Playwright locator with no screenshot step. (3) It no longer names the row-action spec dropped at revision 3, which a ref parser read as a pin. fixtures.knownGaps[0], the objectui-pinned-automation note, said the objectui specs live in a separate repo and none exist here; they are under ui/ in this checkout since the import, so it says where they resolve and how they run (devx seat 2's direction, carried for #26035). Re-read on main cc378e93. No clause changed",
963963
"ref": "#25846"
964+
},
965+
{
966+
"revision": 6,
967+
"date": "2026-10-27",
968+
"change": "automated.ref names the dogfood pin for acceptance[1], acceptance[2]'s server half, acceptance[5]'s API half and negative[0]–[1] at the REST data door (#26573 slice 2). The client lock, acceptance[4] and negative[2] stay browser legs. No clause changed",
969+
"ref": "#26573"
964970
}
965971
]
966972
},
@@ -1105,7 +1111,7 @@
11051111
"title": "Cascading and gated select options: dependsOn + per-option visibleWhen, client narrows / server rejects",
11061112
"since": "v16",
11071113
"status": "active",
1108-
"revision": 6,
1114+
"revision": 7,
11091115
"priority": "P1",
11101116
"surface": "mixed",
11111117
"personas": [
@@ -1175,7 +1181,7 @@
11751181
],
11761182
"automated": {
11771183
"kind": "e2e",
1178-
"ref": "objectui: e2e/live/cascading-options.spec.ts — its re-filter case pins acceptance[0]'s re-filter and clear halves ONLY (on the New form, country cn offers gd and zj, us offers ca and tx, and the chosen Zhejiang leaves the province trigger). It never reads the province before a country is chosen, so 'gates the dependent field until its driver has a value' is driven by hand. Its server case pins acceptance[1] (the out-of-set POST answers 400 VALIDATION_FAILED naming province with invalid_option, the in-set one 201). No pin covers acceptance[2], [3] or [4]"
1184+
"ref": "objectui: e2e/live/cascading-options.spec.ts — its re-filter case pins acceptance[0]'s re-filter and clear halves ONLY (on the New form, country cn offers gd and zj, us offers ca and tx, and the chosen Zhejiang leaves the province trigger). It never reads the province before a country is chosen, so 'gates the dependent field until its driver has a value' is driven by hand. Its server case pins acceptance[1] (the out-of-set POST answers 400 VALIDATION_FAILED naming province with invalid_option, the in-set one 201). packages/qa/dogfood/test/cascade-role-gated-option.dogfood.test.ts, at the REST data door of the showcase as shipped, pins acceptance[2]'s persistence and server halves and negative[1]: a signed-up member graded admin (positions read back with org_admin) stores tier restricted and it re-reads; a plain member (no org_admin) is 400 VALIDATION_FAILED naming tier with invalid_option, nothing stored, and stores tier standard as the control. It also pins acceptance[4] (cn/zj re-reads verbatim over GET). acceptance[2]'s 'sees' half (the picker) and acceptance[3] stay browser legs"
11791185
},
11801186
"source": [
11811187
"examples/app-showcase/src/data/objects/cascading-select.object.ts (the B3 / #1583 fixture, with both-sides contract in its header comment)",
@@ -1218,6 +1224,12 @@
12181224
"date": "2026-10-26",
12191225
"change": "acceptance[1].verify says its pin is a Playwright live spec (Tier 1 run #25815 (6679644a, pin b41ed7f68956)): it scores acceptance[1] and negative[0] only when the run executes it against a booted showcase. fixtures.knownGaps[0], the objectui-pinned-automation note, said the objectui specs live in a separate repo and none exist here; they are under ui/ in this checkout since the import, so it says where they resolve and how they run (devx seat 2's direction, carried for #26035). Re-read on main cc378e93. No clause changed",
12201226
"ref": "#25846"
1227+
},
1228+
{
1229+
"revision": 7,
1230+
"date": "2026-10-27",
1231+
"change": "automated.ref names the dogfood pin for acceptance[2]'s server and persistence halves, acceptance[4] and negative[1] at the REST data door (#26573 slice 2). The org_admin persona is a signed-up member whose membership is graded admin, read back from the resolved positions; the seeded admin is org_owner and does not hold org_admin. No clause changed",
1232+
"ref": "#26573"
12211233
}
12221234
]
12231235
},
@@ -1506,7 +1518,7 @@
15061518
"title": "Action params render their real widgets, and the param contract is enforced at dispatch",
15071519
"since": "v16",
15081520
"status": "active",
1509-
"revision": 4,
1521+
"revision": 5,
15101522
"priority": "P1",
15111523
"surface": "mixed",
15121524
"personas": [
@@ -1575,7 +1587,7 @@
15751587
],
15761588
"automated": {
15771589
"kind": "api",
1578-
"ref": "packages/qa/dogfood/test/action-params-contract.dogfood.test.ts — acceptance[2] ONLY (a malformed param bag is refused before the action body runs; the conformant bag passes). No pin covers acceptance[0], [1] or [3]. The objectui spec cited here until revision 3 asserts none of the gallery action's param widgets and was dropped (history, revision 3); it is not a pin of this item"
1590+
"ref": "packages/qa/dogfood/test/action-params-contract.dogfood.test.ts (the refusal status of a three-way malformed bag) + packages/qa/dogfood/test/action-param-gallery-dispatch.dogfood.test.ts, at POST /api/v1/actions/showcase_field_zoo/showcase_action_param_gallery of the showcase as shipped: acceptance[2] and negative[1] (the conformant bag answers 200 with the body's received echo naming p_text and p_priority; a bag with an out-of-set p_priority and an undeclared key is 400, names both, and carries no received echo, so the body never ran) and acceptance[3]'s server half (a bag missing only the required p_text is 400 naming p_text, with no echo). No pin covers acceptance[0], [1], acceptance[3]'s dialog half or negative[0]; they are browser legs. The objectui spec cited here until revision 3 was dropped (history, revision 3)"
15791591
},
15801592
"source": [
15811593
"#3358 §4 (evidence table)",
@@ -1607,6 +1619,12 @@
16071619
"date": "2026-10-26",
16081620
"change": "automated.ref no longer names the objectui spec it dropped at revision 3. A ref parser read that path as a pin (Tier 1 run #25815 (6679644a, pin b41ed7f68956)), and it scores nothing here. The drop and its reason stay in history revision 3. What the ref pins is unchanged",
16091621
"ref": "#25846"
1622+
},
1623+
{
1624+
"revision": 5,
1625+
"date": "2026-10-27",
1626+
"change": "automated.ref names the dogfood pin that reads whether the action body ran (#26573 slice 2): acceptance[2] and negative[1] now assert the refusal carries no received echo, and acceptance[3]'s server half is pinned by a bag whose only fault is the missing p_text. The dialog half and the dom clauses stay unpinned. No clause changed",
1627+
"ref": "#26573"
16101628
}
16111629
]
16121630
},
@@ -4038,7 +4056,7 @@
40384056
"title": "Cascade clear-semantics and the server boundary: stale-child clear on parent change, the WRITTEN-value server gate, and where cascade scope is client-only",
40394057
"since": "v16",
40404058
"status": "active",
4041-
"revision": 8,
4059+
"revision": 9,
40424060
"priority": "P1",
40434061
"surface": "mixed",
40444062
"personas": [
@@ -4116,7 +4134,7 @@
41164134
],
41174135
"automated": {
41184136
"kind": "e2e",
4119-
"ref": "objectui: e2e/live/cascading-options.spec.ts (acceptance[0]'s client clear-on-change, through its re-filter case: country cn offers gd and zj, us offers ca and tx, and the chosen Zhejiang leaves the province trigger. It never submits, so 'the stale province is not carried into the submit' is driven by hand. Its second case, 'the server rejects an out-of-set option value, and accepts an in-set one', is acceptance[1] at the HTTP door: it POSTs {country:'us', province:'zj'} to the live backend and asserts 400 VALIDATION_FAILED with an invalid_option field on province, then {country:'cn', province:'zj'} and asserts 201)"
4137+
"ref": "objectui: e2e/live/cascading-options.spec.ts (acceptance[0]'s client clear-on-change, through its re-filter case: country cn offers gd and zj, us offers ca and tx, and the chosen Zhejiang leaves the province trigger. It never submits, so 'the stale province is not carried into the submit' is driven by hand. Its second case, 'the server rejects an out-of-set option value, and accepts an in-set one', is acceptance[1] at the HTTP door: it POSTs {country:'us', province:'zj'} to the live backend and asserts 400 VALIDATION_FAILED with an invalid_option field on province, then {country:'cn', province:'zj'} and asserts 201). packages/qa/dogfood/test/cascade-server-boundary.dogfood.test.ts, at the REST data door of the showcase as shipped, pins the two recorded gaps as they stand, so the day the server starts enforcing either one it goes red: acceptance[2] and negative[2] (create {cn, zj}, PATCH {country:'us'} answers 200 and the re-read still holds province zj; the same stale child IN the payload is the 400 invalid_option control, negative[0] and [1]), acceptance[4] and negative[2] (an invoice on Contoso naming an existing Northwind contact is 201 and stored as sent; a fabricated contact id is 400 reference_not_found and nothing is stored) and acceptance[5] (cn/zj and Northwind with a Northwind contact re-read verbatim). No pin covers acceptance[3], a browser leg"
41204138
},
41214139
"source": [
41224140
"packages/objectql/src/validation/rule-validator.ts#evaluateOptionVisibility (evaluateOptionVisibility — WRITTEN-value only via `!(name in data) continue`; a predicate that cannot be evaluated refuses the write as rule_violation / unevaluable (ADR-0137 D2), except a system write with no acting user whose predicate reads one; invalid_option/option_unavailable)",
@@ -4174,6 +4192,12 @@
41744192
"date": "2026-10-26",
41754193
"change": "From Tier 1 run #25815 (6679644a, pin b41ed7f68956), re-read at ui/e2e/live/cascading-options.spec.ts on main cc378e93. (1) acceptance[1].verify expected 200 for the in-set write; it is a create and answers 201. The verify now also says the pin drives {country:'us', province:'zj'} rather than its cn/ca vector and asserts the invalid_option code alone, so the option_unavailable message key is the run's. (2) automated.ref no longer lists rule-validator.option-visibility.test.ts, which by its own words scores no clause (validator layer); acceptance[1].verify still names it, and acceptance[2].verify now does, as validator-layer evidence. No clause changed",
41764194
"ref": "#25846"
4195+
},
4196+
{
4197+
"revision": 9,
4198+
"date": "2026-10-27",
4199+
"change": "automated.ref names the dogfood pin for acceptance[2], [4], [5] and negative[2] at the REST data door (#26573 slice 2). The two KNOWN GAP clauses are pinned as recorded, 201/200 today, so new server enforcement turns them red to be filed rather than read as a pass. acceptance[0] and [1] keep the objectui pin; acceptance[3] stays a browser leg. No clause changed",
4200+
"ref": "#26573"
41774201
}
41784202
]
41794203
},
@@ -4816,7 +4840,7 @@
48164840
"title": "Per-field trackHistory: a tracked edit lands the ADR-0052 §5b old→new timeline summary with display values, an untracked edit does not, and object-level enable.trackHistory gates the History tab and derived history op both ways",
48174841
"since": "v15",
48184842
"status": "active",
4819-
"revision": 7,
4843+
"revision": 8,
48204844
"priority": "P1",
48214845
"surface": "mixed",
48224846
"personas": [
@@ -4883,7 +4907,7 @@
48834907
],
48844908
"automated": {
48854909
"kind": "unit",
4886-
"ref": "packages/plugins/plugin-audit/src/audit-lookup-summary.test.ts (reference titles + read plan); audit-option-label-summary.test.ts (option labels); objectui e2e/live/record-history-display.spec.ts (the History tab's display contract, which negative[3] assigns to records-forms.crud-roundtrip. It opens showcase_account's History tab in a browser, the enable.trackHistory object, so it holds acceptance[2]'s flag-true half; it never reads the task detail, so the absence half has no pin and is driven by hand)"
4910+
"ref": "packages/plugins/plugin-audit/src/audit-lookup-summary.test.ts (reference titles + read plan); audit-option-label-summary.test.ts (option labels); objectui e2e/live/record-history-display.spec.ts (the History tab's display contract, which negative[3] assigns to records-forms.crud-roundtrip. It opens showcase_account's History tab in a browser, the enable.trackHistory object, so it holds acceptance[2]'s flag-true half; it never reads the task detail, so the absence half has no pin and is driven by hand). packages/qa/dogfood/test/field-history-tracking-activity.dogfood.test.ts, at the REST doors of the showcase with AuditPlugin added as objectstack serve composes it: acceptance[0] and negative[2] (PATCH industry retail → finance lands a sys_activity row whose summary is exactly 'Industry: Retail → Finance', message key fieldChanges), acceptance[1] and negative[0] (a website-only PATCH lands the generic frame naming the Website label with no arrow and neither URL, message key activityUpdatedFields) and acceptance[3] (GET /api/v1/auth/me/permissions: showcase_account's apiOperations carry history, showcase_task's carry get and not history). acceptance[4] stays the unit pin's"
48874911
},
48884912
"source": [
48894913
"packages/plugins/plugin-audit/src/audit-writers.ts#planTrackedLookupReads (planTrackedLookupReads), (renderTrackedChangeSummary — ADR-0052 §5b, #7230/#7289 localization), (zero-reads-by-default plan)",
@@ -4933,6 +4957,12 @@
49334957
"date": "2026-10-26",
49344958
"change": "automated.ref: record-history-display.spec.ts does hold acceptance[2]'s flag-true half, since it opens showcase_account's History tab in a browser; only the task-detail absence half is unpinned (Tier 1 run #25815 (6679644a, pin b41ed7f68956); re-read at ui/e2e/live/record-history-display.spec.ts on main cc378e93). No clause changed",
49354959
"ref": "#25846"
4960+
},
4961+
{
4962+
"revision": 8,
4963+
"date": "2026-10-27",
4964+
"change": "automated.ref names the dogfood pin for acceptance[0], [1], [3] and negative[0], [2] over REST (#26573 slice 2). Measured: the untracked edit's row is the #25787 generic frame, which names the changed field's label and never its values, so acceptance[1]'s 'no field-diff summary naming website' holds as 'no old → new for website'. acceptance[2]'s absence half and negative[1] stay browser legs. No clause changed",
4965+
"ref": "#26573"
49364966
}
49374967
]
49384968
},

0 commit comments

Comments
 (0)