docs: record ChatEmbed plan-action exclusion with a pinning test (#6057) - #6748
Conversation
ChatEmbed destructures only followUpOptions from deriveFollowUpOptions, dropping followUpIsPlan. Re-triage of #6057 verified this is a deliberate exclusion, not a live defect: app-token embeds cannot reach plan-bearing slots (_deny_cross_app_slot_access, App Kit section 5.2), the slot-detail payload carries no mode field so the embed has no orchestrator-mode source, and non-protocol plan-shaped labels fall through harmlessly via the isPlanAction allowlist. Records the exclusion in a comment at the drop site and pins it with a test asserting a plan-shaped chip stays on the composer-draft path and never issues a plan-action POST -- the inverse of the ChatPane/ChatPage dispatch tests.
Design Review (Fable 5) — ✅ PASSDesign-level review of Design-Verdict: PASS A latent-ambiguity record plus a self-premise-pinning test is exactly proportionate — Path B's product wiring is correctly deferred, not half-built. Suggestions
[DESIGN-REVIEWED] 184de3a |
UX Review (Fable 5) — ✅ PASSUX-level review of UX-Verdict: PASS Zero rendered change: the diff adds a code comment and a pinning test; every pixel, string, and flow a user touches is identical to base. [UX-REVIEWED] 184de3a |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsThe diff contains only a comment block addition in No findings. [OPUS-REVIEWED] 184de3a Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All claims verified: four hosts call First-Principles-Verdict: CONCERNS The record settles ChatEmbed but the identical unrecorded drop survives one grep away in SideChat — half of the named harm remains. What this change shipsIntent: record that ChatEmbed's silent drop of the plan flag is deliberate, and pin it so nobody "fixes" it — an ADDITION (docs + test), scoped by issue #6057.
No behavior change, no new public surface, nothing undeclared. Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 184de3a |
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: |
First Principles disposition (head
|
…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
bolichen97
left a comment
There was a problem hiding this comment.
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.
Problem / Motivation
deriveFollowUpOptionsreturnsfollowUpIsPlanon every branch, butChatEmbeddestructures only{ followUpOptions }, silently dropping it. After #6040 wired plan-action dispatch into ChatPane and ChatPage, ChatEmbed was the one follow-up-rendering host left unsettled: is the drop a defect (same class as #5893) or a deliberate exclusion? Issue #6057 asks to settle and record it.Why it matters
An unrecorded drop is indistinguishable from an oversight. The next contributor auditing plan-chip coverage either wastes an investigation re-deriving why ChatEmbed is safe, or "fixes" it by wiring dispatch into a surface that structurally lacks the mode gate the dispatch path requires — reintroducing exactly the ambiguity #6040 closed elsewhere.
What changed (motivation → approach → change)
Re-triage on main verified the defect is latent, not live, so this takes the issue's own "if not reachable, record it" branch (Path A) — a documentation-plus-pin change, deliberately NOT the full parity wiring (Path B):
deriveFollowUpOptionsdestructure inwebsite/src/app-sdk/ChatEmbed.tsxrecording the exclusion and why it holds: the slot-detail payload this embed polls carries nomodefield (so the embed structurally lacks the orchestrator-mode gate ChatPane/ChatPage consult before dispatching), and_deny_cross_app_slot_accessnarrows exposure by 404ing app-token embeds on any foreign or unscoped slot. The comment is explicit that the ownership guard alone does not rule out a plan-bearing slot (an app could embed its own orchestrator-mode slot) — the missing mode source is what carries the exclusion. SideChat makes the same exclusion silently; that is stated truthfully rather than claimed as a recorded precedent.website/src/test/ChatEmbed.test.tsxasserting a plan-shaped chip stays on the composer-draft path. It pins its own premise (deriveFollowUpOptions(fixture).followUpIsPlan === true, so grammar/fixture drift fails loudly instead of degrading the test into a duplicate of the plain-chip case) and spies the global api client'splanAction— the transport a future dispatch wiring would actually use — so a wiring that dispatches AND fills the draft cannot pass.Path B remains the future parity option: if dashboard-token embeds ever need working plan chips, the wiring is
usePlanActionMutationplus a mode source in ChatEmbed. That is a product decision nobody has asked for, and this PR deliberately does not make it (no mode field added to the endpoint, nousePlanActionMutationimport, SideChat untouched).Pre-push adversarial review
Two rounds, two model-pinned blind lanes (GPT + Opus mirrors) per round. Round 1: BLOCK/BLOCK — 4 convergent actionable findings, all fixed (overbroad ownership-guard claim rescoped; false "SideChat records the same exclusion" corrected to "silently makes"; premise assertion added; dead same-mock URL-filter assertion replaced with a real-transport spy). Round 2: PASS/PASS, one Low advisory adopted (spy stubbed so the failing case surfaces as an assertion, not an unhandled rejection).
Tests
a plan-shaped chip edits the draft and never dispatches a plan action(website/src/test/ChatEmbed.test.tsx) — locks in: (1) the fixture genuinely derivesfollowUpIsPlan=true; (2) clicking the chip lands the label in the composer draft; (3) no call on the embed's own API surface; (4) no call onapi.planAction, the global-client transport plan dispatch uses.npx vitest run src/test/ChatEmbed.test.tsx), plusChatEmbed.framelessandChatEmbed.approvalRollbacksuites.npx tsc -bclean, eslint 0 errors, brand gate green.Manual verification
N/A — unit coverage sufficient: the change is a comment plus a test; no runtime behavior changes.
Screenshots / video
No UI change, no screenshots — comment + test only, zero visual delta.
Related Issues
Closes #6057
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)