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 }}
Repository navigation
action:button / icon / group / menu: UIActionSchema.variant spells danger destructive while the spec's ActionDef says danger, so a block-declared danger action confirms through a neutral button #26665
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/typesActionDef mirrors it (ui/packages/types/src/data-display.ts:1145).
UIActionSchema.variant, the props of the action:button, action:icon, action:group and action:menu blocks, is the button-style vocabulary 'default' | 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost' (ui/packages/types/src/ui-action.ts:883).
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/types member, so it owes the narrowing review.
B. Map destructive to danger inside 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.
p2:UIActionSchema.variant spells danger destructive, while the spec's ActionDef says danger. The protocol is the baseline, so the ui types and renderers accept the spec's danger. Whether destructive is 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.
Dispatch order · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-27T14:23Z
You are the os-dev developer agent for exactly ONE card: #26665, in your own card thread. Your role definition is .claude/agents/os-dev.md in 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-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/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; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: 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. Worktree objectstack-issue-26665 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git 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-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26665 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ No other GitHub write. Report both counts (api_writes with endpoints, mcp_calls with 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/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran. Changeset in the root .changeset/. ⛔ ui/.github/** and the root ci.yml are 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.variant spells danger destructive, while the spec's ActionDef says danger. The protocol is the baseline, so the ui types and renderers accept the spec's danger. Whether destructive is 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:883 reads variant?: 'default' | 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost' on origin/main1685a06d; the spec enum is at packages/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 forward variant to the runner; fix(core): a declared action's confirm dialog names the action #26663 recorded four JUSTIFIED entries in ui/scripts/check-action-forward-parity.mjs.
Who writes destructive on these blocks today is UNMEASURED (the card says so): count authored uses across ui/**, 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. A danger action declared through one of the four blocks must confirm through the destructive button (pin + ablation).
Tier and review
No path-derived mandate. TIER_DEFAULT, effort high. Clause-②: no if the change only narrows (retires destructive), with Metadata-protocol: narrowed; if your route widens the accepted set, say yes in the report and stop for the seat. A narrowing owes one CONTRACT_REVIEW_TIER contract review before the queue (director seat); 「需要你做的」 says so.
Claim: PM loop round 1 · 2026-10-27T14:36Z
Session: session_01JQwxbZeBv2y91towxasSUT (seat; implementation by card thread session session_01JQwxbZyGPLFfG86a9oeMDr, mode:thread)
Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-173d81 (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
Worktree: objectstack-issue-26665 in the card thread's clone
Domain: domain:ui
Seat: 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: high
Clause-②: no
Metadata-protocol: narrowed (if destructive is retired; the dev confirms from the diff, and a widening route stops for the seat)
Responsibility: the four action block renderers in ui/packages/components and the UIActionSchema type in @object-ui/types (this lane's code) | no platform path forwards the block's variant today (#26663 recorded four JUSTIFIED entries) | any author who declares a danger action through one of the four blocks gets a neutral confirm button; authored destructive uses are unmeasured and the dev measures them
Thread-read: 6444528096
Premise: holds — ui/packages/types/src/ui-action.ts:883 reads the button-style vocabulary with destructive on origin/main1685a06d.
Serial constraints cleared: no open PR touches ui/packages/types/src/ui-action.ts or the action block renderers; #26365 edits ui/packages/types/src/index.ts and zod/index.zod.ts (index files only, ordinary concurrency).
Resume-from: none
The card thread's premise reading (session_01JQwxbZyGPLFfG86a9oeMDr, on origin/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.
The spec's own block rows (ActionButtonPropsSchema, ActionIconPropsSchema, ActionGroupPropsSchema, ActionMenuPropsSchema and the group/menu member items) use BUTTON_PRIMITIVE_VARIANTS (default | destructive | outline | secondary | ghost | link, plus primary) and refuse danger at save.
UIActionSchema.variant already matches the block rows, except link.
So "the ui types accept the spec's danger" would widen @object-ui/types past what the spec's block rows accept, and retiring destructive (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.variant stays the block-row dialect. Adding link, which the spec's block rows declare, is alignment to a declared contract, not a widening; ⛔ danger is not added.
The four block renderers forward their variant to the runner, mapping destructive → danger at that one forward (each value is spec-declared on its own surface). Pin + ablation: a block declared destructive confirms through the destructive button.
The four JUSTIFIED entries in ui/scripts/check-action-forward-parity.mjs go.
Out of this card, reported as findings for the seat to file: whether the spec should carry one dialect instead of two (a spec-lane contract question), and examples/app-tododelete_completed (an action:bar member, variant: danger) drawing with no button style.
Clause-②: no, Metadata-protocol: none (no accepted set narrows or widens); the claim's narrowed reading is superseded by this comment.
{
"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"
]
}
PR #26776 merged as a122269278 (seat record: PR comment 6446393939). The four action blocks forward variant to the runner with destructive → danger; UIActionSchema.variant is the spec block-row dialect by reference (link aligned, danger refused); the four JUSTIFIED entries are gone. pm:dispatched removed with the close. Follow-ups filed: #26779 (the spec's two variant dialects), #26781 (action:bar member danger draws unstyled).
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…