Skip to content

[Phase 3] Plan/apply split: apply consumes the dry-run's authoritative plan.json #604

Closed

Description

@github-actions

Story

As a maintainer who reviewed a dry-run plan,
I want the apply run to load the exact plan.json the dry-run produced (optionally human-edited) instead of re-planning from scratch,
so that the preview binds the result — what a maintainer reviewed is what materializes.

Acceptance Criteria

  1. The dry-run produces an authoritative plan.json artifact (already uploaded today) that the apply run can be pointed at, and apply-plan.sh applies it without a re-plan (apply-plan.sh already reads PLAN_PATH).
  2. A documented mechanism lets a maintainer supply the reviewed plan.json to the apply run (workflow input / artifact handoff — chosen and documented; see open_questions).
  3. When a plan.json is supplied, the LLM planning step is skipped (no re-plan); validate-plan.py and apply-plan.sh still run on the supplied artifact.
  4. Backward path preserved: with no supplied plan, behavior is unchanged (Bob plans, then applies).
  5. scripts/initiative-planner/README.md and docs/initiatives/idea-to-initiative-pipeline.md describe the plan -> review -> apply split and where the human review point sits.

Tasks / Subtasks

Dev Notes

  • apply-plan.sh already consumes PLAN_PATH (apply-plan.sh:30-35) — the missing piece is letting the apply run LOAD a prior artifact instead of regenerating it. The dry-run already uploads plan.json at .github/workflows/initiative-planner.yml:178-186.
  • This is discussion 💡 Adversarial Plan-Critic + Structural Gates for the Initiative-Planner (Bob) #593's explicit follow-on ("once the critic is trusted") — hence blocked by the critic story (id 6).
  • Decide the handoff: a workflow_dispatch input pointing at a prior run/artifact to download vs a committed plan file. Artifact retention + cross-run download is the likely path — see open_questions.
  • Keep the inert-epic discipline: even a human-reviewed plan still materializes WITHOUT initiative:auto (apply-plan.sh enforces this).
  • Update both docs so the pipeline diagram in docs/initiatives/idea-to-initiative-pipeline.md reflects the new review point.

Project Structure Notes

Primarily a workflow + docs change; apply-plan.sh already supports loading an arbitrary PLAN_PATH. Sequenced last because it only pays off once the critic-improved plan is worth pinning.

References

  • .github/workflows/initiative-planner.yml#L178-L186
  • scripts/initiative-planner/apply-plan.sh#L30-L35
  • scripts/initiative-planner/README.md
  • docs/initiatives/idea-to-initiative-pipeline.md

Likely target surface

  • .github/workflows/initiative-planner.yml
  • scripts/initiative-planner/README.md
  • docs/initiatives/idea-to-initiative-pipeline.md

Story prepared by the BMAD Scrum Master (Bob) for epic #597. Status: ready-for-dev.

Activity

  1. don-petry commented on Jun 17, 2026

    @don-petry
    Collaborator

    Dev-Lead Implementation Plan

    Issue: #604 — [Phase 3] Plan/apply split: apply consumes the dry-run's authoritative plan.json

    Scope

    Add an apply-from-artifact path to the initiative-planner workflow so a maintainer can point the apply run at a prior dry-run's reviewed plan.json (downloaded by run ID), skipping the LLM re-plan while still validating and applying the supplied artifact.

    Handoff mechanism (AC #2 decision)

    New optional plan_artifact_run_id workflow_dispatch input. When set, the workflow downloads the initiative-plan-dry-run artifact (which already contains plan.json) from that run via gh run download, then applies it. Empty input ⇒ unchanged default (Bob plans then applies).

    Implementation Checklist

    • scripts/initiative-planner/apply-reviewed-plan.sh — thin orchestrator: verify supplied PLAN_PATH, run validate-plan.py, then apply-plan.sh (no re-plan)
    • .github/workflows/initiative-planner.yml — add plan_artifact_run_id input + PLAN_ARTIFACT_RUN_ID env; add actions: read for artifact download; download step; gate the Bob LLM step if PLAN_ARTIFACT_RUN_ID == ''; add reviewed-plan apply step
    • scripts/initiative-planner/README.md — document the plan → review → apply split + handoff
    • docs/initiatives/idea-to-initiative-pipeline.md — reflect the new review/apply gate in the diagram + prose

    Tests to Write

    • apply-reviewed-plan.sh validates then applies a supplied plan (DRY_RUN) — full DAG created
    • apply-reviewed-plan.sh rejects an invalid supplied plan (cycle) before applying — zero mutations
    • apply-reviewed-plan.sh errors on a missing/empty supplied plan file
    • (added to tests/test_initiative_planner.bats, already in the lint.yml bats list)

    Test Command

    scripts/run-bats.sh tests/test_initiative_planner.bats and bash .dev-lead/scripts/dev-lead-lint.sh

  2. don-petry commented on Jun 17, 2026

    @don-petry
    Collaborator

    Dev-Lead: Implementation Complete

    Plan Execution

    • Added apply-reviewed-plan.sh — validates the supplied (possibly hand-edited) plan.json then runs apply-plan.sh, with no LLM re-plan
    • Wired the apply-from-artifact path into initiative-planner.yml (new plan_artifact_run_id input, actions: read, artifact download, gated Bob step, reviewed-plan apply step)
    • Preserved the default plan-then-apply flow (empty plan_artifact_run_id ⇒ unchanged)
    • Documented the plan → review → apply split + handoff in README.md and the pipeline doc
    • Tests written first (red → green), full suite + dev-lead lint pass

    Handoff mechanism (AC #2)

    Chosen: artifact-download-by-run-ID (gh run download <run> --name initiative-plan-dry-run), not a committed plan file — keeps reviewed plans out of git and ties each apply to a specific, auditable dry-run. Documented in both docs.

    Test Results

    $ scripts/run-bats.sh tests/test_initiative_planner.bats tests/test_initiative_planner_redispatch.bats
    ... (42 tests) ...
    ok 29 apply-reviewed-plan validates then applies the supplied plan (DRY_RUN)
    ok 30 apply-reviewed-plan rejects an invalid supplied plan before applying anything
    ok 31 apply-reviewed-plan errors on a missing supplied plan file
    ok 32 apply-reviewed-plan honors the blocking open-questions gate from apply-plan
    ok 33..42 (redispatch suite) ...
    
    $ bash .dev-lead/scripts/dev-lead-lint.sh
      [lint] shellcheck on 61 file(s)...
      [lint] validating 4 agent profile(s)...
      [lint] all checks passed
    

    Files Changed

    • scripts/initiative-planner/apply-reviewed-plan.sh (new): no-re-plan handoff — re-validate then apply-plan.sh
    • .github/workflows/initiative-planner.yml: plan_artifact_run_id input, actions: read, download-reviewed-plan step, if-gate on the Bob step, apply-reviewed-plan step
    • scripts/initiative-planner/README.md: documents the split + handoff and the new script row
    • docs/initiatives/idea-to-initiative-pipeline.md: diagram + prose reflect the plan-review gate
    • tests/test_initiative_planner.bats: 4 new tests (already in the lint.yml bats list — no new file to register)

    Notes

    • Acceptance criteria mapping: AC#1 (apply-plan.sh already reads PLAN_PATH) — confirmed unchanged; AC#2 — artifact-by-run-ID handoff; AC#3 — Bob step if-gated off when a plan is supplied, while validate-plan.py + apply-plan.sh still run via apply-reviewed-plan.sh; AC#4 — empty input ⇒ unchanged; AC#5 — both docs updated.
    • gather-context.sh intentionally still runs on the apply path: it resolves DISCUSSION_NODE_ID so apply-plan can post the summary back. It does not plan — the LLM step is the only thing skipped.
    • The inert-epic discipline is unchanged: a reviewed plan still materializes WITHOUT initiative:auto; the blocking-open-questions and idempotency/supersede gates are honored by apply-plan.sh regardless of path (covered by the new gate test).
    • Workflow-level steps (artifact download) aren't unit-testable offline; the testable orchestration logic was extracted into apply-reviewed-plan.sh and covered.
  3. added a commit that references this issue on Jun 18, 2026
  4. added 9 commits that reference this issue on Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev-leadFor dev-lead agent pickupinitiativeEpic / initiative tracking issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions