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
@@ -12,9 +12,11 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--pr PR_NUMB
12
12
  **Invoked by**: `work-on.md` Phase 6–7, after `review.md` returns `REVIEW_RESULT: status: COMPLETE`.
13
13
  **Output**: Update project board, close issue, update parent tracker, post trajectory log. Return final summary.
14
14
 
15
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
15
+ **Agent model policy**: `model: "haiku"`, `effort: low` (mechanical tier — label transitions, annotation posting, board updates). Fallback: `model: "sonnet"` if rate-limited. Feature gate: pass `effort` only on Claude Code >= 2.1.154.
16
16
  **NEVER use plan mode (EnterPlanMode).**
17
17
 
18
+ <!-- FORGE:SPEC_LOADED — work-on/close.md loaded and active. Agent is bound by this spec. -->
19
+
18
20
  ---
19
21
 
20
22
  ## Inputs
@@ -179,13 +181,15 @@ ISSUE_STATE=$(gh issue view {NUMBER} {GH_FLAG} --json state --jq '.state')
179
181
 
180
182
  **If `REMAINING_AFTER > 0`** (multi-phase: uncompleted phases remain):
181
183
  ```bash
182
- # Post phase-complete marker — router state 10 (MULTI_PHASE) will re-detect this issue
184
+ # Post phase-complete marker — work-on.md's Universal continuation rule will re-read labels and continue to the next phase
183
185
  gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:PHASE:COMPLETE -->
184
186
  Phase complete. PR #{PR_NUMBER} merged to \`{PR_BASE}\`. ${REMAINING_AFTER} phase item(s) remain — leaving issue open for next pipeline iteration."
185
187
 
186
- # Update labels to reflect phase complete (not yet fully merged)
188
+ # Update labels to reflect phase complete — remove current-phase labels and set next-phase label
189
+ # so the router has a signal for which phase comes next (fixes: issue #1381)
187
190
  gh issue edit {NUMBER} {GH_FLAG} \
188
- --remove-label "workflow:in-review,workflow:building,workflow:investigating" 2>/dev/null || true
191
+ --remove-label "workflow:in-review,workflow:building,workflow:investigating" \
192
+ --add-label "workflow:investigating" 2>/dev/null || true
189
193
 
190
194
  # EXIT — do not close, do not post trajectory, do not run C3–C6
191
195
  # Return CLOSE_RESULT: status: PHASE_COMPLETE to caller
@@ -444,6 +448,129 @@ Where:
444
448
 
445
449
  ---
446
450
 
451
+ ## Phase C5.2: Memory Index Update <!-- Added: forge#1316 -->
452
+
453
+ **Goal**: Append this run's learnings to the per-repo memory index so future `investigate` runs can retrieve relevant priors. This is the write side of the compounding intelligence loop.
454
+
455
+ **This phase is non-blocking** — if Gist creation or update fails, log the reason and continue to Phase C5.5. Never stall close for memory.
456
+
457
+ **Skip if**: Terminal state is `INVALID` (nothing useful to learn from an invalid issue) OR `<!-- FORGE:TRAJECTORY -->` was already posted AND `<!-- FORGE:MEMORY_INDEXED -->` comment exists on the issue (idempotency guard).
458
+
459
+ ### Step 1: Compose memory entry
460
+
461
+ Extract key fields from the pipeline:
462
+
463
+ ```bash
464
+ ROOT_CAUSE=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
465
+ --jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' \
466
+ | sed -n '/### Root Cause/{n;p;q}' | head -1 | cut -c1-120)
467
+
468
+ AFFECTED_FILES_BRIEF=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
469
+ --jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body' \
470
+ | sed -n '/### Affected Files/{n;p;q}' | head -1 | cut -c1-120)
471
+
472
+ DOMAIN_TAGS=$(gh issue view {NUMBER} {GH_FLAG} --json labels \
473
+ --jq '[.labels[].name | select(test("^(auth|billing|database|security|payments|gdpr|perf|ui|api|config)"))] | join(",")' 2>/dev/null || echo "")
474
+
475
+ MEMORY_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
476
+
477
+ MEMORY_ENTRY="MEMORY_ENTRY: issue={NUMBER} title=\"{TITLE}\" domain=\"${DOMAIN_TAGS}\" root_cause=\"${ROOT_CAUSE}\" outcome=\"${CARD_STATUS}\" files=\"${AFFECTED_FILES_BRIEF}\" lesson=\"${ROOT_CAUSE}\" timestamp=${MEMORY_TIMESTAMP}"
478
+ ```
479
+
480
+ ### Step 2: Find or create the memory index Gist
481
+
482
+ ```bash
483
+ MEMORY_INDEX_ID=$(gh gist list --limit 100 \
484
+ --jq '.[] | select(.description | contains("FORGE:MEMORY_INDEX: {GH_REPO}")) | .id' 2>/dev/null | head -1)
485
+
486
+ if [ -z "$MEMORY_INDEX_ID" ]; then
487
+ # First run — create the index Gist
488
+ TMPFILE=$(mktemp --suffix=.md)
489
+ cat > "$TMPFILE" <<GIST_EOF
490
+ # ForgeDock Memory Index — {GH_REPO}
491
+ <!-- FORGE:MEMORY_INDEX: {GH_REPO} -->
492
+ Generated by ForgeDock close phase. Each line is a prior pipeline run.
493
+
494
+ ${MEMORY_ENTRY}
495
+ GIST_EOF
496
+ # Memory gists MUST be secret — never pass --public here (forge#1587).
497
+ # The entry content below embeds real issue titles, root causes, and file
498
+ # paths; for a private consumer repo, --public would publish that content
499
+ # to a world-readable Gist. `gh gist create` is secret by default, so
500
+ # simply omitting --public is sufficient — the read side (investigate.md
501
+ # Phase 0.5, via `gh gist view`/`gh gist list`) works unchanged against
502
+ # secret gists for the authenticated owner.
503
+ MEMORY_INDEX_URL=$(gh gist create "$TMPFILE" \
504
+ --desc "FORGE:MEMORY_INDEX: {GH_REPO} — per-codebase learning index" \
505
+ 2>/dev/null | head -1)
506
+ MEMORY_INDEX_ID=$(echo "$MEMORY_INDEX_URL" | sed 's|.*/||')
507
+ rm -f "$TMPFILE"
508
+ echo "[MEMORY] Created memory index Gist: ${MEMORY_INDEX_URL}"
509
+ else
510
+ # Append to existing index
511
+ EXISTING_CONTENT=$(gh gist view "$MEMORY_INDEX_ID" 2>/dev/null)
512
+ UPDATED_CONTENT="${EXISTING_CONTENT}
513
+ ${MEMORY_ENTRY}"
514
+ INDEX_FILENAME=$(gh api gists/${MEMORY_INDEX_ID} --jq '.files | keys[0]' 2>/dev/null)
515
+ INDEX_FILENAME="${INDEX_FILENAME:-memory_index.md}"
516
+ TMPFILE=$(mktemp --suffix=.md)
517
+ echo "$UPDATED_CONTENT" > "$TMPFILE"
518
+ gh gist edit "$MEMORY_INDEX_ID" -f "$INDEX_FILENAME" "$TMPFILE" 2>/dev/null
519
+ EDIT_EXIT=$?
520
+ rm -f "$TMPFILE"
521
+ MEMORY_INDEX_URL="https://gist.github.com/${MEMORY_INDEX_ID}"
522
+ if [ $EDIT_EXIT -eq 0 ]; then
523
+ echo "[MEMORY] Appended to memory index: ${MEMORY_INDEX_URL}"
524
+ else
525
+ echo "WARNING: Failed to update memory index — run will not be persisted"
526
+ MEMORY_INDEX_URL=""
527
+ fi
528
+ fi
529
+ ```
530
+
531
+ ### Migration: replacing an existing public memory-index Gist
532
+
533
+ GitHub does not support flipping a Gist's visibility from public to secret in place. If you find an existing `FORGE:MEMORY_INDEX: {GH_REPO}` Gist that is **public** (check with `gh api gists/${MEMORY_INDEX_ID} --jq '.public'`), replace it:
534
+
535
+ ```bash
536
+ # The gist ID here is the same one found by the FORGE:MEMORY_INDEX search above.
537
+ OLD_PUBLIC_GIST_ID="$MEMORY_INDEX_ID"
538
+
539
+ # 1. Save the existing content so no learnings are lost — and verify the save
540
+ # succeeded BEFORE deleting anything.
541
+ gh gist view "$OLD_PUBLIC_GIST_ID" > /tmp/memory_index_migrate.md
542
+ if [ ! -s /tmp/memory_index_migrate.md ]; then
543
+ echo "ABORT: failed to save gist content — not deleting the public gist." >&2
544
+ exit 1
545
+ fi
546
+
547
+ # 2. Delete the public gist (removes the world-readable copy)
548
+ gh gist delete "$OLD_PUBLIC_GIST_ID" --yes
549
+
550
+ # 3. Recreate it secret (no --public) with the same description tag so the
551
+ # next close/investigate run finds it via the FORGE:MEMORY_INDEX search
552
+ gh gist create /tmp/memory_index_migrate.md \
553
+ --desc "FORGE:MEMORY_INDEX: {GH_REPO} — per-codebase learning index"
554
+ ```
555
+
556
+ This is a one-time manual step per affected repo — Phase C5.2 itself only ever creates the index once (Step 2's `if [ -z "$MEMORY_INDEX_ID" ]` branch) and appends afterward, so a stale public gist is never auto-recreated secret on its own.
557
+
558
+ ### Step 3: Post audit annotation on the issue
559
+
560
+ ```bash
561
+ if [ -n "$MEMORY_INDEX_URL" ]; then
562
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:MEMORY_INDEXED -->
563
+ This run has been indexed in the per-repo memory: ${MEMORY_INDEX_URL}
564
+
565
+ Future \`investigate\` runs on \`{GH_REPO}\` will retrieve this entry as a prior when working on related issues.
566
+
567
+ <!-- FORGE:MEMORY_INDEXED:COMPLETE -->"
568
+ echo "[MEMORY] Indexed issue #{NUMBER} into memory at: ${MEMORY_INDEX_URL}"
569
+ fi
570
+ ```
571
+
572
+ ---
573
+
447
574
  ## Phase C5.5: Graph Decision Record (MANDATORY when PR exists)
448
575
 
449
576
  **Skip if**: `{PR_NUMBER}` is empty OR `<!-- FORGE:DECISION_RECORD -->` already posted on the PR.
@@ -577,7 +704,7 @@ CLOSE_RESULT:
577
704
  parent_closed: {true|false}
578
705
  ```
579
706
 
580
- Where `PHASE_COMPLETE` means the current phase was closed but uncompleted phases remain — the issue is left OPEN for the router to re-evaluate on the next pipeline iteration (state 10, MULTI_PHASE).
707
+ Where `PHASE_COMPLETE` means the current phase was closed but uncompleted phases remain — the issue is left OPEN for work-on.md to re-evaluate on the next invocation (via Universal continuation rule: re-read labels, check terminal state, continue to next phase).
581
708
 
582
709
  ---
583
710
 
@@ -12,7 +12,7 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG]
12
12
  **Invoked by**: `work-on.md` routing loop, when `INVESTIGATE_RESULT.decompose = YES`.
13
13
  **Output**: Create sub-issues, update parent tracker, post `<!-- FORGE:DECOMPOSED -->` comment, set labels. STOP — each sub-issue runs its own /work-on.
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
18
  ---
@@ -108,6 +108,24 @@ For each sub-issue, prepare:
108
108
 
109
109
  For each sub-issue (in dependency order):
110
110
 
111
+ **Before creating each sub-issue, run the deterministic dedup check:** <!-- Added: forge#1335 -->
112
+
113
+ ```bash
114
+ SUB_TITLE="{fix|feat|refactor}: {SUB_ISSUE_TITLE}"
115
+ DEDUP_RESULT=$(scripts/issue-dedup.sh "$SUB_TITLE" {GH_FLAG} 2>&1)
116
+ DEDUP_EXIT=$?
117
+ if [ "$DEDUP_EXIT" -eq 1 ]; then
118
+ echo "DEDUP: Sub-issue near-duplicate detected — $DEDUP_RESULT"
119
+ echo "Skipping creation. Comment on the existing issue instead."
120
+ # Do NOT call gh issue create for this sub-issue
121
+ elif [ "$DEDUP_EXIT" -eq 2 ]; then
122
+ echo "DEDUP: Usage error — $DEDUP_RESULT"
123
+ # Do NOT call gh issue create for this sub-issue — fix the invocation and retry
124
+ fi
125
+ ```
126
+
127
+ Only call `gh issue create` when the dedup script exits 0 (no match):
128
+
111
129
  ```bash
112
130
  gh issue create {GH_FLAG} \
113
131
  --title "{fix|feat|refactor}: {SUB_ISSUE_TITLE}" \
@@ -11,9 +11,11 @@ argument-hint: [issue number] [--repo {owner}/{repo}] [--gh-flag "-R {owner}/{re
11
11
 
12
12
  Standalone investigation phase for the work-on pipeline. Validates whether an issue is real, determines root cause, posts a structured FORGE:INVESTIGATOR comment to GitHub, and updates workflow labels.
13
13
 
14
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`.
14
+ **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
15
  **NEVER use plan mode (EnterPlanMode).**
16
16
 
17
+ <!-- FORGE:SPEC_LOADED — work-on/investigate.md loaded and active. Agent is bound by this spec. -->
18
+
17
19
  ---
18
20
 
19
21
  ## Inputs
@@ -27,6 +29,67 @@ If called from `work-on`, these are passed through. If invoked standalone, `--re
27
29
 
28
30
  ---
29
31
 
32
+ ## Phase 0.5: Memory Retrieval — Prior Run Priors <!-- Added: forge#1316 -->
33
+
34
+ **Goal**: Before investigating, retrieve the top-k relevant prior pipeline runs from the per-repo memory index. Inject confirmed priors into the investigation context so the pipeline compounds intelligence across runs.
35
+
36
+ **This phase is non-blocking** — if the memory index is absent or retrieval fails, log the reason and proceed to Phase 1A. Never stall the pipeline for memory.
37
+
38
+ **Note on Gist visibility (forge#1587)**: The memory-index Gist is created **secret** (see `close.md` Phase C5.2 — no `--public` flag). `gh gist list` and `gh gist view` operate against the authenticated user's own Gists by description/id regardless of public/secret status, so the retrieval steps below work unchanged against a secret Gist. No code change is needed here — this note exists only so a future edit doesn't reintroduce a "must be public to be readable" assumption.
39
+
40
+ ### Step 1: Locate memory index Gist
41
+
42
+ The memory index is a GitHub Gist tagged `<!-- FORGE:MEMORY_INDEX: {GH_REPO} -->`. Find it:
43
+
44
+ ```bash
45
+ MEMORY_INDEX_URL=$(gh gist list --limit 100 \
46
+ --jq '.[] | select(.description | contains("FORGE:MEMORY_INDEX: {GH_REPO}")) | .url' 2>/dev/null | head -1)
47
+
48
+ MEMORY_INDEX_ID=$(gh gist list --limit 100 \
49
+ --jq '.[] | select(.description | contains("FORGE:MEMORY_INDEX: {GH_REPO}")) | .id' 2>/dev/null | head -1)
50
+ ```
51
+
52
+ If no memory index found: log `[MEMORY] No memory index for {GH_REPO} — starting fresh` and skip to Phase 1A.
53
+
54
+ ### Step 2: Retrieve relevant priors (top-k similarity)
55
+
56
+ Read the memory index content:
57
+
58
+ ```bash
59
+ MEMORY_CONTENT=$(gh gist view "$MEMORY_INDEX_ID" 2>/dev/null)
60
+ ```
61
+
62
+ The memory index is a newline-delimited list of prior run entries, each formatted as:
63
+
64
+ ```
65
+ MEMORY_ENTRY: issue={N} title="{TITLE}" domain="{DOMAIN_TAGS}" root_cause="{ROOT_CAUSE_SUMMARY}" outcome="{merged|invalid|blocked}" files="{AFFECTED_FILES}" lesson="{KEY_LESSON_ONE_LINE}" timestamp={ISO}
66
+ ```
67
+
68
+ **Retrieve top-3 relevant priors** by matching against the current issue title and body:
69
+
70
+ 1. Extract keywords from the current issue title: lowercase, remove stop words, keep noun/verb tokens
71
+ 2. Score each memory entry: +2 for a file path overlap, +1 per keyword match in title/root_cause/lesson
72
+ 3. Return the top-3 highest-scoring entries (minimum score ≥ 1 to filter noise)
73
+
74
+ If no entries score ≥ 1: log `[MEMORY] No relevant priors found` and skip to Phase 1A.
75
+
76
+ ### Step 3: Inject priors into investigation context
77
+
78
+ For each retrieved prior, emit a structured block that Phase 1B can reference:
79
+
80
+ ```
81
+ [MEMORY PRIOR #{RANK}]
82
+ Issue: #{issue} — {title}
83
+ Root cause: {root_cause}
84
+ Outcome: {outcome}
85
+ Key lesson: {lesson}
86
+ Affected files: {files}
87
+ ```
88
+
89
+ Print these blocks to stdout before Phase 1A begins. During Phase 1B (step 3 — blame analysis and step 5 — pickaxe pass), **explicitly check whether the current issue's suspected symbol or file appears in any prior root cause or affected files**. If a match is found, cite it in the FORGE:INVESTIGATOR comment's History Findings field as a `[MEMORY PRIOR]` hit.
90
+
91
+ ---
92
+
30
93
  ## Phase 1A: Load Issue & Check Resume State
31
94
 
32
95
  ```bash
@@ -67,10 +130,33 @@ The target repo is `{GH_REPO}` (resolved from `forge.yaml → project`). The wor
67
130
 
68
131
  If the issue specifies a **Code branch** (`**Code branch**: \`{branch}\``), check out that branch — the affected files may not be on the default branch.
69
132
 
133
+ ### Code Index Query (run BEFORE any grep exploration)
134
+
135
+ If `scripts/code-index.sh` exists under `{REPO_PATH}`, query the pre-built symbol/import index first. This yields deterministic answers in one tool call and avoids redundant grep exploration across agents.
136
+
137
+ ```bash
138
+ # Step 0A: Ensure index is current (cache-hit on unchanged HEAD — zero cost if already built)
139
+ bash {REPO_PATH}/scripts/code-index.sh --repo-path {REPO_PATH} 2>/dev/null || true
140
+
141
+ # Step 0B: Look up the symbol or file named in the issue (replace {SYMBOL} with the relevant name)
142
+ bash {REPO_PATH}/scripts/code-index.sh query --symbol {SYMBOL} --repo-path {REPO_PATH} 2>/dev/null || true
143
+
144
+ # Step 0C: Find all callers of that symbol
145
+ bash {REPO_PATH}/scripts/code-index.sh query --callers {SYMBOL} --repo-path {REPO_PATH} 2>/dev/null || true
146
+
147
+ # Step 0D: Find all importers of an affected file
148
+ bash {REPO_PATH}/scripts/code-index.sh query --importers {AFFECTED_FILE} --repo-path {REPO_PATH} 2>/dev/null || true
149
+
150
+ # Step 0E: Get all files in the affected domain (from issue labels/body)
151
+ bash {REPO_PATH}/scripts/code-index.sh query --domain {DOMAIN_LABEL} --repo-path {REPO_PATH} 2>/dev/null || true
152
+ ```
153
+
154
+ **Fallback**: If `scripts/code-index.sh` is absent or returns no results, proceed with standard grep exploration below. The index is an acceleration layer — its absence never blocks investigation.
155
+
70
156
  ### Investigation steps
71
157
 
72
158
  1. **Check the right branch** — read from the branch specified in the issue body (`**Code branch**: \`{branch}\``) if present
73
- 2. **Read domain files** — start with the key files for the affected domain
159
+ 2. **Read domain files** — start with the key files for the affected domain (use index query results from Step 0E as the file list; fall back to directory inspection if index is absent)
74
160
  3. **Verify claims** — does the code actually have the problem described?
75
161
  4. **Git blame** — trace when/why the relevant code was written. Run bounded, local commands (no network round-trip):
76
162
  ```bash
@@ -106,6 +192,19 @@ If the issue specifies a **Code branch** (`**Code branch**: \`{branch}\``), chec
106
192
 
107
193
  The comment MUST include `<!-- INVESTIGATION:COMPLETE -->` at the very end, AFTER all required sections are present. This marker signals the investigation finished successfully.
108
194
 
195
+ Before posting, resolve the attribution annotation link from `forge.yaml`:
196
+
197
+ ```bash
198
+ ATTRIBUTION_ANNOTATION_LINK=$(grep -A5 "^attribution:" forge.yaml 2>/dev/null | grep "annotation_link:" | awk '{print $2}' | tr -d '"' || echo "false")
199
+ ANNOTATION_LINK_FOOTER=""
200
+ if [ "$ATTRIBUTION_ANNOTATION_LINK" = "true" ]; then
201
+ ANNOTATION_LINK_FOOTER="
202
+
203
+ ---
204
+ *Pipeline powered by [ForgeDock](https://github.com/RapierCraftStudios/ForgeDock)*"
205
+ fi
206
+ ```
207
+
109
208
  ```bash
110
209
  gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:INVESTIGATOR -->
111
210
  ## Investigation Report
@@ -146,6 +245,22 @@ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:INVESTIGATOR -->
146
245
  **{YES|NO}** — {reason}
147
246
  {if YES: proposed sub-issues with titles and dependencies}
148
247
 
248
+ ### Acceptance Spec
249
+ {For each item in the issue's ## Acceptance Criteria section, emit one machine-checkable check line using the format below. If the issue has no Acceptance Criteria section, derive checks from the Recommendation above. Each check MUST be specific, observable, and testable — not vague prose. Checks are consumed by build/validate Phase B6.5 as the merge gate.}
250
+
251
+ ```
252
+ ACCEPTANCE_CHECK: id={ac-1} type={exists|contains|command|behavior} target={file_path|command|url} matcher={string|exit_0|regex} description={one-line human description}
253
+ ACCEPTANCE_CHECK: id={ac-2} type={exists|contains|command|behavior} target={file_path|command|url} matcher={string|exit_0|regex} description={one-line human description}
254
+ ```
255
+
256
+ **Check types**:
257
+ - `exists` — assert a file or directory exists (`target` = path, `matcher` = ignored)
258
+ - `contains` — assert a file contains a string or regex (`target` = file path, `matcher` = string/regex)
259
+ - `command` — run a shell command and assert exit 0 (`target` = shell command, `matcher` = `exit_0`)
260
+ - `behavior` — assert a runtime/observable behavior via shell command (`target` = shell command, `matcher` = expected output string or regex)
261
+
262
+ **Skipping**: if the issue has no verifiable acceptance criteria and none can be derived from the recommendation, emit a single sentinel: `ACCEPTANCE_CHECK: id=ac-skip type=skipped target=none matcher=none description=No machine-checkable criteria available — human review required`
263
+ ${ANNOTATION_LINK_FOOTER}
149
264
  <!-- INVESTIGATION:COMPLETE -->"
150
265
  ```
151
266
 
@@ -12,9 +12,11 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--worktree P
12
12
  **Invoked by**: `work-on.md` Phase 4–5, after `build/validate.md` returns `GATE_PASSED: true`.
13
13
  **Output**: Push branch, create PR, invoke /review-pr --auto-merge, 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/review.md loaded and active. Agent is bound by this spec. -->
19
+
18
20
  ---
19
21
 
20
22
  ## Inputs
@@ -81,6 +83,30 @@ Do NOT push this branch. Human review required to identify the source of the mer
81
83
  fi
82
84
  ```
83
85
 
86
+ ## Phase R1: Non-Empty Commit Guard (MANDATORY — run before push) <!-- Added: forge#1305 -->
87
+
88
+ Before pushing, verify the branch has at least one commit ahead of the PR base. This is the last-line defense against the phantom-commit hazard: a session that resumed from a partial FORGE:BUILDER comment (without `:COMPLETE`) would have skipped the commit step and could otherwise push an empty branch.
89
+
90
+ ```bash
91
+ cd {WORKTREE_PATH}
92
+ # Count commits on this branch that are not reachable from origin/{PR_BASE}
93
+ COMMIT_COUNT=$(git rev-list --count HEAD ^origin/{PR_BASE} 2>/dev/null || echo "0")
94
+ if [ "$COMMIT_COUNT" -eq 0 ]; then
95
+ gh issue comment {NUMBER} {GH_FLAG} --body "## Push Blocked — No Commits Ahead of Base
96
+
97
+ Branch \`{BRANCH}\` has 0 commits ahead of \`origin/{PR_BASE}\`. Pushing this branch would create an empty PR.
98
+
99
+ **Likely cause**: Build was interrupted after the FORGE:BUILDER comment was posted (implement.md Phase I6) but before the commit was created (validate.md Phase V5). The branch was pushed with no implementation on it.
100
+
101
+ **Resolution**: Delete this branch, re-run \`/work-on {NUMBER}\` to restart the build phase. The partial FORGE:BUILDER comment (lacking \`FORGE:BUILDER:COMPLETE\`) will be detected and deleted, and the build will restart cleanly.
102
+
103
+ <!-- FORGE:PUSH_BLOCKED_EMPTY_BRANCH -->"
104
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "needs-human"
105
+ exit 1
106
+ fi
107
+ echo "Commit count ahead of origin/{PR_BASE}: $COMMIT_COUNT — OK to push"
108
+ ```
109
+
84
110
  ## Phase R1: Push Branch
85
111
 
86
112
  ```bash
@@ -122,7 +148,21 @@ Derive from issue title:
122
148
  - `docs(...):` → `Docs: {description}`
123
149
  - fallback: use issue title as-is
124
150
 
125
- ### R2B: Create PR
151
+ ### R2B: Resolve attribution footer (optional)
152
+
153
+ Before creating the PR, check `forge.yaml → attribution.pr_footer`:
154
+
155
+ ```bash
156
+ ATTRIBUTION_PR_FOOTER=$(grep -A5 "^attribution:" forge.yaml 2>/dev/null | grep "pr_footer:" | awk '{print $2}' | tr -d '"' || echo "false")
157
+ ```
158
+
159
+ If `ATTRIBUTION_PR_FOOTER` is `true`, append the following footer to the PR body (once — never duplicate on retries):
160
+
161
+ ```
162
+ > Orchestrated with [ForgeDock](https://github.com/RapierCraftStudios/ForgeDock) — state, scheduling, review, and memory on GitHub.
163
+ ```
164
+
165
+ ### R2C: Create PR
126
166
 
127
167
  ```bash
128
168
  gh pr create {GH_FLAG} \
@@ -146,18 +186,22 @@ gh pr create {GH_FLAG} \
146
186
  Closes #{NUMBER}
147
187
 
148
188
  **Implementation branch**: \`{BRANCH}\`
149
- **Base**: \`{PR_BASE}\`"
189
+ **Base**: \`{PR_BASE}\`
190
+ {IF_ATTRIBUTION_PR_FOOTER_TRUE:
191
+ > Orchestrated with [ForgeDock](https://github.com/RapierCraftStudios/ForgeDock) — state, scheduling, review, and memory on GitHub.}"
150
192
  ```
151
193
 
152
194
  **Note**: `Closes #{NUMBER}` documents intent but does NOT auto-close for non-default-branch PRs. The close subcommand handles explicit closure after merge.
153
195
 
196
+ **Attribution guard**: The footer line is appended once at PR creation. If the PR already exists (resume path), do NOT append the footer again — check the existing PR body first.
197
+
154
198
  If PR creation fails because a PR already exists for this branch:
155
199
  ```bash
156
200
  gh pr list {GH_FLAG} --head {BRANCH} --json number,url --jq '.[0]'
157
201
  ```
158
202
  Use the existing PR number and continue.
159
203
 
160
- ### R2C: Update labels
204
+ ### R2D: Update labels
161
205
 
162
206
  ```bash
163
207
  gh issue edit {NUMBER} {GH_FLAG} \
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "[BENCHMARK] Monolithic work-on — single-prompt pipeline with no Skill sub-phase boundaries"
3
3
  argument-hint: [issue number]
4
+ install: internal
4
5
  ---
5
6
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
6
7
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -11,9 +12,14 @@ argument-hint: [issue number]
11
12
 
12
13
  Orchestrator for the full issue lifecycle: investigate → build → review → merge → close. GitHub issues are the persistent context layer — read existing comments before starting, write structured reports back, use `workflow:*` labels to track state.
13
14
 
14
- **Agent model policy**: Default `model: "sonnet"`. Fallback: `model: "opus"` if Sonnet is rate-limited.
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
  **NEVER use plan mode (EnterPlanMode).**
16
17
 
18
+ > **Relationship to `/work-on` (canonical path)**: This file is a `[BENCHMARK]` reference variant. It documents the same inline-execution model that `/work-on` Phase 3 and `work-on/build.md` use as their **default** for STANDARD/fast-lane issues — all build sub-phases (context → architect → implement → validate) run inline in the current context window with no `Skill()` sub-agent spawns. The difference is that this file omits the worktree lifecycle, `FORGE:CONTRACT` posting, and the Spawn-Decision exception path for large builds. Use `/work-on` for production runs; use this file for baseline benchmarking or when comparing single-prompt token cost against the modular path. See `work-on/build.md` (Canonical Build Path section) for the reconciled build topology. <!-- Added: forge#1276 -->
19
+ **NEVER use the Agent tool** — this spec executes all phases inline as a single monolithic prompt. The Agent tool would spawn a subprocess outside this context, breaking the single-prompt contract and losing all accumulated pipeline state.
20
+
21
+ <!-- FORGE:SPEC_LOADED — work-on-monolithic.md loaded and active. Agent is bound by this spec. -->
22
+
17
23
  ### Compaction Resilience
18
24
 
19
25
  1. Write state to GitHub after EVERY significant step
@@ -64,7 +70,7 @@ gh api repos/{GH_REPO}/issues/{NUMBER}/comments --jq '.[] | {id: .id, author: .u
64
70
 
65
71
  **Check**: state (closed → STOP), terminal labels (`workflow:merged`/`workflow:invalid` → STOP), existing agent comments (`FORGE:INVESTIGATOR`, `FORGE:CONTRACT`, `FORGE:BUILDER`, `FORGE:TRAJECTORY`), parent tracker status.
66
72
 
67
- **Determine resume point**: No comments → Phase 1. Investigation exists + ready-to-build → Phase 3. Builder + no PR → Phase 4. Builder + PR open → Phase 5. PR merged + issue open → close issue.
73
+ **Determine resume point**: No comments → Phase 1. Investigation exists + ready-to-build → Phase 3. Builder:COMPLETE + no PR → Phase 4. Builder without :COMPLETE (partial/interrupted build) + no PR → Phase 3 (partial-build cleanup). Builder + PR open → Phase 5. PR merged + issue open → close issue.
68
74
 
69
75
  **Classify lane**: Milestone → feature lane (`milestone/{slug}`). No milestone → fast lane (`staging`).
70
76