forgedock 1.0.22 → 1.1.2

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.
Files changed (184) hide show
  1. package/README.md +255 -211
  2. package/bin/batch-runner.mjs +339 -0
  3. package/bin/cinema.mjs +320 -0
  4. package/bin/demo.mjs +92 -7
  5. package/bin/engine/phases.mjs +168 -0
  6. package/bin/engine/projector.mjs +32 -0
  7. package/bin/engine/reconcile.mjs +11 -0
  8. package/bin/engine/runlog.mjs +79 -0
  9. package/bin/engine/state.mjs +32 -0
  10. package/bin/engine-cli.mjs +222 -0
  11. package/bin/engine.mjs +138 -0
  12. package/bin/forgedock.mjs +896 -1540
  13. package/bin/hooks/interactive-engine.mjs +509 -0
  14. package/bin/hooks/pre-tool-use.mjs +498 -0
  15. package/bin/hooks/subagent-stop-enforce.mjs +197 -0
  16. package/bin/journey.mjs +841 -0
  17. package/bin/registry.mjs +139 -0
  18. package/bin/report.mjs +447 -0
  19. package/bin/runner.mjs +136 -20
  20. package/bin/settings-hook.mjs +346 -0
  21. package/bin/tui.mjs +6 -3
  22. package/commands/adopt.md +4 -1
  23. package/commands/analytics.md +4 -1
  24. package/commands/audit-agents.md +110 -27
  25. package/commands/audit.md +20 -1
  26. package/commands/autopilot.md +84 -12
  27. package/commands/changelog.md +2 -1
  28. package/commands/ci-audit.md +2 -1
  29. package/commands/cleanup.md +161 -1
  30. package/commands/compat-audit.md +2 -1
  31. package/commands/deploy-info.md +63 -4
  32. package/commands/design-bench.md +6 -1
  33. package/commands/design-render-critique-loop.md +2 -1
  34. package/commands/design.md +1 -0
  35. package/commands/diagnose.md +2 -1
  36. package/commands/explain.md +2 -1
  37. package/commands/forge-stats.md +122 -2
  38. package/commands/forgedock-init.md +1 -1
  39. package/commands/geo-audit.md +3 -0
  40. package/commands/incident-response.md +2 -1
  41. package/commands/issue.md +24 -3
  42. package/commands/milestone.md +77 -12
  43. package/commands/optimize.md +2 -1
  44. package/commands/orchestrate/config.md +67 -0
  45. package/commands/orchestrate/phase-1-resolve.md +159 -0
  46. package/commands/orchestrate/phase-2-triage.md +126 -0
  47. package/commands/orchestrate/phase-2.5-synthesis.md +156 -0
  48. package/commands/orchestrate/phase-3-dependency.md +591 -0
  49. package/commands/orchestrate/phase-4-execution.md +962 -0
  50. package/commands/orchestrate/phase-5-cleanup.md +47 -0
  51. package/commands/orchestrate/phase-6-report.md +198 -0
  52. package/commands/orchestrate/safety.md +62 -0
  53. package/commands/orchestrate.md +25 -2027
  54. package/commands/pipeline-health/config.md +34 -0
  55. package/commands/pipeline-health/phase-1-context.md +180 -0
  56. package/commands/pipeline-health/phase-2-metrics.md +1729 -0
  57. package/commands/pipeline-health/phase-3-analyze.md +204 -0
  58. package/commands/pipeline-health/phase-4-proposals.md +117 -0
  59. package/commands/pipeline-health/phase-5-report.md +284 -0
  60. package/commands/pipeline-health/phase-6-summary.md +52 -0
  61. package/commands/pipeline-health.md +25 -2401
  62. package/commands/pipeline-resume.md +24 -1
  63. package/commands/pipeline-status.md +65 -0
  64. package/commands/qa-sweep.md +4 -1
  65. package/commands/quality-gate.md +326 -42
  66. package/commands/replay.md +2 -1
  67. package/commands/review-pr-agents/api.md +135 -0
  68. package/commands/review-pr-agents/auth.md +137 -0
  69. package/commands/review-pr-agents/billing.md +101 -0
  70. package/commands/review-pr-agents/concurrency.md +145 -0
  71. package/commands/review-pr-agents/database.md +103 -0
  72. package/commands/review-pr-agents/frontend.md +89 -0
  73. package/commands/review-pr-agents/infra.md +385 -0
  74. package/commands/review-pr-agents/protocols.md +185 -0
  75. package/commands/review-pr-agents/scraper.md +185 -0
  76. package/commands/review-pr-agents/security.md +406 -0
  77. package/commands/review-pr-agents.md +45 -1722
  78. package/commands/review-pr-staging.md +196 -40
  79. package/commands/review-pr.md +612 -56
  80. package/commands/rollback.md +2 -1
  81. package/commands/scope.md +2 -1
  82. package/commands/security-audit.md +2 -1
  83. package/commands/signal-planner.md +623 -0
  84. package/commands/sync-ecosystem.md +1 -0
  85. package/commands/test-gate.md +17 -1
  86. package/commands/validate.md +2 -1
  87. package/commands/work-on/build/architect.md +28 -0
  88. package/commands/work-on/build/context.md +2 -0
  89. package/commands/work-on/build/implement.md +19 -5
  90. package/commands/work-on/build/validate.md +62 -6
  91. package/commands/work-on/build.md +187 -30
  92. package/commands/work-on/close.md +132 -5
  93. package/commands/work-on/decompose.md +19 -1
  94. package/commands/work-on/investigate.md +117 -2
  95. package/commands/work-on/review.md +48 -4
  96. package/commands/work-on-monolithic.md +8 -2
  97. package/commands/work-on.md +247 -7
  98. package/docs/BRAND.md +16 -5
  99. package/docs/CI.md +2 -2
  100. package/docs/CODEX.md +36 -1
  101. package/docs/CONFIG.md +44 -42
  102. package/docs/FORGE-PROTOCOL.md +15 -1064
  103. package/docs/anthropic-devrel-outreach.md +2 -2
  104. package/docs/articles/command-decomposition-token-savings.md +214 -0
  105. package/docs/articles/model-release-playbook.md +131 -0
  106. package/docs/articles/per-repo-adaptive-scripts-token-savings.md +27 -25
  107. package/docs/claude-breakpoints.json +75 -5
  108. package/docs/design/abc-benchmark.md +1 -1
  109. package/docs/design/design-spec-schema.md +1 -1
  110. package/docs/design/divergent-generation.md +1 -1
  111. package/docs/design/eval-gate-runbook.md +178 -0
  112. package/docs/design/show-hn-draft.md +26 -1
  113. package/docs/design/token-cost-baseline-1298.md +59 -0
  114. package/docs/eval/README.md +117 -0
  115. package/docs/eval/corpus/seed-v1.json +6 -0
  116. package/docs/eval/published/claude-sonnet-4-6-2026-07-04.json +33 -0
  117. package/docs/site/annotations-explained.md +24 -0
  118. package/docs/site/command-learning-path.md +51 -14
  119. package/docs/site/command-reference.md +339 -113
  120. package/docs/site/for-companies.md +95 -0
  121. package/docs/site/forge-annotation-protocol.md +12 -256
  122. package/docs/site/getting-started.md +58 -12
  123. package/docs/site/github-is-the-memory.md +113 -0
  124. package/docs/site/how-it-works.md +3 -13
  125. package/docs/site/index.md +10 -2
  126. package/docs/spec/eval-run-result.md +147 -0
  127. package/docs/spec/forge-protocol-v1.md +441 -18
  128. package/docs/spec/label-state-machine.md +55 -0
  129. package/docs/spec/review-protocol.md +158 -0
  130. package/docs/spec-graph-schema.md +28 -0
  131. package/docs/superpowers/plans/2026-07-03-cinematic-onboarding-tui.md +2339 -0
  132. package/docs/superpowers/plans/2026-07-03-durable-execution-engine.md +1223 -0
  133. package/docs/superpowers/specs/2026-07-03-cinematic-onboarding-tui-design.md +157 -0
  134. package/docs/superpowers/specs/2026-07-03-durable-execution-engine-design.md +194 -0
  135. package/docs/superpowers/specs/2026-07-04-economic-self-governance-design.md +181 -0
  136. package/docs/superpowers/specs/2026-07-04-provenance-trail-design.md +189 -0
  137. package/examples/forgedock-demo/README.md +41 -22
  138. package/examples/forgedock-demo/issues/06-bug-tags-type-validation.md +43 -0
  139. package/examples/forgedock-demo/issues/07-bug-negative-offset-pagination.md +42 -0
  140. package/examples/forgedock-demo/issues/08-bug-patch-mass-assignment.md +49 -0
  141. package/examples/forgedock-demo/issues/09-bug-count-injection.md +47 -0
  142. package/examples/forgedock-demo/issues/10-feature-sort-param.md +39 -0
  143. package/examples/forgedock-demo/issues/11-feature-patch-tags.md +37 -0
  144. package/examples/forgedock-demo/issues/12-feature-bulk-create.md +42 -0
  145. package/examples/forgedock-demo/issues/13-feature-archive-notes.md +46 -0
  146. package/examples/forgedock-demo/issues/14-refactor-extract-title-validation.md +41 -0
  147. package/examples/forgedock-demo/issues/15-refactor-protected-route-flag.md +43 -0
  148. package/examples/forgedock-demo/issues/16-refactor-extract-store.md +45 -0
  149. package/examples/forgedock-demo/issues/17-perf-tags-dedup-set.md +35 -0
  150. package/examples/forgedock-demo/issues/18-perf-remove-redundant-sort.md +37 -0
  151. package/examples/forgedock-demo/issues/19-docs-api-reference-full.md +53 -0
  152. package/examples/forgedock-demo/issues/20-docs-intentional-flaw-convention.md +46 -0
  153. package/examples/forgedock-demo/scripts/smoke.js +18 -1
  154. package/examples/forgedock-demo/src/db.js +36 -11
  155. package/examples/forgedock-demo/src/routes/notes.js +106 -9
  156. package/examples/forgedock-demo/src/server.js +4 -1
  157. package/package.json +12 -4
  158. package/packages/protocol/LICENSE +21 -0
  159. package/packages/protocol/src/cli.js +135 -0
  160. package/packages/protocol/src/emit.js +146 -0
  161. package/packages/protocol/src/index.js +43 -0
  162. package/packages/protocol/src/parse.js +229 -0
  163. package/packages/protocol/src/types.js +171 -0
  164. package/packages/protocol/src/validate.js +122 -0
  165. package/scripts/bench-topology-cost.mjs +372 -0
  166. package/scripts/check-command-docs-drift.sh +198 -0
  167. package/scripts/check-protocol-restatements.sh +176 -0
  168. package/scripts/check-registry/README.md +72 -0
  169. package/scripts/check-registry/manifest.json +6 -0
  170. package/scripts/code-index.sh +454 -0
  171. package/scripts/conformance-check.mjs +168 -0
  172. package/scripts/doctor-pipeline-state.sh +484 -0
  173. package/scripts/eval-gate-baseline.json +17 -0
  174. package/scripts/eval-gate-scorecard.mjs +242 -0
  175. package/scripts/eval-scorecard-aggregator.mjs +252 -0
  176. package/scripts/flaky-quarantine.sh +241 -0
  177. package/scripts/forge-annotation.sh +567 -0
  178. package/scripts/issue-dedup.sh +236 -0
  179. package/scripts/validate-annotation-node.mjs +233 -0
  180. package/scripts/verify-env-vars.sh +18 -2
  181. package/scripts/verify-host-headers.sh +4 -4
  182. package/scripts/verify-route-registration.sh +2 -2
  183. package/scripts/worktree-lifecycle.sh +202 -0
  184. package/templates/devdocs/agent/using-forgedock.md +14 -0
@@ -0,0 +1,157 @@
1
+ # Cinematic Onboarding TUI — Design
2
+
3
+ **Date:** 2026-07-03
4
+ **Status:** Approved (design); pending implementation plan
5
+ **Supersedes/extends:** `2026-06-09-intelligent-onboarding-design.md` (Pillars A & B were built as modules but never wired into the CLI; this design closes that seam and defines the visual/experiential layer on top)
6
+
7
+ ## Problem
8
+
9
+ The onboarding audit (2026-07-03) found two classes of failure:
10
+
11
+ 1. **The intelligent onboarding is dead code.** `init-detect.mjs` (confidence-scored detection), `annotatedReviewScreen` (tui.mjs:835-1170), `init-enrich-api.mjs` (BYO-key AI enrichment), `registry.mjs`, and `bin/hooks/session-start.mjs` all exist with tests — and none are reachable. `forgedock.mjs`'s `init()` uses its own inline template; `install()` never registers the SessionStart hook; `enable`/`disable`/`status` don't exist.
12
+ 2. **The funnel lies.** README advertises `npx forgedock demo` (dead — `Unknown command`), `integrate` (dead), and a CLAUDE.md injection that never happens. `getting-started.md` sends users to `/forgedock-init`, which hard-errors without a forge.yaml. `CONFIG.md` documents `--manual`/`--verbose` flags that parse nowhere. `plugin.json` says 1.0.1 while `package.json` says 1.0.8.
13
+
14
+ Beyond correctness, the shipped experience is plain warnings-and-homework. The goal is an install that feels revolutionary.
15
+
16
+ ## Decisions (locked with user)
17
+
18
+ | Decision | Choice |
19
+ | --- | --- |
20
+ | TUI stack | Zero-dependency, hand-rolled — extend existing `tui.mjs`, no frameworks |
21
+ | Scope | Full onboarding arc: preflight → install → detect → review → celebrate, plus SessionStart hook wiring and `enable`/`disable`/`status`. `forgedock demo` is **out of scope** (own milestone) |
22
+ | Motion | Full cinematic, **always** — no first-run-only fast path; every command plays its full choreography. Automatic degradation (non-TTY/CI/`NO_COLOR`) and explicit escape hatches (`--fast`, `FORGE_NO_MOTION=1`). Note: an already-configured bare invocation shows the status screen (per approved storyboard) — that screen has its own full choreography; it doesn't replay the install acts |
23
+ | Visual identity | **Molten Forge**: fire-orange → amber gradients, "forging" language |
24
+ | Logo treatment | **Chrome & Ember**: block-art F mark keeps the official metallic chrome/champagne gradient; ember lives in the wordmark and UI. Hero mark on install; compact 4-row lockup on all other commands |
25
+ | Flow shape | **One continuous journey**: bare `npx forgedock` plays the whole arc; `install`/`init` are aliases that jump into the relevant acts |
26
+ | Architecture | **Cinema layer + journey orchestrator** (new `bin/cinema.mjs` + `bin/journey.mjs`; `forgedock.mjs` becomes a thin router) |
27
+
28
+ ## The Experience — five acts, one keypress
29
+
30
+ The only interaction in the happy path is a single Enter at Act IV. Total added latency from theater: motion overlays real work wherever work exists; pure-theater beats (shimmer, quench flash) total ≈1.2s.
31
+
32
+ ### Act I — Ignition (~2.5s)
33
+
34
+ Chrome block-art mark materializes with a one-pass heat-shimmer sweep (~800ms); ember gradient wordmark `F O R G E D O C K` + version; rule line "lighting the forge". Preflight rows appear one-by-one, each live (`○` → braille spinner → `✔`):
35
+
36
+ - Node ≥18 (version shown)
37
+ - git present + repo detected
38
+ - Claude Code (`~/.claude` exists)
39
+ - GitHub CLI installed + authenticated (account shown)
40
+
41
+ A failed check renders an ember-bordered **fix card** with the exact copy-paste remedy (e.g. `winget install GitHub.cli`, `gh auth login`) and the journey **continues** with whatever still works. Preflight failures are advisory, not fatal — missing `gh` degrades detection confidence, it does not stop the forge.
42
+
43
+ ### Act II — Forging (real work)
44
+
45
+ - Progress bar with molten leading edge (`█▓▒░`) and per-command name ticker while symlinking the 24 commands into `~/.claude/commands` (existing logic, restyled).
46
+ - **Seam-closing (new):** merge a SessionStart hook entry into `~/.claude/settings.json` (idempotent read-modify-write; preserves existing hooks; removed on `uninstall`; malformed JSON → skip with fix card, never clobber). Write the registry entry marking the directory forge-managed.
47
+ - Settle lines: `✔ 24 slash commands linked`, `✔ SessionStart hook registered`, `✔ directory forge-managed`.
48
+
49
+ ### Act III — Reading your repository
50
+
51
+ Each detection field resolves as a live row: value + confidence badge + source, e.g.
52
+ `✔ owner/repo RapierCraftStudios/ForgeDock [high] git remote`.
53
+ Driven by the existing `detectConfig()` (init-detect.mjs). Fields: owner/repo, default branch, staging branch, project name, description, worktree base, project board (via `gh` when available). If `ANTHROPIC_API_KEY` is set, `init-enrich-api.mjs` fills review/verification sections (`✦ enriching with AI…`); if not, one quiet skip line. Spinners here cover *actual* latency (git/gh/API calls) — nothing is artificially slowed.
54
+
55
+ ### Act IV — The Review (the single interaction)
56
+
57
+ The existing `annotatedReviewScreen` (tui.mjs), wired in at last and restyled to ember: numbered field table with `[high]/[med]/[low]` badges, confidence legend, low-confidence warning. `Press Enter to forge, or a number to edit a field`. Low-confidence fields are written with `# TODO(forgedock:<field>)` comments instead of blocking. Existing forge.yaml → overwrite banner + backup to `forge.yaml.bak` before write (existing behavior preserved).
58
+
59
+ ### Act V — Forged (celebration)
60
+
61
+ Compact mark flashes white-hot once (quench, ~400ms), then settles:
62
+
63
+ - `Forged.` + **real elapsed time** (`install → config in 34s`) — proof, not hype
64
+ - Receipt lines: forge.yaml written (with TODO count), commands + hook active
65
+ - Boxed "what's next" card: `1. open claude in this repo` / `2. run /work-on next`
66
+ - Footer: docs link + star nudge
67
+
68
+ Next Claude Code session, the now-installed SessionStart hook greets the user with the command table — the experience continues past the terminal.
69
+
70
+ ### Re-runs and aliases
71
+
72
+ - Bare `npx forgedock` in an already-configured repo → short status screen (compact lockup, current config summary, hook state) + offer to review config. Not the full movie.
73
+ - `npx forgedock install` → Acts I–II (+ III–V only if unconfigured, matching today's auto-init).
74
+ - `npx forgedock init` → Acts III–V.
75
+ - `enable` / `disable` / `status` → registry operations, compact lockup, instant.
76
+ - `update` / `uninstall` → existing logic, compact restyle; `uninstall` also removes the hook entry and registry entries.
77
+
78
+ ## Architecture
79
+
80
+ ### `bin/cinema.mjs` (new — animation engine)
81
+
82
+ Kept separate from tui.mjs (already 1,171 lines). Exports:
83
+
84
+ - Truecolor per-cell gradient rendering with 256-color fallback (`COLORTERM`/`TERM` detection); gradient text lines and gradient block art
85
+ - `renderMark(size)` — the chrome F mark, hero (8-row) and compact (4-row); block-art geometry approved v1 from mockups, may be pixel-tuned during implementation
86
+ - `shimmer(lines, opts)` — one-pass highlight sweep
87
+ - `reveal(rows, opts)` — staged live rows (`○` → spinner → `✔`/`✖`/fix card)
88
+ - `progressBar` molten variant with ticker
89
+ - `motionEnabled()` — the single motion gate: TTY ∧ ¬`NO_COLOR` ∧ ¬`FORGE_NO_MOTION` ∧ ¬`--fast` ∧ ¬CI
90
+
91
+ **No alternate screen buffer.** Animations redraw in place (cursor-up) only while active, then settle to static lines — scrollback keeps a complete plain receipt of the run.
92
+
93
+ ### `bin/journey.mjs` (new — choreographer)
94
+
95
+ Five act functions — `preflight()`, `forge()`, `read()`, `review()`, `celebrate()` — over a shared context object; each act independently callable (for aliases) and unit-testable. Orchestrates the existing modules: `init-detect.mjs`, `init-enrich-api.mjs`, `annotatedReviewScreen`, `registry.mjs`. The forge.yaml writer moves here, driven from the detection `ConfigDraft` (single source of truth; deletes the duplicate inline template in forgedock.mjs) and emits `# TODO(forgedock:<field>)` for low-confidence values.
96
+
97
+ ### `bin/forgedock.mjs` (shrinks to router)
98
+
99
+ Command dispatch → journey acts as above. Fixes: `HOME` check gains `USERPROFILE`/`os.homedir()` fallback (currently hard-fails on bare Windows shells); flag parsing added (`--fast`, `--manual`, `--verbose`). `--manual` = plain-prompt path (no detection auto-accept), making CONFIG.md's documented flags real.
100
+
101
+ ### Hook wiring (the seam)
102
+
103
+ `forge()` merges into `~/.claude/settings.json`:
104
+
105
+ ```json
106
+ { "hooks": { "SessionStart": [ { "hooks": [ { "type": "command",
107
+ "command": "node \"$FORGE_HOME/bin/hooks/session-start.mjs\"" } ] } ] } }
108
+ ```
109
+
110
+ The command path is resolved to the absolute installed package location at install time (the same resolution `install()` already performs for symlink sources) — written as an absolute path, not a literal env reference, so the hook works regardless of shell profile.
111
+
112
+ Idempotent (detects its own entry, never duplicates), preserves unrelated hooks, guards malformed JSON (skip + fix card, never overwrite), and is removed by `uninstall`. This makes the existing `session-start.mjs` (managed-active greeting / missing-config nudge / one-time unmanaged nudge) actually fire.
113
+
114
+ ## Degradation ladder
115
+
116
+ 1. Full cinematic — interactive TTY, truecolor
117
+ 2. 256-color — same choreography, quantized gradients
118
+ 3. `NO_COLOR` — monochrome, motion intact
119
+ 4. `--fast` / `FORGE_NO_MOTION=1` — instant renders, no animation frames
120
+ 5. Non-TTY/CI — deterministic plain sequential log, same information, zero ANSI animation; review screen auto-accepts nothing — in non-TTY, detection results are written with TODO flags and the run says so (preserves current "never block CI" behavior while still protecting existing configs via the existing non-interactive abort on overwrite)
121
+ 6. Narrow terminals (<60 cols) — compact lockup replaces hero mark; tables wrap to stacked rows
122
+
123
+ ## Error handling
124
+
125
+ - **Never a dead stop, never a lie.** Preflight fix cards + continue; degraded steps stated inline at the moment they happen and echoed in the Act V receipt (e.g. `2 fields flagged # TODO`). No silently skipped sections.
126
+ - **Ctrl-C per act:** restore cursor/style, print partial-state summary (`commands installed, config not written — run npx forgedock init to finish`), exit cleanly. No half-drawn screens, no orphaned temp files.
127
+ - **Filesystem safety unchanged or better:** forge.yaml backup before overwrite; settings.json read-modify-write with parse guard; registry writes stay atomic (existing).
128
+
129
+ ## Testing
130
+
131
+ Extends the existing `node --test` suite in `bin/tests/`:
132
+
133
+ - **Acts:** unit tests with injected exec/IO stubs — preflight verdict matrix, hook-merge idempotency (twice → one entry), unrelated-hook preservation, TODO-flag emission, ConfigDraft→YAML writer output.
134
+ - **Degradation:** snapshot tests of the non-TTY plain log (`FORGE_NO_MOTION=1`, piped stdout) — deterministic byte-for-byte.
135
+ - **Cinema:** frame-function tests (gradient math, color-mode fallback selection), not timing tests — motion verified by eye; everything beneath it deterministic.
136
+ - **Windows first-class:** path handling, `USERPROFILE` fallback, symlink-vs-copy behavior — primary dev platform is Windows.
137
+
138
+ ## Docs truth-pass (ships in this milestone)
139
+
140
+ - **README:** remove `demo` (deferred) and `integrate`; replace CLAUDE.md-injection claim with the (now true) hook story; collapse the two-step install to one `npx forgedock`; requirements list gains Node ≥18.
141
+ - **getting-started.md:** fix the `/forgedock-init`-without-forge.yaml dead end; document the journey.
142
+ - **CONFIG.md:** `--manual`/`--verbose` now real; describe actual flags only.
143
+ - **Versioning:** reconcile `plugin.json` (1.0.1) with `package.json` (1.0.8); ship as **1.1.0**.
144
+ - **demo.tape:** re-record after implementation so the README gif shows the real flow.
145
+
146
+ ## Out of scope
147
+
148
+ - `npx forgedock demo` (sandbox pipeline showcase) — its own future milestone
149
+ - Self-healing `validate` (spec 2026-06-09 Pillar C, AI-fix loop) — future
150
+ - Skill-backend enrichment inside Claude Code — future; API backend + deterministic baseline only for now
151
+
152
+ ## Success criteria
153
+
154
+ - Fresh `npx forgedock` on a clean machine: zero commands to remember, one Enter, ends with a valid forge.yaml, installed commands, live SessionStart hook, and next-step card — in under ~60s on a normal repo.
155
+ - Re-run is a status screen, not a movie sit-through beyond its own short choreography.
156
+ - CI/non-TTY runs produce a stable plain log and never hang on a prompt.
157
+ - No user-facing doc advertises a command or behavior that doesn't exist.
@@ -0,0 +1,194 @@
1
+ # Durable Execution Engine — Design Spec
2
+
3
+ **Date:** 2026-07-03
4
+ **Status:** Implemented (headless engine core) on branch feat/durable-execution-engine — see docs/superpowers/plans/2026-07-03-durable-execution-engine.md
5
+ **Tracking:** #1256 (keystone), epic #1320 (five foundations of autonomy)
6
+ **Scope of this spec:** the durable engine **core** only — phase state machine, run-log, resume, and orchestrator integration for **headless / orchestrated** runs. Verification, learning, economics, and provenance (#1315–#1319) are separate specs that build on this substrate.
7
+
8
+ ---
9
+
10
+ ## 1. Motivation
11
+
12
+ The pipeline today is a **prose-driven state machine**. `work-on.md` describes a linear walk (Phase 0→7) whose only continuation mechanism is imperative text ("do NOT stop"), and its subcommands reference a numbered state router that `work-on.md` never implements (#1308). Phase transitions therefore depend on an LLM *choosing* not to emit `end_turn` at a Skill-return boundary. This produces the recurring failure classes:
13
+
14
+ - **review→close stalls** (~half of runs merge the PR but leave the issue open).
15
+ - **quality-gate→3H stalls.**
16
+ - **"Prompt is too long" deaths** mid-run (#1305), patched with a self-counted "≥20 Skill calls" heuristic.
17
+ - **Lossy state** — GitHub prose comments are the de-facto database; resume re-parses them.
18
+ - **Blind observability** — progress is inferred from JSONL output files, which are 0-byte on Windows (#1307).
19
+
20
+ The insight that makes a fix cheap: **`bin/runner.mjs` already owns the Anthropic tool-use loop** (issue #1151). ForgeDock is not locked inside Claude Code's opaque agent loop — it drives its own loop. So the work is not "adopt a runtime from scratch," it is "make the loop we already own durable."
21
+
22
+ ## 2. Goals / Non-goals
23
+
24
+ **Goals**
25
+ - Phase transitions are decided by **deterministic code**, never by an LLM's choice to continue.
26
+ - A run survives crash / kill / compaction / rate-limit and **resumes from the last committed phase** in a fresh context.
27
+ - State is **machine-readable and shared**, so any machine or the orchestrator can resume and observe a run.
28
+ - Eliminate the stall and "prompt too long" classes structurally, not with prose.
29
+
30
+ **Non-goals (explicitly out; each is its own spec / increment)**
31
+ - The interactive Claude Code `/work-on` path (a later increment adopts the same core via hooks).
32
+ - Per-turn / mid-phase durability (this spec is **per-phase** granularity).
33
+ - The verification gate, learning memory, economic governance, provenance (#1315–#1319).
34
+ - Full per-command parity for the standalone runtime (#1151 follow-up).
35
+
36
+ ## 3. Locked decisions
37
+
38
+ These were settled during design and are not open:
39
+
40
+ 1. **Durability granularity: per-phase.** The engine checkpoints each pipeline *phase*. A mid-phase crash re-runs that one phase (idempotently). Per-turn durability is rejected as over-complex (partial file edits / half-made commits).
41
+ 2. **State authority: hybrid (local hot + GitHub mirror), GitHub wins on divergence.** A local append-only run-log is the crash-safe hot path; a structured `FORGE:STATE` block on the issue is the durable shared mirror. On conflict the GitHub mirror is authoritative and invalidates the local cache.
42
+ 3. **First surface: headless / orchestrated.** The engine drives runs through `runner.mjs` — where autonomy matters most and there is no human to un-stick a stall. Interactive Claude Code adopts the same core later.
43
+ 4. **`FORGE:STATE` is a compact index, not self-describing.** It carries the resume pointer (phase, `committed[]`, branch, pr, version, lease) — **not** the rich per-phase outputs. Rich outputs live in the existing `FORGE:INVESTIGATOR` / `ARCHITECT` / etc. structured comments (which the engine writes anyway). A fresh-clone resume reads the index for *where*, then reads those comments for *content*. This avoids duplicating data and preserves human-readable artifacts.
44
+
45
+ ## 4. Architecture
46
+
47
+ Five components, each with one responsibility and a clean seam so the interactive path can later slot in as a second execution adapter.
48
+
49
+ | Component | File | Responsibility |
50
+ |---|---|---|
51
+ | **Phase state machine** | `bin/engine/phases.mjs` | Declarative table encoding the canonical phase sequence (today's prose in `work-on.md`). Each entry: `id`, `entryCondition(state)`, `command` (spec to run), `terminal?`, `reconcile(state)`. |
52
+ | **Engine loop** | `bin/engine.mjs` | The durable driver. Loads state, picks the next phase deterministically, invokes the phase, commits, handles failure. |
53
+ | **LLM-execution adapter** | `bin/runner.mjs` *(existing)* | Runs one phase = one bounded `runCommand()` with a **fresh context window**. Loop unchanged; new caller. |
54
+ | **Run-log store** | `bin/engine/runlog.mjs` | Append-only `.forge/runs/{issue}.jsonl`. Crash-safe local hot path. |
55
+ | **GitHub adapter (projector)** | `bin/engine/projector.mjs` | Reads/writes the `FORGE:STATE` block; manages the lease. Durable shared mirror + data source for `forgedock watch` (#1312). |
56
+
57
+ The engine core (`phases`, `engine`, `runlog`, `projector`) is runtime-agnostic; `runner.mjs` is the LLM adapter; the projector is the GitHub adapter.
58
+
59
+ ### Engine loop (shape)
60
+
61
+ ```
62
+ state = load(issue) // local log → else FORGE:STATE → else fresh
63
+ while (next = pickPhase(state)) { // ENGINE decides; never the LLM
64
+ if (next.terminal) break
65
+ reconcile(state, next) // make re-entry safe (idempotency)
66
+ result = runner.runCommand(next.command, ctx(state)) // fresh context per phase
67
+ switch (result.status) {
68
+ case 'committed': commit(state, next, result.outputs); break // append log + mirror
69
+ case 'failed': if (attempts(next) < maxAttempts) retry; else block(state, next); break
70
+ case 'blocked': terminate(state, 'needs-human', result.detail); return
71
+ }
72
+ } // no event on crash → next run drops + re-runs
73
+ ```
74
+
75
+ ## 5. State model
76
+
77
+ ### 5.1 Run-log (`.forge/runs/{issue}.jsonl`)
78
+
79
+ Append-only, one JSON event per line. `seq` is a monotonic per-issue version counter.
80
+
81
+ ```jsonc
82
+ {"seq":1,"event":"RUN_START","issue":42,"run":"r_a1","lane":"staging","baseSha":"9ea38…"}
83
+ {"seq":2,"event":"PHASE_START","phase":"investigate"}
84
+ {"seq":3,"event":"PHASE_COMMIT","phase":"investigate","outputs":{"verdict":"CONFIRMED","decompose":false}}
85
+ {"seq":4,"event":"PHASE_START","phase":"build"}
86
+ {"seq":5,"event":"PHASE_FAILED","phase":"build","attempt":1,"reason":"tsc error"}
87
+ {"seq":6,"event":"PHASE_START","phase":"build"}
88
+ {"seq":7,"event":"PHASE_COMMIT","phase":"build","outputs":{"branch":"fix/pay-42","headSha":"…","skipped":false}}
89
+ {"seq":8,"event":"RUN_TERMINAL","reason":"merged"}
90
+ ```
91
+
92
+ Events: `RUN_START`, `PHASE_START`, `PHASE_COMMIT`, `PHASE_FAILED`, `RUN_TERMINAL`.
93
+
94
+ **The commit rule (the entire durability story):** a phase is *committed* iff a `PHASE_COMMIT` follows its latest `PHASE_START`. A `PHASE_START` with no following `PHASE_COMMIT` = a crashed / in-flight phase → **dropped and re-run**.
95
+
96
+ **Corruption tolerance:** a crash mid-write leaves a truncated final line; the reader ignores any final line that does not parse as complete JSON.
97
+
98
+ ### 5.2 GitHub mirror (`FORGE:STATE`)
99
+
100
+ One machine-readable HTML-comment block the projector **overwrites in place** (not appends) after each `PHASE_COMMIT`:
101
+
102
+ ```html
103
+ <!-- FORGE:STATE
104
+ {"v":7,"run":"r_a1","phase":"review","committed":["investigate","context","architect","build"],
105
+ "branch":"fix/pay-42","pr":null,"lane":"staging","terminal":false,
106
+ "lease":{"by":"agent_7","until":"2026-07-03T04:10Z"}}
107
+ -->
108
+ ```
109
+
110
+ `v` mirrors the run-log `seq` at last commit — the shared version used for divergence detection. It carries the **compact index only** (see locked decision 4).
111
+
112
+ ### 5.3 Resume + divergence (`GitHub wins`)
113
+
114
+ ```
115
+ onStart(issue):
116
+ local = readRunLog(issue) // absent on fresh clone / other machine
117
+ remote = projector.read(issue) // FORGE:STATE, may be absent
118
+ state = reconcile(local, remote)
119
+
120
+ reconcile(local, remote):
121
+ if !remote: return local ?? fresh
122
+ if !local: return hydrateFromRemote(remote) // fresh clone / other machine
123
+ if remote.v > local.lastSeq: return hydrateFromRemote(remote) // advanced elsewhere → GitHub wins, discard local
124
+ if remote.v < local.lastSeq: projector.write(fromLocal(local)); return local // we crashed pre-mirror → re-mirror, keep local
125
+ return local // in sync
126
+ ```
127
+
128
+ `hydrateFromRemote` reconstructs working state from the compact index plus, where a phase's rich outputs are needed downstream, the existing `FORGE:*` structured comments on the issue.
129
+
130
+ ## 6. Deterministic transitions & idempotency
131
+
132
+ **`pickPhase(state)`** = the first phase in the `phases.mjs` table whose `entryCondition(state)` holds and whose `id` is not in `state.committed`. If none qualify or a terminal condition holds → terminal. No LLM involvement — this is the fix for the stall class.
133
+
134
+ **`phase.reconcile(state)`** runs *before* the LLM on every entry, because a dropped phase re-runs and must be safe to re-enter:
135
+
136
+ - `build.reconcile`: branch already exists and is ahead of base → resume rather than re-create.
137
+ - `review.reconcile`: a PR already exists for the branch → adopt it, do not open a second.
138
+ - `close.reconcile`: PR already merged → proceed straight to close steps.
139
+
140
+ These leverage the existing `FORGE:*` markers and `gh` queries; the engine makes idempotency a required step rather than an ad-hoc convention.
141
+
142
+ ## 7. Failure policy
143
+
144
+ Each phase returns a typed result; the engine acts on the **type** (replacing prose "try again / do not stop"):
145
+
146
+ | Result | Meaning | Engine action |
147
+ |---|---|---|
148
+ | `committed` | phase produced outputs | write `PHASE_COMMIT`, advance |
149
+ | `failed` | transient (rate-limit, network, `gh` timeout, context-budget hit mid-phase) | `PHASE_FAILED`; retry same phase with backoff up to `maxAttempts` (default 3); on exhaustion → treat as `blocked` |
150
+ | `blocked` | deterministic human-needed (gate failed after loop, contract wrong, ancestry violation, push rejected) | `RUN_TERMINAL{needs-human}`, set label via projector, **stop visibly** |
151
+ | *(no event)* | crash / kill / compaction | next run drops the uncommitted `PHASE_START` and re-runs the phase |
152
+
153
+ **Visible skips (closes #1306):** a phase that no-ops (e.g. missing `verification.commands`) must emit `outputs:{skipped:true, which:"typecheck"}` into its `PHASE_COMMIT` and `FORGE:STATE`. A skip is surfaced (PR body / trajectory / review verdict), never a silent pass.
154
+
155
+ **"Prompt too long" (dissolves #1305):** fresh context per phase removes the dominant cause. If a *single* phase still exhausts context mid-run, it is a `failed` attempt whose `reconcile` resumes from committed artifacts on retry. Note honestly: an oversized single-phase input (e.g. a 10k-line review diff) remains the review phase's own concern — the engine bounds it (`runner` tool-result caps + iteration budget) but does not shrink it; that is the verification/review spec's responsibility.
156
+
157
+ ## 8. Concurrency & orchestrator integration
158
+
159
+ **Lease.** `FORGE:STATE.lease = {by: agentId, until: ts}` is written on `RUN_START`, renewed on each `PHASE_COMMIT`, released on `RUN_TERMINAL`. On start, if a live lease held by another agent exists, the caller defers. This is best-effort mutual exclusion (checked on start; not an atomic CAS) — GitHub issue-edit has no compare-and-swap, so a concurrent start can still race between the lease read and the next write. It replaces the orchestrator's fuzzy "already in progress" label heuristic with a much tighter, race-*reducing* primitive.
160
+
161
+ **`/orchestrate` becomes a thin driver:**
162
+ - Decomposes into the wave/DAG (unchanged), then calls `engine.run(issue)` per issue.
163
+ - Watches `FORGE:STATE` per issue for progress — which also feeds `forgedock watch` (#1312) and removes any dependence on JSONL output files (killing the Windows-blind audit problem #1307 for orchestrated runs).
164
+ - **Exact stall detection:** a lease whose `until` expired on a non-terminal state = a dead agent → re-spawn `engine.run(issue)`, which resumes from the last `PHASE_COMMIT`. This replaces "resume up to 3× with nagging."
165
+ - File-overlap serialization remains the orchestrator's responsibility (unchanged), aided by the engine's `baseSha`/branch tracking.
166
+
167
+ ## 9. Testing strategy
168
+
169
+ Correctness of a durable engine is won in tests. `runner.mjs` already lazy-imports the SDK and separates pure helpers, so the engine is tested with a **fake `runCommand`** that returns scripted phase outputs — no live LLM.
170
+
171
+ - **State-machine units** (`bin/tests/phases.test.mjs`, `engine.test.mjs`): table-driven `pickPhase` over crafted states; `reconcile` across all divergence cases (local-only, remote-only, remote-ahead, local-ahead, in-sync); the commit-detection rule.
172
+ - **Crash-injection harness** (the durability proof): run the engine against the fake runner, kill after each phase boundary *and* mid-phase, assert resume lands on the correct phase with no double-PR / double-commit.
173
+ - **Run-log** (`runlog.test.mjs`): append/read/replay; truncated-final-line tolerance.
174
+ - **Projector** (`projector.test.mjs`): `FORGE:STATE` serialize/parse round-trip; overwrite-in-place; lease acquire / renew / expire against a mocked `gh`.
175
+ - **Per-phase `reconcile`** idempotency tests (build resumes, review adopts existing PR, close handles already-merged).
176
+
177
+ ## 10. Open implementation-time decision (defer to the plan)
178
+
179
+ Whether the engine runs concurrent issues as **separate processes** (matches today's background-agent model; strong isolation) or an **in-process worker pool** (one place to observe; shared rate-limit backpressure). Recommendation: **in-process pool + a git worktree per issue** for filesystem isolation (worktrees are already the pattern). Decide during planning.
180
+
181
+ ## 11. Relationship to existing code & the epic
182
+
183
+ - **Reuses:** `runner.mjs` (`runCommand`, tool handlers, result caps, lazy SDK) as the unmodified LLM adapter; the `work-on` phase sequence as the seed for `phases.mjs`; the existing `FORGE:*` structured comments as rich-output storage; git worktrees for isolation.
184
+ - **Retires / fixes:** the phantom numbered-state router (#1308), the "≥20 Skill calls" heuristic and "prompt too long" deaths (#1305), silent verification skips (#1306), and — for orchestrated runs — the JSONL-based audit blindness (#1307).
185
+ - **Enables (as substrate, not in scope):** the run-log's structured `outputs` and `FORGE:STATE` are deliberately the foundation for verification (#1315), learning memory (#1316), economics (#1317), and provenance (#1318).
186
+
187
+ ## 12. Definition of done
188
+
189
+ - A headless `engine.run(issue)` drives an issue through the full phase sequence with the engine deciding every transition.
190
+ - Killing the process at any phase boundary or mid-phase resumes correctly on the next run, with no duplicated PRs/commits (crash-injection suite green).
191
+ - A fresh clone / second machine resumes a run from `FORGE:STATE` alone.
192
+ - `/orchestrate` drives issues via `engine.run`, coordinates via the lease, and detects/recovers stalls via lease expiry.
193
+ - Skipped verification is visible on the PR; a `blocked` result stops the run with `needs-human`, never silently.
194
+ - Unit + crash-injection + projector/lease test suites pass with a mocked runner and mocked `gh`.
@@ -0,0 +1,181 @@
1
+ # Economic Self-Governance — Design Spec
2
+
3
+ **Date:** 2026-07-04
4
+ **Status:** Design — ready to build
5
+ **Tracking:** #1317 (economics layer), epic #1320 (five foundations of autonomy)
6
+ **Scope:** Risk×cost go/no-go scoring function, budget-aware scheduler, and backpressure model. Unifies #1313 (preserve `needs-human`) and #1314 (autopilot `--yes` for low-risk) into a single decision model.
7
+
8
+ ---
9
+
10
+ ## 1. Motivation
11
+
12
+ Safety Rule 3 in `/orchestrate` today reads: "no artificial concurrency limit — spawn as many agents as there are issues." That is the opposite of autonomy. Autonomy is **knowing when not to act**.
13
+
14
+ The current decision surface has three static switches:
15
+
16
+ | Surface | Policy | Problem |
17
+ |---------|--------|---------|
18
+ | `/work-on` solo | Ask human at every ambiguity | Over-asks on clear issues |
19
+ | `/orchestrate` | "NEVER ask… merge anyway" | Under-asks on high-risk changes |
20
+ | `/autopilot` | Gate every fix | Blocks low-risk wins behind human review |
21
+
22
+ None of these is a decision — they are static switches baked into prose. The result: an agent either burns compute on issues it should not touch, or stalls on issues it could safely auto-run. Neither is economic.
23
+
24
+ The fix is a **self-governing scheduler** that treats compute as a budget and makes an explicit go/no-go per issue before spawning any agent.
25
+
26
+ ---
27
+
28
+ ## 2. Goals / Non-goals
29
+
30
+ **Goals**
31
+ - A scoring function `(expected_cost, risk_tier, confidence) → {auto, escalate, defer}` runs before each issue is dispatched.
32
+ - Per-run and per-wave budget caps with backpressure replace the "no artificial concurrency limit" rule.
33
+ - `#1313` (preserve `needs-human` for high-risk) and `#1314` (autopilot `--yes` for low-risk) both fall out of the single model as threshold configurations — not separate flags.
34
+ - The decision and its inputs are recorded in `FORGE:ECONOMICS` so runs are auditable.
35
+
36
+ **Non-goals**
37
+ - Real-time token streaming cost measurement (post-run accounting only, fed by #1255/#1295).
38
+ - The durable engine state machine (#1256) — assumed as a substrate but not implemented here.
39
+ - Per-turn interruption of in-flight agents (this spec is pre-dispatch).
40
+
41
+ ---
42
+
43
+ ## 3. Locked Decisions
44
+
45
+ 1. **Decision granularity: per-issue, pre-dispatch.** The go/no-go is computed once before an agent is spawned. Mid-run escalation is a separate concern.
46
+ 2. **Three-outcome model: `auto | escalate | defer`.** `auto` = spawn with no human gate. `escalate` = post a comment and wait for human approval. `defer` = place back in queue with lower priority, do not block the wave.
47
+ 3. **Budget authority: the orchestrator holds the budget, not individual agents.** Agents report estimated cost; the orchestrator decides whether to spend it.
48
+ 4. **Score inputs are observable.** Every input to the scoring function is logged in `FORGE:ECONOMICS` before any agent runs — so a human can audit why an issue was auto-run or escalated.
49
+ 5. **Thresholds are configurable in `forge.yaml`.** Default thresholds ship with the spec; operators can tighten or loosen them without editing command files.
50
+
51
+ ---
52
+
53
+ ## 4. Architecture
54
+
55
+ ### 4.1 Scoring Function
56
+
57
+ ```
58
+ score(issue) → { decision, reasoning, estimated_cost, risk_tier, confidence }
59
+ ```
60
+
61
+ **Inputs:**
62
+
63
+ | Input | Source | Type |
64
+ |-------|--------|------|
65
+ | `expected_cost` | Historical cost-per-issue data (#1255/#1295) or heuristic (label + size estimate) | USD float |
66
+ | `risk_tier` | Domain risk tag on issue label (`risk:low`, `risk:medium`, `risk:high`) or inferred from affected paths | `low \| medium \| high` |
67
+ | `confidence` | FORGE:INVESTIGATOR confidence field, or `0.5` if no investigation comment exists | 0.0–1.0 |
68
+ | `budget_remaining` | Current wave budget minus committed spend | USD float |
69
+ | `needs_human` | Issue has `needs-human` label | bool |
70
+
71
+ **Decision matrix (defaults):**
72
+
73
+ | risk_tier | confidence | expected_cost | decision |
74
+ |-----------|-----------|---------------|----------|
75
+ | `low` | ≥ 0.7 | ≤ $0.50 | `auto` |
76
+ | `low` | ≥ 0.7 | > $0.50 | `escalate` |
77
+ | `low` | < 0.7 | any | `escalate` |
78
+ | `medium` | ≥ 0.8 | ≤ $0.30 | `auto` |
79
+ | `medium` | any other | any | `escalate` |
80
+ | `high` | any | any | `escalate` |
81
+ | any | any | > budget_remaining | `defer` |
82
+ | `needs_human=true` | any | any | `escalate` (always) |
83
+
84
+ Thresholds are overridable via `forge.yaml → economics`:
85
+
86
+ ```yaml
87
+ economics:
88
+ auto_cost_ceiling_usd: 0.50 # max cost for auto-run (low risk)
89
+ medium_auto_cost_ceiling_usd: 0.30
90
+ auto_confidence_floor: 0.70
91
+ medium_confidence_floor: 0.80
92
+ wave_budget_usd: 5.00 # per-wave budget cap
93
+ run_budget_usd: 20.00 # per-run (session) budget cap
94
+ ```
95
+
96
+ ### 4.2 Budget Tracker
97
+
98
+ A simple stateful accumulator maintained by the orchestrator across the wave:
99
+
100
+ ```
101
+ budget_tracker = {
102
+ wave_limit: float, # from forge.yaml or --budget flag
103
+ wave_committed: float, # sum of expected_cost for auto-dispatched issues
104
+ wave_actual: float, # sum of reported actual cost from completed agents
105
+ run_limit: float,
106
+ run_committed: float,
107
+ }
108
+ ```
109
+
110
+ `defer` fires when `wave_committed + expected_cost > wave_limit * 0.90` (10% buffer to absorb cost overruns).
111
+
112
+ Backpressure: when the wave budget is exhausted, remaining issues are set to `workflow:deferred` label and the orchestrator reports a budget summary. They are the first candidates in the next wave.
113
+
114
+ ### 4.3 FORGE:ECONOMICS Annotation
115
+
116
+ Written to the issue before the agent is spawned (or before posting the escalation comment):
117
+
118
+ ```html
119
+ <!-- FORGE:ECONOMICS
120
+ decision: auto
121
+ risk_tier: low
122
+ confidence: 0.82
123
+ expected_cost_usd: 0.18
124
+ budget_remaining_usd: 3.47
125
+ wave: 1
126
+ rationale: "low-risk label, high investigation confidence, well within budget"
127
+ timestamp: 2026-07-04T12:00:00Z
128
+ -->
129
+ ```
130
+
131
+ Downstream stages (verification gate, provenance) can read this annotation to understand the economic context of the decision.
132
+
133
+ ### 4.4 Integration Points
134
+
135
+ **`/orchestrate`**: Phase 2B (issue selection) gains a `score_issues()` step before dispatching agents. Issues that score `escalate` are held; `auto` issues proceed; `defer` issues are re-queued.
136
+
137
+ **`/autopilot`**: The `--fix` phase queries the scoring function instead of the current "gate every fix" heuristic. `--yes` flag sets `auto_confidence_floor: 0.0` and raises cost ceilings — effectively the current `--yes` behavior, but explicit and auditable.
138
+
139
+ **`/work-on`**: Solo interactive use is unaffected. The scoring function is opt-in via `forge.yaml → economics.solo_mode: enabled`.
140
+
141
+ ---
142
+
143
+ ## 5. Implementation Plan
144
+
145
+ ### Increment 1: Scoring function + FORGE:ECONOMICS (no budget tracking)
146
+ - Add `score_issue()` logic to `/orchestrate` Phase 2B.
147
+ - Read domain risk labels and FORGE:INVESTIGATOR confidence.
148
+ - Emit `FORGE:ECONOMICS` annotation.
149
+ - `escalate` path posts a comment and adds `needs-human` label; agent is not spawned.
150
+ - `defer` path is treated as `escalate` in this increment.
151
+
152
+ ### Increment 2: Budget tracker + backpressure
153
+ - Add `budget_tracker` state to orchestrator.
154
+ - Read `forge.yaml → economics` thresholds.
155
+ - `defer` path sets `workflow:deferred` label and skips the issue.
156
+ - Post wave budget summary at end of orchestrator run.
157
+
158
+ ### Increment 3: Unify #1313 and #1314
159
+ - Remove hard-coded "NEVER ask" language from `/orchestrate`.
160
+ - Remove hard-coded "gate every fix" from `/autopilot`.
161
+ - Both commands delegate to the scoring function with appropriate threshold profiles (`orchestrate` uses `medium_confidence_floor`, `autopilot --yes` raises ceilings).
162
+
163
+ ---
164
+
165
+ ## 6. Open Questions
166
+
167
+ - **Cost estimation without history**: For issues with no historical data, the default heuristic is label-based (`bug` → $0.20, `feat` → $0.40, `epic` → $1.00). This needs calibration once #1255 data is available.
168
+ - **Risk tag inference**: If no `risk:*` label exists, infer from affected paths (e.g., changes to `bin/`, `commands/quality-gate.md`, or CI workflows → `risk:high`). Path-based inference is a follow-on to Increment 1.
169
+ - **Wave vs. run budget interaction**: A "run" spans multiple waves in `/autopilot`. The run budget should be the outer limit; wave budget is the inner pacing mechanism.
170
+
171
+ ---
172
+
173
+ ## 7. References
174
+
175
+ - #1317 — this issue
176
+ - #1255, #1295, #1296, #1297 — cost-per-issue accounting (feeds `expected_cost`)
177
+ - #1249 — per-agent model/effort tiering (feeds `expected_cost`)
178
+ - #1313 — preserve `needs-human` for high-risk (subsumed by this spec)
179
+ - #1314 — autopilot `--yes` for low-risk (subsumed by this spec)
180
+ - #1320 — five foundations epic (economics layer)
181
+ - #1256 — durable engine (substrate for stateful budget tracking)