Skip to content

docs(sidechat): record the followUpIsPlan exclusion with a pinning test (#6754) - #6759

Merged
bolichen97 merged 1 commit into
mainfrom
fix/sidechat-plan-exclusion-6754
Aug 30, 2026
Merged

docs(sidechat): record the followUpIsPlan exclusion with a pinning test (#6754)#6759
bolichen97 merged 1 commit into
mainfrom
fix/sidechat-plan-exclusion-6754

Conversation

@iamwhatever

@iamwhatever iamwhatever commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Problem / Motivation

deriveFollowUpOptions (website/src/app-sdk/protocol/options.ts) returns followUpOptions, followUpIsPlan, and followUpSourceKey. website/src/pages/chat/SideChat.tsx destructures only followUpOptions, silently dropping followUpIsPlan. The drop is correct in effect — the side panel is not a plan-capable host — but nothing records that: no comment states the rationale, and no test pins the behaviour. A contributor auditing plan-chip coverage finds an undocumented drop and either re-derives the rationale from scratch or "fixes" it by wiring dispatch into a host that has no mode source to gate it.

Why it matters

The undocumented exclusion is a trap for future contributors. Wiring plan dispatch into SideChat without a mode gate would let any plan-shaped side answer cancel or advance the parent slot's real orchestrator plan — a live cross-conversation mis-dispatch. The record (comment + pinning test) is what turns "silent drop" into "reviewed, deliberate exclusion" and makes any future wiring attempt fail a test instead of shipping.

What changed (motivation → approach → change)

Applies the same-size record pattern as PR #6748 does for ChatEmbed (sibling issue #6057 covers the same drop there). Two deliverables, zero runtime behaviour change:

  1. A block comment at SideChat's deriveFollowUpOptions destructure recording the load-bearing facts: a side turn runs as an aside to the parent session and is never an orchestrator turn, so useComposerDraft owning a plan-shaped chip (pick → edits the draft, amendable before send) is correct behaviour, not a fallback; the dispatch path gates on the host slot's mode (ChatPage reads effectiveMode === 'orchestrator' off the slot record), which this panel does not read today; and an unconditional dispatch would let a plan-shaped side answer cancel or advance the parent's real plan.
  2. A pinning test (website/src/test/SideChat.planExclusion.test.tsx), mirroring the ChatEmbed plan-exclusion test shape, with a shared SIDE_MESSAGES fixture feeding both the rendered store and the premise derivation so they cannot drift apart.

Deliberately out of scope (same as #6748): wiring usePlanActionMutation into SideChat. Path B parity is a product decision, not this change.

Tests

New file website/src/test/SideChat.planExclusion.test.tsx, three assertions in one scenario:

  • Premise pin: deriveFollowUpOptions(asTranscript, false).followUpIsPlan === true, where asTranscript is mapped from the same SIDE_MESSAGES array the store renders, through the same role/cls expression SideChat's transcript memo applies (non-streaming, non-error case). Without this the test would pass vacuously the moment the fixture stops being plan-shaped.
  • Composer-draft path: clicking the Go chip lands the label in the side composer's draft (input.value === 'Go').
  • No dispatch: api.planAction is never called (and api.sideTurn is not called either — picking is an edit, not a submit).

Red-before proven: a plan dispatch was temporarily wired into SideChat's chip handler (if (followUpIsPlan) { void api.planAction(slot, o); return }); the test then failed (expected '' to be 'Go' — the draft assertion reds because dispatch short-circuits the draft edit). The scaffolding was reverted; only the comment and the test remain in the diff.

Full frontend suite on the rebased branch: 1638 test files, 25,938 passed, 0 failures (npx vitest run). npx tsc -b clean.

Manual verification

N/A — unit coverage sufficient: the change is a comment plus a test; the pinned interaction (chip click → draft edit, no dispatch) is exactly what the test drives through the real component.

Screenshots / video

Why no screenshot: the diff adds only a code comment and a test file; no rendered output changes anywhere.

N/A — this change adds a comment and a test and alters no rendered output. No pixel changes anywhere; explicitly not a skipped screenshot gate.

Related Issues

Fixes #6754

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title (feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

…st (#6754)

SideChat destructures only followUpOptions from deriveFollowUpOptions,
deliberately dropping followUpIsPlan: the side panel has no orchestrator
mode source, so a plan-shaped chip stays on the composer-draft path. The
drop was correct but unrecorded -- no comment stated the rationale and no
test pinned the behaviour, so an auditor would either re-derive it or
"fix" it by wiring dispatch into a host that cannot gate it.

Two deliverables, no behaviour change (sibling of the ChatEmbed record
on #6057, PR #6748):

- A block comment at the destructure recording the load-bearing facts:
  the dispatch path gates on the host slot's mode which this panel
  cannot express, a side turn is never an orchestrator turn, and
  useComposerDraft is the correct owner of a plan-shaped chip here.
- A pinning test (SideChat.planExclusion.test.tsx): premise pin that
  the fixture derives followUpIsPlan=true, a chip click lands on the
  composer-draft path, and a spy proves no planAction dispatch.

Red-before proven: with a plan dispatch temporarily wired into
SideChat's chip handler, the test fails; scaffolding reverted.

Closes #6754
@iamwhatever
iamwhatever requested a review from a team August 29, 2026 09:49
@iamwhatever
iamwhatever requested a review from a team as a code owner August 29, 2026 09:49
@iamwhatever
iamwhatever requested a review from cixuuz August 29, 2026 09:49
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of 7d7596f5a657973ac9b349cb8797db56a69e7fc5 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

UX-Verdict: PASS

No user-facing change: the diff adds a code comment and a pinning test; no string, pixel, or interaction a user experiences is altered.

[UX-REVIEWED] 7d7596f

@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

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

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 7d7596f

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

@github-actions

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 7d7596f5a657973ac9b349cb8797db56a69e7fc5 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: PASS

A real contributor trap, closed with the cheapest sound mechanism: a rationale comment plus a non-vacuous pinning test, zero runtime change.

The test's design holds up: the premise pin (followUpIsPlan === true derived from the same fixture the store renders) prevents the vacuous-pass failure mode that usually sinks absence-pinning tests, and the draft assertion reds only on an unconditional dispatch wiring — a future properly mode-gated wiring would still pass, which matches the stated scope (Path B parity stays a product decision). The comment's claims check out against ChatPage.tsx:7812 (followUpIsPlan && … && effectiveMode === 'orchestrator'). Pattern is consistent with the ChatEmbed sibling. No design-level concerns.

[DESIGN-REVIEWED] 7d7596f

@github-actions

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 7d7596f5a657973ac9b349cb8797db56a69e7fc5 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All claims verified. The key fact grounding this change: usePlanActionMutation.ts:146 records defect #5893 — ChatPane also dropped followUpIsPlan and there it was a real bug, fixed by wiring dispatch. That prior incident is exactly what would mislead a contributor into "fixing" SideChat the same way, so the harm is derived from a reported defect, not symmetry. Counts: 4 hosts call deriveFollowUpOptions (ChatPage, ChatPane consume followUpIsPlan; ChatEmbed, SideChat drop it); the ChatEmbed sibling drop is declared and tracked (issue #6057 / PR #6748); no existing test pins SideChat's exclusion (7 prior SideChat test files, none touch planAction); the diff ships zero runtime change and zero new public surface.

First-Principles-Verdict: PASS

Both items pin a real hazard with a named precedent — #5893 shows this exact drop was once a live bug in a sibling host — at zero runtime cost.

What this change ships

Intent: make SideChat's deliberate drop of followUpIsPlan un-mistakable for the bug it resembled in ChatPane (#5893). This is an ADDITION (a record: comment + test), declared as such.

  1. Comment at the destructure explaining why the drop is deliberate — justified (derived from defect ChatPane renders plan-approval follow-up chips but cannot dispatch plan actions #5893, usePlanActionMutation.ts:146)
  2. New test failing if plan dispatch is ever wired into SideChat — justified; no prior test covers it (grepped planAction across 7 SideChat test files: 0 hits)

Both items are declared; no config, flag, export, or behavior rides along (diff verified: SideChat.tsx hunk is comment-only). The one sibling of the root cause — ChatEmbed's identical drop — is counted (1) and explicitly tracked in #6057/#6748, so the point-patch scope is declared and deferred, not silent.

[FIRST-PRINCIPLES-REVIEWED] 7d7596f

@github-actions

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

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

Review details

No findings.

[OPUS-REVIEWED] 7d7596f

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

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

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 29, 2026
@bolichen97
bolichen97 enabled auto-merge August 29, 2026 23:50

@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.

Approved after a full-diff review (scope match, no out-of-scope files, security surface checked, tests verified non-vacuous). Review notes available on request.

@bolichen97
bolichen97 merged commit 3ddb67c into main Aug 30, 2026
114 of 116 checks passed
@bolichen97
bolichen97 deleted the fix/sidechat-plan-exclusion-6754 branch August 30, 2026 04:16
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 30, 2026
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.

Record SideChat's followUpIsPlan exclusion with a pinning test (sibling of #6057)

2 participants