Skip to content

fix(chat): retarget the panel to the pane a launch card was clicked in - #3334

Merged
bolichen97 merged 1 commit into
mainfrom
fix/split-view-launch-card-affordance
Aug 13, 2026
Merged

fix(chat): retarget the panel to the pane a launch card was clicked in#3334
bolichen97 merged 1 commit into
mainfrom
fix/split-view-launch-card-affordance

Conversation

@chenmingwei23

@chenmingwei23 chenmingwei23 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3302, answering the reviews it drew. Refs #3332.

1. What is the problem?

WorkflowRunCard and SubagentRunCard are whole-card buttons that deep-link into the Workflows / Subagents side panel (openActivityToTab(...)). That panel is mounted for activeSlot, and split view deliberately never moves activeSlot with pane focus.

#3302 started drawing both cards inside panes. So a pane that is not the active session got a click that opens a different session's panel — typically landing on "No subagents running". Split View exists to watch background sessions, which means most clicks in the surface #3302 targeted hit exactly that case, and the task fails silently every time.

Two smaller defects from the same change:

  • Both cards lay out their own full-width row (they set --mc-content-width themselves), and the registry entries wrapped them in ctx.row as well — doubling the row padding.
  • Design Review's concern that the new module is a second hand-maintained row set with no mechanical protection against drift.

2. Why this issue matters to the user

The card's label promises "Open Subagents panel" and shows a panel chevron. In a background pane that promise was false: the click opened an empty panel belonging to another session. A user cannot tell which pane a panel belongs to, so the natural read is that the feature is broken rather than that they clicked in the "wrong" pane.

3. How our fix solves it

Make the click correct rather than remove it. Opening from a pane whose session is not active now retargets first:

if (slot && slot !== activeSlot) dispatch(switchSlot(slot))
// …then select this wave's first agent and open the tab
  • The panel that opens is the one the label promises, in every pane.
  • Safe inside split view: activeIsSplitAnchor computes to null while splitMode is true, so the auto-enter effect cannot reseed the grid, and SessionGridView's seeding is guarded by its own ref. switchSlot is the same action ChatPage already dispatches when a split collapses.
  • switchSlot.pending assigns activeSlot synchronously as it is dispatched, so the panel is pointed at the right session before the tab opens.
  • Single chat passes no slot and is unchanged. WorkflowRunCard gains an optional slot; SubagentRunCard already took one.
  • No new copy. "Open in the Subagents panel" stays true, so nothing needed rewording across 14 locale catalogues.

An earlier revision of this PR did the opposite — it dropped the button, title, chevron and label in a background pane. UX Review was right that this trades a lying link for a dead end: a user seeing "1 agent failed" in the one surface split view exists for would have had no route to the detail and no cue that one existed, and the static card kept enough of its accent shell (bg-accent/10, pi-morph group) that a habituated click would read as broken rather than as not-applicable. Retargeting removes the class instead of hiding it. That review's alternative suggestion — "let the click activate the slot and then open the panel" — is what shipped here.

ctx.row is dropped for both launch entries, with a comment naming the reason so it is not re-added.

For the drift concern, the registry now carries a guard rather than a promise: transcriptRenderers.test.tsx extracts every role the single-chat chain dispatches on straight out of ChatPage.tsx and asserts each is claimed by the registry a pane renders through. A new row type added to ChatPage now fails a test instead of silently reducing the pane transcript. Grouped roles are excluded via the SDK's own GROUPED_ROLES export (a grouped role is displayed by the group, not by a row entry), so the exclusion moves if grouping does. The endgame — ChatPage consuming these entries so there is one row set — is #3332, and every option with no pane wiring yet now names its tracked consumer in the interface.

4. What tests we did

All new assertions are mutation-verified:

  • SubagentRunCard — a click in a background pane leaves activeSlot on the card's own session and opens the Subagents tab on this wave; the card keeps its button and title there (the dead-end regression the earlier revision would have introduced is pinned against); and a card already in the active session does not retarget.
  • WorkflowRunCard — same three, plus the no-slot single-chat path.
  • Drift guard — every role ChatPage dispatches on is claimed, with a self-check that the extraction actually found the chain, so a rename in ChatPage fails loudly instead of making the guard vacuously pass.

Mutation results: deleting the switchSlot retarget line kills a test in each card. On the drift guard, breaking the nudge and file claims each fails it; breaking thinking does not, which is correct — thinking is a grouped role and excluded by design.

Worth recording two process notes. The drift guard was vacuous on first write — it counted '*' entries as claiming every role, so it passed while a claim was missing; mutation testing caught it, and a shape-matched '*' entry (which carries a match) now explicitly claims no role. And the retarget tests initially failed for the wrong reason: switchSlot.pending reads slotHistory / slotMessages, so a partial preloaded state threw inside the reducer rather than exercising the retarget.

