forgedock 1.1.1 → 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.
- package/README.md +53 -8
- package/bin/batch-runner.mjs +339 -0
- package/bin/demo.mjs +92 -7
- package/bin/engine/phases.mjs +20 -0
- package/bin/engine/state.mjs +8 -3
- package/bin/engine-cli.mjs +177 -5
- package/bin/forgedock.mjs +409 -26
- package/bin/hooks/interactive-engine.mjs +509 -0
- package/bin/hooks/pre-tool-use.mjs +498 -0
- package/bin/hooks/subagent-stop-enforce.mjs +197 -0
- package/bin/journey.mjs +72 -14
- package/bin/registry.mjs +139 -0
- package/bin/report.mjs +447 -0
- package/bin/runner.mjs +68 -19
- package/bin/settings-hook.mjs +235 -1
- package/commands/adopt.md +4 -1
- package/commands/analytics.md +4 -1
- package/commands/audit-agents.md +110 -27
- package/commands/audit.md +20 -1
- package/commands/autopilot.md +80 -8
- package/commands/changelog.md +2 -1
- package/commands/ci-audit.md +2 -1
- package/commands/cleanup.md +161 -1
- package/commands/compat-audit.md +2 -1
- package/commands/deploy-info.md +58 -1
- package/commands/design-bench.md +5 -1
- package/commands/design-render-critique-loop.md +1 -1
- package/commands/diagnose.md +2 -1
- package/commands/explain.md +2 -1
- package/commands/forge-stats.md +121 -2
- package/commands/forgedock-init.md +1 -1
- package/commands/geo-audit.md +3 -0
- package/commands/incident-response.md +2 -1
- package/commands/issue.md +23 -2
- package/commands/milestone.md +77 -12
- package/commands/optimize.md +2 -1
- package/commands/orchestrate/config.md +67 -0
- package/commands/orchestrate/phase-1-resolve.md +159 -0
- package/commands/orchestrate/phase-2-triage.md +126 -0
- package/commands/orchestrate/phase-2.5-synthesis.md +156 -0
- package/commands/orchestrate/phase-3-dependency.md +591 -0
- package/commands/orchestrate/phase-4-execution.md +962 -0
- package/commands/orchestrate/phase-5-cleanup.md +47 -0
- package/commands/orchestrate/phase-6-report.md +198 -0
- package/commands/orchestrate/safety.md +62 -0
- package/commands/orchestrate.md +25 -2045
- package/commands/pipeline-health/config.md +34 -0
- package/commands/pipeline-health/phase-1-context.md +180 -0
- package/commands/pipeline-health/phase-2-metrics.md +1729 -0
- package/commands/pipeline-health/phase-3-analyze.md +204 -0
- package/commands/pipeline-health/phase-4-proposals.md +117 -0
- package/commands/pipeline-health/phase-5-report.md +284 -0
- package/commands/pipeline-health/phase-6-summary.md +52 -0
- package/commands/pipeline-health.md +25 -2401
- package/commands/pipeline-resume.md +24 -1
- package/commands/pipeline-status.md +65 -0
- package/commands/qa-sweep.md +4 -1
- package/commands/quality-gate.md +248 -10
- package/commands/replay.md +2 -1
- package/commands/review-pr-agents/api.md +135 -0
- package/commands/review-pr-agents/auth.md +137 -0
- package/commands/review-pr-agents/billing.md +101 -0
- package/commands/review-pr-agents/concurrency.md +145 -0
- package/commands/review-pr-agents/database.md +103 -0
- package/commands/review-pr-agents/frontend.md +89 -0
- package/commands/review-pr-agents/infra.md +385 -0
- package/commands/review-pr-agents/protocols.md +185 -0
- package/commands/review-pr-agents/scraper.md +185 -0
- package/commands/review-pr-agents/security.md +406 -0
- package/commands/review-pr-agents.md +45 -1722
- package/commands/review-pr-staging.md +196 -40
- package/commands/review-pr.md +591 -52
- package/commands/rollback.md +2 -1
- package/commands/scope.md +2 -1
- package/commands/security-audit.md +2 -1
- package/commands/signal-planner.md +623 -0
- package/commands/sync-ecosystem.md +1 -0
- package/commands/test-gate.md +17 -1
- package/commands/validate.md +2 -1
- package/commands/work-on/build/architect.md +28 -0
- package/commands/work-on/build/context.md +2 -0
- package/commands/work-on/build/implement.md +3 -1
- package/commands/work-on/build/validate.md +26 -7
- package/commands/work-on/build.md +163 -24
- package/commands/work-on/close.md +130 -3
- package/commands/work-on/decompose.md +19 -1
- package/commands/work-on/investigate.md +117 -2
- package/commands/work-on/review.md +24 -4
- package/commands/work-on-monolithic.md +7 -2
- package/commands/work-on.md +202 -4
- package/docs/BRAND.md +14 -7
- package/docs/CI.md +2 -2
- package/docs/CODEX.md +36 -1
- package/docs/CONFIG.md +5 -8
- package/docs/FORGE-PROTOCOL.md +15 -1064
- package/docs/anthropic-devrel-outreach.md +2 -2
- package/docs/articles/command-decomposition-token-savings.md +214 -0
- package/docs/articles/model-release-playbook.md +131 -0
- package/docs/articles/per-repo-adaptive-scripts-token-savings.md +27 -25
- package/docs/claude-breakpoints.json +75 -5
- package/docs/design/abc-benchmark.md +1 -1
- package/docs/design/design-spec-schema.md +1 -1
- package/docs/design/divergent-generation.md +1 -1
- package/docs/design/eval-gate-runbook.md +178 -0
- package/docs/design/show-hn-draft.md +26 -1
- package/docs/design/token-cost-baseline-1298.md +59 -0
- package/docs/eval/README.md +117 -0
- package/docs/eval/corpus/seed-v1.json +6 -0
- package/docs/eval/published/claude-sonnet-4-6-2026-07-04.json +33 -0
- package/docs/site/annotations-explained.md +24 -0
- package/docs/site/command-learning-path.md +51 -14
- package/docs/site/command-reference.md +339 -113
- package/docs/site/for-companies.md +95 -0
- package/docs/site/forge-annotation-protocol.md +12 -256
- package/docs/site/getting-started.md +43 -4
- package/docs/site/github-is-the-memory.md +113 -0
- package/docs/site/how-it-works.md +3 -13
- package/docs/site/index.md +9 -1
- package/docs/spec/eval-run-result.md +147 -0
- package/docs/spec/forge-protocol-v1.md +441 -18
- package/docs/spec/label-state-machine.md +55 -0
- package/docs/spec/review-protocol.md +158 -0
- package/docs/spec-graph-schema.md +28 -0
- package/docs/superpowers/specs/2026-07-04-economic-self-governance-design.md +181 -0
- package/docs/superpowers/specs/2026-07-04-provenance-trail-design.md +189 -0
- package/examples/forgedock-demo/README.md +41 -22
- package/examples/forgedock-demo/issues/06-bug-tags-type-validation.md +43 -0
- package/examples/forgedock-demo/issues/07-bug-negative-offset-pagination.md +42 -0
- package/examples/forgedock-demo/issues/08-bug-patch-mass-assignment.md +49 -0
- package/examples/forgedock-demo/issues/09-bug-count-injection.md +47 -0
- package/examples/forgedock-demo/issues/10-feature-sort-param.md +39 -0
- package/examples/forgedock-demo/issues/11-feature-patch-tags.md +37 -0
- package/examples/forgedock-demo/issues/12-feature-bulk-create.md +42 -0
- package/examples/forgedock-demo/issues/13-feature-archive-notes.md +46 -0
- package/examples/forgedock-demo/issues/14-refactor-extract-title-validation.md +41 -0
- package/examples/forgedock-demo/issues/15-refactor-protected-route-flag.md +43 -0
- package/examples/forgedock-demo/issues/16-refactor-extract-store.md +45 -0
- package/examples/forgedock-demo/issues/17-perf-tags-dedup-set.md +35 -0
- package/examples/forgedock-demo/issues/18-perf-remove-redundant-sort.md +37 -0
- package/examples/forgedock-demo/issues/19-docs-api-reference-full.md +53 -0
- package/examples/forgedock-demo/issues/20-docs-intentional-flaw-convention.md +46 -0
- package/examples/forgedock-demo/scripts/smoke.js +18 -1
- package/examples/forgedock-demo/src/db.js +36 -11
- package/examples/forgedock-demo/src/routes/notes.js +106 -9
- package/examples/forgedock-demo/src/server.js +4 -1
- package/package.json +3 -1
- package/packages/protocol/LICENSE +21 -0
- package/packages/protocol/src/cli.js +135 -0
- package/packages/protocol/src/emit.js +146 -0
- package/packages/protocol/src/index.js +43 -0
- package/packages/protocol/src/parse.js +229 -0
- package/packages/protocol/src/types.js +171 -0
- package/packages/protocol/src/validate.js +122 -0
- package/scripts/bench-topology-cost.mjs +372 -0
- package/scripts/check-command-docs-drift.sh +198 -0
- package/scripts/check-protocol-restatements.sh +176 -0
- package/scripts/check-registry/README.md +72 -0
- package/scripts/check-registry/manifest.json +6 -0
- package/scripts/code-index.sh +454 -0
- package/scripts/conformance-check.mjs +168 -0
- package/scripts/doctor-pipeline-state.sh +484 -0
- package/scripts/eval-gate-baseline.json +17 -0
- package/scripts/eval-gate-scorecard.mjs +242 -0
- package/scripts/eval-scorecard-aggregator.mjs +252 -0
- package/scripts/flaky-quarantine.sh +241 -0
- package/scripts/forge-annotation.sh +567 -0
- package/scripts/issue-dedup.sh +236 -0
- package/scripts/validate-annotation-node.mjs +233 -0
- package/scripts/worktree-lifecycle.sh +3 -3
- package/templates/devdocs/agent/using-forgedock.md +14 -0
- package/docs/site/.vitepress/config.mjs +0 -85
package/commands/test-gate.md
CHANGED
|
@@ -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**:
|
|
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
|
|
package/commands/validate.md
CHANGED
|
@@ -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**:
|
|
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**:
|
|
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
|
|
@@ -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**:
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
@@ -305,9 +320,13 @@ BUILDER_COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
|
305
320
|
--jq '[.[] | select(.body | contains("FORGE:BUILDER") and (contains("FORGE:BUILDER:COMPLETE") | not))] | last | .id // ""')
|
|
306
321
|
|
|
307
322
|
if [ -n "$BUILDER_COMMENT_ID" ]; then
|
|
308
|
-
# Fetch current body and append the completion marker
|
|
323
|
+
# Fetch current body and append the completion marker plus best-effort cost signal
|
|
309
324
|
CURRENT_BODY=$(gh api repos/{GH_REPO}/issues/comments/$BUILDER_COMMENT_ID --jq '.body')
|
|
310
|
-
|
|
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}
|
|
311
330
|
|
|
312
331
|
<!-- FORGE:BUILDER:COMPLETE -->"
|
|
313
332
|
gh api repos/{GH_REPO}/issues/comments/$BUILDER_COMMENT_ID \
|
|
@@ -10,12 +10,30 @@ argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--base PR_BA
|
|
|
10
10
|
**Input**: $ARGUMENTS
|
|
11
11
|
|
|
12
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,
|
|
13
|
+
**Output**: Create worktree, post contract, run build phases, return result to work-on.md.
|
|
14
14
|
|
|
15
|
-
**Agent model policy**:
|
|
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.
|
|
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)
|
|
@@ -64,7 +84,7 @@ Extract from investigation report:
|
|
|
64
84
|
- Recommendation
|
|
65
85
|
- Task type (Bug Fix / Feature / Refactor / Maintenance / UI/UX / Full-Stack)
|
|
66
86
|
|
|
67
|
-
**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 -->
|
|
68
88
|
```bash
|
|
69
89
|
COMPLEXITY_BAND=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
70
90
|
--jq '.[] | select(.body | contains("FORGE:FAST_PATH")) | .body' 2>/dev/null \
|
|
@@ -192,44 +212,46 @@ If `FUNCTION_NAMES` is non-empty, it will be passed via `--functions` to the con
|
|
|
192
212
|
|
|
193
213
|
## Phase B3: Context Gathering (MANDATORY for STANDARD/COMPLEX — skip for TRIVIAL)
|
|
194
214
|
|
|
195
|
-
**Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) —
|
|
215
|
+
**Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — skip this phase entirely. Proceed directly to Phase B4.
|
|
196
216
|
|
|
197
|
-
**For STANDARD and COMPLEX tasks**: Always
|
|
217
|
+
**For STANDARD and COMPLEX tasks**: Always run. Do NOT skip without a TRIVIAL COMPLEXITY_BAND.
|
|
198
218
|
|
|
199
|
-
|
|
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 -->
|
|
200
220
|
|
|
201
|
-
|
|
202
|
-
Skill("work-on:build:context", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} {AFFECTED_FILES} --functions {FUNCTION_NAMES}")
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
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.
|
|
206
222
|
|
|
223
|
+
**Spawn exception** (only when Row (c) applies):
|
|
207
224
|
```
|
|
208
|
-
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}")
|
|
209
226
|
```
|
|
227
|
+
If `FUNCTION_NAMES` is empty, omit `--functions`. The Skill() form above is the exception path — not the default. <!-- Added: forge#1276 -->
|
|
210
228
|
|
|
211
|
-
**After
|
|
212
|
-
-
|
|
213
|
-
-
|
|
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)
|
|
214
232
|
# MUST CONTINUE to Phase B4 — context result is intermediate, NOT terminal.
|
|
215
233
|
|
|
216
234
|
---
|
|
217
235
|
|
|
218
236
|
## Phase B4: Architecture Planning (MANDATORY for STANDARD/COMPLEX — skip for TRIVIAL)
|
|
219
237
|
|
|
220
|
-
**Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) —
|
|
238
|
+
**Skip if COMPLEXITY_BAND: TRIVIAL** (read from FORGE:FAST_PATH in Phase B0) — skip this phase entirely. Proceed directly to Phase B5.
|
|
221
239
|
|
|
222
|
-
**For STANDARD and COMPLEX tasks**: Always
|
|
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.
|
|
223
241
|
|
|
224
|
-
|
|
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 -->
|
|
225
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):
|
|
226
247
|
```
|
|
227
248
|
Skill("work-on:build:architect", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FLAG} --repo-path {WORKTREE_PATH} --files {AFFECTED_FILES}")
|
|
228
249
|
```
|
|
250
|
+
The Skill() form above is the exception path — not the default. <!-- Added: forge#1276 -->
|
|
229
251
|
|
|
230
|
-
**After
|
|
252
|
+
**After architecture planning**:
|
|
231
253
|
- Returns ordered implementation plan → continue to B5
|
|
232
|
-
-
|
|
254
|
+
- BLOCKED (conflicting constraints that cannot be resolved inline) → post comment, add `needs-human`, return `BUILD_RESULT: status: BLOCKED`
|
|
233
255
|
# MUST CONTINUE to Phase B5 — architect result is intermediate, NOT terminal.
|
|
234
256
|
|
|
235
257
|
---
|
|
@@ -262,9 +284,126 @@ Skill("work-on:build:validate", args="{NUMBER} --repo {GH_REPO} --gh-flag {GH_FL
|
|
|
262
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).
|
|
263
285
|
|
|
264
286
|
**After subcommand returns**:
|
|
265
|
-
- `VALIDATE_RESULT: gate_passed: true` →
|
|
287
|
+
- `VALIDATE_RESULT: gate_passed: true` → continue to Phase B6.5 (acceptance gate)
|
|
266
288
|
- `VALIDATE_RESULT: gate_passed: false` → subcommand has already posted comment and added `needs-human` label; return `BUILD_RESULT: status: BLOCKED`
|
|
267
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
|
+
|
|
268
407
|
**When gate_passed is true — write machine-readable phase checkpoint before returning (MANDATORY)**:
|
|
269
408
|
```bash
|
|
270
409
|
CHECKPOINT_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
@@ -295,8 +434,8 @@ BUILD_RESULT:
|
|
|
295
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:
|
|
296
435
|
|
|
297
436
|
```
|
|
298
|
-
Phase 3 (Build) → [THIS MODULE] worktree + contract + context + architect + implement + validate
|
|
299
|
-
→ posts FORGE:BUILDER comment, writes FORGE:CHECKPOINT next_phase=REVIEW
|
|
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
|
|
300
439
|
Phase 4 (PR) → work-on:review — push branch, create PR, set workflow:in-review
|
|
301
440
|
Phase 5 (Review) → work-on:review — invoke /review-pr --auto-merge
|
|
302
441
|
Phase 6 (Close) → work-on:close — trajectory + parent tracker + summary + worktree cleanup
|
|
@@ -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**:
|
|
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
|
|
@@ -183,9 +185,11 @@ ISSUE_STATE=$(gh issue view {NUMBER} {GH_FLAG} --json state --jq '.state')
|
|
|
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
|
|
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"
|
|
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.
|
|
@@ -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**:
|
|
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}" \
|