forgedock 1.0.0

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 (44) hide show
  1. package/LICENSE +244 -0
  2. package/README.md +251 -0
  3. package/bin/forgedock.mjs +232 -0
  4. package/commands/analytics.md +777 -0
  5. package/commands/audit-agents.md +410 -0
  6. package/commands/audit.md +410 -0
  7. package/commands/autopilot.md +432 -0
  8. package/commands/cleanup.md +264 -0
  9. package/commands/deploy-info.md +292 -0
  10. package/commands/failure-recon.md +375 -0
  11. package/commands/forge-stats.md +183 -0
  12. package/commands/geo-audit.md +343 -0
  13. package/commands/incident-response.md +384 -0
  14. package/commands/issue.md +506 -0
  15. package/commands/milestone.md +599 -0
  16. package/commands/orchestrate.md +1044 -0
  17. package/commands/pipeline-health.md +2343 -0
  18. package/commands/qa-sweep.md +237 -0
  19. package/commands/quality-gate.md +777 -0
  20. package/commands/review-pr-agents.md +1711 -0
  21. package/commands/review-pr-staging.md +325 -0
  22. package/commands/review-pr.md +888 -0
  23. package/commands/rollback.md +253 -0
  24. package/commands/security-audit.md +529 -0
  25. package/commands/sync-ecosystem.md +527 -0
  26. package/commands/validate.md +131 -0
  27. package/commands/work-on/build/architect.md +291 -0
  28. package/commands/work-on/build/context.md +349 -0
  29. package/commands/work-on/build/implement.md +280 -0
  30. package/commands/work-on/build/validate.md +292 -0
  31. package/commands/work-on/build.md +262 -0
  32. package/commands/work-on/close.md +350 -0
  33. package/commands/work-on/decompose.md +254 -0
  34. package/commands/work-on/investigate.md +437 -0
  35. package/commands/work-on/review.md +245 -0
  36. package/commands/work-on-monolithic.md +298 -0
  37. package/commands/work-on.md +1089 -0
  38. package/docs/CODEX.md +92 -0
  39. package/docs/WORKFLOW.md +104 -0
  40. package/package.json +45 -0
  41. package/scripts/verify-env-vars.sh +201 -0
  42. package/scripts/verify-host-headers.sh +117 -0
  43. package/scripts/verify-route-registration.sh +118 -0
  44. package/scripts/verify-sops-chain.sh +163 -0
