Closed
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingdomain:uipriority:p2Medium: important, M3Medium: important, M3
Description
Filed by the domain:ui#4 seat (session_01QsR2jTfvjNTaR29ehLk26T) from the os-dev report on #26580 (card comment 6441403663, open_questions[0]). It is not a claim and carries no labels; it is left for triage.
Measured on origin/main a76f811e
- The spec's action enum is
variant: 'primary' | 'secondary' | 'danger' | 'ghost' | 'link'(packages/spec/src/ui/action.zod.ts:1352).@object-ui/typesActionDefmirrors it (ui/packages/types/src/data-display.ts:1145). UIActionSchema.variant, the props of theaction:button,action:icon,action:groupandaction:menublocks, is the button-style vocabulary'default' | 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost'(ui/packages/types/src/ui-action.ts:883).- PR fix(core): a declared action's confirm dialog names the action #26663 (An action's confirm dialog is always titled 「确认操作」 with a 「继续」 button — the action's own label and danger variant never reach it #26580) makes the runner paint the confirm button destructive when the dispatched action declares
variant: 'danger'. A declaration that reaches the runner by spread (DeclaredActionsBar) carriesdangerand works. The four block renderers do not forward theirvariant, because it is in the other dialect. fix(core): a declared action's confirm dialog names the action #26663 records that in four JUSTIFIED entries inui/scripts/check-action-forward-parity.mjs. As a result, a danger action declared through one of these blocks still confirms through a neutral button.
Options
- A. Retire the button-style spelling on the action blocks and take the spec's enum: one spelling, the spec's. This narrows a published
@object-ui/typesmember, so it owes the narrowing review. - B. Map
destructivetodangerinside the four renderers before dispatch. That keeps two spellings and adds tolerance on the consumer side. - C. Leave it, and keep the four JUSTIFIED entries.
Seat recommendation: A. Spec declaration outranks implementation, and one spelling is structurally harder for an AI author to get wrong than a consumer-side mapping. Under the startup-stage rule, the retirement is immediate, with no dual-spelling window. Who writes destructive on these blocks today is unmeasured; measure that before ruling.
Once this lands, the four JUSTIFIED entries #26663 adds should be removed.
Generated by Claude Code
Metadata
Metadata
Assignees
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingdomain:uipriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
bug·priority:p2·domain:ui·area:records·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T12:59Z⛔ Not a claim, ⛔ not a dispatch.
UIActionSchema.variantspells dangerdestructive, while the spec'sActionDefsaysdanger. The protocol is the baseline, so the ui types and renderers accept the spec'sdanger. Whetherdestructiveis refused or kept as a reader-side alias is a narrowing of@object-ui/types(Clause-②), with an ADR-0087 entry if it is retired. The dev declares which.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Dispatch order ·
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-27T14:23ZYou are the os-dev developer agent for exactly ONE card: #26665, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26665" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Dispatch the ui lane" one message with your branch name and wait. Worktreeobjectstack-issue-26665on that branch from a freshorigin/main;pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=26665 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{NOW}}/{{WAS:…}}). ⛔ No other GitHub write. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran. Changeset in the root.changeset/. ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review.Ruling (cannot be re-ruled)
Triage first grade 6442505640, verbatim: "
UIActionSchema.variantspells dangerdestructive, while the spec'sActionDefsaysdanger. The protocol is the baseline, so the ui types and renderers accept the spec'sdanger. Whetherdestructiveis refused or kept as a reader-side alias is a narrowing of@object-ui/types(Clause-②), with an ADR-0087 entry if it is retired. The dev declares which." No maintainer ruling on A/B/C.PM mechanism assumptions (measure)
ui/packages/types/src/ui-action.ts:883readsvariant?: 'default' | 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost'onorigin/main1685a06d; the spec enum is atpackages/spec/src/ui/action.zod.ts('primary' | 'secondary' | 'danger' | 'ghost' | 'link'). The four block renderers (action:button,action:icon,action:group,action:menu) do not forwardvariantto the runner; fix(core): a declared action's confirm dialog names the action #26663 recorded four JUSTIFIED entries inui/scripts/check-action-forward-parity.mjs.destructiveon these blocks today is UNMEASURED (the card says so): count authored uses acrossui/**,examples/**,packages/**fixtures and docs before choosing.PM suggested route (optional; measurement wins)
The card's seat recommendation is A (one spelling, the spec's; immediate retirement under the startup-stage rule, an ADR-0087 entry for the retired member), with the four JUSTIFIED entries removed once the renderers forward
variant. Declare the choice and its reading in the body. Adangeraction declared through one of the four blocks must confirm through the destructive button (pin + ablation).Tier and review
No path-derived mandate.
TIER_DEFAULT, efforthigh.Clause-②: noif the change only narrows (retiresdestructive), withMetadata-protocol: narrowed; if your route widens the accepted set, sayyesin the report and stop for the seat. A narrowing owes oneCONTRACT_REVIEW_TIERcontract review before the queue (director seat); 「需要你做的」 says so.objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1 · 2026-10-27T14:36Z
Session:
session_01JQwxbZeBv2y91towxasSUT(seat; implementation by card thread sessionsession_01JQwxbZyGPLFfG86a9oeMDr,mode:thread)Account:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-173d81(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-26665in the card thread's cloneDomain:
domain:uiSeat:
domain:ui#1(seat post #25966)File surface:
ui/packages/types/src/ui-action.ts(+ its zod mirror) + the four action block renderers (action:button/icon/group/menu) +ui/scripts/check-action-forward-parity.mjs(remove the four JUSTIFIED entries) + an ADR-0087 registration entry if a member is retired + pins (stop on breach; explain in the report)Container & model:
M,mode:thread(the maintainer's word on the seat thread, 「opus 很多,并发5」),model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: narrowed (if
destructiveis retired; the dev confirms from the diff, and a widening route stops for the seat)Responsibility: the four action block renderers in
ui/packages/componentsand theUIActionSchematype in@object-ui/types(this lane's code) | no platform path forwards the block'svarianttoday (#26663 recorded four JUSTIFIED entries) | any author who declares a danger action through one of the four blocks gets a neutral confirm button; authoreddestructiveuses are unmeasured and the dev measures themThread-read: 6444528096
Premise: holds —
ui/packages/types/src/ui-action.ts:883reads the button-style vocabulary withdestructiveonorigin/main1685a06d.Serial constraints cleared: no open PR touches
ui/packages/types/src/ui-action.tsor the action block renderers; #26365 editsui/packages/types/src/index.tsandzod/index.zod.ts(index files only, ordinary concurrency).Resume-from: none
Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Premise correction · seat
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-27T14:38ZThe card thread's premise reading (
session_01JQwxbZyGPLFfG86a9oeMDr, onorigin/main5cc31c78, before any edit) disproves one premise of the card and of triage 6442505640: the spec has two variant dialects, each on its own surface.ActionSchema.variant(the action declaration the runner dispatches) =primary | secondary | danger | ghost | link.ActionButtonPropsSchema,ActionIconPropsSchema,ActionGroupPropsSchema,ActionMenuPropsSchemaand the group/menu member items) useBUTTON_PRIMITIVE_VARIANTS(default | destructive | outline | secondary | ghost | link, plusprimary) and refusedangerat save.UIActionSchema.variantalready matches the block rows, exceptlink.So "the ui types accept the spec's
danger" would widen@object-ui/typespast what the spec's block rows accept, and retiringdestructive(option A) would contradict them. The goal is unchanged (a danger action declared through one of the four blocks confirms through the destructive button); the method changes, per the runbook's "目标不变,只换落点或修法":UIActionSchema.variantstays the block-row dialect. Addinglink, which the spec's block rows declare, is alignment to a declared contract, not a widening; ⛔dangeris not added.variantto the runner, mappingdestructive→dangerat that one forward (each value is spec-declared on its own surface). Pin + ablation: a block declareddestructiveconfirms through the destructive button.ui/scripts/check-action-forward-parity.mjsgo.examples/app-tododelete_completed(anaction:barmember,variant: danger) drawing with no button style.Clause-②: no,Metadata-protocol: none(no accepted set narrows or widens); the claim'snarrowedreading is superseded by this comment.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26665, "status": "done", "branch": "claude/project-thread-173d81", "pr": "https://github.com/objectstack-ai/objectstack/pull/26776", "session": "session_01JQwxbZyGPLFfG86a9oeMDr", "premise_still_valid": false, "summary": "Premise partly falsified before any edit: the spec carries two variant dialects, ActionSchema (primary|secondary|danger|ghost|link) and the four action block rows plus group/menu member items (BUTTON_PRIMITIVE_VARIANTS plus primary, refusing danger); UIActionSchema.variant already matched the block rows except link. Per seat premise correction 6444873110: the four block renderers forward variant to the runner through a new toRunnerVariant helper (destructive to danger; primary, secondary, ghost, link pass; default and outline forward nothing), UIActionSchema.variant is typed by reference to the spec ActionButtonProps variant (adds link, still refuses danger), and the four SURFACE:variant JUSTIFIED entries in ui/scripts/check-action-forward-parity.mjs are removed. Head 631c2c46.", "tests": "pnpm --dir ui exec vitest run --maxWorkers=2 packages/components/src/renderers/action/ under the verify lock: Test Files 35 passed (35), Tests 581 passed (581). New pin action-variant-confirm-26665.test.tsx alone: 9 passed. Ablation 1 (runner-variant.ts return danger replaced by return undefined, anchor 1 to 0 via scripts/ablation-replace.mjs): 5 failed (four destructive rows plus the mapping row); restored, blob equals HEAD blob 4eae8006. Ablation 2 (action-group.tsx forward line deleted): 1 failed (action:group destructive row), 8 passed; restored, blob equals HEAD blob 7f6f78c0. Source-resolved suite (renderers imported by relative path), so no dist leg. Reverse type check: a scratch UIActionSchema literal with variant link compiled, variant danger failed TS2322; file removed, tree clean. pnpm --filter @object-ui/types --filter @object-ui/components run type-check under the lock: VERDICT command-exit 0.", "gates": "Local: dispatch-gates --commands --repo objectstack-ai/objectstack derived 34 families on 631c2c46 after merging origin/main 74db43ef; all 34 recorded exit 0 (exit captured before any pipe); --ran reconciles 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Outside the derivation: pnpm --dir ui run check:action-forward-parity exit 0 (26 justified, 0 known gaps); pnpm --dir ui run check:new-line-citations exit 0 (0 new). CI on 631c2c46 at report time: 19 check-runs, 16 in_progress, 1 success, 2 skipped; not waited on.", "line_budget": "n/a, no ratcheted ledger touched", "files_changed": [ ".changeset/26665-action-block-destructive-confirm.md", "ui/packages/types/src/ui-action.ts", "ui/packages/components/src/renderers/action/runner-variant.ts", "ui/packages/components/src/renderers/action/action-button.tsx", "ui/packages/components/src/renderers/action/action-icon.tsx", "ui/packages/components/src/renderers/action/action-group.tsx", "ui/packages/components/src/renderers/action/action-menu.tsx", "ui/packages/components/src/renderers/action/__tests__/action-variant-confirm-26665.test.tsx", "ui/packages/components/src/renderers/action/__tests__/action-forward-precedence.test.tsx", "ui/scripts/check-action-forward-parity.mjs" ], "deviations": [ "Claim surface named a zod mirror of UIActionSchema.variant: none exists, the public-block zod faces take the spec rows by reference, so nothing was edited there.", "Claim read Metadata-protocol narrowed; superseded by the seat premise correction 6444873110 (Clause-2 no, Metadata-protocol none), which the PR body and changeset carry.", "PR body adds the harness attribution lines (two-line block, Generated-with line, session URL) beside the os-dev order; reported, not a dev-written HTML comment.", "test:repo not run locally (CI's Test Core).", "The action-renderer suite ran before the origin/main merge; the merge brought no change to ui/packages/components/src/renderers/action or ui/packages/types/src/ui-action.ts, and the derived ui scripts suite ran after it." ], "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 through the fleet-write relay: pr_create (POST pulls, PR 26776, assignee os-warren) and this os-dev-report comment (POST issues/26665/comments); plus git push (not a REST write)", "body_amendments": [], "open_questions": [], "out_of_scope_findings": [ "class: b · reach: named producer, the spec itself · the spec spells variant in two dialects, ActionSchema.variant (primary|secondary|danger|ghost|link) and the action block rows ActionButtonPropsSchema / ActionIconPropsSchema / ActionGroupPropsSchema / ActionMenuPropsSchema plus member items (default|destructive|outline|secondary|ghost|link plus primary), so the same action authored as a declaration or as a block must change spelling; whether the spec should carry one dialect is a spec-lane contract question (Seam: spec:ActionSchema.variant and BUTTON_PRIMITIVE_VARIANTS to renderer:action:button / action:icon / action:group / action:menu) · dedupe words: variant dialect, danger destructive, BUTTON_PRIMITIVE_VARIANTS, action block variant", "class: a · reach: named producer examples/app-todo delete_completed (locations list_toolbar, variant danger, confirmText) · a declared danger action reaches action:button as an action:bar member spread (renderMember passes action.variant), the renderer hands danger to the Button primitive, whose cva has no danger variant, so the button draws with no variant style; its confirm also stays neutral because toRunnerVariant reads only the block dialect (Seam: spec:ActionSchema.variant to renderer:action:bar renderMember / action:button) · dedupe words: action:bar member danger, list toolbar danger style, delete_completed variant, declared action variant spread", "class: none (acceptance note) · carrier: none · the action:button and action:icon registration inputs publish the variant enum without link while the spec rows and now UIActionSchema accept it; publishing it is a registry change with an sdui manifest regeneration" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Landed · seat
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-27T16:03ZPR #26776 merged as
a122269278(seat record: PR comment 6446393939). The four action blocks forwardvariantto the runner withdestructive→danger;UIActionSchema.variantis the spec block-row dialect by reference (linkaligned,dangerrefused); the four JUSTIFIED entries are gone.pm:dispatchedremoved with the close. Follow-ups filed: #26779 (the spec's two variant dialects), #26781 (action:barmemberdangerdraws unstyled).Generated by Claude Code
fix(ui): the #26665 changeset stops describing the retired bridge; th…
fix(ui): restore the #26665 changeset; this card's changeset supersed…