docs: complete scene 8 chat entry slice

This commit is contained in:
lda
2026-07-12 05:15:56 +07:00 Verified
parent 3158060211
commit d1128c0b49
9 changed files with 60 additions and 28 deletions
+5 -3
View File
@@ -267,9 +267,11 @@ The next presentation work is intentionally split into five implementation
slices followed by a rehearsal gate. The broader story-flow review remains a
separate activity after these surfaces are stable.
1. **Scene 8 chat entry:** replace the standalone run button with a full-screen
assistant-style chat entry. The composer/send action starts the first
prepared authoring conversation; it does not start the workflow run.
1. **Completed: Scene 8 chat entry:** replaced the standalone run button with
a full-screen assistant-style chat entry. The local composer/send action
reveals the first prepared authoring conversation without starting a
workflow run. Implementation:
[`Scene 8 chat entry`](historical/superpowers/plans/2026-07-12-scene-8-chat-entry.md).
2. **Scene 9 assistant modal:** remove the lower chat dock, give the prepared
lifecycle canvas the available stage, and expose the synchronized authoring
conversation through an assistant-ui modal anchored on the left.
@@ -1,5 +1,8 @@
# Scene 8 Chat Entry Implementation Plan
> Historical: completed on 2026-07-12. Task commits and final verification are
> recorded in repository history.
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox syntax for tracking.
**Goal:** Replace Scene 8's phase-rail transcript and standalone run button with a full-screen assistant-style chat entry whose Send action reveals the first deterministic authoring turn without starting a workflow run.
+12 -9
View File
@@ -180,8 +180,11 @@ claim boundaries and future work explicit, and end on the canonical defense
discussion index rather than a benchmark or generic conclusion.
Scenes 8 and 9 use the canonical prepared-authoring recording as their only
execution evidence. Scene 8 is a full-screen conversation that establishes the
external agent handoff; Scene 9 breaks the prepared authoring into five phases
execution evidence. Scene 8 is a full-screen chat entry: its prefilled request
is submitted locally, then reveals the first deterministic user, assistant, and
Discover tool group. It is deterministic replay, not a live LLM chat, and does
not start a workflow run. The handoff beat reveals the full prepared conversation;
Scene 9 breaks the prepared authoring into five phases
with the same conversation contracted into a synchronized bottom dock. Each
phase opens its matching prepared tool group beneath a factual source, graph,
repair, artifact, or deployment view. Neither scene calls workflow authoring
@@ -330,11 +333,11 @@ Scenes 8 and 9 are the prepared authoring story. They use deterministic data
from the committed `projectPreparedAuthoring()` recording and never call
workflow authoring RPC operations.
- **Scene 8 (Agent Handoff)**: a full-screen prepared conversation that
establishes the external agent interface. The `request` beat shows the
operator requesting a report workflow; the `handoff` beat reveals the full
completed conversation with prepared `wf` tool groups across all authoring
phases.
- **Scene 8 (Agent Handoff)**: a full-screen deterministic chat entry that
pre-fills the report-authoring request. Send is local presentation state and
reveals the first prepared Discover tool group; the `handoff` beat reveals
the full completed conversation with prepared `wf` tool groups across all
authoring phases. This is not a live LLM chat or workflow run.
- **Scene 9 (Prepared Workflow Lifecycle)**: a five-phase lifecycle
(discover, draft, validate, artifact, deployment) with a compact phase rail
and one dominant factual product projection per beat. The Scene 8 thread
@@ -342,8 +345,8 @@ workflow authoring RPC operations.
current beat. There is no detached trace modal or second transcript.
The authoring scenes consume deterministic prepared data and never call
workflow authoring RPCs — only `workflow.health` infrastructure pings are
permitted.
workflow authoring RPCs. Scene 8 also skips live target probing so its request
and Send path remain fully local; later execution scenes own live-run behavior.
### Demo Climax (Scenes 1012)
@@ -263,15 +263,17 @@ describe("PresentationRoute", () => {
expect(screen.queryByText(/checking reachability/i)).not.toBeInTheDocument();
});
it("keeps Scene 8 local after a healthy target probe", async () => {
it("keeps Scene 8 local with a configured target", async () => {
window.sessionStorage.setItem("lda.workflowConsole.target", "http://127.0.0.1:8765/rpc");
window.location.hash = "#scene/agent-handoff/request";
mockedCallOperation.mockClear();
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findByText(/Live target ready/i)).toBeInTheDocument();
expect(await screen.findByText(/Replay evidence is active/i)).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Send" })).toBeEnabled();
expect(screen.queryByRole("button", { name: "Run prepared workflow" })).not.toBeInTheDocument();
expect(mockedCallOperation).not.toHaveBeenCalled();
});
it("opens Scene 10 approval from the canonical hash", async () => {
@@ -53,7 +53,8 @@ export const PresentationRoute = () => {
const presentationTarget = useMemo(() => resolvePresentationTarget(), []);
const demo = useDemoTimeline(presentationTarget.target, recordEvidence, recording);
const targetStatus = usePresentationTargetStatus(presentationTarget, demo.state);
const isScene8 = state.location.kind === "main" && state.location.sceneId === "agent-handoff";
const targetStatus = usePresentationTargetStatus(presentationTarget, demo.state, !isScene8);
const timelineAgent = useTimelineAgent(demo, {
mode: presentationTarget.mode === "live" ? "live" : "replay",
status: targetStatus,
@@ -154,9 +154,14 @@ describe("projectPreparedAuthoringThread", () => {
});
it("keeps the canonical projection unchanged without a request override", () => {
expect(projectPreparedAuthoringThread("discover")).toEqual(
projectPreparedAuthoringThread("discover"),
);
const firstUser = projectPreparedAuthoringThread("discover")
.find((message) => message.role === "user");
expect(firstUser?.parts).toEqual([
{
type: "text",
text: "We need to author a report workflow for the lda_report scenario. What sources and capabilities are available?",
},
]);
});
it("overrides only the first user request and preserves Discover tool data", () => {
@@ -287,15 +287,15 @@ export const projectPreparedAuthoringThread = (
let requestReplaced = false;
return recording.slice(0, finalPhaseIndex + 1).flatMap((phase) => {
const conversation = phase.conversation.map((turn, index) =>
agentTextMessage(
const conversation = phase.conversation.map((turn, index) => {
const shouldReplaceRequest = requestOverride !== undefined && !requestReplaced && turn.role === "user";
if (shouldReplaceRequest) requestReplaced = true;
return agentTextMessage(
`authoring-${phase.phase}-message-${index}`,
turn.role,
requestOverride !== undefined && !requestReplaced && turn.role === "user"
? (requestReplaced = true, requestOverride)
: turn.text,
),
);
shouldReplaceRequest ? requestOverride : turn.text,
);
});
const groupId = authoringToolGroupId(phase.phase);
const toolParts = phase.commands.flatMap((command, index) => {
const callId = `${groupId}-command-${index}`;
@@ -3030,7 +3030,7 @@
padding: clamp(1.5rem, 4vw, 3.75rem) clamp(1rem, 5vw, 4.5rem);
border: 1px solid var(--authoring-rule, var(--stage-line));
border-radius: 0.35rem;
background: color-mix(in oklch, var(--stage-canvas) 92%, white);
background: var(--authoring-paper, var(--stage-canvas));
box-shadow: 0 1.25rem 3rem color-mix(in oklch, var(--stage-ink) 10%, transparent);
}
@@ -3096,7 +3096,7 @@
resize: vertical;
border-color: var(--authoring-rule, var(--stage-line));
border-radius: 0.2rem;
background: color-mix(in oklch, var(--stage-canvas) 82%, white);
background: color-mix(in oklch, var(--authoring-paper, var(--stage-canvas)) 88%, var(--authoring-muted, var(--text-secondary)));
color: var(--authoring-ink, var(--text-primary));
font: 1.05rem/1.45 var(--font-interface);
}
@@ -14,6 +14,7 @@ const liveActive = (state: DemoTimelineState): boolean =>
export const usePresentationTargetStatus = (
targetState: PresentationTargetState,
demoState: DemoTimelineState,
probeEnabled = true,
): PresentationTargetHealth => {
const [probe, setProbe] = useState<TargetProbeState>(
targetState.mode === "live" ? "checking" : "none",
@@ -27,6 +28,11 @@ export const usePresentationTargetStatus = (
setFailureReason(targetState.reason);
return;
}
if (!probeEnabled) {
setProbe("none");
setFailureReason("deterministic Scene 8 replay");
return;
}
setProbe("checking");
setFailureReason(undefined);
@@ -50,7 +56,17 @@ export const usePresentationTargetStatus = (
return () => {
cancelled = true;
};
}, [targetState]);
}, [probeEnabled, targetState]);
if (!probeEnabled) {
return presentationTargetHealth({
target: null,
probe: "none",
liveActive: false,
replayActive: true,
failureReason: "deterministic Scene 8 replay",
});
}
return presentationTargetHealth({
target: targetState.mode === "live" ? targetState.target : null,