Files
lda-wf/docs/superpowers/specs/2026-07-03-demo-autoplay-replay.md
T

12 KiB

Demo Autoplay And Replay

Status

Current design contract for the next Workflow Console slice.

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:

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/:

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:

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:

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:

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

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:

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;
};

cursor is an internal playback-position example, not a persisted recording field or public UI contract. An implementation may instead keep the current event id, split pending/applied event arrays, or derive a stage-to-position map. Presentation meaning always comes from the ordered event and its stage, not from a magic numeric value.

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:

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. The evidence inspector 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.