Structured per-step run reporting as an emitted, consumable schema
State: open/active · Genre: analysis
Use case: structured-run-reporting RFC mapping: new (elevates RFC cross-cutting
‘structured per-step reporting’) Source: cross-repo survey of sksizer/* (2026-07-05),
companion to the workflow-constellation RFC (PR #682).
The need
Section titled “The need”The demand for per-step status/cost reporting is product-scale, not console-scale: an entire observability product was built to reverse-engineer run/step/status records that no orchestrator emits, a dashboard ships a bespoke run-record document schema with a crash-unsafe two-phase write protocol, and engines copy-paste step-journaling boilerplate per step type. Flowline should treat the run/step report as a first-class serializable schema — stable step ids, parent links, status lifecycle, timings, cost — that UIs and stores consume directly.
Evidence
Section titled “Evidence”deprecated-agent-visualizer
Section titled “deprecated-agent-visualizer”A whole product (hook → server → SQLite → WebSocket → dashboard) built solely to reconstruct sessions(runs)/agents(steps)/events(journal) with derived status enums; because the telemetry carries no step/parent ids, Pre/Post correlation is a fuzzy timestamp join and the agent tree shipped flat.
Where: docs/vision.md · src-server/src/models/agents.rs · src-server/src/models/events.rs
Pain: The core feature degraded to forensic reconstruction because hierarchy was never a field; the vision doc is a literal spec of what a workflow layer should emit.
agent-dashboard
Section titled “agent-dashboard”collection_sync: a hand-designed run-record schema (status running/completed/failed, trigger, per-step stats, error) with a two-phase POST-running/PUT-terminal protocol rendered as a Sync History UI — a crash between phases leaves a stuck ‘running’ record forever.
Where: server/schemas/documents/collection_sync.json · server/api/collection-sync.post.ts ·
pages/collections/[id].vue
Pain: Every field invented by hand; no lease/heartbeat/timeout means no crash-safe terminal state.
ontological
Section titled “ontological”StepResult journaling (Running→Completed/Failed with timestamps/output/error) copy-pasted six times across step handlers — roughly half of the 1000-line session.rs is this boilerplate.
Where: src-tauri/src/engine/session.rs · src-tauri/src/schema/step_result.rs
Pain: ~400 lines of repeated create/update bracketing a library report would replace.
harness
Section titled “harness”InstanceState enum variants carry workflow progress data (current_step/total_steps/step_label, ProvisionFailed context), serialized to SQLite and manually mirrored into a frontend TypeScript union; two planning phases spent retrofitting it. The deprecated visualizer prototype in the same repo is second demand-evidence.
Where: prototypes/zoo/code2/src-tauri/src/vm/types.rs ·
prototypes/zoo/code2/src-nuxt/app/utils/types.ts
Pain: A serializable run-state schema would have eliminated the bespoke enum, DB serialization, and Rust↔TS mirror maintenance.
pickaxe
Section titled “pickaxe”The scan UI hand-rolls a four-stage progress machine with pause/cancel buttons that mutate an integer, mocked success/error counts, and a fake activity log — because no backend workflow emits real step events to subscribe to.
Where: src-nuxt/app/stores/scan_state.ts · src-nuxt/app/pages/scan.vue
Pain: The entire per-step status/cancellation surface exists as UI simulation.
Flowline fit
Section titled “Flowline fit”The RFC lists per-step reporting as cross-cutting; the evidence argues it should be a named deliverable: a versioned, serializable run/step report schema (step id, parent id, status, start/stop, cost, error) emitted by every module, so dashboards, visualizers, and DB rows become projections instead of reimplementations. Current design gap: no stated wire/storage schema or stable step-identity contract.
Proposed API
Section titled “Proposed API”Builds on: any runner (03, 09) Introduces: extension: StepEvent, onEvent
A versioned per-step event schema every runner emits — the thing two dashboards were built to reconstruct after the fact:
interface StepEvent { v: 1; runId: string; stepId: string; // stable across retries of the same step parentId?: string; // links nested subloops / fan-out branches status: "pending" | "running" | "ok" | "failed" | "skipped"; startedAt?: string; endedAt?: string; usage?: { inputTokens: number; outputTokens: number; costUsd?: number };}
const result = await run(wf, { onEvent: (e) => bus.publish(e) });Entirely an extension — the RFC lists reporting as cross-cutting but ships no schema.
agent-dashboard becomes a subscriber; ontological’s six copy-pasted StepResult journals
become one emitter.