Skip to content

console: the record ⋯ overflow menu's destructive band honours the spec's variant: 'danger' (objectstack#24277 ruling E1) #12961

Closed as not planned

Description

@objectstack-fleet

Filed by the director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax) from objectstack-ai/objectstack#24277, ruled E1 by the maintainer on 2026-10-18 (batch #365 item 1): keep the header fold and the ⋯ menu as they are — no new spec key, no grouping — and make the menu's existing destructive band honour the spec's own spelling. ⛔ Not a claim.

The defect (read from source at objectui a8560b228527; not yet measured in a browser — the first step below measures it)

  • packages/components/src/renderers/layout/containers.tsx (PageHeaderRenderer, the overflow bands of objectui#12529, around line 2075): isDestructiveAction = (a) => a?.variant === 'destructive' || a?.name === 'sys_delete'. The spec's ActionDefinition.variant enum is primary | secondary | danger | ghost | link (@objectstack/spec packages/spec/src/ui/action.zod.ts, around line 1310) — destructive is the Button primitive's word, not a legal action variant. Nothing on the header path maps danger to destructive (DeclaredActionsBar.tsx:409 does, for its own buttons only).
  • Consequence, if measured true: an object's own variant: 'danger' actions (cloud's sys_environment archive and delete, sys-environment.object.ts:1162 and :1221; sys_user's delete_my_account) sit in the first band of the ⋯ menu, unmarked, while only the console's injected 删除 reaches the red band behind the separator.

What changes

  • The destructive test on the header path recognises the spec's danger (and keeps destructive for host chrome and sys_delete), so an app's danger actions land in the last band, behind the separator, painted red — the band that already exists. Prefer one normalisation where the header actions are memoized over a second spelling test, so the inline button, the overflow row and the disabled-reason branch agree.
  • Nothing else changes: order, maxVisible, record_more routing, the console band and component: 'action:menu' pinning stay as they are.

First measurement (before any PR)

On the local stack, a record whose object declares a variant: 'danger' action folded into ⋯ (a fixture, or sys_user's delete_my_account on your own record): confirm where the row sits today, then after the fix, screenshot each. A premise_still_valid: false report (the row is already red and last) closes this card not_planned with the screenshot.

Acceptance

  • Test in page-header-actions.test.tsx (or the overflow-band test of objectui#12529): a danger action is last, behind a separator, with the destructive row class; a secondary action stays in band 1; the console's 删除 unchanged.
  • Changeset: patch on @object-ui/components.

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 8 (priority:p2)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12961-header-danger-band
    Worktree: objectui-issue-12961
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/components/src/renderers/layout/containers.tsx (the header-actions path: isDestructiveAction at about :2039 and its readers, or one normalisation where the header actions are memoized) and tests beside it (page-header-actions / the objectui#12529 overflow-band test). Plus one .changeset/12961-*.md (@object-ui/components: patch). ⛔ order, maxVisible, record_more routing, the console band and action:menu pinning unchanged; ⛔ no spec key. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: no
    Responsibility: @object-ui/components' header path tests variant === 'destructive', the Button primitive's word, where the spec's ActionDefinition.variant says danger | the platform already maps danger → destructive for DeclaredActionsBar's own buttons (DeclaredActionsBar.tsx:409), not on the header path | every record page whose object declares a variant: 'danger' action folded into ⋯ (cloud's sys_environment archive / delete, sys_user's delete_my_account).
    Thread-read: none
    Serial constraints cleared: no open objectui PR touches packages/components/src/renderers/layout/; the in-flight claims (objectui#12954, #12957, #12960, #12894, #12725) name no file under packages/components/.
    Claimed at: 2026-10-18T12:24Z

  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12961,
    "status": "done",
    "branch": "claude/issue-12961-header-danger-band",
    "pr": null,
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB — the PM's session (mode:subagent)",
    "premise_still_valid": false,
    "summary": "Premise is dead: objectui#12764 (PR #12798, commit 69a408f, merged 2026-10-16T21:28Z) already made page:header read the spec's variant 'danger' as destructive, after the card's source read at a8560b2. On origin/main 7f9cc37 the ONE predicate in PageHeaderActions is isDestructiveAction = (a) => a?.variant === 'danger' || a?.name === 'sys_delete', and it feeds the primary-candidate filter, the three overflow bands, the separator index, the inline button variant and the overflow row's destructive class / disabled-reason branch. A2: there is one copy only; the predicate lives inside the exported PageHeaderActions (objectui#12906) and PageHeaderRenderer renders that component, so the print chrome row and page:header share it. No code written, no PR opened; the empty branch was pushed as the claim marker and can be deleted. Recommend closing #12961 as not_planned, citing #12798 and the measurement below.",
    "tests": "A1, measured on origin/main 7f9cc37 before any edit, with a scratch rendered PageHeaderRenderer test (deleted afterwards, never committed) under os-verify-lock (VERDICT command-exit 1 only because my scratch expectation guessed the order inside the band wrong). Actions: Alpha, Archive Environment (variant danger), Secondary One (variant secondary), Delete My Account (variant danger, locations record_more), maxVisible 1, host Edit/Share/sys_delete as RecordDetailView injects them. Printed reading: MEASURE row=[\"Alpha\",\"Edit\"] overflow=[{\"label\":\"Secondary One\",\"red\":false},{\"label\":\"Share\",\"red\":false},\"---\",{\"label\":\"Archive Environment\",\"red\":true},{\"label\":\"Delete\",\"red\":true},{\"label\":\"Delete My Account\",\"red\":true}]. So the danger rows (record_header folded and record_more alike) are already last, behind the separator and red, and secondary stays in band 1. That matches the role file's stop condition. In the same run, the existing pin packages/components/src/tests/page-header-danger-12764.test.tsx passed 4/4. It already covers pin (a) folded danger is last and red behind the separator, (c) the CONTROL test with sys_delete unchanged, and (d) inline danger draws bg-destructive and is never the filled primary. Pin (b) is covered by that file's CONTROL band order. Ancestry: git merge-base --is-ancestor 69a408f646 a8560b228527 exit 1 (the fix is not in the card's read), and the control leg --is-ancestor a8560b228527 HEAD exit 0. Same check for 69a408f against HEAD: exit 0. The repo is not shallow. No ablation, gates or changeset: there is no diff.",
    "mcp_calls": "0",
    "api_writes": "1 — POST repos//issues/12961/comments (this os-dev-report). git push of the empty branch is not a REST write.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "gates": "none run: no files changed",
    "files_changed": [],
    "deviations": "Did not open a PR or write a changeset, by the premise stop rule. The card asked to keep destructive counting for host chrome, but on main the predicate deliberately does not read variant: 'destructive' (#12798 retired it as a non-spec value). The host Delete still counts by the name sys_delete, so the console delete row is unchanged (the measured last red row). This is recorded here and not changed."
    }

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed not_planned · premise disproved · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-18T12:28Z

    The card's own rule applies: "a premise_still_valid: false report closes this card not_planned". The dev's measurement is in os-dev-report 6249907502; this seat re-verified it on main.

    • Already delivered: objectui#12764, PR fix(components): page:header reads the spec's variant 'danger' as destructive (objectui#12764) #12798, merged as 69a408f646 on 2026-10-16. On main (7f9cc37), packages/components/src/renderers/layout/containers.tsx :2039–:2040 holds one predicate, isDestructiveAction = (a) => a?.variant === 'danger' || a?.name === 'sys_delete', inside the exported PageHeaderActions. Every reader uses it: the primary pick, the three overflow bands, the separator, the inline button face, and the overflow row's destructive class and disabled-reason branch. page:header and the print chrome row share it.
    • Why the card read otherwise: 69a408f646 is not an ancestor of the card's read sha a8560b2 (git merge-base --is-ancestor exits 1), so the card read a tree from before the fix.
    • Measured today, before any edit: a rendered PageHeaderRenderer with a folded variant: 'danger' action, a record_more danger action, a secondary action and the host Edit / Share / sys_delete drew the overflow as Secondary One, Share, separator, Archive Environment (red), Delete (red), Delete My Account (red). So danger rows are last, behind the separator and red, and the secondary action stays in band 1. The existing page-header-danger-12764.test.tsx (4 / 4 pass) already pins the card's Acceptance (a)–(d).
    • One difference from the card's wording, by design: the predicate does not read variant: 'destructive', because PR fix(components): page:header reads the spec's variant 'danger' as destructive (objectui#12764) #12798 retired it as a non-spec value. The host Delete still counts through its name sys_delete, so the console's delete row is unchanged.

    No PR, no code, no changeset. The empty claim branch claude/issue-12961-header-danger-band holds no commits. For objectstack#24277 ruling E1: the menu already honours danger on any console build whose objectui is at or past 69a408f646. Reopen if a console build at that point still draws a danger row in band 1.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions