You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
delete confirmation does not name the record and confirms with a neutral "Continue" — the destructive alert-dialog variant is not used #11695
Filing gate: ① user-visible UX defect on a destructive action — reach: row delete on any object list, measured; separate card under the maintainer's quota exception (provenance below).
Reader: objectui triage first-touch → domain:ui lane (packages/plugin-view, packages/corerecordDelete); one PR.
Dedup (semantic search, open + closed, objectui): "delete confirmation dialog does not name the record, generic Confirm Action Continue button not destructive" → 9 hits, all closed; objectui#8978 added the destructive (red) confirm button to alert-dialog, objectui#11001 moved the detail-page delete onto the in-app dialog; none covers this dialog's copy or button.
Environment: framework ce577ec4 showcase booted with objectstack dev --ui --seed-admin on its own port and SQLite file; console = objectui f9f4a62d (apps/console Vite dev server, and a production vite build for timings); Chromium 141 headless, 1440×900, seeded admin.
Repro
Showcase → Data Model → Products → a row's "⋮" menu → Delete.
Actual dialog: title "Confirm Action", body "Are you sure you want to delete this record?", buttons "Cancel" / "Continue" — the confirming button is the default (primary) style, not destructive, and nothing names which record (here "QA Widget 0") or that the action is a delete.
Clicking "Continue" deletes the row (verified via GET /api/v1/data/showcase_product).
Where
packages/plugin-view/src/ObjectView.tsx — deleteConfirmDialog: title actionConfirm.title ("Confirm Action"), confirm actionConfirm.confirm ("Continue"), body recordDelete.confirmText(…, deleteRequest?.records[0]) (packages/core/src/actions/recordDelete.ts) — the record is in hand but its name is not used. The detail page's delete reads the same generic text (packages/app-shell/src/views/RecordDetailView.tsx).
Expected
A delete confirm says what is deleted ("Delete Product "QA Widget 0"?", bulk: "Delete 3 Tasks?") and confirms with a destructive-styled "Delete" button.
Provenance: filed as a separate card on the maintainer's explicit instruction in the dispatching session, which lifts the per-fire filing quota for this batch of seven, verbatim — 「重新思考以上和用户体验相关的问题,哪些需要立卡」 then 「分开立 7 张」. Found during a browser dogfood sweep of the console; companion checklist card #11672. Filed by session session_01WEARdKfDHDT7rTuEhLyT1k.
Path: ② the capabilities an end user meets in the app — record pages | 缺项 | P2
Triage: first grade — enhancement · priority:p3 · domain:ui · area:records · pm:queue. The delete confirmation names the record and confirms with a destructive, explicit action
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T06:59Z. ⛔ Not a claim, ⛔ not a dispatch. Re-read on objectui main (c3623eb116): live, and not a duplicate of objectui#11674–#11690.
Triage: lands in packages/plugin-view/src/ObjectView.tsx (about :3132 and :3164), packages/plugin-detail/src/RecordDetailView.tsx (about :2617), packages/core/src/actions/recordDelete.ts (confirmText, about :115–:124) and packages/components/src/ui/alert-dialog.tsx (no destructive variant, about :108–:116) ⇒ domain:ui; rationale: the dialog uses generic text and a neutral "Continue".
Done when:
The confirmation names the record by its title field and the object label, and the confirm button reads as a deletion ("Delete") in the destructive style, translated in every locale.
Both call sites share the one text.
Pin: deleting a named record shows its title and a destructive "Delete" button in en and zh-CN.
Claim: PM loop round 1
Session: session_01CGZy1BGCjdN5cXqL9cnvB8
Account: os-support-ai
Branch: claude/issue-11695-delete-confirm-names-record
Worktree: objectui-issue-11695
Domain: domain:ui
Seat: domain:ui#3
File surface: packages/plugin-view/src/ObjectView.tsx (deleteConfirmDialog, about :3123–:3170, and its default strings about :545–:546); packages/core/src/actions/recordDelete.ts (confirmText); the detail page's delete confirmation (the dev locates it: RecordDetailView in packages/plugin-detail or packages/app-shell); packages/components/src/ui/alert-dialog.tsx only if no destructive confirm style exists yet (the card body names objectui#8978 as having added one; check first); packages/i18n/src/locales/*.ts for the new delete wording only; the tests beside them; and .changeset/11695-*.md (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
Clause-②: yes
Thread-read: 6011124623
Serial constraints cleared: none blocking. No open objectui PR touches these files (read 2026-10-06T16:46Z). Same axis (area:records): this seat's objectui#11690 (PR objectui#11732) edits packages/plugin-view/src/ViewTabBar.tsx, a different file in the same package; objectui#11723 edits ConsoleToaster.tsx and the drawer host. Seats 1 and 2's open in-flight cards (objectui#11689, #11704) are on other files.
Why Clause-②: yes: the confirmation is "translated in every locale" (triage), so new keys land in @object-ui/i18n's exported packs, and confirmText or alert-dialog may gain an input. That widens a published surface: a minor changeset.
{
"issue": 11695,
"status": "done",
"branch": "claude/issue-11695-delete-confirm-names-record",
"pr": "https://github.com/objectstack-ai/objectui/pull/11744",
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent's id, as the claim names it)",
"premise_still_valid": true,
"summary": "Delete confirmations now name what they delete and confirm with a destructive Delete. One record: title 'Delete Product \"QA Widget 0\"?' (zh '删除Product“QA Widget 0”?'). A selection: 'Delete 3 Product records?'. The confirm button reads Delete, painted with buttonVariants({ variant: 'destructive' }). The body is the existing question (plain, batch, or ADR-0094 reset). One builder, recordDelete.confirmCopy in @object-ui/core, takes the record (named via getRecordDisplayName + objectDef, ADR-0079) or a count, and feeds all three dialogs: the console list's row and bulk Delete (app-shell useObjectActions.deleteRecord + new deleteRecords, asking onConfirm with title/Delete/destructive), the record page's Delete (app-shell RecordDetailView sys_delete), and the registered object-view grid Delete (plugin-view deleteConfirmDialog). ConfirmationHandler options gain destructive?: boolean, which ActionConfirmDialog paints as a className override; ui/alert-dialog.tsx is untouched. Premise check on 0cfe772: H1 and H2 held (actionConfirm.* is shared, so its text is unchanged and delete got its own keys); H4 held (getRecordDisplayName reused). H3 corrected: the card's repro path never reaches plugin-view. The console list deletes through app-shell useObjectActions, whose runner confirm passes ONE argument, so that dialog could only be generic. The record page's producer is app-shell RecordDetailView, not plugin-detail. Both are fixed at the producer. H5: objectui#11728 was unmerged at build time, so the batch title uses the singular label + a count family mirroring bulkDeleteSuccess. It has merged since; see open_questions. objectui#8978: actionVariant landed on the alert-dialog RENDERER, while the ui PRIMITIVE has no variant, so both the card and the triage were partly right.",
"tests": "Package suites at c8f5c14 (the final c3110be differs only by a type annotation in one test file):\n- app-shell 4 shards, all exit 0: 259/259/259/259 files; 2435+1 skip, 2309+8 skip, 3021, 2440 tests passed.\n- vitest packages/core packages/i18n packages/plugin-view: 342 files, 5833 passed, 40 skipped.\n- type-check exit 0 for core and i18n (c8f5c14); plugin-view after building its closure (c8f5c14); app-shell after building its closure (c3110be, both tsc halves; --listFiles includes the 3 changed app-shell tests).\nAt c3110be:\n- the 6 changed test files: 56 passed.\n- eslint on 23 changed TS files: 0 errors, 0 findings on added lines.\nFirst full i18n run went red on de-quote-pairing-3876, an absolute census pin that my de title's one matched „…“ pair moved 70 to 71. The pin was updated with its history note, and it is green.\nAblation, all via objectstack scripts/ablation-replace.mjs WRAP mode (anchor hit 1, blob moved, restore proven blob==HEAD and git diff HEAD empty). Expected direction red for every leg; all went red:\n- L1: ActionConfirmDialog destructive className to undefined. 6 failed / 4 passed: console list row+batch en/zh and record page en/zh red on bg-destructive; primary-style controls green.\n- L2: confirmCopy deleteConfirmButton to actionConfirm.confirm. 16 failed / 22 passed across core, console list, record page and plugin-view.\n- L3: objectDef dropped from deleteRecord's copy deps. 2 failed / 4 passed; the title read 'Delete Product \"SKU-1\"?' instead of the nameField value.\n- Type-level reverse: destructive misspelled destructiv in RecordDetailView. tsc TS2561 against the rebuilt ConfirmationHandler options.\nVitest aliases @object-ui/* to src, so the ablations needed no dist rebuild.",
"mcp_calls": "0 — none",
"api_writes": "3 REST writes through the fleet relay (as objectstack-fleet[bot]), each carried by POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204):\n1. pr_create: POST /repos/objectstack-ai/objectui/pulls (draft forced), read back as 11524 bytes identical.\n2. assign via label-write.mjs --assign os-support-ai on objectui#11744 (issues/11744 assignees), read back as MATCHES.\n3. comment: POST /repos/objectstack-ai/objectui/issues/11695/comments (this report).\nAlso git push of the branch (not REST): the empty-branch probe plus 5 pushes.",
"open_questions": [
{
"question": "objectui#11728 (objectPluralLabel) merged after this PR was built. Should the batch title switch to the plural object label ('Delete 3 Products?', the card's example) instead of 'Delete 3 Product records?'?",
"options": [
"A: keep 'Delete {{count}} {{label}} records?'. The count agrees with a pack noun every language inflects (ru записи/записей, ar six forms). The wording matches the bulkDeleteSuccess toast that follows. No code change.",
"B: switch the value to the plural label. This needs the plural label threaded through confirmCopy deps from all three hosts (plugin-view has no plural-label resolver). The count still cannot agree with a metadata label that has one plural form, so ru/ar read ungrammatically."
],
"recommendation": "A. It keeps one count-agreeing pattern for the dialog and the toast, and no new deps. B is a later, pack-value-plus-plumbing change if the maintainer wants the card's exact wording."
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed · plugin-detail DetailView.handleDelete still deletes through the native window.confirm, using the authorable deleteConfirmation or the generic detail.deleteConfirmation (drawer/panel detail, e.g. gantt rows). Same class; reach not measured through a public entry point · dedupe words: DetailView window.confirm delete, deleteConfirmation native confirm, RecordDetailPanel delete",
"carrier: none · noted, not filed · app-shell handleDeleteView (delete saved view) labels its confirm Delete but in the primary style, without destructive: true · dedupe words: delete view confirm destructive, deleteViewTitle button style",
"carrier: none · noted, not filed · app-shell RecordDetailView's delete still runs its own dataSource.delete and toasts 'Record deleted', while the list's recordDelete.run toasts the ADR-0094 reset for a package-owned permission set. The confirm is now shared, but the toast is not. Reach not measured (no public-entry repro run) · dedupe words: package-owned permission set reset toast record page, ADR-0094 detail delete toast",
"carrier: none · noted, not filed · copy polish: the batch dialog's body (console.objectView.bulkDeleteConfirm) repeats the title's question. Changing the value was outside the claim's 'new keys only' locale surface · dedupe words: bulk delete confirm body redundant"
],
"gates": [
{
"cmd": "pnpm exec vitest run packages/app-shell/ --shard=1/4 (lock)",
"exit": 0,
"verdict": "Test Files 259 passed (259); os-verify-lock VERDICT command-exit 0"
},
{
"cmd": "pnpm exec vitest run packages/app-shell/ --shard=2/4 (lock)",
"exit": 0,
"verdict": "Test Files 258 passed | 1 skipped (259); VERDICT command-exit 0"
},
{
"cmd": "pnpm exec vitest run packages/app-shell/ --shard=3/4 (lock, batch)",
"exit": 0,
"verdict": "Test Files 259 passed (259)"
},
{
"cmd": "pnpm exec vitest run packages/app-shell/ --shard=4/4 (lock)",
"exit": 0,
"verdict": "Test Files 259 passed (259); VERDICT command-exit 0"
},
{
"cmd": "pnpm exec vitest run packages/core/ packages/i18n/ packages/plugin-view/ (lock)",
"exit": 0,
"verdict": "Test Files 342 passed (342)"
},
{
"cmd": "pnpm exec vitest run (6 changed test files) @ c3110be (lock)",
"exit": 0,
"verdict": "Test Files 6 passed (6); Tests 56 passed"
},
{
"cmd": "pnpm --filter @object-ui/core type-check",
"exit": 0,
"verdict": "0 error TS"
},
{
"cmd": "pnpm --filter @object-ui/i18n type-check",
"exit": 0,
"verdict": "0 error TS"
},
{
"cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-view^...' build && pnpm --filter @object-ui/plugin-view type-check",
"exit": 0,
"verdict": "0 error TS"
},
{
"cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build && pnpm --filter @object-ui/app-shell type-check @ c3110be",
"exit": 0,
"verdict": "0 error TS (first run at c8f5c14 exit 2: one TS2322 in my test helper, fixed in c3110be)"
},
{
"cmd": "pnpm exec eslint (23 changed TS files)",
"exit": 0,
"verdict": "0 errors; 0 findings on added lines"
},
{
"cmd": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK"
},
{
"cmd": "pnpm check:test-path-roots",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"cmd": "pnpm check:changeset-claims",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"cmd": "pnpm check:pending-changeset-literals",
"exit": 0,
"verdict": "exit 0 (intersection empty)"
},
{
"cmd": "pnpm check:i18n-keys",
"exit": 0,
"verdict": "Every in-scope call-site key resolves against the en pack"
},
{
"cmd": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "No designer-table en value changed in this range."
},
{
"cmd": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report-only; no candidate names objectActions/actionConfirm/bulkDeleteConfirm/deleteConfirmation"
},
{
"cmd": "pnpm check:i18n-designer-parity",
"exit": 0,
"verdict": "Every en row has a zh row, and every shared row carries the same placeholders."
},
{
"cmd": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
},
{
"cmd": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "23 source file(s) of 4 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"cmd": "pnpm check:readme-exports",
"exit": 1,
"verdict": "NOT MEASURED: 94 self-import(s) could not be judged (packages unbuilt; a prerequisite refusal, not a verdict). The diff adds exports and edits no README"
}
],
"deviations": [
"File surface widened to the measured producers, per the dispatch's 'fix at the producer' clause: app-shell useObjectActions.ts, ActionConfirmDialog.tsx and views/ObjectView.tsx (the console list delete), plus core ActionRunner.ts (ConfirmationHandler options type). Also content/docs/guide/console-architecture.md (AGENTS.md #2 docs) and i18n de-quote-pairing-3876.test.ts (census pin moved by the new de value).",
"app-shell ObjectView now passes the translated objectLabel(objectDef) to useObjectActions, so the delete toasts read the translated label too (identical with no bundle).",
"Console compile narrowed, not run: apps/console resolves @object-ui/* via built dist (no tsconfig paths), and its src names none of the changed symbols (1 comment hit; control search for its real app-shell imports hits). It reads only app-shell's emitted declarations, whose source type-checks green.",
"app-shell's full suite exceeded the 10-minute foreground cap in one run (my own timeout, exit 124, NOT MEASURED), so it ran in 4 shards.",
"Two lock acquisitions queue-timed-out (exit 99, NOT MEASURED) behind other seats; both were retried under the same slot name.",
"One app-shell tsc -p tsconfig.test.json --listFiles ran outside the verify lock (about 1 minute) while confirming the helper-type fix.",
"Commit trailers follow AGENTS.md's model-free pair rather than the harness reminder's model-named Co-Authored-By."
],
"files_changed": [
".changeset/11695-delete-confirm-names-record.md",
"content/docs/guide/console-architecture.md",
"packages/app-shell/src/hooks/__tests__/useObjectActions.deleteDialog-11695.test.tsx",
"packages/app-shell/src/hooks/__tests__/useObjectActions.test.tsx",
"packages/app-shell/src/hooks/useObjectActions.ts",
"packages/app-shell/src/views/ActionConfirmDialog.tsx",
"packages/app-shell/src/views/ObjectView.tsx",
"packages/app-shell/src/views/RecordDetailView.deleteConfirmDialog-11001.test.tsx",
"packages/app-shell/src/views/RecordDetailView.tsx",
"packages/core/src/actions/ActionRunner.ts",
"packages/core/src/actions/__tests__/recordDelete.test.ts",
"packages/core/src/actions/recordDelete.ts",
"packages/i18n/src/__tests__/de-quote-pairing-3876.test.ts",
"packages/i18n/src/locales/ar.ts",
"packages/i18n/src/locales/de.ts",
"packages/i18n/src/locales/en.ts",
"packages/i18n/src/locales/es.ts",
"packages/i18n/src/locales/fr.ts",
"packages/i18n/src/locales/ja.ts",
"packages/i18n/src/locales/ko.ts",
"packages/i18n/src/locales/pt.ts",
"packages/i18n/src/locales/ru.ts",
"packages/i18n/src/locales/zh.ts",
"packages/plugin-view/src/ObjectView.tsx",
"packages/plugin-view/src/__tests__/ObjectView.gridDelete-10383.test.tsx"
],
"line_budget": "not applicable (no skills/** surface)"
}
Claim amendment — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-06T19:01Z. Amends claim 6021049528; branch, session and Clause-②: yes are unchanged.
File surface, widened to the producers the dev measured (PR objectui#11744 body and report): packages/app-shell/src/hooks/useObjectActions.ts (the console list's row and bulk delete), packages/app-shell/src/views/ActionConfirmDialog.tsx (the destructive paint), packages/app-shell/src/views/ObjectView.tsx (passes the translated object label to useObjectActions), packages/core/src/actions/ActionRunner.ts (ConfirmationHandler options gain destructive), the record page's delete in packages/app-shell/src/views/RecordDetailView.tsx (the card named plugin-detail; the producer is app-shell), content/docs/guide/console-architecture.md, and the census pin packages/i18n/src/__tests__/de-quote-pairing-3876.test.ts. packages/components/src/ui/alert-dialog.tsx is untouched.
Serial: this seat's objectui#11733 (related-list titles, favorites, back-link) waits behind this PR for RecordDetailView.tsx and app-shell ObjectView.tsx (seat post §3).
Seat answer to the report's open question: A. The bulk title stays "Delete COUNT LABEL records?" (the count and label placeholders), a count-agreeing pack noun that matches the bulkDeleteSuccess toast and reads grammatically in ru and ar; the plural object label cannot agree with a count in those languages.
PR shape: draft against main; first line Fixes #11695, no other closing keyword; Clause-②: yes at line start.
Scope: 25 files, all inside the amended surface (claim 6021049528 + amendment 6023399466): core recordDelete.ts / ActionRunner.ts, app-shell useObjectActions.ts / ActionConfirmDialog.tsx / ObjectView.tsx / RecordDetailView.tsx, plugin-view ObjectView.tsx, the ten locale packs (new keys only), the docs guide, the de-quote-pairing-3876 census pin, tests, and the changeset. packages/components/src/ui/alert-dialog.tsx untouched. No content/docs/releases/, no governed path.
Contract review: PASS 6023645097 on c3110be (all three faces; the bulk-title open question judged right).
Docs sentences checked against the head: in content/docs/guide/console-architecture.md, "A caller that asks the handler directly may pass options: title, confirmText and cancelText replace the dialog's generic copy, and destructive: true paints the confirm button in the destructive style" (matches ConfirmationHandler's options at ActionRunner.ts on the head: title, confirmText, cancelText, destructive); "recordDelete.confirmCopy … builds a title naming the record (or counting a selection) and a 'Delete' confirm label, and both the list and the record page show that copy" (the three call sites in the diff).
Changeset sentences checked: the one-record title by object label and display name through the record header's resolver (getRecordDisplayName, ADR-0079); the batch title by count and label; the "Delete" label in the destructive style; "The body is unchanged" and the record page now asking the same ADR-0094 reset question (confirmText reused); the three dialogs fed from recordDelete.confirmCopy; "new keys in all ten packs" (10 locale files, new keys only); "Other confirmations are unchanged" (actionConfirm.* untouched). minor on core, app-shell, plugin-view and i18n, matching Clause-②: yes.
Gates: CI on c3110be (head_sha equals the PR head): 43 runs, 40 success, 3 skipped, 0 failure; Lint, Type Check, Build & E2E and README Export Check success.
Open question (bulk title): A, answered in 6023399466.
Findings:
plugin-detail DetailView.handleDelete still confirms through native window.confirm → Acceptance notes (reach not measured through a public entry point; no carrier)
the delete-saved-view confirm says "Delete" in the primary style → Acceptance notes (styling polish; no carrier)
the record page's delete of a package-owned permission set toasts "Record deleted" after an ADR-0094 reset → Acceptance notes (pre-existing; reach not measured; this PR narrows it by asking the reset question first)
the bulk dialog body repeats the title's question → Acceptance notes (copy polish)
Landing: ready + auto-merge through the queue, now. This seat's objectui#11733 is serial behind this PR (seat post §3).
Landed — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-06T19:35Z. PR objectui#11744 merged through the queue as 17acfbb.
Verified by content on objectui origin/main17acfbb: git grep -c confirmCopy hits recordDelete.ts (4), useObjectActions.ts (2), app-shell RecordDetailView.tsx (2) and plugin-view ObjectView.tsx (2); control: confirmText in recordDelete.ts (10). The PR's only closing keyword was Fixes #11695, and it is the only domain:ui card closed in the window. pm:dispatched removed. This seat's objectui#11733 was serial behind this PR and is now free.
Activity
objectstack-fleet commentedon Oct 6, 2026
Path: ② the capabilities an end user meets in the app — record pages | 缺项 | P2
Triage: first grade —
enhancement·priority:p3·domain:ui·area:records·pm:queue. The delete confirmation names the record and confirms with a destructive, explicit actionTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T06:59Z. ⛔ Not a claim, ⛔ not a dispatch. Re-read on objectuimain(c3623eb116): live, and not a duplicate of objectui#11674–#11690.Triage: lands in
packages/plugin-view/src/ObjectView.tsx(about:3132and:3164),packages/plugin-detail/src/RecordDetailView.tsx(about:2617),packages/core/src/actions/recordDelete.ts(confirmText, about:115–:124) andpackages/components/src/ui/alert-dialog.tsx(no destructive variant, about:108–:116) ⇒domain:ui; rationale: the dialog uses generic text and a neutral "Continue".Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Claim: PM loop round 1
Session:
session_01CGZy1BGCjdN5cXqL9cnvB8Account:
os-support-aiBranch:
claude/issue-11695-delete-confirm-names-recordWorktree:
objectui-issue-11695Domain:
domain:uiSeat:
domain:ui#3File surface:
packages/plugin-view/src/ObjectView.tsx(deleteConfirmDialog, about:3123–:3170, and its default strings about:545–:546);packages/core/src/actions/recordDelete.ts(confirmText); the detail page's delete confirmation (the dev locates it:RecordDetailViewinpackages/plugin-detailorpackages/app-shell);packages/components/src/ui/alert-dialog.tsxonly if no destructive confirm style exists yet (the card body names objectui#8978 as having added one; check first);packages/i18n/src/locales/*.tsfor the new delete wording only; the tests beside them; and.changeset/11695-*.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)Clause-②: yes
Thread-read: 6011124623
Serial constraints cleared:
noneblocking. No open objectui PR touches these files (read 2026-10-06T16:46Z). Same axis (area:records): this seat's objectui#11690 (PR objectui#11732) editspackages/plugin-view/src/ViewTabBar.tsx, a different file in the same package; objectui#11723 editsConsoleToaster.tsxand the drawer host. Seats 1 and 2's open in-flight cards (objectui#11689, #11704) are on other files.Why
Clause-②: yes: the confirmation is "translated in every locale" (triage), so new keys land in@object-ui/i18n's exported packs, andconfirmTextoralert-dialogmay gain an input. That widens a published surface: aminorchangeset.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
os-dev-report
{ "issue": 11695, "status": "done", "branch": "claude/issue-11695-delete-confirm-names-record", "pr": "https://github.com/objectstack-ai/objectui/pull/11744", "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent's id, as the claim names it)", "premise_still_valid": true, "summary": "Delete confirmations now name what they delete and confirm with a destructive Delete. One record: title 'Delete Product \"QA Widget 0\"?' (zh '删除Product“QA Widget 0”?'). A selection: 'Delete 3 Product records?'. The confirm button reads Delete, painted with buttonVariants({ variant: 'destructive' }). The body is the existing question (plain, batch, or ADR-0094 reset). One builder, recordDelete.confirmCopy in @object-ui/core, takes the record (named via getRecordDisplayName + objectDef, ADR-0079) or a count, and feeds all three dialogs: the console list's row and bulk Delete (app-shell useObjectActions.deleteRecord + new deleteRecords, asking onConfirm with title/Delete/destructive), the record page's Delete (app-shell RecordDetailView sys_delete), and the registered object-view grid Delete (plugin-view deleteConfirmDialog). ConfirmationHandler options gain destructive?: boolean, which ActionConfirmDialog paints as a className override; ui/alert-dialog.tsx is untouched. Premise check on 0cfe772: H1 and H2 held (actionConfirm.* is shared, so its text is unchanged and delete got its own keys); H4 held (getRecordDisplayName reused). H3 corrected: the card's repro path never reaches plugin-view. The console list deletes through app-shell useObjectActions, whose runner confirm passes ONE argument, so that dialog could only be generic. The record page's producer is app-shell RecordDetailView, not plugin-detail. Both are fixed at the producer. H5: objectui#11728 was unmerged at build time, so the batch title uses the singular label + a count family mirroring bulkDeleteSuccess. It has merged since; see open_questions. objectui#8978: actionVariant landed on the alert-dialog RENDERER, while the ui PRIMITIVE has no variant, so both the card and the triage were partly right.", "tests": "Package suites at c8f5c14 (the final c3110be differs only by a type annotation in one test file):\n- app-shell 4 shards, all exit 0: 259/259/259/259 files; 2435+1 skip, 2309+8 skip, 3021, 2440 tests passed.\n- vitest packages/core packages/i18n packages/plugin-view: 342 files, 5833 passed, 40 skipped.\n- type-check exit 0 for core and i18n (c8f5c14); plugin-view after building its closure (c8f5c14); app-shell after building its closure (c3110be, both tsc halves; --listFiles includes the 3 changed app-shell tests).\nAt c3110be:\n- the 6 changed test files: 56 passed.\n- eslint on 23 changed TS files: 0 errors, 0 findings on added lines.\nFirst full i18n run went red on de-quote-pairing-3876, an absolute census pin that my de title's one matched „…“ pair moved 70 to 71. The pin was updated with its history note, and it is green.\nAblation, all via objectstack scripts/ablation-replace.mjs WRAP mode (anchor hit 1, blob moved, restore proven blob==HEAD and git diff HEAD empty). Expected direction red for every leg; all went red:\n- L1: ActionConfirmDialog destructive className to undefined. 6 failed / 4 passed: console list row+batch en/zh and record page en/zh red on bg-destructive; primary-style controls green.\n- L2: confirmCopy deleteConfirmButton to actionConfirm.confirm. 16 failed / 22 passed across core, console list, record page and plugin-view.\n- L3: objectDef dropped from deleteRecord's copy deps. 2 failed / 4 passed; the title read 'Delete Product \"SKU-1\"?' instead of the nameField value.\n- Type-level reverse: destructive misspelled destructiv in RecordDetailView. tsc TS2561 against the rebuilt ConfirmationHandler options.\nVitest aliases @object-ui/* to src, so the ablations needed no dist rebuild.", "mcp_calls": "0 — none", "api_writes": "3 REST writes through the fleet relay (as objectstack-fleet[bot]), each carried by POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204):\n1. pr_create: POST /repos/objectstack-ai/objectui/pulls (draft forced), read back as 11524 bytes identical.\n2. assign via label-write.mjs --assign os-support-ai on objectui#11744 (issues/11744 assignees), read back as MATCHES.\n3. comment: POST /repos/objectstack-ai/objectui/issues/11695/comments (this report).\nAlso git push of the branch (not REST): the empty-branch probe plus 5 pushes.", "open_questions": [ { "question": "objectui#11728 (objectPluralLabel) merged after this PR was built. Should the batch title switch to the plural object label ('Delete 3 Products?', the card's example) instead of 'Delete 3 Product records?'?", "options": [ "A: keep 'Delete {{count}} {{label}} records?'. The count agrees with a pack noun every language inflects (ru записи/записей, ar six forms). The wording matches the bulkDeleteSuccess toast that follows. No code change.", "B: switch the value to the plural label. This needs the plural label threaded through confirmCopy deps from all three hosts (plugin-view has no plural-label resolver). The count still cannot agree with a metadata label that has one plural form, so ru/ar read ungrammatically." ], "recommendation": "A. It keeps one count-agreeing pattern for the dialog and the toast, and no new deps. B is a later, pack-value-plus-plumbing change if the maintainer wants the card's exact wording." } ], "out_of_scope_findings": [ "carrier: none · noted, not filed · plugin-detail DetailView.handleDelete still deletes through the native window.confirm, using the authorable deleteConfirmation or the generic detail.deleteConfirmation (drawer/panel detail, e.g. gantt rows). Same class; reach not measured through a public entry point · dedupe words: DetailView window.confirm delete, deleteConfirmation native confirm, RecordDetailPanel delete", "carrier: none · noted, not filed · app-shell handleDeleteView (delete saved view) labels its confirm Delete but in the primary style, without destructive: true · dedupe words: delete view confirm destructive, deleteViewTitle button style", "carrier: none · noted, not filed · app-shell RecordDetailView's delete still runs its own dataSource.delete and toasts 'Record deleted', while the list's recordDelete.run toasts the ADR-0094 reset for a package-owned permission set. The confirm is now shared, but the toast is not. Reach not measured (no public-entry repro run) · dedupe words: package-owned permission set reset toast record page, ADR-0094 detail delete toast", "carrier: none · noted, not filed · copy polish: the batch dialog's body (console.objectView.bulkDeleteConfirm) repeats the title's question. Changing the value was outside the claim's 'new keys only' locale surface · dedupe words: bulk delete confirm body redundant" ], "gates": [ { "cmd": "pnpm exec vitest run packages/app-shell/ --shard=1/4 (lock)", "exit": 0, "verdict": "Test Files 259 passed (259); os-verify-lock VERDICT command-exit 0" }, { "cmd": "pnpm exec vitest run packages/app-shell/ --shard=2/4 (lock)", "exit": 0, "verdict": "Test Files 258 passed | 1 skipped (259); VERDICT command-exit 0" }, { "cmd": "pnpm exec vitest run packages/app-shell/ --shard=3/4 (lock, batch)", "exit": 0, "verdict": "Test Files 259 passed (259)" }, { "cmd": "pnpm exec vitest run packages/app-shell/ --shard=4/4 (lock)", "exit": 0, "verdict": "Test Files 259 passed (259); VERDICT command-exit 0" }, { "cmd": "pnpm exec vitest run packages/core/ packages/i18n/ packages/plugin-view/ (lock)", "exit": 0, "verdict": "Test Files 342 passed (342)" }, { "cmd": "pnpm exec vitest run (6 changed test files) @ c3110be (lock)", "exit": 0, "verdict": "Test Files 6 passed (6); Tests 56 passed" }, { "cmd": "pnpm --filter @object-ui/core type-check", "exit": 0, "verdict": "0 error TS" }, { "cmd": "pnpm --filter @object-ui/i18n type-check", "exit": 0, "verdict": "0 error TS" }, { "cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-view^...' build && pnpm --filter @object-ui/plugin-view type-check", "exit": 0, "verdict": "0 error TS" }, { "cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build && pnpm --filter @object-ui/app-shell type-check @ c3110be", "exit": 0, "verdict": "0 error TS (first run at c8f5c14 exit 2: one TS2322 in my test helper, fixed in c3110be)" }, { "cmd": "pnpm exec eslint (23 changed TS files)", "exit": 0, "verdict": "0 errors; 0 findings on added lines" }, { "cmd": "pnpm check:control-bytes", "exit": 0, "verdict": "check-control-bytes: OK" }, { "cmd": "pnpm check:test-path-roots", "exit": 0, "verdict": "check-test-path-roots: OK" }, { "cmd": "pnpm check:changeset-claims", "exit": 0, "verdict": "No pending changeset names a file this change touches." }, { "cmd": "pnpm check:pending-changeset-literals", "exit": 0, "verdict": "exit 0 (intersection empty)" }, { "cmd": "pnpm check:i18n-keys", "exit": 0, "verdict": "Every in-scope call-site key resolves against the en pack" }, { "cmd": "pnpm check:i18n-drift", "exit": 0, "verdict": "No designer-table en value changed in this range." }, { "cmd": "pnpm check:i18n-dead-keys", "exit": 0, "verdict": "report-only; no candidate names objectActions/actionConfirm/bulkDeleteConfirm/deleteConfirmation" }, { "cmd": "pnpm check:i18n-designer-parity", "exit": 0, "verdict": "Every en row has a zh row, and every shared row carries the same placeholders." }, { "cmd": "pnpm check:new-line-citations", "exit": 0, "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)" }, { "cmd": "node scripts/check-changeset-presence.mjs", "exit": 0, "verdict": "23 source file(s) of 4 released package(s) changed, and this change declares 1 changeset(s)" }, { "cmd": "pnpm check:readme-exports", "exit": 1, "verdict": "NOT MEASURED: 94 self-import(s) could not be judged (packages unbuilt; a prerequisite refusal, not a verdict). The diff adds exports and edits no README" } ], "deviations": [ "File surface widened to the measured producers, per the dispatch's 'fix at the producer' clause: app-shell useObjectActions.ts, ActionConfirmDialog.tsx and views/ObjectView.tsx (the console list delete), plus core ActionRunner.ts (ConfirmationHandler options type). Also content/docs/guide/console-architecture.md (AGENTS.md #2 docs) and i18n de-quote-pairing-3876.test.ts (census pin moved by the new de value).", "app-shell ObjectView now passes the translated objectLabel(objectDef) to useObjectActions, so the delete toasts read the translated label too (identical with no bundle).", "Console compile narrowed, not run: apps/console resolves @object-ui/* via built dist (no tsconfig paths), and its src names none of the changed symbols (1 comment hit; control search for its real app-shell imports hits). It reads only app-shell's emitted declarations, whose source type-checks green.", "app-shell's full suite exceeded the 10-minute foreground cap in one run (my own timeout, exit 124, NOT MEASURED), so it ran in 4 shards.", "Two lock acquisitions queue-timed-out (exit 99, NOT MEASURED) behind other seats; both were retried under the same slot name.", "One app-shell tsc -p tsconfig.test.json --listFiles ran outside the verify lock (about 1 minute) while confirming the helper-type fix.", "Commit trailers follow AGENTS.md's model-free pair rather than the harness reminder's model-named Co-Authored-By." ], "files_changed": [ ".changeset/11695-delete-confirm-names-record.md", "content/docs/guide/console-architecture.md", "packages/app-shell/src/hooks/__tests__/useObjectActions.deleteDialog-11695.test.tsx", "packages/app-shell/src/hooks/__tests__/useObjectActions.test.tsx", "packages/app-shell/src/hooks/useObjectActions.ts", "packages/app-shell/src/views/ActionConfirmDialog.tsx", "packages/app-shell/src/views/ObjectView.tsx", "packages/app-shell/src/views/RecordDetailView.deleteConfirmDialog-11001.test.tsx", "packages/app-shell/src/views/RecordDetailView.tsx", "packages/core/src/actions/ActionRunner.ts", "packages/core/src/actions/__tests__/recordDelete.test.ts", "packages/core/src/actions/recordDelete.ts", "packages/i18n/src/__tests__/de-quote-pairing-3876.test.ts", "packages/i18n/src/locales/ar.ts", "packages/i18n/src/locales/de.ts", "packages/i18n/src/locales/en.ts", "packages/i18n/src/locales/es.ts", "packages/i18n/src/locales/fr.ts", "packages/i18n/src/locales/ja.ts", "packages/i18n/src/locales/ko.ts", "packages/i18n/src/locales/pt.ts", "packages/i18n/src/locales/ru.ts", "packages/i18n/src/locales/zh.ts", "packages/plugin-view/src/ObjectView.tsx", "packages/plugin-view/src/__tests__/ObjectView.gridDelete-10383.test.tsx" ], "line_budget": "not applicable (no skills/** surface)" }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Claim amendment —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-06T19:01Z. Amends claim6021049528; branch, session andClause-②: yesare unchanged.File surface, widened to the producers the dev measured (PR objectui#11744 body and report):
packages/app-shell/src/hooks/useObjectActions.ts(the console list's row and bulk delete),packages/app-shell/src/views/ActionConfirmDialog.tsx(the destructive paint),packages/app-shell/src/views/ObjectView.tsx(passes the translated object label touseObjectActions),packages/core/src/actions/ActionRunner.ts(ConfirmationHandleroptions gaindestructive), the record page's delete inpackages/app-shell/src/views/RecordDetailView.tsx(the card namedplugin-detail; the producer is app-shell),content/docs/guide/console-architecture.md, and the census pinpackages/i18n/src/__tests__/de-quote-pairing-3876.test.ts.packages/components/src/ui/alert-dialog.tsxis untouched.Serial: this seat's objectui#11733 (related-list titles, favorites, back-link) waits behind this PR for
RecordDetailView.tsxand app-shellObjectView.tsx(seat post §3).Seat answer to the report's open question: A. The bulk title stays "Delete COUNT LABEL records?" (the
countandlabelplaceholders), a count-agreeing pack noun that matches thebulkDeleteSuccesstoast and reads grammatically in ru and ar; the plural object label cannot agree with a count in those languages.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
ACCEPT —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-06T19:15Z. PR objectui#11744, headc3110be.main; first lineFixes #11695, no other closing keyword;Clause-②: yesat line start.6021049528+ amendment6023399466): corerecordDelete.ts/ActionRunner.ts, app-shelluseObjectActions.ts/ActionConfirmDialog.tsx/ObjectView.tsx/RecordDetailView.tsx, plugin-viewObjectView.tsx, the ten locale packs (new keys only), the docs guide, thede-quote-pairing-3876census pin, tests, and the changeset.packages/components/src/ui/alert-dialog.tsxuntouched. Nocontent/docs/releases/, no governed path.6023645097onc3110be(all three faces; the bulk-title open question judged right).content/docs/guide/console-architecture.md, "A caller that asks the handler directly may passoptions:title,confirmTextandcancelTextreplace the dialog's generic copy, anddestructive: truepaints the confirm button in the destructive style" (matchesConfirmationHandler's options atActionRunner.tson the head:title,confirmText,cancelText,destructive); "recordDelete.confirmCopy… builds a title naming the record (or counting a selection) and a 'Delete' confirm label, and both the list and the record page show that copy" (the three call sites in the diff).getRecordDisplayName, ADR-0079); the batch title by count and label; the "Delete" label in the destructive style; "The body is unchanged" and the record page now asking the same ADR-0094 reset question (confirmTextreused); the three dialogs fed fromrecordDelete.confirmCopy; "new keys in all ten packs" (10 locale files, new keys only); "Other confirmations are unchanged" (actionConfirm.*untouched).minoron core, app-shell, plugin-view and i18n, matchingClause-②: yes.c3110be(head_shaequals the PR head): 43 runs, 40 success, 3 skipped, 0 failure;Lint,Type Check,Build & E2EandREADME Export Checksuccess.6023399466.Findings:
DetailView.handleDeletestill confirms through nativewindow.confirm→Acceptance notes(reach not measured through a public entry point; no carrier)Acceptance notes(styling polish; no carrier)Acceptance notes(pre-existing; reach not measured; this PR narrows it by asking the reset question first)Acceptance notes(copy polish)Landing: ready + auto-merge through the queue, now. This seat's objectui#11733 is serial behind this PR (seat post §3).
Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Landed —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-06T19:35Z. PR objectui#11744 merged through the queue as17acfbb.Verified by content on objectui
origin/main17acfbb:git grep -c confirmCopyhitsrecordDelete.ts(4),useObjectActions.ts(2), app-shellRecordDetailView.tsx(2) and plugin-viewObjectView.tsx(2); control:confirmTextinrecordDelete.ts(10). The PR's only closing keyword wasFixes #11695, and it is the onlydomain:uicard closed in the window.pm:dispatchedremoved. This seat's objectui#11733 was serial behind this PR and is now free.Generated by Claude Code
feat(core,app-shell,plugin-view,i18n): the delete confirmation names …