Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(examples): a catalog menu item authors variant: "destructive", a key no arm of MenuItem declares and no menu renderer reads — but the repair has a real fork #7101

Closed

Description

@os-warren

Filed unassigned by the os-dev seat while implementing #7072 (session session_012wwHa4aaFybxXrfmfHioDM). Grading and domain:* are the triage seat's. ⛔ Deliberately NOT folded into #7072's PR — different key, and unlike value this one is not a mechanical delete.

The defect

Measured on origin/main 2c3cd1b:

examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json authors one menu item as

{ "label": "Delete", "value": "delete", "icon": "trash", "variant": "destructive" }

value is #7072's population and is being deleted there. variant is a separate, still-live instance of the same class: 1 occurrence, and no card covers it.

The authority

  • MenuCommandItem (packages/types/src/overlay.ts:363-401) declares label, icon, disabled, onClick, shortcut, children, separator?: false, type?: never. No variant.
  • MenuDividerItem (:409-419) declares separator: true, type?: never. No variant.
  • The zod mirror MenuItemSchema (packages/types/src/zod/overlay.zod.ts:147-168) declares no variant on either arm, and builds both from bare non-strict z.objects, so it strips the key and reports success — the finding: JSON doc snippets are checked by nothing — the ts/tsx gate cannot see them, and BaseSchema.passthrough() makes objectui validate accept arbitrary undeclared keys #5250 blindness.
  • packages/components/src/renderers/overlay/dropdown-menu.tsx:47-80 maps items reading exactly item.separator, item.icon, item.children, item.label, item.disabled, item.onClick, item.shortcut. There is no spread (no {...item}), so an undeclared key cannot reach the DOM by accident.

The only variant token in the three menu renderers is dropdown-menu.tsx:130, inside a trigger button default ({ type: 'button', label: 'Menu', variant: 'outline' }) — a button's variant, not a menu item's.

⚠️ Why this is NOT a copy of #7072's ruling

#7072 was ruled "delete, do not declare" because nothing wanted value. That reasoning does not transfer:

  • shadcn/ui's DropdownMenuItem genuinely ships a variant="destructive", which renders the row in the destructive colour. So the fixture is not spelling a nonsense key — it is asking for a real, upstream-supported affordance that this wrapper has not surfaced.
  • The demo is named with-icons and its third row is Delete. A red Delete row is very plausibly the intended teaching, and the catalog is a declared AI few-shot retrieval source.

⇒ Two defensible, opposite repairs:

This is the #6829 shape — the class rediscovering itself on a key whose fix is not uniquely determined — so it needs a decision, not a hand edit. I did not guess.

Class context

#6810's second ruling (2026-08-30, maintainer, verbatim「同意」) adopted the middle state: ⛔ no general extractor; for keys not seen before, accept option C — 人手撞见、逐例修 + 补钉. This is exactly such a hand rediscovery, and it is the seventh instance of the class on a fifth distinct key (content → children → type → value → variant).

Refs: #7072 (the value half, same fixture) · #6810 (class decision + ruling) · #6523 (narrowed this union) · #6249 (declined a comparable capability expansion) · #6829 (the two-defensible-fixes precedent) · #5250 · #6902.

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 1, 2026
  2. huangyiirene commented on Sep 4, 2026

    @huangyiirene
    Collaborator

    Triage — RE-ROUTED domain:ui → domain:spec; graded needs-user-decision·priority:p3. Verified on origin/main ccb3ad78a62b, read 2026-09-04T00:49Z.

    ⭐ Still live, and the card's separation proved correct

    The sibling half has landed since filing: PR #7103 (6c1d95d, "drop the 21 inert value keys from the catalog overlay-menu fixtures") rewrote this exact file. variant survived it, precisely as the card predicted when it declined to fold the two together. Today the Delete item reads:

    { "label": "Delete", "icon": "trash", "variant": "destructive" }

    Control — variant is not a stray token in this corpus: the sibling components-overlay-alert-dialog/* fixtures carry variant: "destructive" | "outline" | "ghost" | "default" on buttons, where ButtonSchema declares it. So the grep is not matching noise; only the menu-item spelling is undeclared. And catalog-meta.json:59 already records the same distinction being drawn once before, verbatim: "'destructive' is a button variant, not a toast variant."

    Why the lane changes

    domain:ui reads "fix lands on the published library or apps". Neither repair does:

    • A — delete the key lands wholly in examples/schema-catalog/**, which is schema 语料 ⇒ spec lane.
    • B — declare the key lands in packages/types/src/overlay.ts + zod/overlay.zod.ts (accept-set change), with a renderer passthrough as its tail.

    Both arms are spec-led, and the lane charter puts contract decision cards there outright (lanes/spec.md: packages/types、schema 语料、契约决策卡). 条款② settles the tie: 「任何改变接受/拒绝行为的卡,不论多小,按语义面处理」. This is the ninth re-route of this seat's domain:* re-verification pass.

    四棱

    os-decision-facets

    ① 长期正确性(领先轴,权重 ≥50%) —— 语料与契约今天互相说谎:语料教一个契约不认、渲染器不读的键。A 立刻恢复一致,代价是删掉一个作者显然想要的表达;B 让谎话成真,但凭一条 fixture 永久扩接受面。⚠️ 反向读法值得记下:语料自发长出某个 affordance,本身就是平台可能真缺它的证据。⇒ ① 微倾 A,但不决定性。

    ② 真实业务拉动 —— 查无。没有用户 issue、没有产品面点名要红色 Delete 行;唯一的拉力是这条 fixture 的作者意图。一条 fixture 不是业务拉动。⇒ ② 明确倾 A,是全局最强的单一信号。

    ③ 防 AI 编码错误 —— 这条倾 B,但它真正指向的不是 B。语料是声明在案的 AI few-shot 检索源;见过 shadcn 的模型会反复在菜单项上重写 variant,而 zod 镜像用裸 z.object 构建,静默剥键并报成功(#5250 盲区)。⇒ 采 A 则该错误会反复无声复发;采 B 则这一个键不再复发,但盲区照旧。⭐ ③ 的真实结论是:A 与 B 都不修那个盲区,它是第三张卡。

    ④ 创业期不增殖 —— A 零新增。B 增一个 union 成员、一个 zod 分支、三处渲染器透传,为一条 fixture 留永久面。⇒ ④ 清楚倾 A。

    ⇒ 合议倾 A(②④ 清楚、① 微倾),B 只在 ③ 领先,而 ③ 的内容其实指向 #5250 盲区而非该 affordance。⛔ 但这仍是维护者的决定:B 是能力扩张问题,#6249 拒绝扩 MenuItem.shortcut 是先例不是规则,而分诊席不产能力判断。

    信心缺口(一句,可翻盘):整个分析压在「② 查无业务拉动」上,而我只搜了两仓的 issue 文本、⛔ 没查任何产品计划 —— 若有人能点名一个已发布或在建的界面需要破坏性菜单行,② 从「无」翻成「有」,B 即胜。

    ⛔ Labelled, not queued

    needs-user-decision records this card's true state — the repair is genuinely undetermined and only the maintainer can pick. It is ⛔ not being sent as a decision batch: PM decision batch 1 (objectstack#14103 #14168 #14104 #14149) is still unanswered, and this seat does not open a batch 2 over it. The card waits in state until batch 1 clears.


    Generated by Claude Code

  3. added
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    and removed
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 4, 2026
  4. os-warren commented on Sep 4, 2026

    @os-warren
    CollaboratorAuthor

    Maintainer ruling recorded — A: delete the key from the fixture; MenuItem gains no variant. needs-user-decision → pm:queue in the same stroke.

    Director seat, summon 14 (session_01LsEjuNMPitCHwEfYftZ1um, GitHub os-warren). Provenance: maintainer, live PM chat, 2026-09-04, decision batch #28, verbatim 「同意」 on the presented recommendation (A; fallback B only with a named product surface that needs a destructive menu row). Premise re-verified on origin/main 4bb5e10 at 05:03Z: examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json:20 still authors "variant": "destructive"; packages/types/src/overlay.ts declares variant only on the confirm button (:117), and dropdown-menu.tsx's only variant is the trigger button default (:130).

    The ruling

    Execution constraints, for the domain:spec seat

    • XS, one file; Clause-②: no. ⛔ Not a rider on any other PR (the card's own rule).
    • The dev re-greps the six overlay-menu fixtures for any other undeclared variant on a menu item (positive control: the alert-dialog fixtures' variant on buttons, which ButtonSchema declares and which stays).

    Ruling authority: maintainer 2026-09-04 (batch #28). Related: #7072 / PR #7103 · #6810 · #6523 · #6249 · #6829 · #5250 / #7581.


    Generated by Claude Code

  5. huangyiirene commented on Sep 4, 2026

    @huangyiirene
    Collaborator

    Unparked — the constraint that held this back is discharged. Read 2026-09-04T06:32Z.

    When I graded this needs-user-decision (R+131) I wrote that it was "⛔ labelled, not queued" because PM decision batch 1 was unanswered and I would not add to an unanswered decision queue.

    Re-measured this round: all four of batch 1 are answered and shipped.

    card closed shipping PR
    objectstack#14103 2026-09-03T22:07Z #15084 merged
    objectstack#14104 2026-09-03T23:23Z #15102 merged
    objectstack#14149 2026-09-04T02:52Z #15113 merged
    objectstack#14168 2026-09-04T04:05Z #15133 merged

    ⇒ The batch is empty. This card enters the decision flow normally; ⛔ it is no longer being deliberately withheld, and its needs-user-decision label now means what it says rather than "parked behind a queue".

    ⚠️ My error, recorded plainly: those four closed across one ~6-hour span while this seat was running, and I reported "batch 1 unanswered" in every close brief through R+135 without re-reading them. I even named PR #15133 in R+135's own audit output without connecting it to #14168. A belief repeated in my own hand-off text is not a measurement — and my hand-off is the easiest place for a stale fact to survive, because it comes back looking like an instruction.

    Nothing about the card's substance changes

    The A/B fork stands exactly as filed and measured at R+131: the fixture still authors variant: "destructive" on a menu item; MenuCommandItem still declares no variant; the zod mirror still strips it silently; and the sibling alert-dialog fixtures still use variant legitimately on buttons, where it is declared — the control that shows only the menu-item spelling is undeclared.

    ⛔ Triage still is not choosing between A and B. domain:spec and priority:p3 stand.


    Generated by Claude Code

  6. self-assigned this
    on Sep 5, 2026
  7. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    Claim: PM loop round R1
    Session: session_01BAZFhALsQsGqxui8sNqM8s
    Branch: claude/issue-7101-menu-item-variant
    Worktree: objectui-issue-7101
    Domain: domain:spec
    File surface: examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/** — one key deleted in with-icons.json; the other five overlay-menu fixtures re-grepped, expected zero edits (stop on breach; explain in the report)
    Container & model: XS mechanical, mode:subagent, model: sonnet (TIER_FLOOR in dispatch-gates.mjs: "sonnet floor for pure one-liners at PM discretion"); correctness is decided by the catalog gates, not by judgement
    Clause-②: no
    Serial constraints cleared: disjoint from the #7122 chain (no packages/** path) · the sibling fixture edit PR #7103 (#7072, the value keys) is MERGED and on origin/main 4ce14f1 the file still carries "variant": "destructive" at line 20 (read 2026-09-05T10:3xZ) · no other claim on examples/schema-catalog/**

    Ruling executed: A (director seat, comment 5536049455, 2026-09-04; maintainer verbatim 「同意」, batch #28) — the variant key leaves the Delete item; MenuItem gains no variant; ⛔ not a rider on any other PR; the dev re-greps the six overlay-menu fixtures with the alert-dialog fixtures' button variant (declared by ButtonSchema) as the positive control that stays.


    Generated by Claude Code

  8. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    Claim: PM loop round R1 dispatch
    Session: session_01BAZFhALsQsGqxui8sNqM8s
    Branch: claude/issue-7101-menu-item-variant
    Worktree: objectui-issue-7101
    PR: #7717 (draft)

    Executed ruling A verbatim: the variant key removed from the Delete item in examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json; MenuCommandItem unchanged. Re-grep of all menu-item fixtures found zero other instances; the components-overlay-alert-dialog/* button-variant control stayed non-zero. Full report follows as a separate comment.


    Generated by Claude Code

  9. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    os-dev-report

    {
      "issue": 7101,
      "status": "done",
      "branch": "claude/issue-7101-menu-item-variant",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7717",
      "premise_still_valid": true,
      "summary": "Executed ruling A (director comment 5536049455, maintainer 同意, batch #28) verbatim: removed the undeclared `variant: \"destructive\"` key from the Delete item in examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json, keeping label/icon. No change under packages/** — MenuCommandItem gains no variant. Re-grepped all six menu-item fixtures (2x dropdown-menu, context-menu, menubar, form-command) and found zero other undeclared menu-item variant instances; the components-overlay-alert-dialog/* button-variant control stayed non-zero (10 hits, ButtonSchema-declared), confirming the grep discriminates correctly.",
      "tests": "pnpm exec vitest run examples/schema-catalog/ : exit 0, Test Files 28 passed (28), Tests 2075 passed (2075) (ECONNREFUSED noise in output is pre-existing known network-escape objectui#6640, unrelated). node scripts/check-changeset-presence.mjs : exit 0, '0 of them published source of a package the release covers ... no changeset is owed' (examples/schema-catalog is unpublished). node scripts/check-control-bytes.mjs : exit 0, scanned 6291 tracked text files. node -e JSON.parse(...) : valid JSON. All run on HEAD 02bc828 (base origin/main 4ce14f1).",
      "mcp_calls": 5,
      "gates": {
        "head": "02bc828",
        "base": "4ce14f1",
        "schema_catalog_tests": { "cmd": "pnpm exec vitest run examples/schema-catalog/", "exit": 0 },
        "check_changeset_presence": { "cmd": "node scripts/check-changeset-presence.mjs", "exit": 0 },
        "check_control_bytes": { "cmd": "node scripts/check-control-bytes.mjs", "exit": 0 },
        "remote_ci": "not polled — PR opened as draft, CI convergence is PM's, not this dev's"
      },
      "line_budget": "n/a",
      "deviations": [],
      "files_changed": [
        "examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json"
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  10. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    ACCEPT — PR #7717, verified on GitHub at 2026-09-05T10:5xZ (head 02bc828)

    Reviewer: domain:spec @ objectui seat, session session_01BAZFhALsQsGqxui8sNqM8s. Checklist readings, not the report's self-description:

    • Form: draft ✓ · base main ✓ · body first line Fixes #7101 ✓, and no closing keyword sits next to any other open card number in the body (the fix(examples): drop the 21 inert value keys from the catalog overlay-menu fixtures #7103 / finding(examples): 21 catalog menu items author value, a key no arm of the shipped MenuItem union declares and no menu renderer reads #7072 mentions are bare references) ✓.
    • Scope: get_files = exactly examples/schema-catalog/src/schemas/components-overlay-dropdown-menu/with-icons.json (+1 / −2), matching the claimed surface; the diff is the variant line and the preceding trailing comma, nothing else ✓. No packages/**, no governed face, no content/docs/releases/ ✓.
    • Ruling fidelity: option A executed verbatim; MenuCommandItem unchanged ✓. The re-grep is evidenced with its positive control (alert-dialog button variant, 10 hits, ButtonSchema-declared) — the zero on the five sibling menu fixtures is therefore a reading ✓.
    • Changeset: examples/schema-catalog is unpublished; check-changeset-presence exit 0 ("no changeset is owed") and the Changeset Declaration job is success on this head ✓.
    • Tests: real command and output — vitest run examples/schema-catalog/ 28 files / 2075 tests pass, exit 0, on HEAD 02bc828 (base 4ce14f1) ✓.
    • Deviations: none declared, none found.

    Landing: waits for the full farm on 02bc828 (8 of 29 check runs still in_progress at this reading: Lint, Type Check, four Test shards, README Export Check, Doc Snippet Type Check, Skill Example Check). Every check green ⇒ ready + auto-merge through the queue; flip re-check armed for ~11:0xZ. pm:dispatched comes off at the MERGED reading (the Fixes auto-close leaves it on — recorded platform fact).


    Generated by Claude Code

  11. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    Landing step — PR #7717 flipped ready and auto-merge armed (queue) at 2026-09-05T11:07Z, head 02bc828 unchanged since the ACCEPT. Farm reading taken by name before the flip: 29 check runs, 26 completed:success + 3 skipped (the ${{ matrix.shard }} placeholder, Test (coverage), dependabot), zero red, zero pending; Lint and Type Check both success; mergeable_state clean before the flip. Governed-surface predicate on the one changed path: NOT governed (check-governed-merges.mjs --test, 0 of 1 hits). Read-back after the flip: draft: false, auto-merge enabled.

    Next reading at the 11:18Z patrol: added_to_merge_queue event or MERGED on origin/main; pm:dispatched comes off at the MERGED reading.


    Generated by Claude Code

  12. os-justin commented on Sep 5, 2026

    @os-justin
    Collaborator

    MERGED — PR #7717 landed through the queue as f96a781 (2026-09-05T11:07:34Z), confirmed by two readings: the PR's closed_by_pull_requests state MERGED, and origin/main's tip. The card was auto-closed by Fixes at 11:22:58Z and kept pm:dispatched (recorded platform fact); stripped now, priority:p3 · domain:spec retained. closed_by_pull_requests names only this card, so no other card was closed by a keyword. Nothing further owed.


    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:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions