@garygentry/feature-forge 0.3.7 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/.feature-forge-bundle.json +1 -1
- package/adapters/claude/hooks/hooks.json +15 -0
- package/adapters/claude/references/forge-config-schema.json +2 -2
- package/adapters/claude/references/preflight-and-self-heal.md +1 -1
- package/adapters/claude/references/ralph-loop-contract.md +5 -3
- package/adapters/claude/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/references/vendor-construct-inventory.md +1 -1
- package/adapters/claude/scripts/forge-session.py +6 -1
- package/adapters/claude/scripts/forge_session/cli.py +2 -1
- package/adapters/claude/scripts/forge_session/doctor.py +42 -2
- package/adapters/claude/scripts/forge_session/exit.py +5 -5
- package/adapters/claude/scripts/forge_session/routes.py +30 -3
- package/adapters/claude/scripts/session-check.sh +16 -0
- package/adapters/claude/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-5-loop/SKILL.md +12 -22
- package/adapters/claude/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/claude/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/claude/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/claude/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/claude/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/claude/skills/forge-init/SKILL.md +7 -5
- package/adapters/claude/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/claude/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/.feature-forge-bundle.json +1 -1
- package/adapters/codex/references/forge-config-schema.json +2 -2
- package/adapters/codex/references/preflight-and-self-heal.md +1 -1
- package/adapters/codex/references/ralph-loop-contract.md +5 -3
- package/adapters/codex/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/references/vendor-construct-inventory.md +1 -1
- package/adapters/codex/scripts/forge-session.py +6 -1
- package/adapters/codex/scripts/forge_session/cli.py +2 -1
- package/adapters/codex/scripts/forge_session/doctor.py +42 -2
- package/adapters/codex/scripts/forge_session/exit.py +5 -5
- package/adapters/codex/scripts/forge_session/routes.py +30 -3
- package/adapters/codex/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-5-loop/SKILL.md +12 -22
- package/adapters/codex/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/codex/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/codex/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/codex/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/codex/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/codex/skills/forge-init/SKILL.md +7 -5
- package/adapters/codex/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/codex/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/.feature-forge-bundle.json +1 -1
- package/adapters/copilot/references/forge-config-schema.json +2 -2
- package/adapters/copilot/references/preflight-and-self-heal.md +1 -1
- package/adapters/copilot/references/ralph-loop-contract.md +5 -3
- package/adapters/copilot/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/references/vendor-construct-inventory.md +1 -1
- package/adapters/copilot/scripts/forge-session.py +6 -1
- package/adapters/copilot/scripts/forge_session/cli.py +2 -1
- package/adapters/copilot/scripts/forge_session/doctor.py +42 -2
- package/adapters/copilot/scripts/forge_session/exit.py +5 -5
- package/adapters/copilot/scripts/forge_session/routes.py +30 -3
- package/adapters/copilot/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +12 -22
- package/adapters/copilot/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/copilot/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/copilot/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/copilot/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/copilot/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/copilot/skills/forge-init/forge-init.md +7 -5
- package/adapters/copilot/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/copilot/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/.feature-forge-bundle.json +1 -1
- package/adapters/cursor/references/forge-config-schema.json +2 -2
- package/adapters/cursor/references/preflight-and-self-heal.md +1 -1
- package/adapters/cursor/references/ralph-loop-contract.md +5 -3
- package/adapters/cursor/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/references/vendor-construct-inventory.md +1 -1
- package/adapters/cursor/scripts/forge-session.py +6 -1
- package/adapters/cursor/scripts/forge_session/cli.py +2 -1
- package/adapters/cursor/scripts/forge_session/doctor.py +42 -2
- package/adapters/cursor/scripts/forge_session/exit.py +5 -5
- package/adapters/cursor/scripts/forge_session/routes.py +30 -3
- package/adapters/cursor/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +12 -22
- package/adapters/cursor/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/cursor/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/cursor/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/cursor/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/cursor/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/cursor/skills/forge-init/forge-init.mdc +7 -5
- package/adapters/cursor/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/cursor/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/.feature-forge-bundle.json +1 -1
- package/adapters/gemini/gemini-extension.json +1 -1
- package/adapters/gemini/references/forge-config-schema.json +2 -2
- package/adapters/gemini/references/preflight-and-self-heal.md +1 -1
- package/adapters/gemini/references/ralph-loop-contract.md +5 -3
- package/adapters/gemini/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/references/vendor-construct-inventory.md +1 -1
- package/adapters/gemini/scripts/forge-session.py +6 -1
- package/adapters/gemini/scripts/forge_session/cli.py +2 -1
- package/adapters/gemini/scripts/forge_session/doctor.py +42 -2
- package/adapters/gemini/scripts/forge_session/exit.py +5 -5
- package/adapters/gemini/scripts/forge_session/routes.py +30 -3
- package/adapters/gemini/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +12 -22
- package/adapters/gemini/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/gemini/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/gemini/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/gemini/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/gemini/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/gemini/skills/forge-init/forge-init.md +7 -5
- package/adapters/gemini/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/gemini/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/.feature-forge-bundle.json +1 -1
- package/adapters/pi/references/forge-config-schema.json +2 -2
- package/adapters/pi/references/preflight-and-self-heal.md +1 -1
- package/adapters/pi/references/ralph-loop-contract.md +5 -3
- package/adapters/pi/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/references/vendor-construct-inventory.md +1 -1
- package/adapters/pi/scripts/forge-session.py +6 -1
- package/adapters/pi/scripts/forge_session/cli.py +2 -1
- package/adapters/pi/scripts/forge_session/doctor.py +42 -2
- package/adapters/pi/scripts/forge_session/exit.py +5 -5
- package/adapters/pi/scripts/forge_session/routes.py +30 -3
- package/adapters/pi/skills/forge/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-5-loop/SKILL.md +12 -22
- package/adapters/pi/skills/forge-5-loop/references/preflight-and-self-heal.md +1 -1
- package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +5 -3
- package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +78 -16
- package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +111 -12
- package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-6-docs/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +1 -1
- package/adapters/pi/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/pi/skills/forge-guide/references/preflight-and-self-heal.md +1 -1
- package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +5 -3
- package/adapters/pi/skills/forge-init/SKILL.md +7 -5
- package/adapters/pi/skills/forge-init/references/preflight-and-self-heal.md +1 -1
- package/adapters/pi/skills/forge-verify/references/stage-exit-protocol.md +1 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/rauf.d.ts +3 -3
- package/dist/rauf.js +2 -2
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -329,10 +329,10 @@ def stage_exit(
|
|
|
329
329
|
capability is permission, not tool presence: a dispatch permitted
|
|
330
330
|
only once the user has asked is still `interactive`, because the
|
|
331
331
|
`standard` gate's own prompt supplies that request.
|
|
332
|
-
cause: Pending-attribution annotation (`dependency-starvation
|
|
333
|
-
only with `--stage forge-5-loop --outcome
|
|
334
|
-
It swaps the partial next-steps sentence
|
|
335
|
-
and changes no routing.
|
|
332
|
+
cause: Pending-attribution annotation (`dependency-starvation`,
|
|
333
|
+
`review-pending` or `runner-stopped`), valid only with `--stage forge-5-loop --outcome
|
|
334
|
+
partial` (REQ-ATTR-04, #339). It swaps the partial next-steps sentence
|
|
335
|
+
for the matching variant and changes no routing.
|
|
336
336
|
|
|
337
337
|
Returns:
|
|
338
338
|
A JSON-serializable `StageExitPayload` dictionary.
|
|
@@ -486,7 +486,7 @@ def stage_exit(
|
|
|
486
486
|
# argparse `choices` already restricts the value; this restricts the combination.
|
|
487
487
|
if cause is not None and not (stage == "forge-5-loop" and outcome == "partial"):
|
|
488
488
|
raise UsageError(
|
|
489
|
-
"--cause
|
|
489
|
+
f"--cause {cause} is valid only with "
|
|
490
490
|
"--stage forge-5-loop --outcome partial"
|
|
491
491
|
)
|
|
492
492
|
|
|
@@ -799,6 +799,27 @@ _LOOP_PARTIAL_STARVED_TEXT: Final[str] = (
|
|
|
799
799
|
"resumable and nothing downstream is ready: unblock the roots named in the "
|
|
800
800
|
"starvation report above, then run the loop again below to continue."
|
|
801
801
|
)
|
|
802
|
+
#: The pending-review variant of the `partial` next-steps sentence: every item may be
|
|
803
|
+
#: done, but the runner's review pass failed or was interrupted, so the run is not
|
|
804
|
+
#: complete. Selected only by ``--cause review-pending`` (issue #339); the route is
|
|
805
|
+
#: still the loop resume, whose Step 2a re-runs exactly that review.
|
|
806
|
+
_LOOP_PARTIAL_REVIEW_PENDING_TEXT: Final[str] = (
|
|
807
|
+
"The loop for {feature} is not finished — its review pass failed or was "
|
|
808
|
+
"interrupted, so the review is still pending even if every item is done. The "
|
|
809
|
+
"recorded state is resumable and nothing downstream is ready: run the loop again "
|
|
810
|
+
"below to re-run the pending review."
|
|
811
|
+
)
|
|
812
|
+
#: The unfinished-runner variant of the `partial` next-steps sentence: the runner's
|
|
813
|
+
#: own terminal state (a crash, a stop, a stale lock, a limit halt) says it did not
|
|
814
|
+
#: finish cleanly, so the run is not complete even when every item reads `done`.
|
|
815
|
+
#: Selected only by ``--cause runner-stopped`` (issue #339); the route is still the
|
|
816
|
+
#: loop resume, whose Step 2a offers the runner's own resume.
|
|
817
|
+
_LOOP_PARTIAL_RUNNER_STOPPED_TEXT: Final[str] = (
|
|
818
|
+
"The loop runner for {feature} did not reach a clean finish — it crashed, was "
|
|
819
|
+
"stopped, or halted on a limit — so the run is not complete even if every item "
|
|
820
|
+
"reads done. The recorded state is resumable and nothing downstream is ready: run "
|
|
821
|
+
"the loop again below to resume the runner."
|
|
822
|
+
)
|
|
802
823
|
#: The `complete` preamble, selected by where the handoff actually lands. The epic
|
|
803
824
|
#: rows name the epic and its live rollup, so the operator can see WHY the handoff is
|
|
804
825
|
#: this member's own documentation rather than another member (or vice versa).
|
|
@@ -956,9 +977,11 @@ def _loop_route(
|
|
|
956
977
|
handoff: findings already exist at this exact revision, so the fenced
|
|
957
978
|
action is applying them, exactly as on a production re-exit.
|
|
958
979
|
cause: The already-validated attribution annotation — only
|
|
959
|
-
``"dependency-starvation"
|
|
960
|
-
|
|
961
|
-
|
|
980
|
+
``"dependency-starvation"``, ``"review-pending"`` or
|
|
981
|
+
``"runner-stopped"`` with
|
|
982
|
+
``outcome == "partial"``, else None. Swaps the partial next-steps
|
|
983
|
+
sentence for the matching variant; the route itself is unchanged
|
|
984
|
+
(partial stays a resume either way).
|
|
962
985
|
|
|
963
986
|
Returns:
|
|
964
987
|
`(primary_canonical, deferred_canonical, outcome_text, advancing)`, matching
|
|
@@ -985,6 +1008,10 @@ def _loop_route(
|
|
|
985
1008
|
)
|
|
986
1009
|
if outcome == "partial" and cause == "dependency-starvation":
|
|
987
1010
|
text = _LOOP_PARTIAL_STARVED_TEXT.format(feature=feature)
|
|
1011
|
+
elif outcome == "partial" and cause == "review-pending":
|
|
1012
|
+
text = _LOOP_PARTIAL_REVIEW_PENDING_TEXT.format(feature=feature)
|
|
1013
|
+
elif outcome == "partial" and cause == "runner-stopped":
|
|
1014
|
+
text = _LOOP_PARTIAL_RUNNER_STOPPED_TEXT.format(feature=feature)
|
|
988
1015
|
else:
|
|
989
1016
|
text = _LOOP_OUTCOME_TEXT[outcome].format(feature=feature)
|
|
990
1017
|
return primary, None, text, False
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -110,7 +110,7 @@ The runner commits each item onto the current branch. Skip if not a git repo or
|
|
|
110
110
|
|
|
111
111
|
### 1g. Stranded-Work Pre-flight (if using git)
|
|
112
112
|
|
|
113
|
-
Run `git status --porcelain`. If it reports changes **and** `{backlogDir}/{loopRunner.stateDir}/state.json` exists from a previous run, **STOP**: name that run (its `startedAt`, `currentItem`, and `blockedItems` from `state.json`) and point the user at the **Post-Run Tree Reconciliation** section of `references/recovery-procedure.md` to commit / stash / discard the stranded work before relaunch — never auto-pass `--force`. If the tree is dirty with **no** prior-run `state.json`, keep today's behavior (surface it; let the user commit/stash or pass `--force`). A clean tree is silent.
|
|
113
|
+
Run `git status --porcelain`. If it reports changes **and** `{backlogDir}/{loopRunner.stateDir}/state.json` exists from a previous run, **STOP**: name that run (its `startedAt`, `currentItem`, and `blockedItems` from `state.json`) and point the user at the **Post-Run Tree Reconciliation** section of `references/recovery-procedure.md` to commit / stash / discard the stranded work before relaunch — never auto-pass `--force`. If the tree is dirty with **no** prior-run `state.json`, keep today's behavior (surface it; let the user commit/stash or pass `--force`). A clean tree is silent.
|
|
114
114
|
|
|
115
115
|
## Step 2: Construct the Loop Command
|
|
116
116
|
|
|
@@ -120,7 +120,7 @@ Run the **list command** (`loopRunner.listCommand`, default `rauf backlog list .
|
|
|
120
120
|
|
|
121
121
|
Calculate the iteration count: `ceil((pending + in_progress) * loopIterationMultiplier)` where `loopIterationMultiplier` comes from `forge.config.json` (default: 1.5, headroom for retries).
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
Then, **whatever the counts**, run the **status-json command**: `reviewPending: true` (optional field) means a prior review pass failed or was interrupted — follow **Pending review** in `references/runner-contract.md` before any fresh run (which would drop it). Otherwise, with no pending or in_progress items: a reported `loopState` that is not a clean finish → follow **Unfinished runner** in that file; else STOP and tell the user: "All backlog items are already done or blocked. Nothing to run."
|
|
124
124
|
|
|
125
125
|
If there are `blocked` items, note them — the user may want `--retry-blocked`.
|
|
126
126
|
|
|
@@ -186,11 +186,11 @@ R="$(bash -c '[ -z "${FEATURE_FORGE_ROOT:-}" ] || [ -x "$FEATURE_FORGE_ROOT/scri
|
|
|
186
186
|
python3 "$R/scripts/forge-session.py" state-enter --feature "{feature}" --stage forge-5-loop --specs-dir "{specsDir}"
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
Then commit this state write before launching (mandatory
|
|
189
|
+
Then commit this state write before launching (mandatory — the runner refuses a dirty tree, and this marker is itself a change) via the shared-conventions **Git Commit Protocol** (epic members: stage `{specsDir}/{epic}/`): `{commitPrefix}({feature}): forge-5-loop in-progress`, regardless of `gitCommitAfterStage`. Unrelated leftover changes still trip the refusal; surface it, never auto-pass `--force`.
|
|
190
190
|
|
|
191
191
|
### 3b. Launch Background Process
|
|
192
192
|
|
|
193
|
-
Launch the loop **backgrounded** (host's background-execution mechanism: true) so it survives session end and does not block the session. For a runner that **persists its own structured event file** (the default — rauf writes `{stateDir}/events.ndjson` natively
|
|
193
|
+
Launch the loop **backgrounded** (host's background-execution mechanism: true) so it survives session end and does not block the session. For a runner that **persists its own structured event file** (the default — rauf writes and rotates `{stateDir}/events.ndjson` natively), launch the **plain `runCommand`** with **no stdout redirect** and supervise that native file; never redirect `--ndjson` into `{stateDir}` (it collides with the runner's own writer). Only a stdout-only runner (no native event file) uses `eventStreamCommand`, redirected to a file **outside** `{stateDir}`. The background task's exit notification is the single authoritative terminal signal (Step 4). For the exact launch commands (incl. the `mkdir -p` state-dir guard and the root→`IS_SANDBOX` sandbox guard) and the self-persisting vs. stdout-only detail, read `references/runner-contract.md`.
|
|
194
194
|
|
|
195
195
|
### 3c. Inform User
|
|
196
196
|
|
|
@@ -198,21 +198,11 @@ Follow the **Inform-user output template (Step 3c)** section of `references/runn
|
|
|
198
198
|
|
|
199
199
|
### 3d. Arm a Monitor on the event stream, and react to events
|
|
200
200
|
|
|
201
|
-
Arm the **host's monitoring mechanism** on the structured event stream (the NDJSON file, or the
|
|
202
|
-
human log as fallback) with **`persistent: true`**, a coverage-complete filter
|
|
203
|
-
matching every terminal and exception state (silence is not success), and react to
|
|
204
|
-
each event as it arrives. Each NDJSON line is a JSON object whose event kind lives
|
|
205
|
-
under the **`type`** field (rauf's schema — e.g. `{"type":"item_completed",…}`), so
|
|
206
|
-
the filter must select on **`.type`**, **not** `kind`: a `kind`-keyed filter surfaces
|
|
207
|
-
nothing (no `grep` match; `jq` aborts on the null `.kind`), so the watch stays dark. The exact Monitor
|
|
208
|
-
commands, the filter event list, and the full per-event reaction rules (`needs_human`
|
|
209
|
-
/ `loop_error` surfaced immediately with a `PushNotification`, `item_completed`
|
|
210
|
-
coalesced into milestones, `llm_stuck_warning` as a hang warning) are in
|
|
211
|
-
`references/runner-contract.md` — follow them verbatim.
|
|
201
|
+
Arm the **host's monitoring mechanism** (`persistent: true`) on the structured event stream (the NDJSON file, or the human log as fallback) with a coverage-complete filter matching every terminal and exception state (silence is not success). The filter selects on each NDJSON line's **`.type`** field, **never** `kind` (a `kind`-keyed filter matches nothing and the watch stays dark). The exact commands, the filter list (incl. `review_failed` and usage-limit events), and the per-event reactions (`needs_human` / `loop_error` / `review_failed` surfaced with a `PushNotification`, `item_completed` coalesced into milestones, `llm_stuck_warning` reported with its in-flight tool) are in `references/runner-contract.md` — follow them verbatim.
|
|
212
202
|
|
|
213
203
|
### 3f. Reach completion
|
|
214
204
|
|
|
215
|
-
Step 4 is reached when the backgrounded process exits (its completion notification is authoritative
|
|
205
|
+
Step 4 is reached when the backgrounded process exits (its completion notification is authoritative; a `loop_completed` / `loop_error` / `loop_cancelled` event is the live heads-up). Stop the Monitor (`TaskStop` if it has not ended) and proceed. Do NOT foreground-sleep or poll — the harness drives both signals.
|
|
216
206
|
|
|
217
207
|
## Step 4: Check Results
|
|
218
208
|
|
|
@@ -224,7 +214,7 @@ Run the **status-json command** (`loopRunner.statusJsonCommand`) and read
|
|
|
224
214
|
`backlogSummary` for the authoritative counts — it separates the three non-done
|
|
225
215
|
outcomes: genuine `blocked`, `needsHuman`, and runner-`deferred` ("false blocks").
|
|
226
216
|
Fall back to the **list command** (`loopRunner.listCommand`) if `statusJsonCommand`
|
|
227
|
-
is not configured. If the run used a review flag (e.g. rauf's `--review`), also read any `review_completed` event (event stream, or `{loopRunner.stateDir}/events.ndjson`) for its `itemsCreated`/`summary` to surface in 4b — see `references/result-reporting.md`.
|
|
217
|
+
is not configured. Also read the optional `loopState`, `reviewPending`, `lock` fields (absent on older runners = unset); **Runner terminal states** in `references/result-reporting.md` maps them. **`reviewPending: true` is never complete, whatever the counts** — offer the resume per **Pending review** in `references/runner-contract.md` before 4b. If the run used a review flag (e.g. rauf's `--review`), also read any `review_completed` event (event stream, or `{loopRunner.stateDir}/events.ndjson`) for its `itemsCreated`/`summary` to surface in 4b — see `references/result-reporting.md`.
|
|
228
218
|
|
|
229
219
|
### 4b. Report Results
|
|
230
220
|
|
|
@@ -233,11 +223,11 @@ blocked and needs-human) and render its report. The five verbatim result-report
|
|
|
233
223
|
|
|
234
224
|
### 4c. Post-Run Recovery Pass (unconditional)
|
|
235
225
|
|
|
236
|
-
Run the **Post-Run Recovery Procedure** (`references/recovery-procedure.md`) now — on **every** run close, before Step 5 writes state, so the tree it inspects is exactly what the run left. The live `needs_human` handler (3d)
|
|
226
|
+
Run the **Post-Run Recovery Procedure** (`references/recovery-procedure.md`) now — on **every** run close, before Step 5 writes state, so the tree it inspects is exactly what the run left. The live `needs_human` handler (3d) is **not** the entry condition: a run that emitted no event still enters here, so blocked-only runs reach the unblock. With nothing to decide, its step 1 skips to the §4 tree reconciliation — silent on a clean tree — which also reconciles work a run stranded uncommitted with no signal (1g is only the next-launch backstop). Its step-7 gate feeds Step 7's `resolved` rung; the stage still closes exactly once, in Step 7.
|
|
237
227
|
|
|
238
228
|
## Step 5: Update Pipeline State
|
|
239
229
|
|
|
240
|
-
Record completion by running `state-complete` (below). Evaluate "all backlog items are `done`" yourself and pass the result as `--status`: `complete`
|
|
230
|
+
Record completion by running `state-complete` (below). Evaluate "all backlog items are `done`" yourself and pass the result as `--status`: `complete` only when Step 7's ladder selects `complete` (every item `done`, `total > 0`, no pending review, a clean runner finish per `references/result-reporting.md`), else `in-progress`. The verb records `completedAt`, the version, `basedOnVersions` and `artifacts`, and refreshes `updatedAt`. Add `--epic "{epic}"` when this feature is an epic member — required, per the Pipeline State Protocol.
|
|
241
231
|
|
|
242
232
|
```bash
|
|
243
233
|
R="$(bash -c '[ -z "${FEATURE_FORGE_ROOT:-}" ] || [ -x "$FEATURE_FORGE_ROOT/scripts/forge-root.sh" ] || { echo "feature-forge: FEATURE_FORGE_ROOT=$FEATURE_FORGE_ROOT has no scripts/forge-root.sh" >&2; exit 2; }; for d in "${FEATURE_FORGE_ROOT:-}" "${CLAUDE_PLUGIN_ROOT:-}" "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/feature-forge/* "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
@@ -272,7 +262,7 @@ python3 "$R/scripts/forge-session.py" state-verify --feature "{feature}" --stage
|
|
|
272
262
|
|
|
273
263
|
Every loop run ends here, and ends here **exactly once** — standalone or epic member, complete or not.
|
|
274
264
|
|
|
275
|
-
First select the single `LoopOutcome` with the ladder in `references/result-reporting.md` (`resolved` → `needs-human` → `blocked` → `deferred` → `partial` → `complete`, first match wins), reading it from Step 4a's authoritative counts and never from the runner's process exit code. If those counts were never obtained, follow that file's operational-failure rule instead: report the failure and its recovery and run no exit at all.
|
|
265
|
+
First select the single `LoopOutcome` with the ladder in `references/result-reporting.md` (`resolved` → unfinished-runner `partial` → `needs-human` → `blocked` → `deferred` → `partial` → `complete`, first match wins, plus any `--cause` it names), reading it from Step 4a's authoritative counts and never from the runner's process exit code. If those counts were never obtained, follow that file's operational-failure rule instead: report the failure and its recovery and run no exit at all.
|
|
276
266
|
|
|
277
267
|
**Close this stage with the Scripted Stage Exit** (contract: `references/stage-exit-protocol.md`; do not improvise a "Next steps" list). Run:
|
|
278
268
|
|
|
@@ -291,8 +281,8 @@ Add `--epic "{epic}"` when this feature is an epic member — required, per the
|
|
|
291
281
|
- **Plugin-root discovery (1b-epic helper) covers installed paths, not workspace-dev checkouts.** The `forge-root.sh` search probes the locations of an **installed** plugin only, so a feature-forge **source checkout** (e.g. `~/workspace/feature-forge`) exits "cannot locate plugin root" unless `FEATURE_FORGE_ROOT` points at it (#323). Expected in a dev environment; run the epic-manifest script from the checkout directly (`python3 <checkout>/scripts/epic-manifest.py …`).
|
|
292
282
|
- `{backlogDir}` is a **directory path**, not a file path. Pass `specs/auth`, not `specs/auth/backlog.json`.
|
|
293
283
|
- rauf resolves `RAUF.md` with fallback (`{backlogDir}/.rauf/RAUF.md` first, then the project's `.rauf/RAUF.md`). State files (state.json, {loopRunner.logFile}, etc.) land at `{backlogDir}/{loopRunner.stateDir}/`, isolated per backlog dir, so concurrent features don't collide.
|
|
294
|
-
- If the session disconnects mid-loop, the runner process continues independently — check results later with the status / list commands. A stale lock
|
|
295
|
-
- Never run the run command in the foreground (without host's background-execution mechanism) — it blocks and will hit the Bash tool timeout for any non-trivial backlog. "Don't block the foreground" is NOT "stay silent": supervise via the host's monitoring mechanism (3d). A `needs_human`/`blocked`/`review` signal does **not** pause the loop — the runner sets the item aside and keeps going; surface it live but don't tell the user the loop is waiting.
|
|
284
|
+
- If the session disconnects mid-loop, the runner process continues independently — check results later with the status / list commands. A crashed run's stale lock (`PAUSED` + `lock.stale`) is cleared by rauf's `resume`, not `--force` (see `references/result-reporting.md`).
|
|
285
|
+
- Never run the run command in the foreground (without host's background-execution mechanism) — it blocks and will hit the Bash tool timeout for any non-trivial backlog. "Don't block the foreground" is NOT "stay silent": supervise via the host's monitoring mechanism (3d). A `needs_human`/`blocked`/`review` signal does **not** pause the loop — the runner sets the item aside and keeps going; surface it live but don't tell the user the loop is waiting.
|
|
296
286
|
- The version gate (1c) uses the `--json` form on purpose; never parse `rauf version`'s human output.
|
|
297
287
|
- **Implementation artifacts must not cite specs.** The loop should **read** specs and `backlog.json` freely — they are the source of truth, and the backlog rightly cites specs for provenance. But artifacts the loop **writes into the target repo** (source code, generated `SKILL.md`/agent files, configs, code comments) must be **self-contained**: no references to feature-forge spec files (no `See specs/{feature}/NN-*.md`, no "source spec" provenance notes) — specs are pre-implementation inputs that may be archived or deleted once the feature ships. This applies only to shipped implementation output, never to the backlog or spec documents, which keep citing specs.
|
|
298
288
|
|
|
@@ -6,7 +6,7 @@ silent unasked mutation. It runs whenever a skill gates on `doctor`'s structured
|
|
|
6
6
|
`checks[]` (`roadmap/self-healing-resilience.md` §5.2); today that is `forge-5-loop`'s
|
|
7
7
|
gates 1c/1d (`skills/forge-5-loop/SKILL.md`), which resolve the loop runner **before**
|
|
8
8
|
touching it, `forge-init`'s install preflight (`skills/forge-init/SKILL.md`), where
|
|
9
|
-
|
|
9
|
+
no check is a stop, and `forge-guide --doctor` (`skills/forge-guide/SKILL.md`), the
|
|
10
10
|
operator-facing repair surface, which gates nothing at all. All three are callers, not
|
|
11
11
|
the procedure's scope: any skill that gates on `checks[]` follows it in full. Its seven
|
|
12
12
|
ordered steps: **enumerate → cluster → consolidated prompts → record → apply → prove →
|
|
@@ -40,9 +40,11 @@ defined authoritatively in rauf's
|
|
|
40
40
|
- **A machine-readable event stream** for live supervision (`loopRunner.eventStreamCommand`,
|
|
41
41
|
rauf: `loop run … --ndjson`): one JSON event per line with a stable `type`
|
|
42
42
|
vocabulary — `item_completed` / `item_blocked` / `needs_human` / `signal_parsed`
|
|
43
|
-
/ `loop_completed` / `loop_error` / `loop_cancelled` / `
|
|
44
|
-
circuit-breaker halt surfaces as `loop_error`) — plus a
|
|
45
|
-
derived-status JSON (`loopRunner.statusJsonCommand`, rauf: `status … --json
|
|
43
|
+
/ `loop_completed` / `loop_error` / `loop_cancelled` / `review_failed` /
|
|
44
|
+
`llm_stuck_warning` (a circuit-breaker halt surfaces as `loop_error`) — plus a
|
|
45
|
+
derived-status JSON (`loopRunner.statusJsonCommand`, rauf: `status … --json`;
|
|
46
|
+
forge-5-loop also reads its optional `loopState` / `lock` / `sleepUntil` /
|
|
47
|
+
`reviewPending` fields when present, and degrades to the counts when absent) and
|
|
46
48
|
per-iteration telemetry with a `stuckWarning` flag (`loopRunner.watchCommand`,
|
|
47
49
|
rauf: `status … --json` — the `loop watch` verb was removed in v0.5.0). `forge-5-loop` supervises the run through these,
|
|
48
50
|
**not** by parsing the human log. `followCommand` / `logCommand` are
|
|
@@ -34,6 +34,16 @@ Runner review pass: {itemsCreated} fix item(s) created and implemented.
|
|
|
34
34
|
Omit this line when no `review_completed` event was emitted (no review flag passed).
|
|
35
35
|
The created items are already counted in the totals above.
|
|
36
36
|
|
|
37
|
+
**Review pending** (`reviewPending: true` — the review pass failed or was interrupted,
|
|
38
|
+
and the user chose **Stop here** at the Pending review offer in
|
|
39
|
+
`references/runner-contract.md`). Never render the all-done report for this run, even
|
|
40
|
+
when every item is `done`:
|
|
41
|
+
```
|
|
42
|
+
Loop finished the backlog for {feature}, but its review pass did not complete.
|
|
43
|
+
Completed: {done}/{total}
|
|
44
|
+
Review pending: {reviewItemIds count} item(s) ({reason from the last `review_failed` event, if any})
|
|
45
|
+
```
|
|
46
|
+
|
|
37
47
|
**Some items need a human:**
|
|
38
48
|
```
|
|
39
49
|
Loop completed for {feature}.
|
|
@@ -71,8 +81,11 @@ Loop completed for {feature}.
|
|
|
71
81
|
Pending: {pending} items ({cause})
|
|
72
82
|
Blocked: {blocked} items
|
|
73
83
|
```
|
|
74
|
-
Render `{cause}`
|
|
75
|
-
|
|
84
|
+
Render `{cause}` from the runner's terminal state first (see **Runner terminal states**
|
|
85
|
+
below): "stopped on request", "the run crashed (stale lock)", or "usage limit — resume
|
|
86
|
+
after {sleepUntil}". Otherwise render it as "iteration limit reached" **only** when
|
|
87
|
+
`loopState` is `ITERATIONS_COMPLETE` (the runner's own attestation, when reported) or
|
|
88
|
+
`iteration == maxIterations`, AND `selectable > 0` — cite the `iteration`/`maxIterations` counters from
|
|
76
89
|
`{loopRunner.stateDir}/state.json` and `selectable` from `backlog-topology --items-stdin
|
|
77
90
|
--json` run over the same authoritative item JSON as the counts above. Otherwise —
|
|
78
91
|
`selectable == 0` with items still pending while `iteration < maxIterations` — the
|
|
@@ -93,6 +106,37 @@ the `backlog-topology` output (`selectable`, `blockingRoots`, `gatedCount`,
|
|
|
93
106
|
`itemCount`). A cause any of those counters contradicts — e.g. "iteration limit
|
|
94
107
|
reached" while `iteration < maxIterations` — is a reportable defect.
|
|
95
108
|
|
|
109
|
+
## Runner terminal states (Step 4a)
|
|
110
|
+
|
|
111
|
+
`status --json` may also carry `loopState`, `lock`, `sleepUntil`, `reviewPending` and
|
|
112
|
+
`reviewItemIds`. All are optional: when a field is absent, skip its row and read the
|
|
113
|
+
counts as before. These mirror the rows of rauf's supervisor decision table
|
|
114
|
+
(`drive-rauf-loop`) that forge-5-loop decides the same way.
|
|
115
|
+
|
|
116
|
+
**Clean runner finish.** When `loopState` is reported, only `COMPLETE` or `IDLE` is a
|
|
117
|
+
clean terminal success. Every other value — `ERROR`, `PAUSED` (on request or with a
|
|
118
|
+
stale lock), `ITERATIONS_COMPLETE`, `PAUSED_USAGE_LIMIT`, `WEEKLY_LIMIT`,
|
|
119
|
+
`SLEEPING_LIMIT`, `PAUSED_HUMAN`, a still-live `RUNNING`/`REVIEWING`, or anything
|
|
120
|
+
unrecognized — means the runner did **not** finish cleanly, and the run is **never**
|
|
121
|
+
`complete`, even when `done == total > 0` (e.g. a process killed after its last commit
|
|
122
|
+
but before writing its final state reads `PAUSED` + stale lock with every item done).
|
|
123
|
+
The ladder's rung 2 (runner not finished) catches it, above the needs-human / blocked / deferred rungs. When `loopState` is absent (an older or
|
|
124
|
+
non-rauf runner), this gate does not apply and the counts decide, as before.
|
|
125
|
+
|
|
126
|
+
| Runner state | What it means here |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `backlogSummary.total == 0` (any `loopState`) | Empty **or unreadable** backlog — a read failure reports all-zero counts. Never `complete`: run the **validate command** and treat it as an **operational failure** (below). |
|
|
129
|
+
| `reviewPending: true` | Not complete, whatever the counts: offer the resume (**Pending review**, `references/runner-contract.md`). If the user stops here, ladder rung 2 closes `partial --cause review-pending` — even with blocked, needs-human or deferred items, which are still reported alongside. |
|
|
130
|
+
| `ITERATIONS_COMPLETE` | Iteration budget spent with eligible work left — the "iteration limit reached" `partial` cause. The next loop run gets a fresh budget. |
|
|
131
|
+
| `PAUSED`, `lock.stale` not true | Stopped on request (Ctrl-C, `SIGTERM`, a stop command). Report "stopped on request"; do not offer to relaunch unless the user asks. |
|
|
132
|
+
| `PAUSED`, `lock.stale: true` | The run died mid-iteration and left its lock. rauf's `{bin} resume . --backlog {backlogDir}` clears the stale lock and continues. Never reach for `--force` or `reset` first. |
|
|
133
|
+
| `PAUSED_USAGE_LIMIT` / `WEEKLY_LIMIT` | Halted on a usage limit: "resume after {sleepUntil}". Not a failure. |
|
|
134
|
+
| `ERROR` | Crash or circuit-breaker halt (`loop_error`). Surface the error alongside the count reports; never `complete`. With work left, the next loop run re-runs it; with none, re-entry offers rauf's resume (**Unfinished runner**, `references/runner-contract.md`). |
|
|
135
|
+
| `COMPLETE` with `done < total` | No eligible work left, but items are unfinished (blocked, needs-human, deferred, or pending behind a blocked dependency). The ladder's non-complete rungs apply; never reset the backlog. |
|
|
136
|
+
|
|
137
|
+
**Exit codes are not the outcome.** rauf exits 1 both for a crash and for a failed review
|
|
138
|
+
pass, and 0 for a requested stop or a spent budget. Read the fields above, never `$?`.
|
|
139
|
+
|
|
96
140
|
## Selecting the one `LoopOutcome` (Step 7)
|
|
97
141
|
|
|
98
142
|
After Step 5's `state-complete`, select exactly **one** `LoopOutcome` from Step 4a's
|
|
@@ -106,26 +150,43 @@ authoritative final counts. Walk this ladder in order and stop at the first matc
|
|
|
106
150
|
stop the recovery just cleared is not re-reported as still needing a human. (Step
|
|
107
151
|
4c runs the procedure on every close, so an empty affected set is the common case —
|
|
108
152
|
it never selects `resolved`; fall through.)
|
|
109
|
-
2. **`
|
|
153
|
+
2. **`partial` (runner not finished)** — otherwise, `reviewPending` is true, **or**
|
|
154
|
+
`loopState` is reported and is not a clean finish (**Clean runner finish**, above).
|
|
155
|
+
Pass `--cause review-pending` when `reviewPending` is true. Otherwise pass
|
|
156
|
+
`--cause runner-stopped`, except for `ITERATIONS_COMPLETE`, which is the plain
|
|
157
|
+
iteration-limit `partial` (no `--cause`). This rung fires **whatever the counts
|
|
158
|
+
say** — including `done == total`, and **above** the needs-human / blocked / deferred
|
|
159
|
+
rungs, following rauf's supervisor table: a crashed, stopped, limit-halted or
|
|
160
|
+
budget-spent runner, or an unfinished review, is recovered or resumed first. It does
|
|
161
|
+
not hide the backlog: the Step 4b needs-human / blocked / deferred reports still
|
|
162
|
+
render alongside it, so every set-aside item is surfaced in the same close (e.g.
|
|
163
|
+
**Stop here** on a pending review with blocked items closes `partial --cause
|
|
164
|
+
review-pending` and still lists the blocked items).
|
|
165
|
+
3. **`needs-human`** — otherwise, `needsHuman > 0`. This wins even when blocked
|
|
110
166
|
items also exist: a decision only a human can make outranks work that merely
|
|
111
167
|
could not proceed.
|
|
112
|
-
|
|
113
|
-
|
|
168
|
+
4. **`blocked`** — otherwise, genuine `blocked > 0`.
|
|
169
|
+
5. **`deferred`** — otherwise, runner-deferred items exist (the "false blocks" the
|
|
114
170
|
runner gave up on after retries).
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
6. **`partial`** — otherwise, `pending`/`in_progress` items remain (the report above
|
|
172
|
+
names the cause). Pass `--cause dependency-starvation` only on the starvation report.
|
|
173
|
+
7. **`complete`** — otherwise, and **only** when `total > 0`, every item is `done`, no
|
|
174
|
+
review is pending, and the runner finished cleanly (or reports no `loopState`).
|
|
118
175
|
|
|
119
176
|
This is a priority order, not a set. A run reporting both a needs-human and a blocked
|
|
120
|
-
count renders both reports above and still exits `needs-human
|
|
177
|
+
count renders both reports above and still exits `needs-human`; a run whose runner did
|
|
178
|
+
not finish renders every applicable count report and still exits rung 2's `partial`.
|
|
121
179
|
|
|
122
180
|
**The runner's process exit code is not the outcome.** A loop runner that exits 0 has
|
|
123
181
|
reported only that its process finished; the final backlog state decides. A clean
|
|
124
|
-
exit 0 that still leaves pending items is `partial`, never `complete
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
182
|
+
exit 0 that still leaves pending items is `partial`, never `complete`; an exit 1 from a
|
|
183
|
+
failed review with every item `done` is `partial` (`--cause review-pending`), not an
|
|
184
|
+
error; and a crash or stale-lock stop with every item `done` is `partial` (`--cause
|
|
185
|
+
runner-stopped`). `complete` is legitimate only when the counts show every item `done`,
|
|
186
|
+
no review is pending, and the runner finished cleanly.
|
|
187
|
+
|
|
188
|
+
**Retrying the non-complete outcomes.** `partial` (every cause), `deferred`, and
|
|
189
|
+
`resolved` fence the loop resume; `blocked` and `needs-human` fence the navigator. Whichever you land on, the
|
|
129
190
|
runner's own retry flags still apply to the next run — e.g. rauf's `--retry-blocked`
|
|
130
191
|
picks the set-aside blocked and deferred items back up at Step 2d. Mention that as
|
|
131
192
|
plain prose in the report if it helps; never as a second command block.
|
|
@@ -133,8 +194,9 @@ plain prose in the report if it helps; never as a second command block.
|
|
|
133
194
|
## Operational failure before the counts are known
|
|
134
195
|
|
|
135
196
|
If the run cannot produce authoritative counts at all — the status/list command fails,
|
|
136
|
-
its output does not parse, the state directory is gone,
|
|
137
|
-
|
|
197
|
+
its output does not parse, the state directory is gone, the summary reports
|
|
198
|
+
`total == 0` (an empty or unreadable backlog — show the validate command's output), or
|
|
199
|
+
the process died in a way that leaves the backlog unreadable — **do not pick an outcome and do not close the
|
|
138
200
|
stage.** There is nothing to select from, and guessing one would record a pipeline
|
|
139
201
|
position that never happened.
|
|
140
202
|
|
|
@@ -152,12 +152,18 @@ maximum `timeout_ms` (1 hour), and a bounded timeout would silently stop watchin
|
|
|
152
152
|
still-running loop.
|
|
153
153
|
|
|
154
154
|
**Coverage-complete filter (silence is not success).** The filter MUST match every
|
|
155
|
-
terminal and
|
|
156
|
-
looks identical to "still running."
|
|
155
|
+
terminal, exception, and pause/limit event, not just the happy path — otherwise a crash,
|
|
156
|
+
hang, or hours-long usage sleep looks identical to "still running." The list below covers
|
|
157
|
+
every such type in rauf's event schema (terminal: `loop_completed` / `loop_error` /
|
|
158
|
+
`loop_cancelled` / `loop_paused`; exception: `item_blocked` / `needs_human` /
|
|
159
|
+
`review_failed` / `llm_stuck_warning`; pause/limit: `usage_limit_hit` /
|
|
160
|
+
`usage_limit_cleared` / `sleep_start` / `sleep_end`); only per-iteration narration
|
|
161
|
+
(`iteration_start`, `llm_*` activity, `item_selected`, …) is left out. Monitor command
|
|
162
|
+
(NDJSON path):
|
|
157
163
|
|
|
158
164
|
```
|
|
159
165
|
tail -n +1 -F {backlogDir}/{loopRunner.stateDir}/events.ndjson 2>/dev/null \
|
|
160
|
-
| jq -rc --unbuffered 'select(.type | test("item_completed|item_blocked|needs_human|signal_parsed|loop_completed|loop_error|loop_cancelled|llm_stuck_warning"))'
|
|
166
|
+
| jq -rc --unbuffered 'select(.type | test("item_completed|item_blocked|needs_human|signal_parsed|loop_completed|loop_error|loop_cancelled|loop_paused|review_failed|llm_stuck_warning|usage_limit_hit|usage_limit_cleared|sleep_start|sleep_end"))'
|
|
161
167
|
```
|
|
162
168
|
|
|
163
169
|
> **Use `tail -F` (follow by name), not `-f` (follow by descriptor).** The runner
|
|
@@ -174,15 +180,20 @@ tail -n +1 -F {backlogDir}/{loopRunner.stateDir}/events.ndjson 2>/dev/null \
|
|
|
174
180
|
|
|
175
181
|
```
|
|
176
182
|
tail -n +1 -F {backlogDir}/{loopRunner.stateDir}/{loopRunner.logFile} 2>/dev/null \
|
|
177
|
-
| grep -E --line-buffered 'Item [^ ]+ (completed|blocked):|Item [^ ]+ needs human input|Loop completed|Loop error:|Circuit breaker
|
|
183
|
+
| grep -E --line-buffered 'Item [^ ]+ (completed|blocked):|Item [^ ]+ needs human input|Loop completed|Loop error:|Circuit breaker:|Loop cancelled|Review pass (cancelled|stopped)|Review returned unexpected signal|for review:|[Uu]sage limit'
|
|
178
184
|
```
|
|
179
185
|
|
|
180
186
|
(Match `needs human input` **without** a trailing colon — the runner writes
|
|
181
|
-
`needs human input (set aside):`.
|
|
187
|
+
`needs human input (set aside):`. `Loop cancelled` also matches *"Loop cancelled during
|
|
188
|
+
review pass (review pending)"* and the between-iteration / mid-sleep cancels;
|
|
189
|
+
`[Uu]sage limit` matches the 5-hour sleep, weekly limit, detection and wake lines.)
|
|
182
190
|
|
|
183
191
|
If the Monitor is ever auto-stopped for event volume, re-arm with a tighter filter
|
|
184
192
|
(drop `item_completed`, keep the exception/terminal events).
|
|
185
193
|
|
|
194
|
+
An older runner that never emits a listed type (e.g. `review_failed`) simply never
|
|
195
|
+
matches it — the filter needs no version gate.
|
|
196
|
+
|
|
186
197
|
## React to events as they land (Step 3e)
|
|
187
198
|
|
|
188
199
|
Each Monitor event arrives as a message. React per type — but keep the user signal
|
|
@@ -210,13 +221,101 @@ high and the noise low:
|
|
|
210
221
|
- **`loop_error`** → a real failure (this is also what a circuit-breaker halt — too many
|
|
211
222
|
consecutive infra failures — emits). Surface now and `PushNotification`. Offer
|
|
212
223
|
inspection / `--force` / re-run as appropriate.
|
|
213
|
-
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
`
|
|
219
|
-
|
|
224
|
+
- **`review_failed`** → the post-loop review pass failed or was stopped by a usage limit
|
|
225
|
+
(payload `reason`). Surface it now with a `PushNotification`. The run is **not**
|
|
226
|
+
complete: the review stays pending (`status --json` → `reviewPending: true`). A failed
|
|
227
|
+
review makes `loop run --review` exit **1**; a usage-limit stop is a resumable limit
|
|
228
|
+
stop, not that exit-1 case. A review **cancelled** mid-pass emits **no**
|
|
229
|
+
`review_failed` — only `loop_cancelled` (human log: *"Loop cancelled during review pass
|
|
230
|
+
(review pending)"*) with `reviewPending` still set — so never rely on this event alone.
|
|
231
|
+
Nothing to do live — Step 4a reads `reviewPending` and offers the resume (**Pending
|
|
232
|
+
review**, below).
|
|
233
|
+
- **Stall detection** → rauf emits an **`llm_stuck_warning`** event when an iteration's
|
|
234
|
+
output stream goes silent. Surface it live as a stall warning, not yet a failure. Read
|
|
235
|
+
its optional `currentTool` / `toolRunningMs` (absent on older runners — then report
|
|
236
|
+
the plain `silentMs` and treat it as a possible hang):
|
|
237
|
+
- `currentTool: null` → **the model itself went silent** with no tool in flight — a
|
|
238
|
+
likely hang. Offer `--force` / re-run if it persists.
|
|
239
|
+
- `currentTool` set → **a quiet tool call outlived the tool ceiling** — report it as
|
|
240
|
+
e.g. *"Bash running 31m"* (`toolRunningMs` rounded to minutes). This is usually a
|
|
241
|
+
slow verification gate, not a hung LLM: say so, and let it run unless it is clearly
|
|
242
|
+
wedged.
|
|
243
|
+
|
|
244
|
+
The thresholds are the runner's `.rauf.json` `options.stuckThresholdMs` (silence
|
|
245
|
+
before the warning, default 5 min) and `options.toolStuckThresholdMs` (how long a
|
|
246
|
+
quiet in-flight tool holds the warning off, default 30 min, measured from the tool's
|
|
247
|
+
start). A repo whose verification gate legitimately runs longer than 30 min should
|
|
248
|
+
raise `toolStuckThresholdMs` rather than learn to ignore the warning. If you instead
|
|
249
|
+
want to probe on quiet, run `{rendered watchCommand}` and key off `health.stuckWarning`.
|
|
250
|
+
Do **not** infer a stall from `state.json.updatedAt` alone — it is not a liveness
|
|
251
|
+
proof.
|
|
252
|
+
- **Usage-limit waits are not stalls.** `usage_limit_hit` (`limitType`, optional
|
|
253
|
+
`reason: "usage_api_disagreement"`) followed by `sleep_start` (`sleepUntil`, `reason`)
|
|
254
|
+
means the runner is sleeping until the limit resets (`SLEEPING_LIMIT`) and will resume
|
|
255
|
+
on its own: surface it once with its `sleepUntil`, and send a `PushNotification` when
|
|
256
|
+
the sleep is long (a 5-hour window). A `sleep_start` whose `reason` begins *"Usage-limit
|
|
257
|
+
banner unconfirmed"* is a 30 s / 60 s backoff (`status --json` still `RUNNING` with
|
|
258
|
+
`sleepUntil`) — narrate it at most briefly. `sleep_end` / `usage_limit_cleared` → the
|
|
259
|
+
loop is working again. A weekly or no-sleep limit halts the run instead (the process
|
|
260
|
+
exits; Step 4a reads `WEEKLY_LIMIT` / `PAUSED_USAGE_LIMIT`). None of these is a stall:
|
|
261
|
+
never offer `--force`.
|
|
262
|
+
- **`loop_paused`** (`reason: "needs_human"`, `itemId`) → the run halted on a needs-human
|
|
263
|
+
item (only under rauf's opt-in `--pause-on-needs-human`; forge does not pass it by
|
|
264
|
+
default). Unlike the default set-aside mode, the loop **is** now stopped: surface it
|
|
265
|
+
with a `PushNotification`; the process exits and Step 4c's recovery pass handles the
|
|
266
|
+
answer.
|
|
267
|
+
|
|
268
|
+
**Pending review (Steps 2a / 4a, rauf).** A rauf `--review` run whose review pass failed, was cancelled, or was stopped by a usage
|
|
269
|
+
limit leaves `status --json` with `reviewPending: true` and `reviewItemIds` (the review's
|
|
270
|
+
exact scope). The loop state can read `COMPLETE`/`IDLE` with every item `done`, or
|
|
271
|
+
`PAUSED`/`PAUSED_USAGE_LIMIT` — either way the run is **not complete**, and the process
|
|
272
|
+
exit code (1 for a failed review) does not decide it. Both fields are optional: a runner
|
|
273
|
+
that never reports them never takes this path.
|
|
274
|
+
|
|
275
|
+
rauf's `resume` re-runs exactly that review (`rauf loop review --items <reviewItemIds>`),
|
|
276
|
+
not a fresh loop. So when Step 4a or Step 2a sees `reviewPending: true`:
|
|
277
|
+
|
|
278
|
+
1. Report it: *"The review pass for {feature} did not finish ({reason from the last
|
|
279
|
+
`review_failed` event, if any}); it covers {reviewItemIds}."*
|
|
280
|
+
2. Via host's question mechanism, offer **Resume the review now (recommended)** · **Stop here**. On a
|
|
281
|
+
usage-limit stop (`PAUSED_USAGE_LIMIT` / `WEEKLY_LIMIT`), say the resume only helps
|
|
282
|
+
once the limit resets (`sleepUntil`). A stop the user requested (`PAUSED`, lock
|
|
283
|
+
released) is theirs: offer, never auto-resume.
|
|
284
|
+
3. **Resume:** launch `{bin} resume . --backlog {backlogDir}` backgrounded, exactly as a
|
|
285
|
+
run command (Step 3b launch guards, 3d Monitor, 3f completion), then return to Step 4a.
|
|
286
|
+
A successful review may file fix items (`review_completed.itemsCreated`); those are
|
|
287
|
+
ordinary pending work for the next loop run. rauf reviews **before** relaunching: when
|
|
288
|
+
pending items also remain (the review ran after the iteration budget ran out, or
|
|
289
|
+
blocked items strand their dependents), `resume` re-runs only the review and the
|
|
290
|
+
remaining items wait for the next loop run — say so, never launch a fresh `loop run`
|
|
291
|
+
first (it overwrites the state and drops the pending review).
|
|
292
|
+
4. **Stop here:** Step 7 closes `partial` with `--cause review-pending` (see
|
|
293
|
+
`references/result-reporting.md`) — a resume route whose Step 2a re-offers this.
|
|
294
|
+
|
|
295
|
+
At rung 3 (no question mechanism), do not launch: print the rendered resume command and
|
|
296
|
+
close as in 4.
|
|
297
|
+
|
|
298
|
+
**Unfinished runner (Step 2a re-entry, rauf).** When Step 2a finds no pending or
|
|
299
|
+
in_progress items and no pending review, but `status --json` reports a `loopState` that
|
|
300
|
+
is not a clean finish (**Clean runner finish** in `references/result-reporting.md` —
|
|
301
|
+
e.g. `ERROR`, `PAUSED` with `lock.stale`, `ITERATIONS_COMPLETE`, a usage halt), the
|
|
302
|
+
prior run closed as `partial` with `--cause runner-stopped` (or the plain iteration-limit
|
|
303
|
+
`partial`), and "Nothing to run" would strand it. Instead:
|
|
304
|
+
|
|
305
|
+
1. Report the state: *"The last run for {feature} did not finish cleanly ({loopState}
|
|
306
|
+
{— stale lock | — resets {sleepUntil}})."*
|
|
307
|
+
2. Via host's question mechanism, offer **Resume the runner (recommended)** · **Stop here**. For a
|
|
308
|
+
usage halt, the resume helps only once the limit resets; for `PAUSED` on request
|
|
309
|
+
(lock released), the stop was the user's — offer, never auto-resume.
|
|
310
|
+
3. **Resume:** launch `{bin} resume . --backlog {backlogDir}` backgrounded exactly as in
|
|
311
|
+
**Pending review** step 3 (it clears a stale lock and finishes the run's bookkeeping,
|
|
312
|
+
including any post-loop review), then continue at Step 4a. rauf's recovery for
|
|
313
|
+
`ERROR` is `resume` or `reset` + re-run — never reach for `reset` or `--force` first.
|
|
314
|
+
4. **Stop here**, or rung 3 (print the rendered command, do not launch): STOP without
|
|
315
|
+
touching the stage — it is already recorded `in-progress`.
|
|
316
|
+
|
|
317
|
+
When `loopState` is absent, this never fires: an older or non-rauf runner keeps the
|
|
318
|
+
plain "Nothing to run" stop.
|
|
220
319
|
|
|
221
320
|
## Inform-user output template (Step 3c)
|
|
222
321
|
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
@@ -47,7 +47,7 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation`, `review-pending` or `runner-stopped` with `--outcome partial` |
|
|
51
51
|
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|