Gates: tsc --noEmit 0 errors · eslint 0 errors · npm run i18n:check OK · npm run i18n:render OK · full vitest 1067 files / 17891 tests passed.

5. Any other suggestions on the work

@chenmingwei23
chenmingwei23 requested a review from a team August 13, 2026 15:48
@chenmingwei23
chenmingwei23 requested a review from a team as a code owner August 13, 2026 15:48
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Aug 13, 2026
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of c473a69dded833d52670575ba7eec5b250351fe0 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] c473a69

False positive or not applicable? A repository writer can comment:
/ai-review override gpt c473a69dded833d52670575ba7eec5b250351fe0: <one-sentence reason>

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Advisory design-level review of c473a69dded833d52670575ba7eec5b250351fe0 — updated in place on each push; does not block merge.

Design-Verdict: PASS

Retargeting fixes the real activeSlot/pane mismatch at its source of truth, and the acknowledged interim debt is mechanically guarded and tracked (#3300/#3332).

[DESIGN-REVIEWED] c473a69

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

Advisory UX-level review of c473a69dded833d52670575ba7eec5b250351fe0 — updated in place on each push; does not block merge.

UX-Verdict: PASS

The click now keeps its label's promise in every pane — panel opens on the clicked session, affordance preserved, no new copy, padding doubled no more.

[UX-REVIEWED] c473a69

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed c473a69dded833d52670575ba7eec5b250351fe0 — this comment is updated in place on each push.

Review details

The candidate is self-admittedly low-confidence and describes the PR's intended behavior (retargeting activeSlot so the panel opens on the correct session) as if it were the defect. Its own outcome clause concludes the state migration is "Invisible while split," and the only concrete effect it can name is a redundant fetchSlotDetail round-trip — an efficiency concern this pipeline owns deterministically, not an observable wrong outcome. It fails to establish (c) a wrong outcome; the whole point of the change is that the panel must be repointed to the clicked pane's session. Dropped under Step 1.

No findings.

[OPUS-REVIEWED] c473a69

Verdict parsed from the review's SHA-scoped output markers for commit c473a69dded833d52670575ba7eec5b250351fe0.

False positive or not applicable? A repository writer can comment:
/ai-review override fable c473a69dded833d52670575ba7eec5b250351fe0: <one-sentence reason>

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 13, 2026
The workflow and sub-agent launch cards deep-link into the Workflows /
Subagents side panel. That panel is mounted for activeSlot, and split view
deliberately never moves activeSlot with pane focus, so #3302 — which started
drawing these cards in panes — gave a background pane a click that opens a
DIFFERENT session's panel, usually reading "No subagents running". Split view
exists to watch background sessions, so most clicks hit it.

Make the click correct instead of removing it: opening from a pane whose
session is not active dispatches switchSlot first, so the panel that opens is
the one the card's label promises. Safe inside split view — the auto-enter
effect is gated on splitMode being off, so switching neither reseeds nor leaves
the grid. Single chat passes no slot and is unchanged.

An earlier revision instead dropped the affordance in background panes. UX
review was right that this trades a lying link for a dead end: a user seeing
"1 agent failed" in the surface split view exists for would have no route to
the detail and no cue that one exists, and the card keeps enough of its accent
shell that a habituated click reads as broken. Retargeting removes the class
rather than hiding it, and needs no new copy — "Open in the Subagents panel"
stays true.

Also drops a double row wrapper: both cards lay out their own full-width row,
so wrapping them in the registry's ctx.row doubled the padding.

Adds a drift guard pinning that every role the single-chat chain dispatches on
is claimed by the registry a pane renders through, and names the tracked
consumer of each option that has no pane wiring yet.

Refs #3302, #3332
@chenmingwei23
chenmingwei23 force-pushed the fix/split-view-launch-card-affordance branch from f5c8878 to c473a69 Compare August 13, 2026 16:41
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: passed Eligible automated validation passed for the current revision labels Aug 13, 2026
@chenmingwei23 chenmingwei23 changed the title fix(chat): scope the launch cards' panel affordance to the panel they open fix(chat): retarget the panel to the pane a launch card was clicked in Aug 13, 2026
@chenmingwei23

Copy link
Copy Markdown
Contributor Author

UX Review — adopted, and it changed the design. Both watch items were right, and they were right about the same thing: dropping the affordance traded a lying link for a dead end. In the one surface split view exists for, "1 agent failed" with no route to the detail and no cue that one exists is worse than the bug it replaced, and the static card kept enough of its accent shell that a habituated click would read as broken rather than as not-applicable.

Shipped the review's own better alternative instead — the click activates the slot, then opens the panel:

if (slot && slot !== activeSlot) dispatch(switchSlot(slot))

So the card stays interactive in every pane and the panel that opens is the one the label promises. This also means no copy changes: "Open in the Subagents panel" stays true, so the suggested explanatory title is not needed and nothing had to be reworded across 14 locale catalogues.

Two things I checked before choosing retarget over an explanatory title:

  • It does not disturb the split. activeIsSplitAnchor computes to null while splitMode is true, so the auto-enter effect cannot reseed the grid, and SessionGridView's seeding is guarded by its own ref. switchSlot is the same action ChatPage already dispatches when a split collapses.
  • The panel is pointed before the tab opens. switchSlot.pending assigns activeSlot synchronously as it is dispatched, so there is no window where the tab opens against the old session.

New tests pin the retarget in both cards (mutation-verified: deleting the retarget line fails one test in each) and also pin that the card keeps its button and title in a background pane, so the dead-end variant cannot come back unnoticed.

Head is now c473a69dd. Screenshot Evidence stays red until evidence lands: the retarget is a sequence, not a still, so it needs a short recording rather than a screenshot — that follows in a revision.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97
bolichen97 enabled auto-merge (squash) August 13, 2026 17:01

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: small-fix (6 files). Criteria: no conflict, no requested changes, no security surface, AI reviewers green. Category: small-fix — fixes panel targeting to respect which pane the launch card was clicked in.

@bolichen97
bolichen97 merged commit 62d91f2 into main Aug 13, 2026
62 of 65 checks passed
@bolichen97
bolichen97 deleted the fix/split-view-launch-card-affordance branch August 13, 2026 17:02
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 13, 2026

@iamwhatever iamwhatever left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: fix (6 files). Criteria: no conflict, no requested changes, no security surface, AI reviewers green. Category: UI fix — launch card click now retargets to the correct chat pane instead of default.

@chenmingwei23

Copy link
Copy Markdown
Contributor Author

Post-merge record: the retarget was verified end-to-end on an isolated pod after this merged, so the behaviour claim in the description is not just unit-tested.

Setup: two sessions, one carrying a spawn_run launch card; the OTHER one active; split view entered from the active one and the launch session pulled into the second cell, so the card sat in a pane that was not the active slot — the case the fix is about.

Observed on click:

active before = chat-3-…   after = chat-2-…      ← the card's own session
panel "No subagents running" = False
agent ids on screen = ['bba969a8', '72f9703f']    ← the same ids the card shows

The sidebar selection moved to the card's session, the Subagents panel opened showing that wave's two agents with their real inputs (echo alpha / echo beta), and the split layout survived the retarget.

Two things worth recording for whoever picks up #3332 or #3300, because both cost real time here:

  • localStorage is the wrong signal to assert on. ChatPage does not necessarily persist the active slot while in split mode, so an assertion on mc-active-slot-chat can read "unchanged" for a retarget that worked. Assert on what the panel shows instead.
  • A pod can serve a stale SPA bundle. pod up --provision did not rebuild an existing dist, so the pod served a build from three hours earlier and the fix appeared not to work at all — I reported it as broken on that basis before checking the bundle's timestamp. make frontend before pod up, and check the built asset's mtime against the commit you are testing.

Split View is also opt-in (dashboard.session_grid), so ⌘D is silently inert in a fresh pod until that is set — worth knowing before concluding the keybinding is broken.

encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
kirodotdev#3334)

The workflow and sub-agent launch cards deep-link into the Workflows /
Subagents side panel. That panel is mounted for activeSlot, and split view
deliberately never moves activeSlot with pane focus, so kirodotdev#3302 — which started
drawing these cards in panes — gave a background pane a click that opens a
DIFFERENT session's panel, usually reading "No subagents running". Split view
exists to watch background sessions, so most clicks hit it.

Make the click correct instead of removing it: opening from a pane whose
session is not active dispatches switchSlot first, so the panel that opens is
the one the card's label promises. Safe inside split view — the auto-enter
effect is gated on splitMode being off, so switching neither reseeds nor leaves
the grid. Single chat passes no slot and is unchanged.

An earlier revision instead dropped the affordance in background panes. UX
review was right that this trades a lying link for a dead end: a user seeing
"1 agent failed" in the surface split view exists for would have no route to
the detail and no cue that one exists, and the card keeps enough of its accent
shell that a habituated click reads as broken. Retargeting removes the class
rather than hiding it, and needs no new copy — "Open in the Subagents panel"
stays true.

Also drops a double row wrapper: both cards lay out their own full-width row,
so wrapping them in the registry's ctx.row doubled the padding.

Adds a drift guard pinning that every role the single-chat chain dispatches on
is claimed by the registry a pane renders through, and names the tracked
consumer of each option that has no pane wiring yet.

Refs kirodotdev#3302, kirodotdev#3332
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants