-
Notifications
You must be signed in to change notification settings - Fork 0
Pipeline Plan inline
Plan written to .claude/pipeline-artifacts/plan.md. Here's the summary:
Root cause: resume_state() in pipeline-state.sh:607-620 only clears pipeline-tasks.md when the issue number differs or the file is malformed. When resuming a failed build for the same issue, stale tasks (with checked-off items from the failed attempt) survive and get re-injected into the build loop.
Fix: Replace the conditional validation block with an unconditional rm -f "$TASKS_FILE". The tasks file is a derivative of plan.md and should not persist across resume boundaries.
Changes needed:
-
scripts/lib/pipeline-state.sh— 1 line replacing 13 lines of conditional logic -
scripts/sw-lib-pipeline-stages-test.sh— Update 2 tests that assert the buggy "keep" behavior
Why this approach: Simplest fix with smallest blast radius. plan.md provides equivalent context, so losing the task checklist on resume is harmless. Eliminates the entire class of stale-task bugs including goal-based pipelines with no issue number.
SUE` is empty, the issue-mismatch check at line 615 short-circuits, keeping any tasks file regardless of staleness.
| Location | Finding |
|---|---|
pipeline-state.sh:452-465 |
initialize_state() correctly clears TASKS_FILE via rm -f
|
pipeline-state.sh:607-620 |
resume_state() only clears on issue mismatch or malformed file; keeps matching-issue tasks
|
pipeline-stages-build.sh:172-183 |
Build stage injects tasks file contents verbatim into enriched_goal
|
pipeline-stages-intake.sh:440-464 |
Tasks file is generated during intake stage from plan checklist |
sw-pipeline.sh:2534-2544 |
Resume path calls resume_state() (not initialize_state()) for failed/interrupted pipelines |
| Test line 474 | Existing test asserts the buggy behavior: "resume_state keeps tasks when issue matches" |
Always clear pipeline-tasks.md in resume_state(), replacing the conditional validation block with an unconditional rm -f. Rationale:
- If resuming before intake: intake will regenerate the tasks file from the plan
- If resuming at/after build: stale tasks (with checked-off items from a failed attempt) should not be re-injected;
plan.mdstill provides full context - If resuming after build (test, review, etc.): build won't re-run, so the cleared file is irrelevant
This is simpler and more correct than trying to "reset checkboxes" — the tasks file is a derivative artifact of plan.md and should not persist across resume boundaries.
| Approach | Complexity | Trade-off |
|---|---|---|
A: Unconditional clear in resume_state() (chosen) |
Minimal — 1 line change + test update | Loses task checklist on build resume, but plan.md provides equivalent context. Eliminates entire class of stale-task bugs. |
| B: Reset checkboxes to unchecked on resume | Medium — sed/awk to convert [x] to [ ]
|
Preserves task tracking but adds complexity. Still risks other forms of staleness (tasks added/removed between attempts). |
| C: Regenerate tasks from plan.md on resume | Higher — extract + rebuild logic duplicated from intake | Most "correct" but duplicates intake logic, adding maintenance burden. |
Approach A wins on simplicity and blast radius.
-
scripts/lib/pipeline-state.sh— Replace conditional task validation inresume_state()with unconditional clear -
scripts/sw-lib-pipeline-stages-test.sh— Update tests that assert tasks are kept on matching issue; assert unconditional clear on resume
-
In
pipeline-state.sh, replace lines 607-620 (the conditional validation block inresume_state()) with an unconditional clear:# Clear pipeline-tasks.md on resume — stale tasks from previous attempts must not # leak into the build loop. Intake will regenerate if the pipeline resumes before build. [[ -n "${TASKS_FILE:-}" ]] && rm -f "$TASKS_FILE"
-
In
sw-lib-pipeline-stages-test.sh, update the test at ~line 457 ("resume_state keeps tasks when issue matches") to assert that tasks are removed on resume, even when the issue matches. -
Update the "Issue: line has no leading dash" test (~line 637) to assert tasks are cleared on resume.
-
Run the test suite to confirm no regressions.
- Task 1: Replace conditional validation block in
resume_state()with unconditionalrm -f "$TASKS_FILE"(pipeline-state.sh:607-620) - Task 2: Update test "resume_state keeps tasks when issue matches" to assert deletion instead (
sw-lib-pipeline-stages-test.sh:~457-478) - Task 3: Update test for "Issue: line has no leading dash" format variant to assert deletion (
sw-lib-pipeline-stages-test.sh:~637-655) - Task 4: Run
./scripts/sw-lib-pipeline-stages-test.shto verify all tests pass - Task 5: Run
npm testfor full regression check
-
Unit tests (
sw-lib-pipeline-stages-test.sh):- Existing test "resume_state clears stale tasks when issue differs" — should still pass (tasks cleared)
- Updated test "resume_state keeps tasks when issue matches" → now asserts tasks are cleared
- Existing test "resume_state removes malformed pipeline-tasks.md" — should still pass
- Updated "Issue: no leading dash" test → now asserts tasks are cleared
-
Integration:
sw-pipeline-test.shfor end-to-end pipeline resume scenarios -
Manual verification: Create a pipeline, let build fail, resume, confirm tasks file is absent when build stage starts
-
resume_state()unconditionally removespipeline-tasks.mdon every resume - No test expects
pipeline-tasks.mdto survive aresume_state()call -
./scripts/sw-lib-pipeline-stages-test.shpasses all assertions -
npm testpasses with no regressions - Goal-based pipelines (no issue number) also clear tasks on resume
| Risk | Impact | Mitigation |
|---|---|---|
| Build stage loses task checklist context | Low — plan.md provides equivalent task breakdown |
Plan is always available and is the source of truth for tasks |
| Tests that assert "keep" behavior fail | Expected — these tests encode the buggy behavior | Update tests to assert the corrected behavior |
| Intake stage not re-run on resume means no task regeneration | None — tasks are a convenience, not a requirement for build | Build stage works without tasks file; plan.md suffices |