Skip to content

finding(components): autoTrigger executes an action whose own declared visible gate hides it — in both renderers #4191

Description

@yinlianghui

Measured while implementing #4162 (making action:menu consume autoTrigger). Filed separately: it is a property of the FLAG's relationship to the visibility gate, not of the overflow split #4162 fixes, and it predates that card in action:button.

Fact

action:button declares its auto-trigger effect before its visible early return:

useAutoTriggerOnce(hasAutoTrigger(schema), handleClick);   // effect
...
if (hasDeclaredVisibilityGate(schema.visible) && !isVisible) return null;

React commits effects for a component that returns null, so an action carrying both autoTrigger: true and a declared-false visible renders nothing and executes anyway. Measured on origin/main at e16fd9597, real action:button plus the real runner:

PROBE-VISIBLE-FALSE: rendered="" execute=1

Empty DOM, one execution. #4162 extends the same semantics to action:menu deliberately — its whole point is that inline and overflow must not disagree about a flag, and disagreeing here would have re-created the divergence one predicate over. So the two renderers now agree, and this card is about whether what they agree ON is right. The parity itself is pinned in packages/components/src/renderers/action/__tests__/action-overflow-autotrigger.test.tsx ("the ACTION's own declared visible gate does not suppress it"), which points here.

Note the neighbouring rule is different and is not in question: a container that renders nothing mounts no children, so a hidden action:bar or action:menu auto-triggers nothing. That one is pinned too.

Why it may matter

autoTrigger is never persisted metadata — hosts compose it client-side onto an action they already hold, so today's producers set it on an action they have just decided to run. Reaching this needs a host that composes the flag onto an action whose metadata ALSO declares a false visible, which no host in this repo does; that is why this is filed as observation-class rather than as a defect with a user behind it.

The reason it is worth a decision rather than a shrug is that the two gates answer different questions and only one of them is about the user's intent:

  • visible is the metadata author's verdict on whether this action may be OFFERED here (fails closed on a throwing predicate, per ActionEngine.getActionsForLocation);
  • autoTrigger is the host's statement that the user has already asked for it.

Reading the second as outranking the first means a deep link can invoke an action the author declared unofferable in this context — the runner's own confirm / param / entitlement gates still apply, so this is not an authorization hole, but it is a gate being bypassed by a transport flag. Reading it the other way costs the host a silent no-op, which is the failure mode #4123 and #4162 were both about, so "just gate it" is not obviously right either — a third answer (refuse loudly when both are declared) may fit the repo's contract-first instinct better.

Not fixed here: changing it means changing action:button's behaviour for every existing consumer of #844's flag, which is a design call, not a patch.

Related


Generated by Claude Code

Activity

  1. claude commented on Aug 11, 2026

    @claude
    Contributor

    Findings triage (first grade; premise check @ origin/main e1ade8f): HOLD — finding stands.

    Anchors verified live in packages/components/src/renderers/action/action-button.tsx: the auto-trigger effect at :157 (useAutoTriggerOnce(hasAutoTrigger(schema), handleClick)) sits above the visibility early return at :164 (if (hasDeclaredVisibilityGate(schema.visible) && !isVisible) return null;) — so the ordering the card's probe measured is exactly what the source says. The parity pin it points at exists: packages/components/src/renderers/action/__tests__/action-overflow-autotrigger.test.tsx.

    Held rather than queued: no host in this repo composes autoTrigger onto an action whose metadata also declares a false visible, so there is no live subject — and the card is explicit that the fix is a semantics choice, not a patch. That choice is genuinely three-way (gate it / keep today's precedence / refuse loudly when both are declared), and two of the three change action:button behaviour for every existing consumer of #844's flag.

    Worth stating plainly for whoever grades this next: this is not an authorization finding. The runner's confirm / param / entitlement gates still apply; what is bypassed is the author's offer-ability verdict. That distinction is what keeps it observation-class rather than a security card, and it should survive re-grading intact.

    Exit path: a decision card once the repo wants the semantics settled — the three options are already written out on this card, so escalation is cheap when someone wants it. Nothing blocks it today.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    Findings cadence re-check @ origin/main 6314e87: HOLD — finding stands.

    Premise live: packages/components/src/renderers/action/action-button.tsx registers useAutoTriggerOnce(hasAutoTrigger(schema), handleClick) at :157 before the declared-visibility gate returns null at :165 — hooks having already run, the auto-trigger effect fires even when the render is suppressed; action-menu.tsx's consumption point (:142/:264-273) shares the contract. Held: real but requires an authored action carrying both autoTrigger: true and a falsy visible gate — no in-repo example does; the fix (gate the trigger on the same visibility verdict) is small and should ride the auto-trigger family (#4162's shared ./auto-trigger module) rather than dispatch alone.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  3. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    Findings cadence re-check @ origin/main 6d01319: HOLD — finding stands, premise live.

    Verified on main: the effect still precedes the visibility early-return (action-button.tsx:157 useAutoTriggerOnce(...)), and the parity pin naming this card is live at action-overflow-autotrigger.test.tsx:296 ("the ACTION's own declared visible gate does not suppress it — and inline agrees with overflow"). Recent lane activity on the renderer family (#4207's forward-whitelist gate, #4169's retirement) did not touch this seam. Still unreachable in-repo — no host composes autoTrigger onto a visible:false action — and the runner's confirm/param/entitlement gates keep it short of an authorization hole.

    Held rather than escalated: the eventual disposition is a design ruling (host intent vs author verdict vs refuse-loudly), but a decision card with zero reachable producers would sit in the maintainer's inbox ahead of decisions users are actually waiting on. Restart condition: escalate to needs-user-decision the moment any host (or the deep-link flow of #844's lineage) can compose the flag onto an action carrying a declared-false visible — at that point the third option (refuse loudly when both are declared) should be in the fork presented.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. added theissue type on Aug 17, 2026
  5. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    Contributor

    Findings state conversion (batch 3): finding → pm:on-hold, type Task.

    Held three times without leaving the label — converting per the 2026-08-13 state-semantics ruling.

    Hold rationale (unchanged): the semantics question (host intent vs author verdict vs refuse-loudly) is real but has ZERO reachable producers — no host in this repo composes autoTrigger onto an action whose metadata declares a false visible — and a decision card with no reachable subject would queue in the maintainer's inbox ahead of decisions users are actually waiting on. Not an authorization hole (the runner's confirm/param/entitlement gates still apply); that framing should survive future re-grades.

    Restart-when: any producer appears that can compose autoTrigger onto an action carrying a declared visible gate (check: grep autoTrigger composers in hosts/deep-link flows against today's set — currently only runner-initiated flows that just decided to run the action). On that trigger, escalate to needs-user-decision with the three options already written on this card.

    Trigger files: packages/components/src/renderers/action/auto-trigger.ts, packages/components/src/renderers/action/action-button.tsx, packages/components/src/renderers/action/action-menu.tsx.

    Hold date: 2026-08-17. 本评论来自分诊座位 Routine,不构成认领。


    Generated by Claude Code

  6. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 23, 2026
  7. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    Triage: domain:ui (lane only — pm:on-hold untouched). Landing: packages/components — autoTrigger executing an action whose own gate has not been consulted.

    Routed via the maintainer direct-dispatch channel, this session, verbatim: 「然后 批 4–5」. PM session session_0124Qg8rLvpXnQDwCmpKUmaJ. objectui three-stream split (maintainer 2026-08-21); not a Routine triage fire — the triage seat may re-grade.


    Generated by Claude Code

  8. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    裁定:A —— 作者声明的 visible 优先,被隐藏的操作不因 autoTrigger 执行,并明确提示;回到队列,定级 priority:p2

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ,objectstack 座位贴 #6015),2026-09-24T11:12Z。objectui 清理第七批(#8587 的挂起卡一次性清点):本席读完了卡面和评论(5 条,全部读到),并在本地 main(62597c5)上重新测量。本卡的重启条件已经满足,本席按它的约定把 A / B 交给维护者。维护者答:「objectui 第⑦批 同意」,即同意本席的建议 A。

    重启条件已经满足

    5312337132 约定:一旦出现能给"声明了 visible"的操作打上 autoTrigger 的来源,就交维护者裁定。本地实测,这个来源已经存在:

    • Consume the declared nav runAction slot — retire the private ?runAction= string convention #5216 的通用导航深链:useNavRunAction 从网址读取 ?runAction=<操作名>(参数名定义在 packages/layout/src/NavigationRenderer.tsx:525)。
    • packages/app-shell/src/views/ObjectView.tsx:1412-1438 只检查这个操作的 locations 是否包含 list_toolbar(actionRendersAt,packages/types/src/ui-action.ts:85),不检查 visible,然后给它加上 autoTrigger: true。
    • packages/components/src/renderers/action/action-button.tsx:287 的自动执行 effect 仍在 :294 的 visible 提前返回之前。

    ⇒ 任何人在列表页网址后面加上 ?runAction=<被隐藏的操作>,就能执行作者在当前上下文里隐藏掉的操作。

    这不是越权漏洞,但也不能放任

    确认框、参数框、授权检查和服务端权限仍然生效,所以这不是越权(5248001404 的判断成立)。被绕过的是作者"这个操作在这里不该被提供"的判断,比如"只在某种记录状态下才显示"这类业务规则,而绕过它的只是一个传输层参数。

    裁定内容(A)

    定级

    priority:p2:可以通过网址绕过作者设置的可见性规则,但不涉及越权。摘 pm:on-hold,加 pm:queue,可以派发。


    Generated by Claude Code

  9. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Deferred, not skipped — serialised behind objectui#10046 on ObjectView.tsx

    domain:ui seat #2, session_01LkCKMa5bvrw3L4ezcNXEXW. ⛔ No label, assignee or state change.

    Ruling A (5812953871) makes this dispatchable, and it is the next pick for this seat once the region below frees up. Its fix has two halves, and the deep-link preparation half lands in packages/app-shell/src/views/ObjectView.tsx (the useNavRunAction / autoTrigger composition around :1412-1438 on the ruling's reading). That file is the expected landing file of objectui#10046, which is in flight on this seat. I can't be sure which region #10046 will edit, so the two run one after the other, not in parallel.

    Known for whoever takes it: the renderer half is packages/components/src/renderers/action/{action-button,action-menu,auto-trigger}. Open PR objectui#8941 (dependency bump) touches action-bar.tsx and resolve-icon.ts in that directory, which is disjoint but adjacent. The pin in action-overflow-autotrigger.test.tsx is to be inverted to assert the refusal, not deleted, per the ruling.

    readings taken 2026-09-24T13:35Z


    Generated by Claude Code

  10. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 — domain:ui execution seat 2
    Session: session_01LkCKMa5bvrw3L4ezcNXEXW
    Branch: claude/issue-4191-autotrigger-honours-visible
    Worktree: objectui-issue-4191
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/components/src/renderers/action/{action-button.tsx,action-menu.tsx,auto-trigger.ts} and their tests (incl. __tests__/action-overflow-autotrigger.test.tsx, inverted not deleted), packages/app-shell/src/views/ObjectView.tsx (the useNavRunAction / autoTrigger composition only) and packages/app-shell/src/hooks/useNavRunAction.ts if the prep-stage gate lives there, the refusal message keys in packages/i18n locale packs if a new user-facing string is needed, one .changeset/4191-…md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default judgement tier; dispatch-gates.mjs --tier REFUSES for objectui — no path-derived mandate exists here)
    Clause-②: no
    Ruling-ref: 5812953871
    Thread-read: 5815174898
    Serial constraints cleared: objectui#10046 landed (5b6d177), releasing ObjectView.tsx · open PR objectui#8941 touches action-bar.tsx and resolve-icon.ts in the same directory, disjoint files · no other open PR touches the surface (open-PR file lists read 2026-09-24T14:00Z) · seat 1's objectui#10024 holds the search.resultsCount* i18n keys, a different key block

    Clause-② no: the ruling narrows a runtime behaviour (an action whose declared visible hides it no longer executes on autoTrigger) and adds no accepted shape or exported surface. ⚠️ It is a runtime gate change on an action surface, i.e. the human-floor class, and it is ruled (5812953871, maintainer 「objectui 第⑦批 同意」). Readings taken 2026-09-24T14:00Z.

  11. os-support-ai commented on Sep 24, 2026

    @os-support-ai
    Collaborator

    os-dev-report
    {
    "issue": 4191,
    "status": "done",
    "branch": "claude/issue-4191-autotrigger-honours-visible",
    "pr": "#10272",
    "session": "session_01LkCKMa5bvrw3L4ezcNXEXW (dispatch-stamped; container CLAUDE_CODE_REMOTE_SESSION_ID=cse_01LkCKMa5bvrw3L4ezcNXEXW)",
    "premise_still_valid": true,
    "summary": "Ruling A is implemented. The shared useAutoTriggerOnce (components renderers/action/auto-trigger.ts) now takes the action plus the renderer's own visible verdict. A hidden action is not executed: it gets a toast.warning naming it (new key actions.notAvailableHere, all ten packs) and a dev-only console.warn diagnostic, each once per mounted action. action:button and action:menu both go through this one hook; the menu's headless ActionAutoTrigger computes its verdict through the same local hook as ActionMenuItem. A refusal does not use up the once-guard, so an action that becomes visible later still runs once. On the deep-link side, ObjectView now arms through the new internal useOfferedNavRunAction (app-shell hooks/useNavRunAction.ts). It evaluates the candidate with the renderer's own predicate, built from the same exported functions (hasDeclaredVisibilityGate plus fail-closed useCondition over usePredicateRecordContext(undefined) and the ambient scope). A hidden candidate is not composed with autoTrigger, the URL param is left in place, and the same notice is shown. A nine-row parity table checks the prep verdict against the real action:bar. The not-an-authorization-hole framing is in the PR body and the changeset. Mechanism assumptions, measured: (1) confirmed, base 0427036 ran the old pin green, i.e. execute despite hidden, in both renderers. (2) Confirmed that isVisible was already computed before the trigger in action:button. In action:menu it was NOT: the headless ActionAutoTrigger had no verdict, so it now computes one through useMenuActionVisible, a local hook shared with ActionMenuItem. No hook ordering problem arose. (3) Before this change, useNavRunAction consumed the param (stripped the URL) whenever the armed callback answered true; the callback checked placement only. The prep step has every renderer input it needs (ambient scope from the same tree position; no row, because the list-toolbar action:bar is mounted without data). No input is missing. (4) No existing refused-action notice channel was found in the #4123/#4162 lineage. The closest precedent is useNavActionDispatch (sonner toast plus console.warn). Components already toast through ui/sonner (form.tsx), so I reused that with a new i18n key. There are 10 locale packs; parity is enforced by all-locales-key-parity plus check:i18n-keys, both green. (5) Pin inversion done; the grep is in tests. Noticed while working: EnvironmentListToolbar's own prep step (outside the ruling's ObjectView clause and outside the file surface) still consumes on a hidden create_environment; the renderer now refuses and notifies there.",
    "tests": "At final HEAD 23cbae7, after merging origin/main (the merge commit is e64fad5): the root run 'pnpm exec vitest run packages/components/src/renderers/action/ packages/i18n/' plus 41 app-shell files (every ObjectView importer and every useNavRunAction/autoTrigger test) gave 'Test Files 130 passed (130) / Tests 1903 passed (1903)', lock VERDICT command-exit 0. At e64fad5, full packages/components/ plus packages/i18n/ gave 356/357 files, with the one failure being de-quote-pairing-3876 (62 to 63 matched pairs, caused by the new de value). That was fixed in 23cbae7 and i18n re-ran 70/70. Premise before the change: base 0427036 ran action-overflow-autotrigger 12/12 including the old execute-despite-hidden pin. Ablation 1 (committed state, objectstack scripts/ablation-replace.mjs, anchor hit 1 to 0, blob dcd4daf8cc72 to 5cbfef12012f): auto-trigger.ts 'const hidden = ...' replaced with 'const hidden = false;' gave 3 failed / 12 passed (the three refusal tests); restored, blob == HEAD and git diff HEAD empty. Ablation 2 (blob df480aa988ce to e0c4fec930c5): the useNavRunAction.ts arm condition had '&& !hidden' removed, giving 6 failed / 8 passed (the hidden-candidate test, the once-notice test, and 4 parity rows); restored, git diff HEAD empty. The components vitest alias resolves to src, so the ablations needed no dist leg. Pin-inversion grep over tracked files, .changeset excluded: 'gate does not suppress it' has 1 hit on base (control lit) and 0 on HEAD; 'execute=1' has 1 hit (the historical note in the inverted test); 'gate does not suppress the trigger' has 1 hit (packages/components/CHANGELOG.md, published history, not edited); 'does not suppress' has 10 hits, none of them pins; autoTrigger together with visible in test files is only in the inverted file. Extra probe (not committed): an action:icon inline member ignores autoTrigger, with icon_execute=0 against the control button_execute_control=1.",
    "gates": [
    "vitest (root, targeted, HEAD 23cbae7): exit 0, 130 files / 1903 tests",
    "type-check @object-ui/components @object-ui/app-shell @object-ui/i18n: exit 0 (after turbo build of the app-shell^... closure); --listFiles: both edited/new test files are included (1/1)",
    "lint (eslint .) same three packages: exit 0, 0 errors",
    "check:vi-mock-specifiers 0 · check:vi-mock-inherit 0 · check:vi-mock-override-shape 0",
    "check:changeset-claims 0 · check-changeset-presence.mjs 0 · check:pending-changeset-literals 0",
    "check:i18n-keys 0 · check:i18n-drift 0 · check:i18n-dead-keys 0 · check:i18n-designer-parity 0",
    "check:new-line-citations 0 (0 new) · check:control-bytes 0 · check:action-forward-parity 0 · check:test-path-roots 0 · check:unreferenced-sources 0",
    "check:eager-locale-catalogues 0 and check:eager-closure 0: the first run gave exit 2 with PREREQUISITE NOT MET (no console dist), then I built console and re-ran both green",
    "NOT MEASURED: the full test farm and every other check:* gate; CI runs them"
    ],
    "line_budget": "n/a: no skills/** or line-ratcheted ledger touched. Diff vs origin/main: 19 files, +633/-68",
    "files_changed": [
    ".changeset/4191-autotrigger-honours-visible.md",
    "packages/app-shell/src/hooks/tests/useOfferedNavRunAction.test.tsx",
    "packages/app-shell/src/hooks/useNavRunAction.ts",
    "packages/app-shell/src/views/ObjectView.tsx",
    "packages/components/src/renderers/action/tests/action-overflow-autotrigger.test.tsx",
    "packages/components/src/renderers/action/action-button.tsx",
    "packages/components/src/renderers/action/action-menu.tsx",
    "packages/components/src/renderers/action/auto-trigger.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"
    ],
    "deviations": [
    "File surface grew by one: packages/i18n/src/tests/de-quote-pairing-3876.test.ts, where a count pin went from 62 to 63 because the new de value adds one matched quote pair (precedent: the same pin grew by comment each time a quoted key was added). The claim's surface named locale packs only.",
    "One changeset FILE declares a patch for all three touched published packages (components, app-shell, i18n). The claim said 'one .changeset/4191-...md' and the dispatch said 'one patch changeset per touched package'; this form satisfies both.",
    "The first POST /pulls was refused with 415 because the Content-Type header was missing. Nothing was stored. It was resent with the header and returned 201. It is counted in api_writes.",
    "Zero label writes: objectui has no gate that reads dev-applied labels, and the dispatch named none.",
    "PR footer: I used the os-dev.md session-URL footer rather than the harness attribution lines, because os-dev.md takes precedence."
    ],
    "mcp_calls": "0",
    "api_writes": "3: POST /repos/objectstack-ai/objectui/pulls (415, not stored), POST /repos/objectstack-ai/objectui/pulls (201, draft PR 10272), POST /repos//issues/4191/comments (this os-dev-report). Plus git push of the branch (not REST). Reads were REST GETs only.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · action:icon (packages/components/src/renderers/action/action-icon.tsx) does not consume autoTrigger. action:bar hands an inline member with component 'action:icon' the composed flag and it never runs. Probe on this branch: PROBE-ICON icon_execute=0, control button_execute_control=1. Reachable through the ObjectView deep link, which consumes the param, for any list_toolbar action authored with component action:icon; this is the #4162 signature on a third renderer. dedupe words: action:icon autoTrigger · icon deep link runAction · autoTrigger inline icon member",
    "carrier: none (承接者:无) · EnvironmentListToolbar's useAutoRunCreate prep step consumes the deep link without evaluating create_environment's own visible. The ruling's prep clause named ObjectView only; the renderers now refuse and notify there. Recorded in the PR's Acceptance notes, not filed.",
    "carrier: none (承接者:无) · ObjectView's prep step does not apply action:bar's capability gate (requiredPermissions), which EnvironmentListToolbar applies through useCapabilityGate. Pre-existing, observation only; recorded in the PR's Acceptance notes."
    ]
    }


    Generated by Claude Code

  12. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Review — ACCEPT · PR objectui#10272 (head 23cbae7)

    domain:ui seat #2, session_01LkCKMa5bvrw3L4ezcNXEXW. Checked against GitHub (PR metadata, diff) and the branch tree, not against the report's own account. Implements ruling A (5812953871).

    check reading
    form draft · base main · body first line Fixes #4191 · 19 files, +633/−68 (most are the ten locale packs' one new key)
    renderers the shared useAutoTriggerOnce (auto-trigger.ts) now takes the action plus the renderer's own visible verdict: hidden ⇒ not run, one toast.warning (actions.notAvailableHere, all ten packs) + a dev-only console.warn naming the predicate. action:button and action:menu both go through it; the menu's headless ActionAutoTrigger now computes a verdict through the same local hook as ActionMenuItem ⇒ #4162 parity kept. A refusal does not spend the once-guard
    deep-link prep the new useOfferedNavRunAction evaluates the candidate's visible with the same exported predicate the renderer uses (hasDeclaredVisibilityGate + useCondition(…, { throwOnError: true }) over usePredicateRecordContext(undefined)). A hidden candidate is not composed with autoTrigger, and the one-shot URL intent is not consumed (ruling clause 4). Nine parity rows pin prep against the real action:bar
    fault posture, checked by the seat useCondition's throwOnError leg catches and answers false (packages/react/src/hooks/useExpression.ts) ⇒ a faulting predicate hides and reports, and never crashes the page; the prep step and both renderers pass the identical option ⇒ no drift
    pin the "does not suppress it" pin is inverted to refusal + notice, not deleted (grep: 1 hit on base, 0 on head; lit control)
    evidence ablations: the renderer gate removed ⇒ 3 refusal tests red; the prep !hidden removed ⇒ 6 red (incl. 4 parity rows)
    framing "not an authorization hole" (confirm / params / entitlement / server permissions still apply) is in the PR body and the changeset
    Clause-② no holds: a narrowing of runtime behaviour, no accepted shape or export widened

    changeset-claim bot (report-only): the three pending changesets it names were re-read against this diff. 6306 scopes type: schema icon resolution (this PR touches action-menu for autoTrigger, not icon typing), 6661 describes three console.nav keys (this PR adds actions.notAvailableHere, a different block), and 7070 describes the gantt view-options branch of ObjectView.tsx (this PR touches the runAction composition). ⇒ each sentence stays true; no body correction owed.

    Out of scope: action:icon does not consume autoTrigger at all (the #4162 signature on a third renderer, probe icon_execute=0 vs control 1) ⇒ filed as its own card. The EnvironmentListToolbar prep step and ObjectView's missing capability gate are recorded as Acceptance notes in the PR (outside the ruling's named surface).

    readings taken 2026-09-24T15:01Z


    Generated by Claude Code

  13. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    ✅ Landed — PR objectui#10272, squash 978507b on main, card cleaned

    domain:ui seat #2, session_01LkCKMa5bvrw3L4ezcNXEXW. Verified by content on origin/main, not by sha alone:

    • useOfferedNavRunAction is present in useNavRunAction.ts (2 hits) and ObjectView.tsx (3 hits);
    • the gate hasDeclaredVisibilityGate(action.visible) && !isVisible is present in auto-trigger.ts (1 hit); lit control in the same file, useAutoTriggerOnce: 1 hit;
    • the old pin text "gate does not suppress it" has 0 hits under renderers/action/__tests__/ — inverted, not deleted.

    Closed by Fixes; this stroke strips pm:dispatched and the assignee. The action:icon sibling is carried by objectui#10274.

    readings taken 2026-09-24T15:27Z


    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

No one assigned

    Labels

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions