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
@@ -2,6 +2,7 @@
2
2
  description: Deterministic deploy-gate — verify a staging→main bundle's acceptance criteria against running code before deploy
3
3
  argument-hint: [--prs "<N1 N2 ...>"] [--base <branch>]
4
4
  allowed-tools: Task, Bash, Read, Grep, Glob
5
+ install: extras
5
6
  ---
6
7
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
7
8
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -12,7 +13,22 @@ allowed-tools: Task, Bash, Read, Grep, Glob
12
13
 
13
14
  Verifies a staging→main bundle's acceptance criteria against running code before deploy. Called by `/review-pr-staging` (Phase 6.5) with the bundle PRs, or run standalone when `--prs` is absent (computes the bundle itself). Returns a machine-readable BLOCK / PASS / SKIP verdict for the caller to consume.
14
15
 
15
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
16
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
17
+ **NEVER use plan mode (EnterPlanMode).**
18
+ **NEVER use the Agent tool** — test-gate dispatches test clusters via `Task` only. The Agent tool bypasses the allowed-tools constraint and produces output that cannot be structured into the machine-readable BLOCK / PASS / SKIP verdict.
19
+
20
+ <!-- FORGE:SPEC_LOADED — test-gate.md loaded and active. Agent is bound by this spec. -->
21
+
22
+ ## Forbidden Tools Self-Check
23
+
24
+ **Before executing any phase**, verify you are NOT using any of these tools:
25
+
26
+ | Tool | Status | Reason |
27
+ |------|--------|--------|
28
+ | `Agent` | **FORBIDDEN** | Bypasses allowed-tools constraint; produces unstructured output that cannot be parsed into the machine-readable BLOCK / PASS / SKIP verdict |
29
+ | `EnterPlanMode` | **FORBIDDEN** | Breaks execution context; gate phases must execute, not be planned |
30
+
31
+ If you find yourself about to call `Agent(...)`, stop and use `Task(...)` instead.
16
32
 
17
33
  **Posture**: Blocking-with-override at the staging→main boundary (mirrors the Phase 0A open-finding gate in `/review-pr-staging`). Posture is config-driven via `verification.test_gate`.
18
34
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: Independently verify if a reported issue is actually a problem before making code changes.
3
3
  argument-hint: [issue description or #number]
4
+ install: extras
4
5
  ---
5
6
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
6
7
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -11,7 +12,7 @@ argument-hint: [issue description or #number]
11
12
 
12
13
  Verify whether a reported issue is real before anyone writes code. This command exists for reports that come from outside the pipeline — user complaints, DevOps alerts, monitoring triggers, gut feelings. It is the checkpoint before creating a GitHub issue.
13
14
 
14
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
15
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
15
16
 
16
17
  **Output**: A verdict (CONFIRMED / NOT A PROBLEM / NEEDS MORE DATA) with evidence.
17
18
 
@@ -11,6 +11,11 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--files AFFE
11
11
  **Time budget**: Max 3 minutes. Skip any file read that times out.
12
12
  **Output**: Post `<!-- FORGE:ARCHITECT -->` comment on the issue, then return structured plan to caller.
13
13
 
14
+ **Agent model policy**: `model: "sonnet"`, `effort: xhigh` (deep tier — full code-path tracing, multi-file architecture planning). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` only on Claude Code >= 2.1.154.
15
+ **NEVER use plan mode (EnterPlanMode).**
16
+
17
+ <!-- FORGE:SPEC_LOADED — work-on/build/architect.md loaded and active. Agent is bound by this spec. -->
18
+
14
19
  ---
15
20
 
16
21
  ## COMPLEXITY_BAND Guard (check BEFORE all phases)
@@ -50,6 +55,7 @@ Parse from $ARGUMENTS:
50
55
  Also read from the calling context (in-memory, passed by parent agent):
51
56
  - `{INVESTIGATION_REPORT}` — full text of FORGE:INVESTIGATOR comment
52
57
  - `{CONTEXT_BRIEFING}` — full text of FORGE:CONTEXT comment (empty string if context step was skipped)
58
+ - `{MEMORY_PRIORS}` — structured prior run blocks emitted by investigate Phase 0.5 (empty string if no priors found or investigate predates memory). When non-empty, treat each `[MEMORY PRIOR]` block as a high-confidence prior: if any prior's affected files overlap with the current plan's affected files, explicitly note the prior's root cause and key lesson in the FORGE:ARCHITECT comment's **Prior Run Priors** section (add this section after **Context Briefing** when priors exist). <!-- Added: forge#1316 -->
53
59
 
54
60
  If any of these are not passed directly, read them from GitHub (fallback/recovery path):
55
61
 
@@ -316,6 +322,28 @@ agent defaults ← Built-in behaviors
316
322
 
317
323
  Identify every entry point that initiates the affected logic. Start from the files named in the investigation report.
318
324
 
325
+ ### A1.0: Code Index Query (run FIRST — deterministic, one tool call)
326
+
327
+ If `scripts/code-index.sh` exists under `{REPO_PATH}`, query the pre-built index before any grep. The index provides caller lists and import graphs without re-scanning the repo:
328
+
329
+ ```bash
330
+ # Ensure index is current (cache-hit on unchanged HEAD — instant if already built)
331
+ bash {REPO_PATH}/scripts/code-index.sh --repo-path {REPO_PATH} 2>/dev/null || true
332
+
333
+ # Get callers of the primary function under change
334
+ bash {REPO_PATH}/scripts/code-index.sh query --callers {PRIMARY_FUNCTION} --repo-path {REPO_PATH} 2>/dev/null || true
335
+
336
+ # Get all files that import the affected module
337
+ bash {REPO_PATH}/scripts/code-index.sh query --importers {AFFECTED_FILE} --repo-path {REPO_PATH} 2>/dev/null || true
338
+
339
+ # Get all files in the same domain as affected files (for sibling path detection)
340
+ bash {REPO_PATH}/scripts/code-index.sh query --domain {DOMAIN} --repo-path {REPO_PATH} 2>/dev/null || true
341
+ ```
342
+
343
+ Use index results to populate the caller list and sibling candidates below. If the index returns results, **skip the grep fallback** — do not re-scan what the index already answered. If the index is absent or returns nothing, fall back to grep.
344
+
345
+ ### A1.1: Grep fallback (only when index absent or returned no results)
346
+
319
347
  For each affected file, read it and identify:
320
348
  1. The primary function/method being changed
321
349
  2. All callers of that function (grep for usages)
@@ -11,6 +11,8 @@ argument-hint: [issue number] [affected_files...] [--functions function_names...
11
11
  **Time budget**: Max 2 minutes of queries. Skip any query that times out.
12
12
  **Output**: Post `<!-- FORGE:CONTEXT -->` comment on the issue, then return structured briefing to caller.
13
13
 
14
+ <!-- FORGE:SPEC_LOADED — work-on/build/context.md loaded and active. Agent is bound by this spec. -->
15
+
14
16
  ---
15
17
 
16
18
  ## COMPLEXITY_BAND Guard (check BEFORE all phases)
@@ -12,9 +12,11 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
12
12
  **Invoked by**: `work-on.md` Step 3F, after worktree is created and context is gathered.
13
13
  **Output**: Write code, commit(s), post `<!-- FORGE:BUILDER -->` comment, return result to caller.
14
14
 
15
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
15
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
16
16
  **NEVER use plan mode (EnterPlanMode).**
17
17
 
18
+ <!-- FORGE:SPEC_LOADED — work-on/build/implement.md loaded and active. Agent is bound by this spec. -->
19
+
18
20
  ---
19
21
 
20
22
  ## Inputs
@@ -53,7 +55,17 @@ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
53
55
  --jq '.[] | select(.body | contains("FORGE:CONTEXT")) | .body'
54
56
  ```
55
57
 
56
- **Resume check**: If `<!-- FORGE:BUILDER -->` comment already exists, the implementation is done — EXIT and return `IMPLEMENT_RESULT: status: ALREADY_DONE` to caller.
58
+ **Resume check**:
59
+ - If `<!-- FORGE:BUILDER:COMPLETE -->` is present in a BUILDER comment → implementation is done — EXIT and return `IMPLEMENT_RESULT: status: ALREADY_DONE` to caller.
60
+ - If `<!-- FORGE:BUILDER -->` exists BUT `<!-- FORGE:BUILDER:COMPLETE -->` is ABSENT → implementation was interrupted after the comment was posted but before the commit (validate.md V5). Delete the partial comment and restart from Phase I2:
61
+ ```bash
62
+ PARTIAL_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
63
+ --jq '[.[] | select(.body | contains("FORGE:BUILDER") and (contains("FORGE:BUILDER:COMPLETE") | not))] | last | .id // ""')
64
+ if [ -n "$PARTIAL_ID" ]; then
65
+ gh api repos/{GH_REPO}/issues/comments/$PARTIAL_ID -X DELETE
66
+ echo "Deleted partial FORGE:BUILDER comment (no FORGE:BUILDER:COMPLETE) — restarting implementation"
67
+ fi
68
+ ```
57
69
 
58
70
  **Primary guide**: If `<!-- FORGE:ARCHITECT -->` is present, it is the **primary implementation input**. Follow its ordered implementation list exactly — it defines which files change, in what order, and what consistency checks must pass. The investigation report and contract are secondary context.
59
71
 
@@ -225,6 +237,8 @@ gh issue edit {NUMBER} {GH_FLAG} --body "{UPDATED_BODY}"
225
237
 
226
238
  ## Phase I6: Post FORGE:BUILDER Comment
227
239
 
240
+ Post the implementation summary comment. **Do NOT include `<!-- FORGE:BUILDER:COMPLETE -->` here** — that marker is posted by `validate.md` Phase V5 after the commit succeeds. A crash between I6 and V5 would otherwise leave a completion-marked comment with no commit on the branch.
241
+
228
242
  ```bash
229
243
  gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:BUILDER -->
230
244
  ## Implementation Complete
@@ -247,11 +261,11 @@ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:BUILDER -->
247
261
  - [ ] {Test scenario 2} [type:unit]
248
262
  - [ ] {Test scenario 3} [type:e2e]
249
263
 
250
- > **Test-type annotation** (optional): Append `[type:api]`, `[type:unit]`, `[type:e2e]`, or `[type:manual]` to each checklist item. The test gate reads this annotation directly and skips regex inference. Omit it to rely on regex classification fallback.
251
-
252
- <!-- FORGE:BUILDER:COMPLETE -->"
264
+ > **Test-type annotation** (optional): Append `[type:api]`, `[type:unit]`, `[type:e2e]`, or `[type:manual]` to each checklist item. The test gate reads this annotation directly and skips regex inference. Omit it to rely on regex classification fallback."
253
265
  ```
254
266
 
267
+ **Note**: `<!-- FORGE:BUILDER:COMPLETE -->` is intentionally absent from this comment. It is appended to this comment by `validate.md` Phase V5 after the git commit completes — see `validate.md § Phase V5`. This ordering ensures the completion marker only exists when a real commit is present on the branch.
268
+
255
269
  ---
256
270
 
257
271
  ## Output
@@ -12,9 +12,11 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
12
12
  **Invoked by**: `work-on.md` Step 3F.5, after `implement.md` has written and staged code (not committed).
13
13
  **Output**: Return `GATE_PASSED: true/false` to caller. On failure after max iterations, post comment and set `needs-human`.
14
14
 
15
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
15
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
16
16
  **NEVER use plan mode (EnterPlanMode).**
17
17
 
18
+ <!-- FORGE:SPEC_LOADED — work-on/build/validate.md loaded and active. Agent is bound by this spec. -->
19
+
18
20
  ---
19
21
 
20
22
  ## Inputs
@@ -52,10 +54,22 @@ while iteration < max_iterations:
52
54
  GATE_PASSED = true
53
55
  break
54
56
  else:
55
- Fix each HIGH and MEDIUM finding in the code at {WORKTREE_PATH}
56
- (Do NOT commit yet — fixes are staged for the next gate run)
57
-
58
- if iteration == max_iterations AND result != PASS:
57
+ # Separate quarantined test findings from real blocker findings.
58
+ # quality-gate Step 2R classifies each failing test as PRE_BROKEN, FLAKY, or REAL.
59
+ # TEST-QUARANTINE findings (LOW) are advisory — do not fix, do not count as gate failures.
60
+ # TEST-REAL findings (HIGH) and all other HIGH/MEDIUM findings must be fixed.
61
+ quarantine_findings = findings where severity == LOW and code starts with "TEST-QUARANTINE"
62
+ blocker_findings = findings where code != "TEST-QUARANTINE"
63
+
64
+ if blocker_findings is empty:
65
+ # All remaining findings are quarantined tests — gate passes from the builder's perspective.
66
+ GATE_PASSED = true
67
+ break
68
+ else:
69
+ Fix each HIGH and MEDIUM finding in blocker_findings at {WORKTREE_PATH}
70
+ (Do NOT commit yet — fixes are staged for the next gate run)
71
+
72
+ if iteration == max_iterations AND result != PASS AND blocker_findings not empty:
59
73
  GATE_PASSED = false
60
74
  → post comment (see V1-FAIL below)
61
75
  → add label needs-human
@@ -71,6 +85,7 @@ Skill("quality-gate", args="{CHANGED_FILES} --worktree {WORKTREE_PATH}")
71
85
  - Re-run after EVERY fix pass — never trust that fixes resolved findings without verification
72
86
  - Each iteration re-scans ALL changed files — fixes can introduce new issues
73
87
  - Only HIGH and MEDIUM findings must be fixed; LOW findings are advisory only
88
+ - `TEST-QUARANTINE | LOW` findings (pre-broken or flaky tests classified by Step 2R) do **not** require fixing and do **not** count toward gate failure — include them in the V5 commit comment for reviewer visibility
74
89
 
75
90
  **V1-FAIL comment** (post when gate never passes):
76
91
  ```bash
@@ -90,7 +105,12 @@ Needs human review before proceeding to commit.
90
105
 
91
106
  ## Phase V2: Format and Verify
92
107
 
93
- Run after quality gate passes. All tool commands are read from `forge.yaml → verification.commands`; each step logs `SKIPPED — not configured` when the corresponding key is absent rather than silently passing:
108
+ Run after quality gate passes. All tool commands are read from `forge.yaml → verification.commands`; each step logs `SKIPPED — not configured` when the corresponding key is absent rather than silently passing.
109
+
110
+ **Track skipped checks** — initialize before any check runs:
111
+ ```bash
112
+ SKIPPED_CHECKS=""
113
+ ```
94
114
 
95
115
  **Python**:
96
116
  ```bash
@@ -101,6 +121,7 @@ if [ -n "$PYTHON_FORMAT" ]; then
101
121
  eval "$PYTHON_FORMAT" 2>&1
102
122
  else
103
123
  echo "SKIPPED — python.format not configured in verification.commands"
124
+ SKIPPED_CHECKS="${SKIPPED_CHECKS:+$SKIPPED_CHECKS, }python.format"
104
125
  fi
105
126
 
106
127
  # Compile check always runs for Python files (no config needed — catches syntax errors)
@@ -120,6 +141,7 @@ if [ -n "$TS_FORMAT" ]; then
120
141
  eval "$TS_FORMAT" 2>&1
121
142
  else
122
143
  echo "SKIPPED — typescript.format not configured in verification.commands"
144
+ SKIPPED_CHECKS="${SKIPPED_CHECKS:+$SKIPPED_CHECKS, }typescript.format"
123
145
  fi
124
146
 
125
147
  if [ -n "$TS_TYPECHECK" ]; then
@@ -130,6 +152,7 @@ elif [ -n "$TS_BUILD" ]; then
130
152
  TS_EXIT=$?
131
153
  else
132
154
  echo "SKIPPED — typescript.typecheck and typescript.build not configured in verification.commands"
155
+ SKIPPED_CHECKS="${SKIPPED_CHECKS:+$SKIPPED_CHECKS, }typescript.typecheck/build"
133
156
  TS_EXIT=0
134
157
  fi
135
158
  ```
@@ -287,6 +310,36 @@ If `origin/{PR_BASE}` does not exist yet (new branch), skip this check — no co
287
310
  git ls-remote --exit-code origin {PR_BASE} >/dev/null 2>&1 || echo "PR_BASE not on origin — skipping ancestry audit"
288
311
  ```
289
312
 
313
+ ### V5 Post-Commit: Mark Build Complete (MANDATORY)
314
+
315
+ After the ancestry audit passes (or is skipped), append `<!-- FORGE:BUILDER:COMPLETE -->` to the existing FORGE:BUILDER comment. This is the **only** place this marker is written — it signals that a real commit exists on the branch and the build is safe to resume-skip. <!-- Added: forge#1305 -->
316
+
317
+ ```bash
318
+ # Find the FORGE:BUILDER comment posted by implement.md Phase I6
319
+ BUILDER_COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
320
+ --jq '[.[] | select(.body | contains("FORGE:BUILDER") and (contains("FORGE:BUILDER:COMPLETE") | not))] | last | .id // ""')
321
+
322
+ if [ -n "$BUILDER_COMMENT_ID" ]; then
323
+ # Fetch current body and append the completion marker plus best-effort cost signal
324
+ CURRENT_BODY=$(gh api repos/{GH_REPO}/issues/comments/$BUILDER_COMMENT_ID --jq '.body')
325
+ # Best-effort cost append: only include if session telemetry provides a value; never block
326
+ PHASE_COST_LINE=""
327
+ [ -n "${PHASE_COST_USD:-}" ] && PHASE_COST_LINE="
328
+ cost_usd: ${PHASE_COST_USD}"
329
+ UPDATED_BODY="${CURRENT_BODY}${PHASE_COST_LINE}
330
+
331
+ <!-- FORGE:BUILDER:COMPLETE -->"
332
+ gh api repos/{GH_REPO}/issues/comments/$BUILDER_COMMENT_ID \
333
+ -X PATCH \
334
+ --field body="$UPDATED_BODY"
335
+ echo "FORGE:BUILDER:COMPLETE appended to comment $BUILDER_COMMENT_ID"
336
+ else
337
+ echo "WARNING: FORGE:BUILDER comment not found or already marked complete — skipping BUILDER:COMPLETE append"
338
+ fi
339
+ ```
340
+
341
+ **Why here and not in implement.md**: The commit (`git commit`) runs in this phase (V5). Appending `:COMPLETE` after the commit ensures that a session crash between implement.md I6 (comment posted) and this step (commit) leaves a partial BUILDER comment without `:COMPLETE`. The next resume will detect the partial comment, delete it, and restart the build. See `implement.md § Phase I1 resume check`.
342
+
290
343
  ---
291
344
 
292
345
  ## Output
@@ -302,6 +355,9 @@ VALIDATE_RESULT:
302
355
  deploy_completeness_fixes: [{VAR_NAME: location_added}, ...]
303
356
  commits_added: [{SHA}, ...] # from V5 if any
304
357
  blocker: {description if gate_passed=false}
358
+ verification_skipped: [] # empty when all configured checks ran; list of skipped check names otherwise
359
+ # e.g. ["python.format", "typescript.typecheck/build"]
360
+ # populated from SKIPPED_CHECKS in Phase V2
305
361
  ```
306
362
 
307
363
  ---
@@ -9,13 +9,31 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--base PR_BA
9
9
 
10
10
  **Input**: $ARGUMENTS
11
11
 
12
- **Invoked by**: `work-on.md` state 8 (READY_TO_BUILD).
13
- **Output**: Create worktree, post contract, sequence build subcommands, return result to router.
12
+ **Invoked by**: `work-on.md` Phase 3 — entered when the issue carries label `workflow:ready-to-build` or `workflow:building` (see Universal Phase Dispatcher in work-on.md).
13
+ **Output**: Create worktree, post contract, run build phases, return result to work-on.md.
14
14
 
15
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
15
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
16
16
  **NEVER use plan mode (EnterPlanMode).**
17
17
 
18
- **CRITICAL: You MUST execute ALL phases B0–B6 in order. After each Skill() call returns, you MUST continue to the next phase. Phases B3 (context) and B4 (architect) are skipped ONLY when COMPLEXITY_BAND: TRIVIAL (read from FORGE:FAST_PATH comment in Phase B0). For STANDARD and COMPLEX tasks they are NOT optional — skipping them degrades build quality.**
18
+ **CRITICAL: You MUST execute ALL phases B0–B6 in order. Phases B3 (context) and B4 (architect) are skipped ONLY when COMPLEXITY_BAND: TRIVIAL (read from FORGE:FAST_PATH comment in Phase B0). For STANDARD and COMPLEX tasks they are NOT optional — skipping them degrades build quality.**
19
+
20
+ ### Canonical Build Path (STANDARD/fast-lane) <!-- Added: forge#1276 -->
21
+
22
+ **Default execution model: inline.** For STANDARD and fast-lane issues, phases B3 (context gathering) and B4 (architecture planning) run **inline in the current context window** — not as separate `Skill()` sub-agent spawns. B5 (implement) and B6 (validate) also run inline.
23
+
24
+ `Skill()` invocations for context/architect sub-phases are only permitted when the Spawn-Decision Table (work-on.md `##Spawn-Decision Policy`) explicitly applies — specifically Row (c) (parent context near overflow: ≥20 Skill invocations or ≥10 files already changed before the build sub-phase). For most issues, the Skill() forms shown in B3 and B4 below are **reference documentation** describing the sub-phase contract, not mandatory sub-agent invocations.
25
+
26
+ **Build topology summary**:
27
+
28
+ | Path | When | Phases |
29
+ |------|------|--------|
30
+ | **STANDARD/fast-lane (default)** | All issues not matching exceptions below | B0 → B1 → B2 → B2.5 → [B3] → [B4] → B5 → B6 — all inline |
31
+ | **Spawn exception (Row c)** | ≥20 Skill invocations OR ≥10 files changed before build | Spawn B3/B4 as fresh sub-agents via `Skill()` |
32
+ | **TRIVIAL fast-path** | COMPLEXITY_BAND: TRIVIAL | Skip B3 and B4 entirely |
33
+
34
+ This resolves the three-topology conflict: `work-on.md` Phase 3 (inline 3A–3M), `work-on/build.md` (this file), and `work-on-monolithic.md` ([BENCHMARK]) all describe the **same canonical inline path**. `work-on/build.md` adds worktree lifecycle management (B1) and the FORGE:CONTRACT handoff (B2) that the monolithic variant omits for brevity. The `Skill()` forms in B3/B4 below document the sub-phase contract and serve as the exception path only. <!-- Added: forge#1276 -->
35
+
36
+ <!-- FORGE:SPEC_LOADED — work-on/build.md loaded and active. Agent is bound by this spec. -->
19
37
 
20
38
  ---
21
39
 
@@ -27,6 +45,8 @@ Parse from $ARGUMENTS:
27
45
  - `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R {owner}/{repo}`)
28
46
  - `--base {PR_BASE}` — PR target branch (e.g. `milestone/modular-pipeline-architecture` or `staging`)
29
47
 
48
+ **Phase notation**: This file uses **B0–B6** for its own phases. The calling orchestrator (`work-on.md`) uses **3A–3M** for its sub-phases. Mapping: work-on.md Phase 3A = B0 (load state), Phase 3B = complexity classification (posts `FORGE:FAST_PATH` before invoking build), Phase 3C onward maps to B1+ in this file. When cross-references mention "Phase 3B", they refer to work-on.md's Phase 3B, not a phase in this file. <!-- Added: forge#1380 -->
49
+
30
50
  ---
31
51
 
32
52
  ## Phase B0: Load State from GitHub (MANDATORY)
@@ -46,7 +66,16 @@ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
46
66
  ```
47
67
 
48
68
  **Resume check**:
49
- - If `<!-- FORGE:BUILDER -->` comment exists → build already complete. Return `BUILD_RESULT: status: ALREADY_DONE` to router.
69
+ - If `<!-- FORGE:BUILDER:COMPLETE -->` is present in a BUILDER comment → build already complete. Return `BUILD_RESULT: status: ALREADY_DONE` to router.
70
+ - If `<!-- FORGE:BUILDER -->` exists BUT `<!-- FORGE:BUILDER:COMPLETE -->` is ABSENT → build was interrupted after the comment was posted but before the commit (validate.md V5). Delete the partial comment and restart from Phase B2 (contract): <!-- Added: forge#1305 -->
71
+ ```bash
72
+ PARTIAL_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
73
+ --jq '[.[] | select(.body | contains("FORGE:BUILDER") and (contains("FORGE:BUILDER:COMPLETE") | not))] | last | .id // ""')
74
+ if [ -n "$PARTIAL_ID" ]; then
75
+ gh api repos/{GH_REPO}/issues/comments/$PARTIAL_ID -X DELETE
76
+ echo "Deleted partial FORGE:BUILDER comment (no FORGE:BUILDER:COMPLETE) — restarting build from Phase B2"
77
+ fi
78
+ ```
50
79
  - If no `<!-- FORGE:INVESTIGATOR -->` comment with `<!-- INVESTIGATION:COMPLETE -->` → EXIT with `BUILD_RESULT: status: BLOCKED`, blocker: "Investigation not complete — run investigate first".
51
80
 
52
81
  Extract from investigation report:
@@ -55,7 +84,7 @@ Extract from investigation report:
55
84
  - Recommendation
56
85
  - Task type (Bug Fix / Feature / Refactor / Maintenance / UI/UX / Full-Stack)
57
86
 
58
- **Read COMPLEXITY_BAND** (from FORGE:FAST_PATH comment posted by Phase 3B):
87
+ **Read COMPLEXITY_BAND** (from `FORGE:FAST_PATH` comment posted by Phase 3B of `work-on.md` — the complexity classification step that runs before invoking this file): <!-- Fixed: forge#1380 -->
59
88
  ```bash
60
89
  COMPLEXITY_BAND=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
61
90
  --jq '.[] | select(.body | contains("FORGE:FAST_PATH")) | .body' 2>/dev/null \
@@ -82,6 +111,14 @@ Append `-{NUMBER}` to ensure uniqueness: e.g. `fix/work-on-build-landing-file-85
82
111
 
83
112
  - Review-finding issue → parse `**Code branch**: \`{branch}\`` from issue body; branch from `origin/{branch}`
84
113
  - **Milestone review-finding hybrid lane** (ONLY when Code branch matches `milestone/*`): This is a high-risk lane. The worktree will carry the full milestone history. The PR target is `staging` (or the base specified). **DANGER: Agents MUST NOT use `git merge` to resolve any conflicts in this lane.** Merge-based conflict resolution will pull the entire milestone commit tree onto staging, contaminating it with unapproved code. Use `git rebase` or `git cherry-pick` only. If conflicts cannot be resolved without a merge, post a comment on the issue, add `needs-human`, and STOP.
114
+ - **Missing ref fallback**: After parsing, verify the Code branch still exists on remote. If not, fall back to the lane default (`staging` for fast lane, `milestone/{slug}` for feature lane) and note the fallback:
115
+ ```bash
116
+ SOURCE_BRANCH="{CODE_BRANCH_FROM_ISSUE_BODY}"
117
+ if ! git ls-remote --exit-code origin "$SOURCE_BRANCH" >/dev/null 2>&1; then
118
+ echo "WARNING: Code branch '$SOURCE_BRANCH' not found on remote — falling back to lane default '$PR_BASE'"
119
+ SOURCE_BRANCH="$PR_BASE"
120
+ fi
121
+ ```
85
122
  - Feature lane (has milestone) → branch from `origin/{PR_BASE}`
86
123
  - Fast lane (no milestone) → branch from `origin/staging`
87
124
 
@@ -175,44 +212,46 @@ If `FUNCTION_NAMES` is non-empty, it will be passed via `--functions` to the con
175
212
 
176
213
  ## Phase B3: Context Gathering (MANDATORY for STANDARD/COMPLEX — skip for TRIVIAL)
177
214
 
178
- **Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — do not invoke the context subcommand. Proceed directly to Phase B4.
215
+ **Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — skip this phase entirely. Proceed directly to Phase B4.
179
216
 
180
- **For STANDARD and COMPLEX tasks**: Always invoke. Do NOT skip without a TRIVIAL COMPLEXITY_BAND.
217
+ **For STANDARD and COMPLEX tasks**: Always run. Do NOT skip without a TRIVIAL COMPLEXITY_BAND.
181
218
 
182
- Invoke the context subcommand to surface historical review findings and bug patterns:
219
+ **Execution model**: Run **inline** (see Canonical Build Path above). Read the `commands/work-on/build/context.md` spec and execute its steps directly in this context window. Only spawn a Skill() sub-agent when the Spawn-Decision Table Row (c) applies (≥20 prior Skill invocations or ≥10 files already changed). <!-- Added: forge#1276 -->
183
220
 
184
- ```
185
- Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES} --functions {FUNCTION_NAMES}")
186
- ```
187
-
188
- If `FUNCTION_NAMES` is empty, omit the `--functions` flag entirely:
221
+ Surface historical review findings and bug patterns for the affected files. The full step-by-step logic is defined in `commands/work-on/build/context.md`. Key steps: search closed issues with `review-finding` label on the affected files; check git log for past bug patterns; synthesize a `FORGE:CONTEXT` annotation and post it as a GitHub comment.
189
222
 
223
+ **Spawn exception** (only when Row (c) applies):
190
224
  ```
191
- Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES}")
225
+ Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES} --functions {FUNCTION_NAMES}")
192
226
  ```
227
+ If `FUNCTION_NAMES` is empty, omit `--functions`. The Skill() form above is the exception path — not the default. <!-- Added: forge#1276 -->
193
228
 
194
- **After subcommand returns**:
195
- - Returns structured context briefing (or indicates no relevant history) → continue to B4
196
- - If subcommand times out or errors → log warning, continue to B4 with empty context (non-blocking)
229
+ **After context gathering**:
230
+ - Structured context briefing produced (or no relevant history found) → continue to B4
231
+ - Context gathering timed out or errored → log warning, continue to B4 with empty context (non-blocking)
197
232
  # MUST CONTINUE to Phase B4 — context result is intermediate, NOT terminal.
198
233
 
199
234
  ---
200
235
 
201
236
  ## Phase B4: Architecture Planning (MANDATORY for STANDARD/COMPLEX — skip for TRIVIAL)
202
237
 
203
- **Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — do not invoke the architect subcommand. Proceed directly to Phase B5.
238
+ **Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — skip this phase entirely. Proceed directly to Phase B5.
204
239
 
205
- **For STANDARD and COMPLEX tasks**: Always invoke. Even a 1-file STANDARD fix benefits from cross-path consistency checks. Do NOT skip without a TRIVIAL COMPLEXITY_BAND.
240
+ **For STANDARD and COMPLEX tasks**: Always run. Even a 1-file STANDARD fix benefits from cross-path consistency checks. Do NOT skip without a TRIVIAL COMPLEXITY_BAND.
206
241
 
207
- Invoke the architect subcommand to trace all affected code paths and produce an ordered implementation plan:
242
+ **Execution model**: Run **inline** (see Canonical Build Path above). Read the `commands/work-on/build/architect.md` spec and execute its steps directly in this context window. Only spawn a Skill() sub-agent when the Spawn-Decision Table Row (c) applies. <!-- Added: forge#1276 -->
208
243
 
244
+ Trace all affected code paths and produce an ordered implementation plan. The full step-by-step logic is defined in `commands/work-on/build/architect.md`. Key steps: map all callers and importers of changed functions; check consistency rules across paths; post a `FORGE:ARCHITECT` annotation with the ordered plan and a risk table.
245
+
246
+ **Spawn exception** (only when Row (c) applies):
209
247
  ```
210
248
  Skill("work-on:build:architect", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} --files {AFFECTED_FILES}")
211
249
  ```
250
+ The Skill() form above is the exception path — not the default. <!-- Added: forge#1276 -->
212
251
 
213
- **After subcommand returns**:
252
+ **After architecture planning**:
214
253
  - Returns ordered implementation plan → continue to B5
215
- - If subcommand returns BLOCKED → post comment, add `needs-human`, return `BUILD_RESULT: status: BLOCKED`
254
+ - BLOCKED (conflicting constraints that cannot be resolved inline) → post comment, add `needs-human`, return `BUILD_RESULT: status: BLOCKED`
216
255
  # MUST CONTINUE to Phase B5 — architect result is intermediate, NOT terminal.
217
256
 
218
257
  ---
@@ -245,9 +284,126 @@ Skill("work-on:build:validate", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FL
245
284
  Where `{CHANGED_FILES}` is the space-separated list of files changed by the implement subcommand (read from `IMPLEMENT_RESULT` or from the `<!-- FORGE:BUILDER -->` comment).
246
285
 
247
286
  **After subcommand returns**:
248
- - `VALIDATE_RESULT: gate_passed: true` → write checkpoint, then return `BUILD_RESULT: status: COMPLETE`
287
+ - `VALIDATE_RESULT: gate_passed: true` → continue to Phase B6.5 (acceptance gate)
249
288
  - `VALIDATE_RESULT: gate_passed: false` → subcommand has already posted comment and added `needs-human` label; return `BUILD_RESULT: status: BLOCKED`
250
289
 
290
+ ---
291
+
292
+ ## Phase B6.5: Acceptance Gate (MANDATORY — cannot be silently skipped) <!-- Added: forge#1315 -->
293
+
294
+ **Goal**: Execute the machine-checkable acceptance spec emitted by investigate Phase 1C and block merge if any check fails. This is a hard gate — not advisory.
295
+
296
+ **Read acceptance spec from FORGE:INVESTIGATOR comment**:
297
+
298
+ ```bash
299
+ ACCEPTANCE_CHECKS=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
300
+ --jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' \
301
+ | grep "^ACCEPTANCE_CHECK:" )
302
+ ```
303
+
304
+ **If `ACCEPTANCE_CHECKS` is empty** (investigation predates this feature or comment was deleted): post a warning comment and **block** — do not silently pass:
305
+
306
+ ```bash
307
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ACCEPTANCE_GATE -->
308
+ ## Acceptance Gate — No Spec Found
309
+
310
+ No \`ACCEPTANCE_CHECK:\` lines found in the FORGE:INVESTIGATOR comment. This may mean:
311
+ - The investigation was run before acceptance spec emission was added (re-run investigate to generate the spec), or
312
+ - The investigator comment was deleted.
313
+
314
+ **Gate result: BLOCKED** — re-run \`/work-on:investigate {NUMBER}\` to regenerate the acceptance spec, then retry the build.
315
+
316
+ <!-- FORGE:ACCEPTANCE_GATE:BLOCKED -->"
317
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "needs-human"
318
+ ```
319
+ Return `BUILD_RESULT: status: BLOCKED`, blocker: "No acceptance spec — re-run investigate to emit ACCEPTANCE_CHECK lines".
320
+
321
+ **If all checks are `type=skipped`**: post a pass comment noting human review is required, then continue to the checkpoint (non-blocking — skip was deliberate):
322
+
323
+ ```bash
324
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ACCEPTANCE_GATE -->
325
+ ## Acceptance Gate — Skipped (No Machine-Checkable Criteria)
326
+
327
+ The acceptance spec contains only a skip sentinel (\`type=skipped\`). No automated checks were run. Human review is required before merge.
328
+
329
+ <!-- FORGE:ACCEPTANCE_GATE:PASSED -->"
330
+ ```
331
+
332
+ **Otherwise — execute each check**:
333
+
334
+ ```bash
335
+ GATE_PASS=true
336
+ FAILED_CHECKS=""
337
+
338
+ while IFS= read -r check_line; do
339
+ ID=$(echo "$check_line" | sed -n 's/.*id=\([^ ]*\).*/\1/p')
340
+ TYPE=$(echo "$check_line" | sed -n 's/.*type=\([^ ]*\).*/\1/p')
341
+ TARGET=$(echo "$check_line"| sed -n 's/.*target=\([^ ]*\).*/\1/p')
342
+ MATCHER=$(echo "$check_line"| sed -n 's/.*matcher=\([^ ]*\).*/\1/p')
343
+ DESC=$(echo "$check_line" | sed -n 's/.*description=\(.*\)/\1/p')
344
+
345
+ [ "$TYPE" = "skipped" ] && continue
346
+
347
+ RESULT="PASS"
348
+ DETAIL=""
349
+
350
+ case "$TYPE" in
351
+ exists)
352
+ [ -e "$TARGET" ] || { RESULT="FAIL"; DETAIL="path not found: $TARGET"; }
353
+ ;;
354
+ contains)
355
+ grep -qE "$MATCHER" "$TARGET" 2>/dev/null || { RESULT="FAIL"; DETAIL="'$MATCHER' not found in $TARGET"; }
356
+ ;;
357
+ command|behavior)
358
+ if [ "$MATCHER" = "exit_0" ]; then
359
+ eval "$TARGET" >/dev/null 2>&1 || { RESULT="FAIL"; DETAIL="command exited non-zero: $TARGET"; }
360
+ else
361
+ OUTPUT=$(eval "$TARGET" 2>&1)
362
+ echo "$OUTPUT" | grep -qE "$MATCHER" || { RESULT="FAIL"; DETAIL="output did not match '$MATCHER'. Got: $(echo "$OUTPUT" | head -3)"; }
363
+ fi
364
+ ;;
365
+ *)
366
+ RESULT="FAIL"; DETAIL="unknown check type: $TYPE"
367
+ ;;
368
+ esac
369
+
370
+ if [ "$RESULT" = "FAIL" ]; then
371
+ GATE_PASS=false
372
+ FAILED_CHECKS="${FAILED_CHECKS}\n- **$ID** ($DESC): $DETAIL"
373
+ fi
374
+ done <<< "$ACCEPTANCE_CHECKS"
375
+ ```
376
+
377
+ **Post gate result comment**:
378
+
379
+ ```bash
380
+ if [ "$GATE_PASS" = "true" ]; then
381
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ACCEPTANCE_GATE -->
382
+ ## Acceptance Gate — PASSED
383
+
384
+ All machine-checkable acceptance criteria verified against real behavior.
385
+
386
+ <!-- FORGE:ACCEPTANCE_GATE:PASSED -->"
387
+ else
388
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ACCEPTANCE_GATE -->
389
+ ## Acceptance Gate — FAILED
390
+
391
+ The following acceptance checks did not pass:
392
+
393
+ $(echo -e "$FAILED_CHECKS")
394
+
395
+ Merge is blocked. Fix the failing criteria and re-run the validate phase.
396
+
397
+ <!-- FORGE:ACCEPTANCE_GATE:FAILED -->"
398
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "needs-human"
399
+ # Return BLOCKED — merge gate failed
400
+ fi
401
+ ```
402
+
403
+ If `GATE_PASS = false`: return `BUILD_RESULT: status: BLOCKED`, blocker: "Acceptance gate failed — see FORGE:ACCEPTANCE_GATE comment".
404
+
405
+ If `GATE_PASS = true`: continue to write the phase checkpoint below.
406
+
251
407
  **When gate_passed is true — write machine-readable phase checkpoint before returning (MANDATORY)**:
252
408
  ```bash
253
409
  CHECKPOINT_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
@@ -275,13 +431,14 @@ BUILD_RESULT:
275
431
 
276
432
  ## Integration Point in work-on.md
277
433
 
278
- This module runs at **state 8 (READY_TO_BUILD)** in the routing loop:
434
+ This module runs during **Phase 3** of the work-on.md pipeline (label: `workflow:ready-to-build` or `workflow:building`). The full sequence is defined by the Universal Phase Dispatcher in work-on.md:
279
435
 
280
436
  ```
281
- state 8 → [THIS MODULE] worktree + contract + context + architect + implement + validate
282
- → BUILD_RESULT: COMPLETE
283
- states 7, 6 → work-on:review (push + PR + /review-pr --auto-merge)
284
- states 5, 4 → work-on:close (trajectory + parent tracker + summary)
437
+ Phase 3 (Build) → [THIS MODULE] worktree + contract + context + architect + implement + validate + acceptance-gate
438
+ → posts FORGE:BUILDER comment + FORGE:ACCEPTANCE_GATE comment, writes FORGE:CHECKPOINT next_phase=REVIEW
439
+ Phase 4 (PR) → work-on:review — push branch, create PR, set workflow:in-review
440
+ Phase 5 (Review) → work-on:review — invoke /review-pr --auto-merge
441
+ Phase 6 (Close) → work-on:close — trajectory + parent tracker + summary + worktree cleanup
285
442
  ```
286
443
 
287
- The router re-reads GitHub state after this module returns COMPLETE — it will then detect state 6 (IN_REVIEW) or 7 (BUILD_NO_PR) and invoke `work-on:review`.
444
+ After this module posts `FORGE:BUILDER` and returns, work-on.md's Universal continuation rule re-reads the issue labels. Since the label is not yet terminal (`workflow:merged` / `workflow:invalid` / `needs-human`), it proceeds immediately to Phase 4 (PR Creation) and then Phase 5 (Auto-Review).