@@ -0,0 +1,1089 @@
1
+ ---
2
+ description: Pick up a GitHub issue and run the full investigate-build-review-merge pipeline
3
+ argument-hint: [issue number or "next" to pick highest priority]
4
+ ---
5
+
6
+ # /work-on — Full Issue Pipeline
7
+
8
+ **Input**: $ARGUMENTS
9
+
10
+ Orchestrator for the full issue lifecycle: investigate → decompose (if needed) → 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.
11
+
12
+ **Agent model policy**: Default `model: "sonnet"`. Fallback: `model: "opus"` if Sonnet is rate-limited.
13
+ **NEVER use plan mode (EnterPlanMode).**
14
+
15
+ ### Compaction Resilience
16
+
17
+ 1. Write state to GitHub after EVERY significant step
18
+ 2. Re-read GitHub state at the START of each phase (don't rely on in-memory context)
19
+ 3. After compaction: re-read issue (body + comments + labels) to reconstruct state
20
+ 4. Key principle: A NEW session running `/work-on {number}` should pick up where the last left off by reading GitHub state alone
21
+
22
+ ### Universal Phase Dispatcher
23
+
24
+ <!-- FORGE:DISPATCHER — This is the SINGLE source of truth for phase transitions. Every phase boundary references this section. -->
25
+
26
+ **Phase sequence** (canonical order):
27
+
28
+ | Step | Phase | Entry Condition | Terminal? |
29
+ |------|-------|-----------------|-----------|
30
+ | 1 | Phase 0: Resolve Issue | Always first | No |
31
+ | 2 | Phase 1: Investigation | No `INVESTIGATION:COMPLETE` comment | No |
32
+ | 3 | Phase 1D: Route | Investigation complete | No |
33
+ | 4 | Phase 2: Decomposition | decompose: YES | Yes (spawns sub-issues) |
34
+ | 5 | Phase 3: Build (3A–3M) | `workflow:ready-to-build` or `workflow:building` | No |
35
+ | 6 | Phase 4: PR Creation | Builder comment posted, no PR exists | No |
36
+ | 7 | Phase 5: Auto-Review | PR exists, `workflow:in-review` | No |
37
+ | 8 | Phase 6: Close & Cleanup | PR merged | No |
38
+ | 9 | Phase 7: Trajectory | Issue closed | Yes |
39
+
40
+ **Phase 3 sub-phase sequence** (all mandatory, execute in order):
41
+
42
+ 3A → 3B → 3C → 3C.5 → 3C.6 → 3D → 3E → 3F → 3F.5 → 3G → 3H → 3I → 3I.5 → 3J → 3K → 3L → 3M
43
+
44
+ **Universal continuation rule**: After ANY phase or sub-phase completes, check whether a terminal state has been reached. Terminal states are:
45
+ - `workflow:merged` label is set
46
+ - `workflow:invalid` label is set
47
+ - `needs-human` label is set
48
+ - `workflow:decomposed` label is set (sub-issues spawned)
49
+ - Issue state is CLOSED with terminal label
50
+
51
+ **If the current state is NOT terminal: proceed to the next phase in the sequence immediately. Do NOT stop. Do NOT emit a summary. Do NOT treat any intermediate phase completion as a terminal signal.** Every phase completion — investigation done, quality gate passed, PR merged, review complete — is an intermediate result. Only the terminal states listed above allow stopping.
52
+
53
+ **Adding a new phase**: Insert it into the phase sequence table above and the sub-phase sequence if it belongs to Phase 3. No per-boundary transition code is needed — the universal continuation rule handles all transitions.
54
+
55
+ ---
56
+
57
+ ## Pipeline Rules
58
+
59
+ - **NEVER merge to main.** PRs target `staging` (fast lane) or `milestone/{slug}` (feature lane).
60
+ - **`Closes #N` does not auto-close for non-default-branch PRs.** You MUST explicitly `gh issue close`.
61
+ - **Review findings are NOT merge blockers.** They become separate issues.
62
+
63
+ ---
64
+
65
+ ## Multi-Repo Support
66
+
67
+ | Input | Resolves To | GH_REPO | STAGING_BRANCH |
68
+ |-------|-------------|---------|----------------|
69
+ | `123` / `#123` | AlterLab (default) | `RapierCraft/AlterLab` | `staging` |
70
+ | `mcp:5` | MCP Server | `RapierCraft/alterlab-mcp-server` | `main` |
71
+ | `n8n:12` | n8n Node | `RapierCraft/n8n-nodes-alterlab` | `main` |
72
+
73
+ Satellite repos (MCP, n8n) have no staging — fast-lane PRs go to `main`.
74
+
75
+ ---
76
+
77
+ ## Phase 0: Resolve Issue & Load Context
78
+
79
+ ### 0A: Parse input
80
+ Extract project prefix and issue number. If `next`/`pick`: list open issues sorted by priority, skip `needs-human` and `workflow:decomposed`, pick highest priority.
81
+
82
+ ### 0B: Load issue + existing context
83
+ ```bash
84
+ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,comments,milestone
85
+ gh api repos/{GH_REPO}/issues/{NUMBER}/comments --jq '.[] | {id: .id, author: .user.login, body: .body}'
86
+ ```
87
+
88
+ **Check**: state (closed → STOP), terminal labels (`workflow:merged`/`workflow:invalid` → STOP), existing agent comments (`FORGE:INVESTIGATOR`, `FORGE:DECOMPOSED`, `FORGE:CONTRACT`, `FORGE:BUILDER`, `FORGE:TRAJECTORY`), parent tracker status, sub-issue status.
89
+
90
+ **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 → Phase 6.
91
+
92
+ **Classify lane**: Milestone → feature lane (`milestone/{slug}`). No milestone → fast lane (`staging`).
93
+
94
+ **Source branch for review-findings**: Parse `**Code branch**: \`{branch}\`` from body. Branch from there, not main.
95
+
96
+ ### 0C: Sync to Project board
97
+ Add issue to project, set Status=In Progress, Lane, Component, Priority, Workflow=Investigating.
98
+
99
+ ---
100
+
101
+ ## Phase 1: Investigation
102
+
103
+ **Skip if**: `<!-- FORGE:INVESTIGATOR -->` or `<!-- ALTERLAB:INVESTIGATOR -->` exists with `<!-- INVESTIGATION:COMPLETE -->` in the SAME comment.
104
+
105
+ **Partial investigation**: If investigator comment exists BUT `<!-- INVESTIGATION:COMPLETE -->` is ABSENT → investigation was interrupted. Delete the partial comment and restart:
106
+ ```bash
107
+ COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
108
+ --jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .id')
109
+ gh api repos/{GH_REPO}/issues/comments/$COMMENT_ID -X DELETE
110
+ ```
111
+
112
+ ### 1A: Set label
113
+ ```bash
114
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "workflow:investigating"
115
+ gh issue edit {NUMBER} {GH_FLAG} --remove-label "workflow:ready-to-build,workflow:building,workflow:in-review" 2>/dev/null || true
116
+ ```
117
+
118
+ ### 1A.5: Normalize Issue Body (MANDATORY)
119
+
120
+ Before investigation begins, verify the issue body contains the four mandatory pipeline sections. If any are missing, add placeholder content so the investigator has the correct scaffolding.
121
+
122
+ **Skip if**: All four sections (`## Problem`, `## Affected Files`, `## Expected Behavior`, `## Acceptance Criteria`) are already present.
123
+
124
+ ```bash
125
+ ISSUE_BODY=$(gh issue view {NUMBER} {GH_FLAG} --json body --jq '.body')
126
+
127
+ MISSING_SECTIONS=""
128
+ echo "$ISSUE_BODY" | grep -q "^## Problem" || MISSING_SECTIONS="$MISSING_SECTIONS PROBLEM"
129
+ echo "$ISSUE_BODY" | grep -q "^## Affected Files" || MISSING_SECTIONS="$MISSING_SECTIONS AFFECTED_FILES"
130
+ echo "$ISSUE_BODY" | grep -q "^## Expected Behavior" || MISSING_SECTIONS="$MISSING_SECTIONS EXPECTED_BEHAVIOR"
131
+ echo "$ISSUE_BODY" | grep -q "^## Acceptance Criteria" || MISSING_SECTIONS="$MISSING_SECTIONS ACCEPTANCE_CRITERIA"
132
+
133
+ if [ -n "$MISSING_SECTIONS" ]; then
134
+ echo "Missing sections:$MISSING_SECTIONS — normalizing issue body before investigation"
135
+
136
+ APPEND_TEXT=""
137
+ echo "$MISSING_SECTIONS" | grep -q "PROBLEM" && APPEND_TEXT="$APPEND_TEXT
138
+ ## Problem
139
+
140
+ Root cause unknown — investigation needed."
141
+
142
+ echo "$MISSING_SECTIONS" | grep -q "AFFECTED_FILES" && APPEND_TEXT="$APPEND_TEXT
143
+ ## Affected Files
144
+
145
+ Files to be identified during investigation."
146
+
147
+ echo "$MISSING_SECTIONS" | grep -q "EXPECTED_BEHAVIOR" && APPEND_TEXT="$APPEND_TEXT
148
+ ## Expected Behavior
149
+
150
+ Expected behavior to be determined during investigation."
151
+
152
+ echo "$MISSING_SECTIONS" | grep -q "ACCEPTANCE_CRITERIA" && APPEND_TEXT="$APPEND_TEXT
153
+ ## Acceptance Criteria
154
+
155
+ - [ ] Fix confirmed during investigation."
156
+
157
+ # Append missing sections to the existing body (never replace — only extend)
158
+ NORMALIZED_BODY="${ISSUE_BODY}${APPEND_TEXT}"
159
+ gh issue edit {NUMBER} {GH_FLAG} --body "$NORMALIZED_BODY"
160
+ echo "Issue body normalized — added:$MISSING_SECTIONS"
161
+ else
162
+ echo "Issue body already contains all mandatory sections — skipping normalization"
163
+ fi
164
+ ```
165
+
166
+ **Continue to Phase 1B unconditionally.** Normalization is a compensation step — it never blocks investigation.
167
+
168
+ ### 1B: Investigate the issue
169
+
170
+ Mission: Validate whether the issue is real. Assume description is wrong until proven otherwise.
171
+
172
+ **Resolve target repo and branch**:
173
+
174
+ For Forge issues (repo = `RapierCraftStudios/forge`):
175
+ - Key files: `commands/work-on.md`, `commands/review-pr.md`, `commands/quality-gate.md`, `commands/orchestrate.md`, `install.sh`, `CLAUDE.md`
176
+
177
+ For AlterLab issues (repo = `RapierCraft/AlterLab`):
178
+
179
+ | Domain | Key files |
180
+ |--------|-----------|
181
+ | BILLING | `routers/billing.py`, `core/pricing.py`, `services/credit_service.py` |
182
+ | SCRAPING | `unified_consumer.py`, `queues.py`, `domain_playbooks.json` |
183
+ | AUTH | `core/auth.py`, `routers/auth.py`, `dependencies.py` |
184
+ | DATABASE | `infra/migrations/`, `models/`, `db/` |
185
+ | FRONTEND | `web/src/app/`, `web/src/components/`, `web/src/lib/` |
186
+ | CORTEX | `cortex_client.py`, `routers/cortex.py` |
187
+ | INFRA | `.github/workflows/`, `docker-compose.yml`, `infra/traefik/` |
188
+
189
+ **INFRA domain known footguns** (read before writing any `.github/workflows/*.yml` changes):
190
+ - **appleboy/ssh-action Go template preprocessing**: Any `{{` in a `script:` block is interpreted as a Go template directive **before the script reaches SSH**. This means `docker ps --format '{{.Names}}'` and `docker inspect --format '{{index .RepoTags 0}}'` will crash the action with exit 1. Both function calls (`{{index .X Y}}`) AND field accessors (`{{.Names}}`, `{{.Status}}`) fail on the action's empty data context. Shell error handlers (`|| fallback`, `set -e`, `2>/dev/null`) are bypassed because the failure is client-side. Always use `docker inspect IMAGE | jq -r '.[0].RepoTags[0]'` and `docker ps --format json | jq -r '.Names'` patterns in `appleboy/ssh-action` scripts. (Ref: forge#226 — 6-day silent deploy failure masked by `continue-on-error: true`)
191
+
192
+ **Steps**:
193
+ 1. Check the right branch — read from branch specified in issue body (`**Code branch**: \`{branch}\``) if present
194
+ 2. Read domain files — start with key files for the affected domain
195
+ 2.5. **Existing system search (conditional)**: If the issue describes a gap in a functional capability — content not being distributed, notifications not sending, jobs not running, data not being synced — MUST search for an existing automated system before proposing a new one. The issue body may name a specific tool or path (e.g., `reddit-bot/`, `marketing/`) — do NOT anchor on that path alone. Expand the search to all service layers:
196
+ ```bash
197
+ # For AlterLab: check Herald, worker, and scheduler for the capability
198
+ grep -rn "{capability_keyword}" services/herald/app/scheduler/ services/herald/app/content/ services/worker/
199
+ grep -rn "{capability_keyword}" services/ --include="*.py" -l | head -20
200
+ # Look for scheduled jobs, automated runners, existing integrations
201
+ grep -rn "scheduler\|celery\|cron\|nightly\|periodic" services/ --include="*.py" -l | head -10
202
+ ```
203
+ If an existing system is found that already handles the capability: the fix MUST route through the existing system (fix its config, env var, or gate) — NOT create a new parallel tool. Document the existing system in the investigation report and make it the centerpiece of the recommendation. This check is especially critical when the issue references a standalone tool directory (`reddit-bot/`, `scripts/`, `tools/`) — those directories often duplicate functionality that a service already owns. (Ref: forge#279 — investigator anchored on `reddit-bot/` from issue body, never checked `services/herald/app/scheduler/`, built parallel PRAW integration alongside Herald's existing automated crosspost scheduler)
204
+ 3. Verify claims — does the code actually have the problem described?
205
+ 3.5. **Type Invariant Verification (MANDATORY)**: Before declaring that a field, key, or parameter has a specific type (e.g. "content is always a dict", "status is always an int"), search for ALL code paths that write to that field across ALL services:
206
+ ```bash
207
+ grep -rn '"field_name"\s*:' services/ # Python dict key assignments
208
+ grep -rn 'result\["field_name"\]\s*=' services/ # Direct assignments
209
+ grep -rn '\.field_name\s*=' services/ # Attribute assignments
210
+ ```
211
+ If the field is written with different types in different code paths (e.g. dict in the standard path, string in the auth-gated path), document ALL variants. The fix must handle every variant — not just the one on the primary investigated code path. A type guard like `or {}` only protects against falsy values; a non-empty string is truthy and bypasses it.
212
+ 4. Git blame — trace when/why the relevant code was written
213
+ 4.5. **Rogue commit pre-state comparison (conditional)**: If the issue body references a specific commit as rogue, bad, or unintended (e.g., "rogue commit `abc1234`", "bad commit", "this was never intended"), MUST run `git show {commit}^:{file}` to see the file before that commit. Compare the pre-commit state against the current file. Any block present in the current file but absent in the pre-commit state was introduced by that commit chain and is a candidate for full reversion — not just partial editing. Report the delta (pre vs. current) in the investigation report. Do NOT assume surrounding code near a named import/bug is correct simply because the issue only named a specific sub-problem. (Ref: forge#278 — investigator confirmed the broken import but never ran `git show 18a3a2cf3^:batch.py`; the surrounding 50-line feature gate was also rogue and was preserved by the fix PR, causing a P1 access regression for all non-Scale users)
214
+ 5. Domain context discovery (narrow scope only, 1–5 files):
215
+ ```bash
216
+ git log --oneline --all -30 -- {affected_files} | grep -oP '#\d+' | sort -u
217
+ gh issue list -R {GH_REPO} --state closed --limit 8 --search "{function_name}"
218
+ ```
219
+ Keep only file/function-level overlap. Max 5 related issues.
220
+ 6. Determine root cause
221
+ 7. Identify affected files — full list of files that need changes
222
+ 7.5. **Sibling Pattern Sweep** *(conditional — when the bug is a condition, gated function call, or field presence check)*: After identifying the affected files, grep for the same pattern in sibling files within the same directory. The issue spec may name only the file where the error was first observed — but the same commit or PR that introduced the bug often applied it uniformly across related handlers.
223
+ ```bash
224
+ # Identify the broken condition or gated function call from the issue
225
+ # Then search sibling files in the same router/service directory
226
+ AFFECTED_DIR=$(dirname {PRIMARY_AFFECTED_FILE})
227
+ grep -rn "{broken_pattern}" "$AFFECTED_DIR" --include="*.py" | grep -v "{PRIMARY_AFFECTED_FILE}"
228
+ ```
229
+ **If identical patterns are found in files NOT listed in the issue spec**, output a scope-gap warning:
230
+ > **Scope-Gap Warning**: The issue spec lists `{PRIMARY_FILE}` but the same pattern exists in `{SIBLING_FILE}:{LINE}`. These were likely introduced together. Recommend widening scope to fix all callers in this PR, or creating follow-up issues for the other files before proceeding.
231
+
232
+ Do NOT silently exclude sibling matches. The appropriate output when sibling files have the same bug is to flag them explicitly — even if the issue spec's silence appears intentional. The fix-approach validation step (step 8) will confirm whether to widen scope or create follow-ups. <!-- Added: forge#383 -->
233
+ 8. Fix-approach validation — if issue proposes a fix, don't adopt as spec. Trace through middleware, auth, routing, config. Cross-domain: if fix in domain A interacts with domain B, read domain B's files too.
234
+
235
+ ### 1C: Post investigation comment
236
+
237
+ The comment MUST include `<!-- INVESTIGATION:COMPLETE -->` at the very end.
238
+
239
+ ```bash
240
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:INVESTIGATOR -->
241
+ ## Investigation Report
242
+
243
+ **Verdict**: {CONFIRMED|PARTIAL|INVALID}
244
+ **Confidence**: {HIGH|MEDIUM|LOW}
245
+ **Severity**: {CRITICAL|HIGH|MEDIUM|LOW}
246
+ **Task Type**: {Bug Fix|Feature|Refactor|Maintenance|Investigation}
247
+
248
+ ### What Was Claimed
249
+ {summary of what the issue describes}
250
+
251
+ ### What We Found
252
+ {what the code actually shows}
253
+
254
+ ### Root Cause
255
+ {specific root cause, with file:line references where applicable}
256
+
257
+ ### Affected Files
258
+ {numbered list of files that need changes}
259
+
260
+ ### Evidence
261
+ {specific findings — function names, line numbers, behavior observed}
262
+
263
+ ### Recommendation
264
+ {what to build/fix, concrete and actionable}
265
+
266
+ ### Related Issues
267
+ {if any found via domain context discovery, max 5}
268
+
269
+ ### Decomposition Assessment
270
+ **{YES|NO}** — {reason}
271
+ {if YES: proposed sub-issues with titles and dependencies}
272
+
273
+ <!-- INVESTIGATION:COMPLETE -->"
274
+ ```
275
+
276
+ ### 1D: Update labels & route
277
+
278
+ **CONFIRMED or PARTIAL with decompose: NO**:
279
+ ```bash
280
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "workflow:ready-to-build" --remove-label "workflow:investigating"
281
+ ```
282
+ <!-- FORGE:PHASE_COMPLETE — Investigation routed to build. See Universal Phase Dispatcher: next phase is Phase 3. Not terminal — continue immediately. -->
283
+ → Continue to Phase 3.
284
+
285
+ **CONFIRMED or PARTIAL with decompose: YES**:
286
+ ```bash
287
+ gh issue edit {NUMBER} {GH_FLAG} --remove-label "workflow:investigating"
288
+ ```
289
+ <!-- FORGE:PHASE_COMPLETE — Investigation routed to decomposition. See Universal Phase Dispatcher: next phase is Phase 2. Not terminal — continue immediately. -->
290
+ → Continue to Phase 2 (Decomposition).
291
+
292
+ **INVALID**:
293
+ ```bash
294
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "workflow:invalid" --remove-label "workflow:investigating"
295
+ gh issue close {NUMBER} {GH_FLAG} --comment "Closing as invalid: {reason from investigation}"
296
+ ```
297
+ → STOP.
298
+
299
+ ---
300
+
301
+ ## Phase 2: Decomposition (Conditional)
302
+
303
+ **Skip if**: Already decomposed, is a sub-issue, or investigation says decompose: NO.
304
+
305
+ **Trigger if**: Investigation assessment says YES — 2+ signals match (at least 1 Strong): multiple task types, 3+ service groups, phased requirements, 6+ files across directories.
306
+
307
+ ### 2A: Load state
308
+ ```bash
309
+ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
310
+ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
311
+ --jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .body'
312
+ ```
313
+
314
+ **MANDATORY — Owner override detection**: After reading the investigation comment, read ALL comments on the issue to check for owner override signals:
315
+ ```bash
316
+ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
317
+ --jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR")) | not) | {author: .user.login, body: .body}'
318
+ ```
319
+
320
+ Scan non-agent comments for override signals — phrases like "do not", "do NOT", "instead", "revert", "remove this", "override", "actually", or explicit disagreement with the investigation's recommendation. If an override comment is found from a repo owner or admin (not a bot):
321
+
322
+ 1. **Document the override**: Note which direction the owner is steering (e.g., "remove the feature" vs. investigation's "keep with warnings")
323
+ 2. **Re-derive sub-issue scopes**: Derive sub-issue titles, bodies, and file scope from the override direction — NOT from the original investigation recommendation. The investigation's Decomposition Assessment may list sub-issues that are now stale or contradictory with the override.
324
+ 3. **If override makes a sub-issue obsolete**: Skip creating it. Note the skip reason in the decomposition comment.
325
+ 4. **If override changes the sequencing dependency**: Revise the execution order so that the override's primary action (e.g., "strip the feature") completes before any downstream doc/SDK sub-issues are built against it.
326
+
327
+ **Why this matters**: Sub-issues scoped before an override are built against a stale premise. A docs sub-issue scoped as "neutralize liability language" becomes incorrect if the upstream schema sub-issue will fully remove the feature — the docs sub-issue should instead be "remove all references to the deleted feature." Building both in parallel against the pre-override scope produces contradictory staging state.
328
+
329
+ ### 2B: Design sub-issues
330
+ From the Decomposition Assessment (adjusted for any owner override detected in 2A), extract sub-issue titles (dependency order — independent first), dependencies, and descriptions.
331
+
332
+ For each sub-issue:
333
+ - **Title**: from investigation report
334
+ - **Body**: brief scope + `**Parent**: #{NUMBER}` + dependency note
335
+ - **Labels**: inherit priority label from parent; do NOT copy workflow labels
336
+ - **Milestone**: same as parent
337
+
338
+ ### 2C: Create sub-issues
339
+ ```bash
340
+ gh issue create {GH_FLAG} \
341
+ --title "{fix|feat|refactor}: {SUB_ISSUE_TITLE}" \
342
+ --body "$(cat <<'SUB_BODY_EOF'
343
+ ## Problem
344
+
345
+ {1-3 sentences: what this sub-issue specifically addresses. What's wrong or what needs to be built.}
346
+
347
+ ## Root Cause (if known)
348
+
349
+ {Specific root cause for this sub-task. Reference the parent investigation findings where applicable. If unknown: "Root cause unknown — investigation needed."}
350
+
351
+ ## Affected Files
352
+
353
+ Files that need changes:
354
+ 1. `{filepath}` — {what needs to change}
355
+ 2. `{filepath}` — {what needs to change}
356
+
357
+ ## Acceptance Criteria
358
+
359
+ - [ ] {Specific, testable criterion}
360
+ - [ ] {Specific, testable criterion}
361
+ - [ ] No regression in {related feature}
362
+
363
+ ## Context
364
+
365
+ **Parent**: #{NUMBER}
366
+ {If depends on another sub-issue: "**Depends on**: #{SUB_ISSUE_N} — {reason}"}
367
+ SUB_BODY_EOF
368
+ )" \
369
+ --label "{PRIORITY_LABEL}" \
370
+ --milestone "{MILESTONE_TITLE}"
371
+ ```
372
+
373
+ ### 2D: Update parent issue body
374
+ Add tracker checklist with all sub-issues in dependency order.
375
+
376
+ ### 2E: Post decomposition comment
377
+ ```bash
378
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:DECOMPOSED -->
379
+ ## Decomposition Complete
380
+
381
+ ### Sub-Issues Created
382
+ - #{SUB_NUMBER}: {TITLE}
383
+
384
+ ### Decomposition Rationale
385
+ {brief summary}
386
+
387
+ <!-- FORGE:DECOMPOSED:COMPLETE -->"
388
+ ```
389
+
390
+ ### 2F: Update labels
391
+ ```bash
392
+ gh issue edit {NUMBER} {GH_FLAG} \
393
+ --add-label "workflow:decomposed" \
394
+ --remove-label "workflow:ready-to-build,workflow:building,workflow:investigating" 2>/dev/null || true
395
+ ```
396
+
397
+ → STOP. Each sub-issue runs its own `/work-on`.
398
+
399
+ ---
400
+
401
+ ## Phase 3: Build
402
+
403
+ <!-- FORGE:PHASE_COMPLETE — Entering Phase 3 (Build). See Universal Phase Dispatcher: sub-phases 3A–3M execute in sequence. No sub-phase completion is terminal. -->
404
+
405
+ **Skip if**: `<!-- FORGE:BUILDER -->` or `<!-- ALTERLAB:BUILDER -->` exists.
406
+
407
+ **CRITICAL: You MUST execute ALL sub-phases 3A–3M in order. Do NOT skip phases 3C.5 (context) or 3C.6 (architect) — they post mandatory `FORGE:CONTEXT` and `FORGE:ARCHITECT` comments that Phase 3F reads as its primary input. Skipping them degrades build quality and causes review findings. After each sub-phase, continue to the next — no sub-phase is terminal.**
408
+
409
+ ### 3A: Re-read state from GitHub (MANDATORY)
410
+ ```bash
411
+ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state,milestone
412
+
413
+ # Read investigation report
414
+ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
415
+ --jq '.[] | select(.body | (contains("FORGE:INVESTIGATOR") or contains("ALTERLAB:INVESTIGATOR"))) | .body'
416
+
417
+ # Check if build already completed
418
+ gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
419
+ --jq '.[] | select(.body | (contains("FORGE:BUILDER") or contains("ALTERLAB:BUILDER"))) | .body'
420
+ ```
421
+
422
+ If no investigation comment with `<!-- INVESTIGATION:COMPLETE -->` → STOP (investigation not complete).
423
+
424
+ Extract from investigation: affected files, root cause, recommendation, task type.
425
+
426
+ ### 3B: Classify task type
427
+
428
+ | Signal | Type | Approach |
429
+ |--------|------|----------|
430
+ | Title: "Investigate"/"Audit"/"Research" | Investigation | Produce issues as deliverables |
431
+ | UI/UX, feature + web/ files | UI/UX | `frontend-design` skill |
432
+ | Feature + services/ | Backend Feature | Implement directly |
433
+ | Feature + both | Full-Stack | Backend first, then frontend-design |
434
+ | Bug + web/ | Frontend Fix | Direct |
435
+ | Bug + services/ | Backend Fix | Direct |
436
+ | Refactor/docs | Maintenance | Direct |
437
+
438
+ **Investigation tasks**: Research deeply, create GitHub issues for each finding, post deliverables comment, close issue, skip to Phase 7.
439
+
440
+ ### 3C: Builder Contract (MANDATORY)
441
+
442
+ Post `<!-- FORGE:CONTRACT -->` comment with: task type, proposed approach, deliverables table (file/change/why), acceptance criteria, quality considerations (auth model, new env vars, SQL safety, security surface), out of scope, alternatives.
443
+
444
+ ```bash
445
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:CONTRACT -->
446
+ ## Builder Contract
447
+
448
+ **Task type**: {TASK_TYPE}
449
+
450
+ ### Proposed Approach
451
+ {BRIEF_APPROACH_DESCRIPTION}
452
+
453
+ ### Deliverables
454
+ | File | Change | Why |
455
+ |------|--------|-----|
456
+ {DELIVERABLES_ROWS}
457
+
458
+ ### Acceptance Criteria
459
+ {ACCEPTANCE_CRITERIA_CHECKLIST}
460
+
461
+ ### Quality Considerations
462
+ {AUTH_MODEL_NEW_ENV_VARS_SQL_SAFETY_SECURITY_SURFACE}
463
+
464
+ ### Out of Scope
465
+ {OUT_OF_SCOPE_ITEMS}"
466
+ ```
467
+
468
+ Contract must be grounded in the investigation report. Adversarially validate proposed fixes against adjacent system layers.
469
+
470
+ ### 3C.5: Context Gathering (MANDATORY — max 2 minutes)
471
+
472
+ **This phase is NOT optional.** Always run it regardless of issue size or complexity. Do NOT skip it — trivial cases return quickly on their own.
473
+
474
+ Surface institutional memory before writing code. Extract function names from the contract deliverables table:
475
+
476
+ ```bash
477
+ FUNCTION_NAMES=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
478
+ --jq '.[] | select(.body | contains("FORGE:CONTRACT")) | .body' \
479
+ | awk '/^### Deliverables/{p=1; next} /^### /{p=0} p' \
480
+ | grep -oP '`[A-Za-z_][A-Za-z0-9_]*`' \
481
+ | tr -d '`' | sort -u | tr '\n' ' ' | xargs)
482
+ ```
483
+
484
+ **The ONLY acceptable skip conditions** (all must be true): Issue is a 1-file config/docs edit with no code logic AND affected files have zero git history. In all other cases, run context gathering.
485
+
486
+ Run these queries (20s timeout each, 2 min total budget):
487
+
488
+ **C1: Past Review Findings on These Files**
489
+ ```bash
490
+ for file in {AFFECTED_FILES}; do
491
+ basename=$(basename "$file" .py)
492
+ gh issue list -R {GH_REPO} --state closed --label "review-finding" \
493
+ --search "$basename" --limit 10 \
494
+ --json number,title,body \
495
+ --jq '.[] | {number, title,
496
+ pattern: (.body | capture("\\*\\*Pattern\\*\\*: *(?<p>[^\\n]+)").p // null),
497
+ prevention: (.body | capture("\\*\\*Prevention\\*\\*: *(?<v>[^\\n]+)").v // null),
498
+ root_cause: (.body | capture("\\*\\*Root cause\\*\\*: *(?<rc>[^\\n]+)").rc // (.body | capture("Root Cause[^\\n]*\\n(?<rc>[^\\n]+)").rc // "see body"))
499
+ }'
500
+ done
501
+ ```
502
+
503
+ **C2: Past Bugs in the Same Module**
504
+ ```bash
505
+ git log --oneline -30 -- {AFFECTED_FILES} | grep -oP '#\d+' | sort -u | head -8
506
+ # For each issue: fetch title + root cause, keep only bug/fix/review-finding labeled. Max 5.
507
+ ```
508
+
509
+ **C3: Related Code Paths** (callers/importers of FUNCTION_NAMES)
510
+ ```bash
511
+ for fn in {FUNCTION_NAMES}; do
512
+ grep -r "$fn" {WORKTREE_PATH} --include="*.py" -l | grep -v __pycache__ | head -5
513
+ grep -r "$fn" {WORKTREE_PATH}/web/src --include="*.ts" --include="*.tsx" -l 2>/dev/null | head -5
514
+ done
515
+ ```
516
+
517
+ **C4: Successful Similar Implementations**
518
+ ```bash
519
+ gh pr list -R {GH_REPO} --state merged --search "{domain_keywords}" --limit 5 \
520
+ --json number,title,files --jq '.[] | {number, title, file_count: (.files | length)}'
521
+ ```
522
+
523
+ Post `<!-- FORGE:CONTEXT -->` comment with findings:
524
+ ```bash
525
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:CONTEXT -->
526
+ ## Implementation Context for #{NUMBER}
527
+
528
+ ### Known Pitfalls for This Area
529
+ {prevention rules from past review-findings}
530
+
531
+ ### Historical Findings on These Files
532
+ {past review-finding issues}
533
+
534
+ ### Past Bugs in This Module
535
+ {closed bug issues from git log mining}
536
+
537
+ ### Related Code Paths (must stay consistent)
538
+ {files that import/call changed functions}
539
+
540
+ ### Patterns That Cause Bugs Here
541
+ {recurring bug types synthesized from C1+C2}
542
+
543
+ ### Successful Similar Implementations
544
+ {positive patterns from C4}
545
+
546
+ <!-- FORGE:CONTEXT:COMPLETE -->"
547
+ ```
548
+
549
+ If total time exceeds 2 minutes, post partial results with `<!-- FORGE:CONTEXT:PARTIAL -->`.
550
+
551
+ ### 3C.6: Architecture Plan (MANDATORY)
552
+
553
+ **This phase is NOT optional.** Always run it regardless of issue size or complexity. Even a 1-file fix benefits from cross-path consistency checks. Do NOT invent skip heuristics — the phase handles simple changes gracefully and returns quickly.
554
+
555
+ Trace ALL affected code paths before writing code.
556
+
557
+ **The ONLY acceptable skip conditions** (all must be true): Issue creates ONLY new files with no existing callers AND title starts with "docs:" or "chore:".
558
+
559
+ **A1: Read Entry Points** — For each affected file: identify the primary function, all callers (grep), and sibling implementations. Read 3–5 most relevant files, max 8 total.
560
+
561
+ **A1.5: Route-Tree Classification for Shared Components** *(conditional — skip if no files under `components/` are affected, except `components/ui/primitives/`)* — When a change adds a new hook call or context dependency to a shared component, classify ALL call sites found in A1 by route context:
562
+ 1. **Authenticated routes**: Callers under `app/dashboard/`, `app/(authenticated)/`, or any layout that wraps children with an auth provider (e.g., `UserProvider`, `SessionProvider`).
563
+ 2. **Public routes**: Callers under `app/(public)/`, `app/playground/`, `app/(marketing)/`, or any layout without the relevant provider.
564
+ 3. **If both categories have callers AND the new hook throws when its provider is absent**: add an explicit implementation step to either (a) guard the hook call with a null-context check, (b) make the hook return a safe default when called outside its provider, or (c) remove the hook from the shared component and move it to the authenticated-route-only caller. Document the split in the FORGE:ARCHITECT affected paths table. Do NOT leave a shared component that crashes public routes to be discovered by the FE review agent. <!-- Added: forge#381 -->
565
+
566
+ **A2: Trace Data Flow** — From each entry point: Entry → Transform → Persist/Relay → Exit. Check if the proposed change needs to propagate to each step. **For every field or key read by the changed code, enumerate ALL write paths first** — search across all services for assignments to that field. If multiple code paths write different types to the same field (e.g. dict in the standard path, string in the auth-gated path), the implementation must handle all variants. Do not assume the type you see on the primary code path is the only possible type.
567
+
568
+ **A2.1: Runtime UID × Volume Ownership Check** *(conditional — skip if no Dockerfile or entrypoint is affected)* — When the PR changes the container's runtime user (Dockerfile `USER` directive, `su-exec`, `gosu`, `setuid`), the architect MUST trace the full write-path chain before writing the implementation plan:
569
+ 1. **Enumerate volume mounts**: Read all `docker-compose*.yml` files for the affected service. List every named volume and its container mount point (e.g. `storage_shared:/app/storage`). Docker named volumes are created as root-owned by default — any UID change without a corresponding ownership fix will silently break writes.
570
+ 2. **Grep for filesystem writes**: Search the affected service's codebase for all filesystem write operations (`mkdir`, `Path.mkdir`, `write_bytes`, `open(`, `os.makedirs`, `shutil.copy`, `shutil.move`). For each write operation, identify the target path.
571
+ 3. **Cross-reference**: For each write path that falls under a named volume mount point, add an explicit implementation step to ensure ownership compatibility before the privilege drop — typically `chown -R <user>:<group> <mount_point>` in the entrypoint script before the `exec su-exec` / `exec gosu` call.
572
+ 4. **Add to FORGE:ARCHITECT deliverables table**: List the entrypoint or docker-compose change as an explicit deliverable. Do NOT leave volume ownership to be discovered by the builder or reviewer. <!-- Added: forge#323 -->
573
+
574
+ **A2.2: Gate-Condition Caller Sweep** *(conditional — when the fix changes a gate condition that guards a function call or restricts a field)*: Before finalizing the affected-paths table, grep for all callers of the gated function across sibling files in the same service directory. For each caller, verify that the gate condition applied at the call site is semantically correct.
575
+ ```bash
576
+ # Identify the gated function from the issue/contract
577
+ GATED_FUNCTION="{function_being_called_inside_the_gate}"
578
+ SERVICE_DIR=$(dirname {PRIMARY_AFFECTED_FILE})
579
+ # Find all call sites
580
+ grep -rn "$GATED_FUNCTION" "$SERVICE_DIR" --include="*.py" | grep -v "#"
581
+ ```
582
+ For each call site found: read the surrounding gate condition (±10 lines). If the condition includes fields that do NOT require the gated resource (e.g., `extraction_schema` gated behind an LLM key check when `extraction_schema` is processed without an LLM), add that caller file to the FORGE:ARCHITECT affected-paths table with a note explaining the incorrect gate condition.
583
+
584
+ **Do NOT** omit sibling callers from the affected-paths table simply because they were not listed in the issue spec. The architect's scope is determined by code correctness, not by the issue spec's file list. A gate-condition bug that exists identically in 3 router files must be fixed in all 3 — even if the issue only named 1. <!-- Added: forge#383 -->
585
+
586
+ **A2.5: Pipeline Phase-Dependency Check** *(Forge pipeline changes only — skip if no `commands/*.md` file is affected)* — Identify artefact contracts the changed file produces (comment markers, structured output blocks, Skill() invocation signatures, label transitions). Find downstream pipeline phases that consume those artefacts. Flag any invocation signature change and verify all callers. Emit a checklist of downstream phases that must be updated — appended to the Consistency Checks block in the FORGE:ARCHITECT comment.
587
+
588
+ **A3: Consistency Rules** — Identify invariants all paths must satisfy: null handling, validation, logging, error response shape, auth checks.
589
+
590
+ **A4: Sequence Implementation** — Order: schema/type changes first → core logic → secondary paths → tests → config/env. Files imported by others change before importers. Higher risk first.
591
+
592
+ **A5: Risk Assessment** — Rate each non-obvious interaction: HIGH/MEDIUM/LOW with mitigation.
593
+
594
+ Post `<!-- FORGE:ARCHITECT -->` comment:
595
+ ```bash
596
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ARCHITECT -->
597
+ ## Implementation Plan for #{NUMBER}
598
+
599
+ ### Affected Paths (ALL must be updated)
600
+ | # | File | Function/Class | Change Required | Why |
601
+ |---|------|----------------|-----------------|-----|
602
+ {rows}
603
+
604
+ ### Implementation Order
605
+ 1. {FIRST_CHANGE} — {WHY_FIRST}
606
+ 2. {SECOND_CHANGE} — {WHY_SECOND}
607
+
608
+ ### Consistency Checks
609
+ - [ ] {INVARIANT_1}
610
+ - [ ] {INVARIANT_2}
611
+
612
+ ### Risk Assessment
613
+ | Risk | Severity | Mitigation |
614
+ |------|----------|------------|
615
+ {rows}
616
+
617
+ ### Files to Read Before Coding
618
+ - \`{FILE}\` — {WHY_READ_IT}
619
+
620
+ <!-- FORGE:ARCHITECT:COMPLETE -->"
621
+ ```
622
+
623
+ If budget exceeded (3 min), use `<!-- FORGE:ARCHITECT:PARTIAL -->`.
624
+
625
+ ### 3D: Set building label
626
+ ```bash
627
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "workflow:building" --remove-label "workflow:ready-to-build,workflow:investigating"
628
+ ```
629
+
630
+ ### 3E: Create worktree
631
+
632
+ Branch slug from title (lowercase, hyphenated, max 40 chars). Prefix: `fix/` (bugs) or `feat/` (features).
633
+
634
+ **Determine source branch**:
635
+ - Review-finding → parse `**Code branch**: \`{branch}\`` from issue body; branch from `origin/{branch}`
636
+ - **Milestone review-finding hybrid lane** (Code branch matches `milestone/*`): High-risk lane. NEVER use `git merge` to resolve conflicts — use `git rebase` or `git cherry-pick` only. If conflicts can't be resolved without merge, post comment, add `needs-human`, STOP.
637
+ - Feature lane (has milestone) → branch from `origin/{PR_BASE}`
638
+ - Fast lane (no milestone) → branch from `origin/{STAGING_BRANCH}`
639
+
640
+ ```bash
641
+ cd {REPO_PATH}
642
+ git fetch origin
643
+ BRANCH="fix/{slug}-{NUMBER}"
644
+ WORKTREE_PATH="{REPO_PATH}/.claude/worktrees/{BRANCH_SLUG}"
645
+ git worktree add {WORKTREE_PATH} -b {BRANCH} origin/{SOURCE_BRANCH}
646
+ ```
647
+
648
+ If worktree already exists: verify correct branch, reuse or remove and recreate.
649
+
650
+ ### 3F: Implement
651
+
652
+ **Load context chain** — Read these from GitHub BEFORE writing code:
653
+ 1. `FORGE:ARCHITECT` comment (primary implementation guide — if present, follow its ordered list exactly)
654
+ 2. `FORGE:INVESTIGATOR` comment (root cause, affected files)
655
+ 3. `FORGE:CONTRACT` comment (deliverables, acceptance criteria)
656
+ 4. `FORGE:CONTEXT` comment (pitfalls, related paths, past bugs)
657
+
658
+ If `FORGE:ARCHITECT` is absent, fall back to investigation report + contract.
659
+
660
+ **Route by task type**: Bug Fix → implement directly. Feature (backend) → implement directly. Feature (UI/UX) → invoke `frontend-design` skill. Full-Stack → backend first, then frontend-design. Investigation → create issues, skip to Phase 7.
661
+
662
+ **Implementation rules**:
663
+ - Work in `{WORKTREE_PATH}` — all file reads, writes, git ops happen here
664
+ - Read the current file before modifying it — never assume its state
665
+ - Read related files identified in context briefing before touching changed code
666
+ - Follow architect plan's implementation order exactly (when present)
667
+ - For each acceptance criterion: implement it, then verify it's met
668
+ - Do NOT add unrequested scope — contract out-of-scope stays out
669
+ - **Library callback verification**: When writing a lambda/callable passed to a library parameter, MUST verify expected calling convention BEFORE writing it. Check library's default value, documentation, or source code. Wrong arity causes runtime `TypeError` invisible to static analysis. (Ref: PR #14391 — `lambda _: ""` passed where SQLAlchemy expects 0 args)
670
+ - **Cross-lane import guard**: Before adding any `import` or `from X import Y` statement for a service-internal module (`app.*`), verify the module exists on the PR's base branch — NOT just on your local disk or a milestone branch. Run `git show origin/{base_branch}:{module_path}.py` (replacing dots with slashes) to confirm. If the module only exists on a milestone branch, do NOT import it — find an alternative implementation or make the import conditional with a `try/except ImportError` fallback. A milestone-only import on a fast-lane PR will crash production on every request with `ModuleNotFoundError`. (Ref: forge#277 — builder imported `app.billing.subscriptions` from `milestone/subscription-model`, which doesn't exist on `staging`/`main`, causing P1 production crash for paying customer)
671
+ - **Deliverable-type consistency check**: Before committing, compare the actual output against the CONTRACT's deliverable list. If the CONTRACT explicitly states "no code changes required", "docs only", or "configuration update only" AND the diff introduces new executable files (`.py`, `.js`, `.ts`, `.sh` — not test, config, or documentation files), STOP. Do NOT commit. Re-read the CONTRACT, the investigation recommendation, and the ARCHITECT plan. If all three agree that code is needed, update the CONTRACT comment to reflect the new deliverable type before proceeding. If only the builder decided to add code without contract support, discard the code change and implement the contracted deliverable instead. <!-- Added: forge#279 -->
672
+ - **Pipeline check documentation — generalization rule**: When writing or updating pipeline check documentation (in `commands/*.md`), describe the **bug class**, not a specific incident. Do NOT embed: PR numbers, issue numbers, run IDs, timestamps, function names, dollar amounts, or multi-sentence incident timelines in check prose or `**Evidence**:` blocks. One brief HTML comment `<!-- Added: forge#NNN -->` is acceptable per check for traceability. `**Evidence**:` blocks must describe the vulnerability pattern (what the class of bug looks like, why it's dangerous) — not narrate a single historical occurrence. CHANGELOG entries may reference originating issues; command prompt text must not.
673
+ - **Endpoint response contract consumer tracing**: When changing an endpoint's response body shape or status field values (e.g., changing `"status": "healthy"` to `"status": "ok"`, renaming response keys, removing fields), grep the full repo for ALL consumers of that response body before committing. Consumers are not limited to the service being changed — they include deploy scripts, CI health checks, monitoring configs, docker-compose healthcheck definitions, Traefik probes, and any script that parses or pattern-matches on the response body. Run: `grep -rn "{old_value}\|{endpoint_path}" scripts/ infra/ .github/ docker-compose*.yml traefik/ 2>/dev/null`. All consumers whose behavior depends on the old response format MUST be updated in the same PR — a response contract change that updates only one consumer while leaving others on the old format is a deploy-time breakage. <!-- Added: forge#321 -->
674
+ - If contract is wrong (file doesn't exist, function has different signature): STOP, post comment, add `needs-human`, EXIT
675
+
676
+ ### 3F.5: Env/Config Completeness Check
677
+
678
+ Run BEFORE committing. Read-only scan of working changes.
679
+
680
+ **Trigger**: Run whenever diff introduces env vars, touches infra/deploy configs, or adds literal IPs.
681
+
682
+ **Check 1 — New env var sync**: Scan for `os.getenv`/`process.env.` references. For each, verify present in `.env.example`, `ENV_VARS.md`, `env_validation.py`. Add if missing.
683
+
684
+ **Check 2 — Deploy/infra restart risk**: If docker-compose/deploy/infra files changed, scan for restart-inducing changes. Annotate commit with `[restart: <service>]`.
685
+
686
+ **Check 3 — Hardcoded IPs and credentials**: Scan for bare IPv4 literals and credential-like assignments. HARD BLOCKER — replace with env vars before staging.
687
+
688
+ **Check 4 — SDK/API Literal sync advisory** (trigger: diff contains `Literal[` in a schema file):
689
+ ```bash
690
+ # Detect Literal type changes in API schema files
691
+ cd {WORKTREE_PATH}
692
+ LITERAL_CHANGES=$(git diff HEAD -- | grep -E '^\+.*Literal\[' | grep -v '^\+\+\+')
693
+ if [ -n "$LITERAL_CHANGES" ]; then
694
+ echo "SDK SYNC ADVISORY: Literal type changed in schema."
695
+ echo "Changed Literal lines:"
696
+ echo "$LITERAL_CHANGES"
697
+ echo ""
698
+ echo "ACTION REQUIRED — verify SDK method/type lists match new API schema:"
699
+ echo " - sdk/python/*/client.py: check _valid_methods or equivalent list"
700
+ echo " - sdk/node/src/index.ts: check JSDoc @param Literal type annotation"
701
+ echo " - web/public/openapi*.json: check enum arrays for affected field"
702
+ echo " - web/public/openapi-versions/*.json: check all versioned specs"
703
+ echo ""
704
+ echo "Inconsistency example: API schema narrows Literal['GET','POST','PUT','PATCH','DELETE']"
705
+ echo "to Literal['GET','POST'] but SDK JSDoc still lists all 5 methods — API returns 422"
706
+ echo "for callers following SDK docs. This produces silent user-facing failures."
707
+ fi
708
+ ```
709
+
710
+ This advisory is informational — it does NOT block the commit. But the implementer MUST check each listed file and add to the implementation scope if any SDK/spec file still documents the removed/changed Literal values. If SDK files need changes, add them to the current PR rather than leaving the inconsistency for review to catch.
711
+
712
+ ### 3G: Quality Gate
713
+
714
+ Skip for 1-file config/docs edits.
715
+
716
+ ```
717
+ iteration = 0
718
+ max_iterations = 3
719
+
720
+ while iteration < max_iterations:
721
+ iteration += 1
722
+ Skill("quality-gate", args="{CHANGED_FILES} --worktree {WORKTREE_PATH}")
723
+ if result == "QUALITY GATE: PASS":
724
+ GATE_PASSED = true
725
+ break
726
+ else:
727
+ Fix each HIGH and MEDIUM finding in {WORKTREE_PATH}
728
+ Re-stage fixes
729
+
730
+ if iteration == max_iterations AND not PASS:
731
+ Post "Quality Gate Failed After 3 Iterations" comment
732
+ Add needs-human label → STOP
733
+ ```
734
+
735
+ <!-- FORGE:PHASE_COMPLETE — Quality gate done. See Universal Phase Dispatcher: next sub-phase is 3H. Not terminal — continue immediately. -->
736
+
737
+ **After quality gate completes (PASS or fixes applied): proceed to the next sub-phase per the Universal Phase Dispatcher. Quality gate is an intermediate check — "PASS" means the code is clean, NOT that the build is done.**
738
+
739
+ ### 3H: Format and verify
740
+
741
+ **Python**:
742
+ ```bash
743
+ cd {WORKTREE_PATH}
744
+ black {PYTHON_FILES} && isort {PYTHON_FILES} && python -m py_compile {PYTHON_FILES}
745
+ ```
746
+ `py_compile` failures are BLOCKING.
747
+
748
+ **TypeScript (AlterLab)**:
749
+ ```bash
750
+ cd {WORKTREE_PATH}
751
+ prettier --write {TS_FILES} && tsc --noEmit
752
+ ```
753
+ `tsc --noEmit` failures are BLOCKING.
754
+
755
+ **TypeScript (satellite repos)**:
756
+ ```bash
757
+ cd {WORKTREE_PATH}
758
+ npm run build && prettier --write {TS_FILES}
759
+ ```
760
+
761
+ ### 3I: Frontend proxy wiring check (MANDATORY)
762
+
763
+ Skip if no TS/TSX files changed.
764
+
765
+ All client-side `fetch`/`useSWR`/`apiFetch`/`axios` MUST use `/api/...` proxy routes, NEVER `/api/v1/...` or hardcoded host:port. Scan and fix violations.
766
+
767
+ ### 3I.5: Database Configuration Change Advisory
768
+
769
+ Skip if no changed Python files contain DB engine/session/pool patterns.
770
+
771
+ ```bash
772
+ cd {WORKTREE_PATH}
773
+ for f in $(echo {CHANGED_FILES} | tr ' ' '\n' | grep -E '\.py$'); do
774
+ grep -qE "create_async_engine|AsyncSession|connect_args|pool_size|prepared_statement|engine_from_config|sessionmaker" "$f" 2>/dev/null && \
775
+ echo "DB CONFIG CHANGE DETECTED in: $f"
776
+ done
777
+ ```
778
+
779
+ Advisory only — does not block build. Check for lambda/callable in connect_args (the exact bug class from PR #14391).
780
+
781
+ ### 3J: Deployment completeness check (MANDATORY)
782
+
783
+ Skip if no new env vars introduced.
784
+
785
+ For each new env var, verify present in ALL required locations:
786
+
787
+ | Location | Required for |
788
+ |----------|-------------|
789
+ | `.env.example` | All new vars |
790
+ | `infra/secrets/prod.enc.yaml` (SOPS) | Production secrets |
791
+ | `infra/decrypt-secrets.sh` ENV_MAPPING | All vars in deploy chain |
792
+ | `app/env_validation.py` | API service vars |
793
+ | `docker-compose.prod.yml` | Vars needing explicit injection |
794
+
795
+ Deploy chain: SOPS → `decrypt-secrets.sh` (ENV_MAPPING) → `.env.secrets` → `merge-env-secrets.sh` → `.env.production` → docker-compose `env_file`.
796
+
797
+ **Operator-set var classification** *(trigger: new env var is NOT present in `infra/secrets/prod.enc.yaml`)*: <!-- Added: forge#380 -->
798
+
799
+ Some env vars are operator-set (non-secret, not sourced from SOPS) — they must be manually added to `.env.production` on the production server. The SOPS deploy chain does not carry them. When a new env var has no entry in `prod.enc.yaml`, classify it as operator-set and add a **HARD BLOCKER** item to the Testing Checklist:
800
+
801
+ ```
802
+ - [ ] HARD BLOCKER: Add {VAR_NAME} to .env.production on the production server.
803
+ This var is operator-set (not in SOPS) — it does NOT flow through the automated
804
+ deploy chain. It must be added manually before or after deploy.
805
+ Verify with: docker exec {service}-blue env | grep {VAR_NAME}
806
+ ```
807
+
808
+ **`env_file` re-read warning** *(trigger: any new env var added to `.env.production` path)*:
809
+
810
+ > **Docker `env_file` re-read behavior**: New entries in `.env.production` are only read when a container is **recreated** (e.g., `docker compose up --force-recreate`). A plain `docker restart` restarts the existing container with its frozen env — new `env_file` entries are silently absent. The standard deploy workflow uses `--force-recreate` and handles this correctly. If any out-of-band restart is used, new env vars will not take effect.
811
+
812
+ Add this warning to the Testing Checklist whenever a new env var is introduced (whether secret or operator-set).
813
+
814
+ **Post-deploy in-container verification** *(trigger: any new env var)*:
815
+
816
+ Add the following to the Testing Checklist so the deployer can confirm delivery after deploy:
817
+
818
+ ```bash
819
+ # Verify env var reached the running container (run post-deploy)
820
+ docker exec {service}-blue env | grep {VAR_NAME}
821
+ # Expected: {VAR_NAME}={value}
822
+ # If blank: container was not recreated — run: docker compose up --no-deps --force-recreate {service}
823
+ ```
824
+
825
+ ### 3K: Commit
826
+
827
+ Stage all changes and commit:
828
+
829
+ ```bash
830
+ cd {WORKTREE_PATH}
831
+ git add -u
832
+ git commit -m "fix({SCOPE}): {description} (#{NUMBER})"
833
+ ```
834
+
835
+ Conventional prefix: `fix`/`feat`/`refactor`/`docs`. Reference `#{NUMBER}` in message.
836
+
837
+ **Post-commit ancestry audit (MANDATORY)**:
838
+ ```bash
839
+ cd {WORKTREE_PATH}
840
+ if git ls-remote --exit-code origin {PR_BASE} >/dev/null 2>&1; then
841
+ MERGE_COMMITS=$(git log --merges HEAD ^origin/{PR_BASE} 2>/dev/null)
842
+ if [ -n "$MERGE_COMMITS" ]; then
843
+ # Post ancestry audit failure comment, add needs-human → STOP
844
+ fi
845
+ fi
846
+ ```
847
+
848
+ ### 3L: Update issue body (MANDATORY)
849
+ Check off completed items, mark phases complete, add PR references.
850
+
851
+ ### 3M: Post implementation comment
852
+ ```bash
853
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:BUILDER -->
854
+ ## Implementation Complete
855
+
856
+ **Branch**: \`{BRANCH}\`
857
+ **Commits**: {COMMIT_SHA(S)}
858
+ **Files changed**: {COUNT}
859
+
860
+ ### Approach
861
+ {what was built, key decisions}
862
+
863
+ ### Changes
864
+ {bulleted list of file changes}
865
+
866
+ ### Acceptance Criteria Status
867
+ {checklist from contract, marked pass/fail}
868
+
869
+ ### Testing Checklist
870
+ - [ ] {scenario 1}
871
+ - [ ] {scenario 2}
872
+
873
+ <!-- FORGE:BUILDER:COMPLETE -->"
874
+ ```
875
+
876
+ ---
877
+
878
+ ## Phase 4: PR Creation
879
+
880
+ ### 4A: Pre-push ancestry guard
881
+
882
+ ```bash
883
+ cd {WORKTREE_PATH}
884
+ if git ls-remote --exit-code origin {PR_BASE} >/dev/null 2>&1; then
885
+ MERGE_COMMITS=$(git log --merges {BRANCH} ^origin/{PR_BASE} 2>/dev/null)
886
+ if [ -n "$MERGE_COMMITS" ]; then
887
+ # Post ancestry guard failure, add needs-human → STOP
888
+ fi
889
+ fi
890
+ ```
891
+
892
+ ### 4B: Push branch
893
+ ```bash
894
+ cd {WORKTREE_PATH} && git push -u origin {BRANCH}
895
+ ```
896
+ If fails: try `--force-with-lease`. If still fails: post comment, add `needs-human`, STOP.
897
+
898
+ ### 4C: Determine PR target
899
+ No milestone → `staging`. Has milestone → `milestone/{slug}`. NEVER `main`.
900
+
901
+ ### 4D: Create PR
902
+ ```bash
903
+ gh pr create {GH_FLAG} --base {PR_BASE} --head {BRANCH} \
904
+ --title "{Fix|Feat|Refactor}: {description}" \
905
+ --body "## Summary
906
+ {BRIEF_DESCRIPTION}
907
+
908
+ ## Changes
909
+ {CHANGES_LIST}
910
+
911
+ ## Testing
912
+ {TESTING_CHECKLIST}
913
+
914
+ ---
915
+ Closes #{NUMBER}
916
+ **Implementation branch**: \`{BRANCH}\`
917
+ **Base**: \`{PR_BASE}\`"
918
+ ```
919
+
920
+ `Closes #{NUMBER}` documents intent but does NOT auto-close for non-default-branch PRs.
921
+
922
+ If PR already exists for this branch, use the existing PR number.
923
+
924
+ ### 4E: Update labels
925
+ ```bash
926
+ gh issue edit {NUMBER} {GH_FLAG} --add-label "workflow:in-review" --remove-label "workflow:building"
927
+ ```
928
+
929
+ ---
930
+
931
+ ## Phase 5: Auto-Review
932
+
933
+ ### 5A: Re-read state from GitHub (MANDATORY)
934
+ ```bash
935
+ gh issue view {NUMBER} {GH_FLAG} --json number,title,body,labels,state
936
+ PR_NUMBER=$(gh pr list {GH_FLAG} --head {BRANCH} --json number --jq '.[0].number')
937
+ ```
938
+
939
+ ### 5B: Post progress comment
940
+ ```bash
941
+ gh issue comment {NUMBER} {GH_FLAG} --body "## Submitting for Review
942
+
943
+ PR #${PR_NUMBER} created targeting \`{PR_BASE}\`. Invoking /review-pr with --auto-merge.
944
+
945
+ <!-- FORGE:REVIEW_STARTED -->"
946
+ ```
947
+
948
+ ### 5C: Invoke /review-pr with --auto-merge
949
+ ```
950
+ Skill(skill="review-pr", args="{PR_NUMBER} --auto-merge --issue {NUMBER} --base {PR_BASE} --gh-flag {GH_FLAG}")
951
+ ```
952
+
953
+ Review-pr handles: full domain-agent review → post findings as separate issues → merge PR. It does NOT close the issue or clean up the worktree — those run in Phase 6.
954
+
955
+ ### 5D: Verify merge and close (recovery)
956
+
957
+ ```bash
958
+ gh pr view {PR_NUMBER} {GH_FLAG} --json state,mergedAt --jq '{state: .state, mergedAt: .mergedAt}'
959
+ gh issue view {NUMBER} {GH_FLAG} --json state --jq '.state'
960
+ ```
961
+
962
+ - PR MERGED + issue CLOSED → proceed to Phase 6
963
+ - PR MERGED + issue OPEN → close issue manually
964
+ - PR NOT MERGED → `gh pr merge {PR_NUMBER} {GH_FLAG} --merge --auto`. If fails → post comment, add `needs-human`, STOP.
965
+
966
+ <!-- FORGE:PHASE_COMPLETE — Review done, PR merged. See Universal Phase Dispatcher: next phase is Phase 6 (Close & Cleanup). Not terminal — continue immediately. -->
967
+
968
+ ---
969
+
970
+ ## Phase 6: Close & Cleanup
971
+
972
+ ### 6A: Final issue body update
973
+
974
+ **Multi-phase guard**: Detect whether the issue has multiple phases. Only check off items belonging to the current completed phase.
975
+
976
+ ```bash
977
+ BODY=$(gh issue view {NUMBER} {GH_FLAG} --json body --jq '.body')
978
+ REMAINING_BEFORE=$(echo "$BODY" | grep -c '^- \[ \]' || true)
979
+ HAS_PHASE_HEADINGS=$(echo "$BODY" | grep -cP '^#{2,3} ' || true)
980
+ ```
981
+
982
+ If multi-phase (`HAS_PHASE_HEADINGS > 0` AND `REMAINING_BEFORE > 0`): do NOT check off future phase items. Add PR reference only.
983
+
984
+ If single-phase or final phase: check off all `[ ]` items, add PR reference.
985
+
986
+ ### 6B: Project board update (Status=Done, Workflow=Merged)
987
+ ```bash
988
+ ISSUE_URL="https://github.com/{GH_REPO}/issues/{NUMBER}"
989
+ ITEM_ID=$(gh project item-list 1 --owner RapierCraft --format json --limit 200 \
990
+ --jq ".items[] | select(.content.url == \"$ISSUE_URL\") | .id" 2>/dev/null | head -1)
991
+ ```
992
+
993
+ If found: set Status=Done, Workflow=Merged using project field IDs.
994
+
995
+ ### 6C: Ensure issue is closed
996
+
997
+ **Multi-phase guard**: If `REMAINING_AFTER > 0`, uncompleted phases remain. Post phase-complete comment, leave issue open, EXIT — router picks up next phase on next iteration.
998
+
999
+ If all phases complete:
1000
+ ```bash
1001
+ gh issue close {NUMBER} {GH_FLAG} \
1002
+ --comment "Closed: PR #{PR_NUMBER} merged to \`{PR_BASE}\`. Closes #{NUMBER}."
1003
+ gh issue edit {NUMBER} {GH_FLAG} \
1004
+ --add-label "workflow:merged" \
1005
+ --remove-label "workflow:in-review,workflow:building,workflow:investigating" 2>/dev/null || true
1006
+ ```
1007
+
1008
+ ### 6D: Parent tracker update (sub-issues only)
1009
+
1010
+ **Skip if**: Not a sub-issue (no parent reference in body).
1011
+
1012
+ ```bash
1013
+ PARENT_REF=$(gh issue view {NUMBER} {GH_FLAG} --json body --jq '.body' \
1014
+ | grep -oP '(?i)(part of|spawned from|sub-issue of|parent issue[:]?|parent[:])\s*#\K\d+' | head -1)
1015
+ ```
1016
+
1017
+ If parent found: check off this sub-issue in parent body. If ALL sub-issues checked off → close parent with `workflow:merged`.
1018
+
1019
+ ### 6E: Worktree & branch cleanup
1020
+
1021
+ ```bash
1022
+ if [ -n "{WORKTREE_PATH}" ] && [ -d "{WORKTREE_PATH}" ]; then
1023
+ GIT_COMMON=$(git -C {WORKTREE_PATH} rev-parse --git-common-dir 2>/dev/null)
1024
+ REPO_ROOT=$(dirname "$(realpath "$GIT_COMMON" 2>/dev/null || echo "$GIT_COMMON")")
1025
+ git -C "$REPO_ROOT" worktree remove {WORKTREE_PATH} --force 2>/dev/null || true
1026
+ if [ -n "{BRANCH}" ]; then
1027
+ git -C "$REPO_ROOT" branch -D {BRANCH} 2>/dev/null || true
1028
+ fi
1029
+ fi
1030
+ ```
1031
+
1032
+ ---
1033
+
1034
+ ## Phase 7: Summary & Trajectory
1035
+
1036
+ ### 7A: Report
1037
+ ```
1038
+ ## Done: #{NUMBER} — {TITLE}
1039
+ - Investigation: {VERDICT} ({CONFIDENCE})
1040
+ - Lane: {FAST/FEATURE}
1041
+ - Fix: {BRANCH} → PR #{PR_NUMBER} → merged to `{PR_BASE}`
1042
+ - Files changed: {COUNT}
1043
+ ```
1044
+
1045
+ ### 7B: Trajectory Log (MANDATORY)
1046
+
1047
+ **Review-presence check** (run before filling in Phase 4-5 row): <!-- Added: forge#381 -->
1048
+ ```bash
1049
+ # Check whether /review-pr was actually invoked — look for review agent comments on the PR
1050
+ REVIEW_PRESENT=$(gh pr view {PR_NUMBER} {GH_FLAG} --json reviews,comments \
1051
+ --jq '([.reviews[].body // ""] + [.comments[].body // ""]) |
1052
+ map(select(test("APPROVED:|CHANGES REQUESTED:|FORGE:REVIEWER|review-pr";"i"))) |
1053
+ length > 0')
1054
+ # Set Phase 4-5 row: ✅ Merged if review present, ⚠ Skipped (no review) if not
1055
+ REVIEW_ROW=$([ "$REVIEW_PRESENT" = "true" ] && echo "✅ Merged" || echo "⚠ Skipped (no review)")
1056
+ ```
1057
+
1058
+ This check is **audit-only** — it annotates the trajectory for visibility. It cannot retroactively block a merged PR. If `⚠ Skipped (no review)` is emitted, log it in the Anomalies field so the skip is surfaced during pipeline health review.
1059
+
1060
+ Post `<!-- FORGE:TRAJECTORY -->` comment with phase-by-phase results table:
1061
+
1062
+ ```bash
1063
+ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:TRAJECTORY -->
1064
+ ## Pipeline Trajectory — #{NUMBER}
1065
+
1066
+ | Phase | Result | Notes |
1067
+ |-------|--------|-------|
1068
+ | Phase 0: Context Load | ✅ Complete | {lane} → \`{PR_BASE}\` |
1069
+ | Phase 1: Investigation | ✅ {VERDICT} ({CONFIDENCE}) | Task type: {TASK_TYPE} |
1070
+ | Phase 2: Decomposition | ⏭ Skipped | {reason} |
1071
+ | Phase 3: Build | ✅ Complete | Branch: \`{BRANCH}\` |
1072
+ | Phase 3G: Quality Gate | ✅ Gate passed | {iterations} iterations |
1073
+ | Phase 4–5: Review + PR | {REVIEW_ROW} | PR #{PR_NUMBER} → \`{PR_BASE}\` |
1074
+ | Phase 6: Close | ✅ Complete | Issue closed |
1075
+
1076
+ **Decisions**: {key decisions}
1077
+ **Anomalies**: {anomalies or None}
1078
+ **Pipeline completed**: {TIMESTAMP}"
1079
+ ```
1080
+
1081
+ ---
1082
+
1083
+ ## Error Handling
1084
+
1085
+ - Worktree exists: reuse or clean up
1086
+ - PR creation fails: check if branch pushed, if PR already exists
1087
+ - Merge conflicts: report to user, do NOT auto-resolve
1088
+ - gh CLI fails: check `gh auth status`
1089
+ - Label missing: `gh label create "{name}" --color {hex} -R {GH_REPO}`