docs: design demo autoplay and replay

This commit is contained in:
lda
2026-07-03 01:23:01 +07:00 Verified
parent f5a0d2d9e2
commit a603ad78fa
2 changed files with 368 additions and 0 deletions
@@ -0,0 +1,365 @@
# Demo Autoplay And Replay
## Status
Current design contract for the next Workflow Console slice.
## Related Designs
- [Workflow console, agent demo, and defense presentation](2026-07-01-workflow-console-agent-demo.md)
- [Workflow console lifecycle explorer](2026-07-02-workflow-console-lifecycle-explorer.md)
- [Self-describing interrupt contracts](2026-07-01-self-describing-interrupt-contracts.md)
## Purpose
The prepared `lda_report_workflow` now works through the console, but its
controls expose implementation actions rather than a coherent presentation
sequence. The defense also needs a deterministic fallback when the live RPC
server, model provider, or local environment fails.
This slice turns the working demo into a lifecycle timeline with two modes:
- **Live** executes public JSON-RPC operations and records normalized events.
- **Replay** reads one committed, reviewed recording and renders the same event
stream without contacting the workflow server.
The timeline replaces the prominent refresh/start controls with a presentation
flow: Start, Pause, Next, Continue at the human interrupt, and Restart.
## Scope
The slice includes:
- a normalized demo event envelope;
- a deterministic timeline state machine;
- stepwise live execution of the prepared deployment;
- Play, Pause, Next, Continue, and Restart controls;
- automatic pause on `issue_review`, errors, and completion;
- capture of live public-RPC evidence into timeline events;
- one committed canonical recording;
- replay of that recording through the same view components;
- visible mode and replay attribution.
The slice does not include:
- an LLM or demo-agent integration;
- workflow authoring or deployment setup inside the UI;
- Astro routes or presentation slides;
- backward stepping in live mode;
- automatic approval of an interrupt;
- arbitrary recording import or editing;
- persistence of ad-hoc recordings outside the browser session.
## Product Boundary
The UI remains an ordinary client of the public JSON-RPC surface. Live mode
uses the existing console backend and operation registry. Replay mode does not
claim that recorded operations are live. It is labeled visibly and does not
contact the workflow server.
The prepared deployment remains external to the console:
```text
lda_report_case_study.default
```
If it is absent in live mode, the existing missing-deployment instructions are
shown. Replay mode remains available because it does not depend on the store.
## Architecture
The slice introduces four focused units under
`web/apps/console/src/demo/timeline/`:
```text
timeline/
models.ts # Event and recording schemas/types
reducer.ts # Pure timeline state machine
live.ts # Live operation queue and event capture
replay.ts # Canonical recording loader
useDemoTimeline.ts # React adapter around live/replay controllers
```
The existing `LdaReportDemoPanel` remains responsible for report, issue, and
interrupt presentation. It consumes a timeline controller instead of owning
the operation sequence directly.
The existing `useLdaReportDemo` operation logic is either moved into `live.ts`
or reduced to a thin compatibility adapter. There must be only one owner of the
live sequence.
## Demo Event Envelope
Every visible lifecycle action uses one normalized event shape:
```ts
type DemoEventStage =
| "deployment_check"
| "run_start"
| "interrupt"
| "run_resume"
| "trace_read"
| "completed"
| "failed";
type DemoEvent = {
readonly id: string;
readonly sequence: number;
readonly stage: DemoEventStage;
readonly operation: string | null;
readonly reason: string;
readonly equivalentCli: string | null;
readonly params: unknown;
readonly rawResponse: unknown;
readonly interpreted: unknown;
readonly durationMs: number;
readonly resultingIds: {
readonly deploymentId: string | null;
readonly runId: string | null;
};
readonly recordedAt: string;
};
```
Synthetic presentation events such as `interrupt`, `completed`, and `failed`
may have `operation: null`. They identify a state transition derived from a
real operation result; they are not presented as agent or RPC calls.
Event ids are stable inside a recording. The committed recording uses fixed
ids and timestamps. Live events may derive ids from the sequence and current
run id; they must not rely on `Date.now()` alone.
## Recording Contract
A recording contains metadata and an ordered event list:
```ts
type DemoRecording = {
readonly schemaVersion: 1;
readonly recordingId: string;
readonly title: string;
readonly createdAt: string;
readonly deploymentId: "lda_report_case_study.default";
readonly source: "reviewed_live_capture";
readonly events: ReadonlyArray<DemoEvent>;
};
```
The canonical recording is committed at:
```text
web/apps/console/src/demo/recordings/lda-report-success.v1.json
```
The recording must contain no machine-specific paths, credentials, session
tokens, or unrelated store contents. Raw request and response fields are kept
only for the prepared demo operations. The recording is decoded with Valibot
before use; malformed recordings fail visibly rather than partially rendering.
The reviewed recording covers:
1. deployment inspection;
2. run start;
3. `issue_review` interrupt;
4. submitted resume with at least one selected issue;
5. final trace read;
6. completed report and created issue output.
## Timeline State Machine
```mermaid
stateDiagram-v2
[*] --> Ready
Ready --> Running: Start presentation
Running --> Paused: Pause
Paused --> Running: Play
Paused --> Running: Next
Running --> Review: issue_review
Review --> Running: Submit or cancel
Running --> Completed: final event
Running --> Failed: operation or decode error
Paused --> Failed: malformed next event
Completed --> Ready: Restart
Failed --> Ready: Reset
```
Timeline state contains:
```ts
type DemoTimelineState = {
readonly mode: "live" | "replay";
readonly phase:
| "ready"
| "running"
| "paused"
| "review"
| "completed"
| "failed";
readonly events: ReadonlyArray<DemoEvent>;
readonly cursor: number;
readonly autoplay: boolean;
readonly error: string | null;
};
```
Invariants:
- `cursor` is the index of the last applied event, or `-1` before playback.
- Replay may move only forward in this slice. Timeline scrubbing remains a
later presentation refinement.
- Live mode cannot apply an event before its RPC operation completes.
- Pause stops before executing the next operation; it does not cancel an RPC
already in flight.
- `issue_review` always enters `review` and disables Play/Next until the user
submits or cancels.
- Completion and failure stop autoplay.
- Restart clears transient live state and returns to `ready` without deleting
persisted runs or issue-board records.
## Live Mode
Live mode uses a small explicit operation queue:
```text
workflow.deployments.inspect
workflow.runs.start
pause for issue_review
workflow.runs.resume
workflow.runs.trace
```
Each queue step declares:
- operation name;
- why the operation is performed;
- parameter builder from current live context;
- result decoder;
- event builder;
- next stage.
The executor performs one step at a time. Autoplay schedules the next step only
after the current event has been recorded and rendered. `Next` performs exactly
one eligible step. Mutation operations are never retried automatically.
The live executor records failed operation evidence as a `failed` event before
entering the failed phase. Missing deployment remains a specific recoverable
failure with the existing setup instructions.
## Replay Mode
Replay loads and decodes the canonical recording when selected. It does not
call `connectToServer()` or `callOperation()` for timeline playback.
Replay timing is presentation timing, not the original network timing:
- default delay between ordinary events: 900 ms;
- transition to review: immediate after the interrupt event;
- completion: immediate after the final event;
- Pause and Next use the same reducer actions as live mode.
The UI displays a persistent `Recorded replay` label. Raw evidence drawers may
show the recording's stored request and response, but must also identify the
recording id.
The human approval remains interactive in replay mode. The replay recording
contains the reviewed submitted branch; selecting Continue advances through
that branch. The UI must not imply that replay choices alter the stored
recording or create real issues.
## Controls
The primary controls are:
- mode selector: `Live` / `Replay`;
- `Start presentation` in ready state;
- `Pause` while autoplay is running;
- `Play` while paused;
- `Next` while paused;
- `Continue` or `Cancel review` at the interrupt;
- `Restart` after completion;
- `Reset` after failure.
`Refresh demo state` is secondary live-mode recovery. It is hidden or disabled
while starting, interrupted, or resuming. It is not shown in replay mode.
The UI includes a compact timeline showing stage label, status, and the current
event. Raw payloads remain collapsed by default.
## Rendering
The timeline drives existing views:
- deployment check updates demo readiness;
- run start updates run id and interrupt payload;
- interrupt renders the existing issue selection form;
- resume renders created issues and final markdown;
- trace read renders the existing trace table;
- raw event data remains available through evidence details.
Live and replay must not fork into separate report or trace components. Mode
differences belong in controllers and attribution labels.
## Error Handling
Failures are typed at the controller boundary into these visible categories:
- prepared deployment missing;
- RPC transport or remote error;
- malformed interpreted run result;
- unexpected run state or interrupt kind;
- malformed canonical recording;
- trace unavailable after successful resume.
The timeline stops on every failure. It shows the failed operation, reason,
equivalent CLI when available, and raw evidence. It does not silently switch
from live mode to replay. The operator may choose replay explicitly.
## Testing
Unit tests cover:
- reducer transitions and invariants;
- Play, Pause, Next, Restart, and Reset;
- automatic pause at review/completion/failure;
- recording schema decoding;
- stable ordering and ids;
- replay performs no RPC calls;
- live Next performs one operation;
- live autoplay never crosses the interrupt;
- mutation calls are not retried;
- malformed recording and malformed RPC result failures.
Component tests cover:
- mode attribution;
- control availability by phase;
- timeline event rendering;
- interactive live interrupt;
- interactive replay interrupt without real mutation;
- completed markdown, issue, and trace rendering;
- missing deployment instructions in live mode.
Live browser smoke covers:
1. run the console against `examples/lda_report_workflow/wf.config.json`;
2. start live presentation;
3. confirm autoplay stops at `issue_review`;
4. select one issue and continue;
5. confirm completion, issue output, trace, and evidence;
6. restart in replay mode with the RPC server unavailable;
7. confirm the same visible story completes with a replay label.
## Success Criteria
The slice is complete when:
1. one primary control starts the prepared live story;
2. Play, Pause, and Next deterministically control progress;
3. autoplay never approves or crosses the human interrupt;
4. live operations produce normalized timeline events with evidence;
5. one reviewed recording is committed and schema-validated;
6. replay works with the RPC server unavailable;
7. live and replay use the same report, issue, trace, and evidence components;
8. mode attribution prevents recorded behavior from appearing live;
9. the complete sequence can be demonstrated in under three minutes.