Skip to content

feat(flow): flow doctor + local run-state materialization#22

Draft
skapoor8 wants to merge 8 commits into
mainfrom
feat/flow-doctor-and-local-runstate
Draft

feat(flow): flow doctor + local run-state materialization#22
skapoor8 wants to merge 8 commits into
mainfrom
feat/flow-doctor-and-local-runstate

Conversation

@skapoor8

Copy link
Copy Markdown
Contributor

Changes

Two related fixes for flow run-state. Feature B is the preventive fix; feature A cleans up the same class of problem reactively.

A — flow doctor

  • New verb: flow doctor [name] [--fix] [--global]. Diagnoses a flow's run-state.
  • Dry-run by default (reports issues, changes nothing). --fix applies repairs.
  • 6 checks: cross-run clobber, stale context, orphaned worktree/branch, step-file drift, schema drift, placeholder coherence.
  • 5 heals for the repairable checks.
  • Critical guard: never deletes a legitimately-interrupted resume context. A paused/resumable run looks similar to stale state, so the guard protects it before any cleanup runs.

B — Local run-state materialization

  • flow go now writes mutable run-state (progress + context) to a local run instance at .codevoyant/runs/<slug>/ instead of mutating the flow definition in place.
  • Flow definitions become read-only templates.
  • Fixes the root cause: concurrent runs and global-flow runs previously clobbered each other's state because they shared one mutable definition. Separate run instances keep their state isolated.

Validation

  • flow go writes progress/context to .codevoyant/runs/<slug>/, leaves the flow definition unchanged
  • flow doctor (no flag) reports issues without modifying anything
  • flow doctor --fix repairs the 5 healable checks
  • Doctor guard leaves an interrupted/resumable context intact
  • Two concurrent runs of the same flow no longer clobber each other
  • Existing tests pass

Notes for reviewers

skapoor8 added 3 commits July 10, 2026 08:17
Move mutable run-state out of the flow definition into a local run
instance under .codevoyant/runs/<slug>/ (progress.md + context.md), so
flow definitions stay read-only templates and global flows are no longer
clobbered by concurrent or cross-project runs.

- flow-dir.md: add Run instance section defining RUN_DIR
- go.md: seed/read progress.md + context.md from RUN_DIR; never mutate
  the definition's flow.md
- status.md: prefer run instance progress/Status, fall back to definition
- list.md: note that live progress lives in the run instance
Add references/workflows/doctor.md: diagnoses (default) and repairs
(--fix) one flow or every flow across both scopes. Runs six checks
(clobber, stale context, orphaned worktree/branch, step-file drift,
schema drift, placeholder coherence) as PASS/WARN/FAIL, and five heals
under --fix. Honors the critical guard that a legitimately-interrupted
context.md matching its own steps is never deleted. Built against the
Phase 1 run-instance layout: a global definition paired with a local
run instance is treated as normal, not drift.
Expose the flow doctor workflow and the definition-vs-run-instance
model across the dispatcher, help, and public docs.

- SKILL.md: add fix/diagnose/check → doctor aliases, --fix pass-through
  note, and doctor row in the workflow index
- help.md: add the doctor usage line, doctor aliases, and a run-instance
  storage note
- docs/skills/flow.md: add a doctor section and a definition-vs-run-instance
  note under go
@skapoor8 skapoor8 self-assigned this Jul 10, 2026
Comment thread skills/flow/references/workflows/doctor.md Outdated
Comment thread skills/flow/references/workflows/doctor.md Outdated
Comment thread skills/flow/references/workflows/doctor.md Outdated
Comment thread skills/flow/references/workflows/doctor.md Outdated
skapoor8 added 3 commits July 10, 2026 08:32
go.md now writes a run.md identity file into the run instance capturing
the resolved slug/branch/spec-slug/worktree, backfilling identifiers as
steps produce them. This gives /flow doctor a concrete anchor to compare
context.md against, since the definition and progress.md only ever hold
{{placeholders}}. Documents run.md in flow-dir.md and help.md.
…positive signal

Check 1 now compares context.md against the run's recorded identity in
run.md instead of the placeholder-bearing step text, so a legitimately
interrupted run is no longer misread as unrelated. Heal A deletes a
context.md ONLY on a positive clobber signal (identifier differs from
run.md, legacy context beside a global definition, or Status=Complete)
and preserves on uncertainty or match — inverting the previous
delete-unless-PASS bias that risked destroying live resume state.

Also inspect both RUN_DIR/context.md and a legacy FLOW_DIR/context.md
independently rather than first-match, so an old clobber beside the
definition still gets cleaned, and announce any deletion under
~/.codevoyant/flows (global scope) before acting.
Update the flow docs to describe the run.md identity file in the run
instance and the revised doctor behaviour: clobber detection anchored on
run identity, delete only on a positive signal, both context locations
inspected, and explicit announcement of global-scope deletions.
Comment thread skills/flow/references/workflows/go.md Outdated
Comment thread skills/flow/references/workflows/go.md Outdated
skapoor8 added 2 commits July 10, 2026 12:57
Step 3 left progress.md on disk (all [x], Status=Complete) and only
removed context.md, but Step 1's resume branch was keyed on progress.md
existence — so a second /flow go of a finished flow took Resume, found
zero pending steps, and exited 'already complete'. A completed run could
never re-run.

Step 1 now classifies the run instance into three states: first run
(no progress.md), completed run (all [x] or Status=Complete — archive
the stale instance to RUN_DIR/archive and re-seed a clean run), and
resume (partially complete — preserved, never wiped). Step 3's wording
now matches the mechanism. Genuinely in-progress runs still resume with
their context intact.
…-dir

A step handoff reports slug= (the resolved spec slug), but run.md has
two slug-like fields — the flow's own slug: and spec-slug: — so the
backfill target and doctor's comparison field were ambiguous. Pin one
canonical mapping everywhere: handoff slug= -> run.md spec-slug: (never
the flow slug:), branch= -> branch:, worktree= -> worktree:. go.md
(backfill), doctor.md (Check 1), and flow-dir.md now spell out and share
the same field names, so Check 1's identity match is reliable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant