fix(chat): retarget the panel to the pane a launch card was clicked in - #3334
Conversation
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — ✅ PASSAdvisory design-level review of 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 |
UX Review (Fable 5) — ✅ PASSAdvisory UX-level review of 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 |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsThe candidate is self-admittedly low-confidence and describes the PR's intended behavior (retargeting No findings. [OPUS-REVIEWED] c473a69 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
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
f5c8878 to
c473a69
Compare
|
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:
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 |
bolichen97
left a comment
There was a problem hiding this comment.
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.
iamwhatever
left a comment
There was a problem hiding this comment.
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.
|
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 Observed on click: The sidebar selection moved to the card's session, the Subagents panel opened showing that wave's two agents with their real inputs ( Two things worth recording for whoever picks up #3332 or #3300, because both cost real time here:
Split View is also opt-in ( |
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
Follow-up to #3302, answering the reviews it drew. Refs #3332.
1. What is the problem?
WorkflowRunCardandSubagentRunCardare whole-card buttons that deep-link into the Workflows / Subagents side panel (openActivityToTab(...)). That panel is mounted foractiveSlot, and split view deliberately never movesactiveSlotwith 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:
--mc-content-widththemselves), and the registry entries wrapped them inctx.rowas well — doubling the row padding.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:
activeIsSplitAnchorcomputes tonullwhilesplitModeis true, so the auto-enter effect cannot reseed the grid, andSessionGridView's seeding is guarded by its own ref.switchSlotis the same action ChatPage already dispatches when a split collapses.switchSlot.pendingassignsactiveSlotsynchronously as it is dispatched, so the panel is pointed at the right session before the tab opens.slotand is unchanged.WorkflowRunCardgains an optionalslot;SubagentRunCardalready took one.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.rowis 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.tsxextracts every role the single-chat chain dispatches on straight out ofChatPage.tsxand 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 ownGROUPED_ROLESexport (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:
activeSloton 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.slotsingle-chat path.Mutation results: deleting the
switchSlotretarget line kills a test in each card. On the drift guard, breaking thenudgeandfileclaims each fails it; breakingthinkingdoes not, which is correct —thinkingis 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 amatch) now explicitly claims no role. And the retarget tests initially failed for the wrong reason:switchSlot.pendingreadsslotHistory/slotMessages, so a partial preloaded state threw inside the reducer rather than exercising the retarget.Gates:
tsc --noEmit0 errors ·eslint0 errors ·npm run i18n:checkOK ·npm run i18n:renderOK · fullvitest1067 files / 17891 tests passed.5. Any other suggestions on the work
🔧 0 tool callsboxes, which are permission-only groups that single chat drops outright. Not fixable from the registry — the group is assembled before per-row resolution (chat SDK: let a host renderer opt a grouped role out of the collapsible group #2940) — and it belongs to the grouping convergence named in chat transcript: ChatPage should consume the shared row registry so there is one row set #3332.