Repository navigation
the permission-mode menu lists only the modes; grants are revoked in Session Info (carry #28580) - #28617
Conversation
…Session Info Leo, 2026-10-29: "What the hell is this? Why the fuck is this? Grant access, trust this. What is this bottom fucking bullshit? ... It's not fucking good." The composer's permission-mode menu drew a "Granted access" section under the modes (a "Trusted <folder>" row and an "Allow for this chat" row, each with an x), added in #20339. The menu now lists the modes alone. The two grants move to Session Info's Environment section as rows with Revoke, through the same callbacks (folder trust undo, chat.permission_chat.revoke). Chats that offer no modes no longer draw a lock-only Access chip for a grant. Removes access-grants-columns.test.ts (#27579), which measured only the section's columns, and the LockIcon left without a caller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-f2206f5448805d85f14b
…rant comments Adds the Environment gallery's granted variant (folder trust and a chat allowance, each with Revoke), updates three comments that still placed grants in the mode menu, and removes the now-unused permission.grants string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-f2206f5448805d85f14b
|
Found 4 test failures on Blacksmith runners: Failures
|
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by web and size checks: green Shipped in:
|
|
Review (codex gpt-6-astra high, next-review): BLOCK at 617a991
|
|
Visual review (independent, Claude Opus): SHIP at 617a991 Viewed the after images (light and dark). The mode menu is two plain rows (Default with its hint and check, Full access with its warning shield), a single-purpose menu in line with ChatGPT and Claude, and it fits on screen. Session Info shows Trusted and Allow-for-this-chat as one row each with a quiet Revoke at the end, in the list's own row style, with no control repeated across rows. This is the visual verdict only; the Codex BLOCK at this head (folder-trust revoke unreachable when |
…evoke shows on its row's hover Review of #28617 at 617a991 (P1): with default settings Session Info is off (Debug Settings `agent.inspector`), and once trust is decided the trust bar is gone, so a trusted folder had no visible way back. The chat menu (…), in every chat, now ends its tools rows with Revoke Granted Access when the chat has grants: a submenu naming each one (the folder's trust, a chat-wide allowance), whose pick revokes it through the same callbacks. Never the composer's mode menu (Leo, 2026-10-29: "What is this bottom fucking bullshit?"). header/grantsMenu.ts builds the grants once for both places. chat-menu-revoke-access.test.tsx: with Session Info off and a decided trust grant, the chat menu lists the grant and picking it revokes (red with no row, green with it). P2: Session Info's Environment shows a grant's Revoke only while that row is hovered or holds focus, at once with no fade, as the pull request chips' x does (#28533); it stays in the Tab order. Gallery: header-tools `menu-revoke-access`; environment-save `granted-hover`. The design-token baseline shrinks by the access-grants height the first commit removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Review (codex gpt-6-astra high, next-review): SHIP at 456cd87 No blocking findings.
Static review only; tests were not run and screenshots were not inspected. |
…ry-28580 # Conflicts: # webviews/src/agent-session/acpmux/App.tsx # webviews/src/agent-session/acpmux/Localizable.xcstrings # webviews/src/agent-session/acpmux/composerLocation.css
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
Resolve App.tsx (keep the grants block and base's Remote Control row), Composer.tsx (chips no longer take permissionAccess) and ChatInspector.tsx (AccessGrant plus base's InspectorSectionList). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
…evoke Pins inspector.css: a grant's Revoke is transparent at rest and lights only on its own row's :hover/:focus-within (456cd87), so a list of grants never repeats a lit Revoke on every row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Evidence on the BLOCK at 9fab10f ("Revoke repeated on every grant row"): the gallery still it was read from was captured at 617a991, before 456cd87 made each grant's Revoke transparent at rest and visible only while its own row is hovered or focused ( New head e89ba08 adds |
A newer verdict blocks 2dc4161 (no independent SHIP at the head).
|
Review (codex gpt-6.1-sol xhigh, next-review): BLOCK at 2dc4161 BLOCK at 2dc4161 Visual verdict: inspected all 18 after images and their before pairs. The compact modes-only picker follows Claude’s pattern; no visual blocker found.
Full Bun tests were unavailable because Bun and dependencies are absent. Follow-ups:
|
…eveal check Revoke is a plain button that revokes on click and opens no popup, so it needs no :has([data-popup-open]) twin; check:popup-hover-reveals was red at 2dc4161. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Review (codex-review-box/gpt-6-astra high, lane-place): SHIP at c10205d SHIP at c10205d Visual verdict: Both after screenshots pass. The compact mode menu matches Claude’s focused picker pattern, with no repeated revoke controls or off-screen content.
No blocking code findings. String generation and duplicate-key validation passed. Runtime tests were unavailable because Bun and dependencies are absent. Follow-ups:
|
There was a problem hiding this comment.
8 issues found across 24 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/src/agent-session/acpmux/header/grantsMenu.ts">
<violation number="1" location="webviews/src/agent-session/acpmux/header/grantsMenu.ts:39">
P3: The chat-allowance grant appears enabled while its refresh is unread, but its revoke callback is a no-op. Mark the grant unavailable in this state and propagate that disabled state to both the menu child and Session Info's Revoke button.</violation>
</file>
<file name="webviews/src/agent-session/acpmux/App.tsx">
<violation number="1" location="webviews/src/agent-session/acpmux/App.tsx:7660">
P2: Read-only subagent panes still receive `accessGrants` in Session Info and the chat menu. Guard both surfaces with `readOnlySubagent` so a subagent cannot display or revoke the parent chat's grants.</violation>
</file>
<file name="webviews/test/chat-inspector-environment.test.tsx">
<violation number="1" location="webviews/test/chat-inspector-environment.test.tsx:288">
P3: Please replace this profane personal quote with a neutral description; committed test comments should remain professional and focused on the behavior under test.</violation>
<violation number="2" location="webviews/test/chat-inspector-environment.test.tsx:302">
P2: This test does not verify the stated “listed last” behavior because the fixture has no non-grant Environment rows. Add another row, such as Remote Control or a repository row, and assert that the grant rows are the final list items.</violation>
</file>
<file name="webviews/test/chat-menu-revoke-access.test.tsx">
<violation number="1" location="webviews/test/chat-menu-revoke-access.test.tsx:29">
P3: This test does not actually verify that Session Info is hidden when `agent.inspector` is off; it never mounts the Inspector, so the null assertions are vacuous. Render the Inspector in the fixture or remove the Session Info claims and test only the chat-menu revocation path.</violation>
</file>
<file name="webviews/src/agent-session/acpmux/ComposerPickers.gallery.tsx">
<violation number="1" location="webviews/src/agent-session/acpmux/ComposerPickers.gallery.tsx:425">
P3: `modesOnly` can't catch a regression: this variant no longer seeds any grants, so the absence check passes even if the mode menu starts rendering grants. Give the variant a seeded grant source again, or drop the play's grant-absence check in favor of a stronger assertion.</violation>
</file>
<file name="webviews/test/access-chip-pending-warning.test.tsx">
<violation number="1" location="webviews/test/access-chip-pending-warning.test.tsx:228">
P2: This regression test no longer supplies any grant, so its “no Granted access section” assertion only covers the empty state and cannot verify the menu stays grant-free for a chat that actually has grants. Add an App-level fixture with folder/chat grants and assert those grants appear only in Session Info or the chat menu, never in this mode popup.</violation>
</file>
<file name="webviews/test/inspector-grant-revoke-hover.test.ts">
<violation number="1" location="webviews/test/inspector-grant-revoke-hover.test.ts:27">
P2: This negative assertion misses broader selectors that target the shared grant-button class, so a list-wide hover rule could regress the stated invariant while the test remains green. Include selectors targeting `acpmux-chat-inspector-link` or the grant row when collecting lit rules.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| { id: "chat-permission", label: "Allow for this chat", onRemove: () => revoked.push("chat-permission") }, | ||
| ], | ||
| }); | ||
| const rows = [...environment.querySelectorAll<HTMLElement>("li[data-grant]")]; |
There was a problem hiding this comment.
P2: This test does not verify the stated “listed last” behavior because the fixture has no non-grant Environment rows. Add another row, such as Remote Control or a repository row, and assert that the grant rows are the final list items.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/chat-inspector-environment.test.tsx, line 302:
<comment>This test does not verify the stated “listed last” behavior because the fixture has no non-grant Environment rows. Add another row, such as Remote Control or a repository row, and assert that the grant rows are the final list items.</comment>
<file context>
@@ -284,3 +284,28 @@ test("Environment Save also handles a synchronous callback failure", async () =>
+ { id: "chat-permission", label: "Allow for this chat", onRemove: () => revoked.push("chat-permission") },
+ ],
+ });
+ const rows = [...environment.querySelectorAll<HTMLElement>("li[data-grant]")];
+ expect(rows.map((row) => row.dataset.grant)).toEqual(["folder-trust", "chat-permission"]);
+ expect(rows[0]!.textContent).toContain("Trusted scratchpad");
</file context>
| // Leo, 2026-10-29, on the mode menu's "Granted access" section: "What is this bottom fucking | ||
| // bullshit?" The menu lists the modes alone; grants are revoked in Session Info's Environment. | ||
| test("the access menu lists the modes alone, with no granted access section", async () => { | ||
| await render(reported("chat", "default")); |
There was a problem hiding this comment.
P2: This regression test no longer supplies any grant, so its “no Granted access section” assertion only covers the empty state and cannot verify the menu stays grant-free for a chat that actually has grants. Add an App-level fixture with folder/chat grants and assert those grants appear only in Session Info or the chat menu, never in this mode popup.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/access-chip-pending-warning.test.tsx, line 228:
<comment>This regression test no longer supplies any grant, so its “no Granted access section” assertion only covers the empty state and cannot verify the menu stays grant-free for a chat that actually has grants. Add an App-level fixture with folder/chat grants and assert those grants appear only in Session Info or the chat menu, never in this mode popup.</comment>
<file context>
@@ -227,21 +222,21 @@ test("a new chat acpmux starts in full access draws its warning chip on the firs
+// Leo, 2026-10-29, on the mode menu's "Granted access" section: "What is this bottom fucking
+// bullshit?" The menu lists the modes alone; grants are revoked in Session Info's Environment.
+test("the access menu lists the modes alone, with no granted access section", async () => {
+ await render(reported("chat", "default"));
const chip = host.querySelector<HTMLElement>(".acpmux-mode")!;
- expect(chip.querySelector(".acpmux-access-grant-count")).toBeNull();
</file context>
| const shown = block(".acpmux-chat-inspector-row--grant:is(:hover, :focus-within) > .acpmux-chat-inspector-link"); | ||
| expect(shown).toMatch(/opacity:\s*1;/); | ||
| // No other rule lights every grant's Revoke at once (a list-wide :hover, or the list itself). | ||
| const lit = [...css.matchAll(/([^{}]*row--grant[^{}]*)\{[^}]*opacity:\s*1/g)].map((m) => m[1].trim()); |
There was a problem hiding this comment.
P2: This negative assertion misses broader selectors that target the shared grant-button class, so a list-wide hover rule could regress the stated invariant while the test remains green. Include selectors targeting acpmux-chat-inspector-link or the grant row when collecting lit rules.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/inspector-grant-revoke-hover.test.ts, line 27:
<comment>This negative assertion misses broader selectors that target the shared grant-button class, so a list-wide hover rule could regress the stated invariant while the test remains green. Include selectors targeting `acpmux-chat-inspector-link` or the grant row when collecting lit rules.</comment>
<file context>
@@ -0,0 +1,29 @@
+ const shown = block(".acpmux-chat-inspector-row--grant:is(:hover, :focus-within) > .acpmux-chat-inspector-link");
+ expect(shown).toMatch(/opacity:\s*1;/);
+ // No other rule lights every grant's Revoke at once (a list-wide :hover, or the list itself).
+ const lit = [...css.matchAll(/([^{}]*row--grant[^{}]*)\{[^}]*opacity:\s*1/g)].map((m) => m[1].trim());
+ expect(lit).toEqual([".acpmux-chat-inspector-row--grant:is(:hover, :focus-within) > .acpmux-chat-inspector-link"]);
+});
</file context>
| const lit = [...css.matchAll(/([^{}]*row--grant[^{}]*)\{[^}]*opacity:\s*1/g)].map((m) => m[1].trim()); | |
| const lit = [...css.matchAll(/([^{}]*(?:\.acpmux-chat-inspector-row(?:\b|--grant)|\.acpmux-chat-inspector-link\b)[^{}]*)\{[^}]*opacity:\s*1/g)].map((m) => m[1].trim()); |
| machineName, | ||
| repository: githubRepository, | ||
| shell, | ||
| grants: accessGrants, |
There was a problem hiding this comment.
P2: Read-only subagent panes still receive accessGrants in Session Info and the chat menu. Guard both surfaces with readOnlySubagent so a subagent cannot display or revoke the parent chat's grants.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/App.tsx, line 7660:
<comment>Read-only subagent panes still receive `accessGrants` in Session Info and the chat menu. Guard both surfaces with `readOnlySubagent` so a subagent cannot display or revoke the parent chat's grants.</comment>
<file context>
@@ -7635,6 +7657,7 @@ function AcpmuxPane() {
machineName,
repository: githubRepository,
shell,
+ grants: accessGrants,
onOpenOutput: quick ? undefined : inspectorSubagent ? openSubagentOutput : openOutput,
onOpenSourceFile: quick || !inspectorLocal ? undefined : (path) => openSourceFile(path, callNative),
</file context>
| // Leo, 2026-10-29, on the composer mode menu's "Granted access" section: "What is this bottom | ||
| // fucking bullshit?" The grants moved here: each one is a row with its own Revoke. |
There was a problem hiding this comment.
P3: Please replace this profane personal quote with a neutral description; committed test comments should remain professional and focused on the behavior under test.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/chat-inspector-environment.test.tsx, line 288:
<comment>Please replace this profane personal quote with a neutral description; committed test comments should remain professional and focused on the behavior under test.</comment>
<file context>
@@ -284,3 +284,28 @@ test("Environment Save also handles a synchronous callback failure", async () =>
expect(container.querySelector('[role="alert"]')).not.toBeNull();
});
+
+// Leo, 2026-10-29, on the composer mode menu's "Granted access" section: "What is this bottom
+// fucking bullshit?" The grants moved here: each one is a row with its own Revoke.
+test("what the chat was granted is listed last, each with Revoke", async () => {
</file context>
| // Leo, 2026-10-29, on the composer mode menu's "Granted access" section: "What is this bottom | |
| // fucking bullshit?" The grants moved here: each one is a row with its own Revoke. | |
| // Grants moved here from the composer mode menu: each grant is a row with its own Revoke. |
| pretendToBeVisual: true, | ||
| }); | ||
| // Debug Settings `agent.inspector` at its default: off, so Session Info never shows. | ||
| setHeaderState({ inspector: false }); |
There was a problem hiding this comment.
P3: This test does not actually verify that Session Info is hidden when agent.inspector is off; it never mounts the Inspector, so the null assertions are vacuous. Render the Inspector in the fixture or remove the Session Info claims and test only the chat-menu revocation path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/chat-menu-revoke-access.test.tsx, line 29:
<comment>This test does not actually verify that Session Info is hidden when `agent.inspector` is off; it never mounts the Inspector, so the null assertions are vacuous. Render the Inspector in the fixture or remove the Session Info claims and test only the chat-menu revocation path.</comment>
<file context>
@@ -0,0 +1,169 @@
+ pretendToBeVisual: true,
+ });
+ // Debug Settings `agent.inspector` at its default: off, so Session Info never shows.
+ setHeaderState({ inspector: false });
+ class FakeResizeObserver {
+ observe() {}
</file context>
| await ctx.click({ selector: ".acpmux-access-grant-remove" }); | ||
| await ctx.waitFor(() => ctx.document.querySelectorAll(".acpmux-access-grant").length === 1); | ||
| await ctx.waitFor(() => ctx.document.querySelector('[role="menuitemradio"]') !== null); | ||
| if (ctx.document.querySelector(".acpmux-access-grants, .acpmux-access-grant")) |
There was a problem hiding this comment.
P3: modesOnly can't catch a regression: this variant no longer seeds any grants, so the absence check passes even if the mode menu starts rendering grants. Give the variant a seeded grant source again, or drop the play's grant-absence check in favor of a stronger assertion.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/ComposerPickers.gallery.tsx, line 425:
<comment>`modesOnly` can't catch a regression: this variant no longer seeds any grants, so the absence check passes even if the mode menu starts rendering grants. Give the variant a seeded grant source again, or drop the play's grant-absence check in favor of a stronger assertion.</comment>
<file context>
@@ -422,20 +417,13 @@ const managedMode: Play = async (ctx) => {
- await ctx.click({ selector: ".acpmux-access-grant-remove" });
- await ctx.waitFor(() => ctx.document.querySelectorAll(".acpmux-access-grant").length === 1);
+ await ctx.waitFor(() => ctx.document.querySelector('[role="menuitemradio"]') !== null);
+ if (ctx.document.querySelector(".acpmux-access-grants, .acpmux-access-grant"))
+ throw new Error("The mode menu shows granted access");
await ctx.press("Escape");
</file context>
| { | ||
| id: "chat-permission", | ||
| label: t("permission.allowChat"), | ||
| onRemove: () => (sources.allowanceUnread ? undefined : sources.revokeAllowance()), |
There was a problem hiding this comment.
P3: The chat-allowance grant appears enabled while its refresh is unread, but its revoke callback is a no-op. Mark the grant unavailable in this state and propagate that disabled state to both the menu child and Session Info's Revoke button.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/header/grantsMenu.ts, line 39:
<comment>The chat-allowance grant appears enabled while its refresh is unread, but its revoke callback is a no-op. Mark the grant unavailable in this state and propagate that disabled state to both the menu child and Session Info's Revoke button.</comment>
<file context>
@@ -0,0 +1,61 @@
+ {
+ id: "chat-permission",
+ label: t("permission.allowChat"),
+ onRemove: () => (sources.allowanceUnread ? undefined : sources.revokeAllowance()),
+ },
+ ]
</file context>
…ry-28580 # Conflicts: # webviews/scripts/check-popup-hover-reveals.ts
Resolves the conflicts from the Inspector -> Session Info rename (#29921) and Codex's look composer row (#30395): grant rows, CSS, hover-reveal exemption and tests move to the session-info names; the composer bar keeps base's layout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Review (subagent claude-opus-5-5): SHIP at b120bb2 Delta review of the merge resolution (Inspector -> Session Info rename #29921, composer bar #30395): nothing base added is dropped, the PR intent is intact, no stale inspector names. Follow-ups:
|
… rename (#29921) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Review (subagent claude-opus-5-5): SHIP at f8e0741 Delta since b120bb2: test/session-info-environment.test.tsx calls renderSessionInfo (base renamed renderInspector, #29921). No other stale Inspector-era names in the PR files. Follow-ups:
|
# Conflicts: # webviews/src/agent-session/acpmux/session-info/SessionInfo.tsx
|
Review (subagent claude-opus-5-5): SHIP at 4ee378d Delta: merge of base cb44deb (#30953 cloudRepositoryAvailable) kept beside the PR grants prop at every level; the subagent guard Follow-ups:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo, 2026-10-29: "What the hell is this? Why the f*** is this? Grant access, trust this. What is this bottom fing nonsense? Who the f? What did this? It's not fing good. What the f is this? And clicking out of a fing context menu is sometimes slow as fing balls. What the f***?"
Carries #28580 (original lane's commits kept with authorship); #28580 closes once this lands. The original lane can no longer push, so this lane branch carries the same commits unchanged.
Takes back #27579: on purpose. #27579 aligned the mode menu's Granted access section and added access-grants-columns.test.ts to measure it; this PR removes that section (grants move to Session Info), so the test has nothing left to measure.
What changed
The composer's permission-mode menu (the "Bypass permissions ⌄" chip) drew a Granted access section under its modes: a "Trusted " row and an "Allow for this chat" row, each with an ×. The section came from #20339 (
fix(cx-gakp): make permission cards honest per harness), and #27579 later aligned its columns.permission.grantsstring are gone.trustAsk.undofor the folder's trust;chat.permission_chat.revoke, still guarded byready === false, for the chat allowance). A subagent's Session Info doesn't list them, because they belong to the chat. The chat allowance also keeps its existing Revoke menu action (permissionRevoke).access-grants-columns.test.ts(fix(composer): Access menu's allowed rules sit on the mode rows' columns, and only their × lights #27579) measured only the removed section's columns, so it goes. So does theLockIconit leaves without a caller, and its gallery-coverage allowlist line.Known gap, not changed here: Session Info sits behind Debug Settings
agent.inspector, which is off by default. With default settings a grant is still revoked the way it was before it showed in this menu: the folder trust bar's Undo while it shows, and the Revoke menu action for a chat allowance. This PR doesn't change that default (the rulebook says never flip a default unasked). If Leo wants a default-visible home, Settings → Folder Trust is the natural one. It holds the trust rules but no per-folder answers today.Spec:
design/menus.md(this lane owns the mode-menu trust section) anddesign/session-info.md. After landing,menus.mdgets the rule "the mode menu lists modes only; grants are revoked in Session Info".Tests
test/access-chip-pending-warning.test.tsx: the access menu lists modes and draws no granted-access section and no "Granted access" text. This replaces the test that asserted the section.test/chat-inspector-environment.test.tsx: new test. Environment lists both grants last, each with a Revoke button whose label names the grant, and each click calls its own revoke.ComposerPickersmodes-onlyreplacesaccess-grants;agent-pane.environment-savegainsgranted;bottomStacktrustThenPermissionnow asserts the composer draws no Access menu for a grant.bun run typecheck: no type errors in 3237 files, at 617a991, on Linux.bun testaccess-chip, chat-inspector-environment, composer-row-layout, gallery-coverage and strings-build-output: 25 pass, 1 skip (browser lane).gallery-coverage.test.tshas 3 failures that are base reds: the same three tests fail at base 17368d2 with the same lists. The only difference is the component count (818 → 817, the removedLockIcon).Carry re-run (
cmux-ci test, Linux, at 617a991): typecheck clean; access-chip-pending-warning, chat-inspector-environment, composer-row-layout, quiet-access-chip, access-chip-refused-mode, agent-pane-bottom-stack and strings-build-output pass.gallery-coverage.test.tsfails 2 tests scoped to this PR's files (a RowFrame cover in App.tsx, and the stale ChatComposerChips and NewTabComposerChips allowlist lines). Both fail the same way, with the same lists, at base 17368d2: base reds, not changed here.Screenshots
Gallery stills, Linux Chromium at 2x, synthetic fixtures, from a
cmux-ci testgallery run at 617a991 (before: base 17368d2, entryagent-pane.composer-pickersvariantaccess-grants; after:modes-onlyandagent-pane.environment-savegranted). Each menu still is the play step right after clicking Mode. The before stage is 260 px tall, so the top of that menu (which opens upward) is cut off; the Granted access section under the modes is the part that matters.The Session Info grants still was taken at 617a991, before 456cd87 made each grant's Revoke show only while its own row is hovered or focused (inspector.css,
.acpmux-chat-inspector-row--grant), so it was removed as stale. Leo, 2026-10-31: "We don't need screenshots, just let me try the stuff out."Viewed after image: yes
Visual verdict: The mode menu now holds only its mode rows, like the mode menus in ChatGPT and Claude, and the two grants sit as plain rows with Revoke at the end of Session Info's Environment list, in its own row style.
Review
Independent review (Codex gpt-6-astra, high, fast) at 234f147: SHIP, no correctness findings. The stale comments and the unused string it noted are fixed in 617a991. A delta review at the final head follows.
Agent session: agent session
🤖 Generated with Claude Code