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.
- package/LICENSE +244 -0
- package/README.md +251 -0
- package/bin/forgedock.mjs +232 -0
- package/commands/analytics.md +777 -0
- package/commands/audit-agents.md +410 -0
- package/commands/audit.md +410 -0
- package/commands/autopilot.md +432 -0
- package/commands/cleanup.md +264 -0
- package/commands/deploy-info.md +292 -0
- package/commands/failure-recon.md +375 -0
- package/commands/forge-stats.md +183 -0
- package/commands/geo-audit.md +343 -0
- package/commands/incident-response.md +384 -0
- package/commands/issue.md +506 -0
- package/commands/milestone.md +599 -0
- package/commands/orchestrate.md +1044 -0
- package/commands/pipeline-health.md +2343 -0
- package/commands/qa-sweep.md +237 -0
- package/commands/quality-gate.md +777 -0
- package/commands/review-pr-agents.md +1711 -0
- package/commands/review-pr-staging.md +325 -0
- package/commands/review-pr.md +888 -0
- package/commands/rollback.md +253 -0
- package/commands/security-audit.md +529 -0
- package/commands/sync-ecosystem.md +527 -0
- package/commands/validate.md +131 -0
- package/commands/work-on/build/architect.md +291 -0
- package/commands/work-on/build/context.md +349 -0
- package/commands/work-on/build/implement.md +280 -0
- package/commands/work-on/build/validate.md +292 -0
- package/commands/work-on/build.md +262 -0
- package/commands/work-on/close.md +350 -0
- package/commands/work-on/decompose.md +254 -0
- package/commands/work-on/investigate.md +437 -0
- package/commands/work-on/review.md +245 -0
- package/commands/work-on-monolithic.md +298 -0
- package/commands/work-on.md +1089 -0
- package/docs/CODEX.md +92 -0
- package/docs/WORKFLOW.md +104 -0
- package/package.json +45 -0
- package/scripts/verify-env-vars.sh +201 -0
- package/scripts/verify-host-headers.sh +117 -0
- package/scripts/verify-route-registration.sh +118 -0
- package/scripts/verify-sops-chain.sh +163 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Pre-implementation architecture planning — traces ALL affected code paths and produces an ordered implementation plan before any code is written
|
|
3
|
+
argument-hint: [issue number] [--repo GH_REPO] [--gh-flag GH_FLAG] [--files AFFECTED_FILES]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# work-on/build/architect — Multi-Path Implementation Planning
|
|
7
|
+
|
|
8
|
+
**Invoked by**: `work-on.md` Step 3C.6, between Context Gathering and Implement.
|
|
9
|
+
**Time budget**: Max 3 minutes. Skip any file read that times out.
|
|
10
|
+
**Output**: Post `<!-- FORGE:ARCHITECT -->` comment on the issue, then return structured plan to caller.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Mission
|
|
15
|
+
|
|
16
|
+
Eliminate cross-path inconsistency bugs before any code is written. The single biggest class of production bugs is a change applied to one code path but not all sibling paths that share the same logic. This agent traces the FULL request/data flow from every entry point, identifies every file that must change, and produces an ordered implementation plan the builder follows exactly.
|
|
17
|
+
|
|
18
|
+
**Principle**: A builder with an explicit plan produces consistent changes. Consistent changes produce zero cross-path review findings.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Inputs
|
|
23
|
+
|
|
24
|
+
Parse from $ARGUMENTS:
|
|
25
|
+
- `{NUMBER}` — issue number (required, positional first arg)
|
|
26
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `RapierCraft/AlterLab`)
|
|
27
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R RapierCraft/AlterLab`)
|
|
28
|
+
- `--repo-path {REPO_PATH}` — local filesystem path to the worktree (e.g. `/path/to/.claude/worktrees/fix/issue-121`); used by Phase A1 grep commands
|
|
29
|
+
- `--files {AFFECTED_FILES}` — space-separated list of files from investigation report (passed by `build.md` Phase B4)
|
|
30
|
+
|
|
31
|
+
Also read from the calling context (in-memory, passed by parent agent):
|
|
32
|
+
- `{INVESTIGATION_REPORT}` — full text of FORGE:INVESTIGATOR comment
|
|
33
|
+
- `{CONTEXT_BRIEFING}` — full text of FORGE:CONTEXT comment (empty string if context step was skipped)
|
|
34
|
+
|
|
35
|
+
If any of these are not passed directly, read them from GitHub (fallback/recovery path):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Read investigation report
|
|
39
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
40
|
+
--jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
|
|
41
|
+
|
|
42
|
+
# Read context briefing (may be absent — that's OK)
|
|
43
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
44
|
+
--jq '.[] | select(.body | contains("FORGE:CONTEXT")) | .body'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Resume Check
|
|
50
|
+
|
|
51
|
+
Before doing any work:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
55
|
+
--jq '.[] | select(.body | contains("FORGE:ARCHITECT")) | .body'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- If `<!-- FORGE:ARCHITECT -->` comment exists AND `<!-- FORGE:ARCHITECT:COMPLETE -->` is present in the SAME comment → plan already complete, return existing plan to caller, EXIT.
|
|
59
|
+
- If `<!-- FORGE:ARCHITECT -->` comment exists BUT `<!-- FORGE:ARCHITECT:COMPLETE -->` is ABSENT → plan was interrupted, delete the partial comment and restart:
|
|
60
|
+
```bash
|
|
61
|
+
COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
|
|
62
|
+
--jq '.[] | select(.body | contains("FORGE:ARCHITECT")) | .id')
|
|
63
|
+
gh api repos/{GH_REPO}/issues/comments/$COMMENT_ID -X DELETE
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Phase A1: Read Entry Points
|
|
69
|
+
|
|
70
|
+
Identify every entry point that initiates the affected logic. Start from the files named in the investigation report.
|
|
71
|
+
|
|
72
|
+
For each affected file, read it and identify:
|
|
73
|
+
1. The primary function/method being changed
|
|
74
|
+
2. All callers of that function (grep for usages)
|
|
75
|
+
3. All sibling implementations (same interface, different path — e.g. HTTP vs worker vs relay)
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Find all callers of the primary function
|
|
79
|
+
grep -r "{PRIMARY_FUNCTION}" {REPO_PATH} \
|
|
80
|
+
--include="*.py" --include="*.ts" --include="*.tsx" \
|
|
81
|
+
-l | grep -v "__pycache__" | grep -v ".pyc"
|
|
82
|
+
|
|
83
|
+
# Find sibling implementations (same base class or interface)
|
|
84
|
+
grep -r "class.*{BASE_CLASS}\|implements.*{INTERFACE}" {REPO_PATH} \
|
|
85
|
+
--include="*.py" --include="*.ts" \
|
|
86
|
+
-l | grep -v "__pycache__"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Read the 3–5 most relevant files identified. Do NOT read more than 8 files total — this is a planning step, not a deep audit.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase A2: Trace the Data Flow
|
|
94
|
+
|
|
95
|
+
From each entry point identified in A1, trace what happens to the data being changed:
|
|
96
|
+
|
|
97
|
+
1. **Entry**: Where does the data first arrive? (API endpoint, queue consumer, webhook handler)
|
|
98
|
+
2. **Transform**: What functions process it? Which fields are read/written?
|
|
99
|
+
3. **Persist or relay**: Is it saved to DB? Forwarded to another service? Queued?
|
|
100
|
+
4. **Exit**: Where does it leave the system? (response body, downstream call, emitted event)
|
|
101
|
+
|
|
102
|
+
For each step in the flow, check:
|
|
103
|
+
- Does the proposed change need to propagate here?
|
|
104
|
+
- Is there a validation or coercion that must be updated consistently?
|
|
105
|
+
- Is there a test that covers this path?
|
|
106
|
+
|
|
107
|
+
Produce a table of ALL files/functions that must change to maintain consistency.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Phase A2.5: Pipeline Phase-Dependency Check
|
|
112
|
+
|
|
113
|
+
**Skip if**: None of the `{AFFECTED_FILES}` are Forge pipeline command files (i.e., no file matches `commands/**/*.md`). When skipped, proceed directly to A3.
|
|
114
|
+
|
|
115
|
+
**Applies when**: The change touches one or more files in `commands/` — these files define the pipeline's phase contracts, and a change to one phase frequently requires coordinated updates to sibling or downstream phases.
|
|
116
|
+
|
|
117
|
+
### Why This Phase Exists
|
|
118
|
+
|
|
119
|
+
GATE_LOGIC defects (phase-ordering errors, dropped functionality, missing implementations) are the #1 review finding category in the Forge pipeline. They occur when a change is applied to one pipeline phase but the downstream phases that depend on that phase's output contract are not updated. Code-level grep (A1) cannot catch these because pipeline dependencies are expressed in markdown artefact contracts — comment markers, structured output blocks, Skill() invocation signatures, and label state machine transitions — not in code imports.
|
|
120
|
+
|
|
121
|
+
### Steps
|
|
122
|
+
|
|
123
|
+
**P1: Identify artefact contracts produced by the changed file**
|
|
124
|
+
|
|
125
|
+
For each affected `commands/*.md` file, identify what it produces that other phases consume:
|
|
126
|
+
|
|
127
|
+
1. **Comment markers** — HTML comment markers the phase writes to GitHub (e.g., `<!-- FORGE:ARCHITECT -->`, `<!-- FORGE:ARCHITECT:COMPLETE -->`). Search for `<!-- FORGE:` patterns in the affected file.
|
|
128
|
+
2. **Structured output blocks** — named result blocks returned to the caller (e.g., `BUILD_RESULT:`, `VALIDATE_RESULT:`, `IMPLEMENT_RESULT:`). Search for lines ending in `:` that start a return block.
|
|
129
|
+
3. **Skill() invocation signatures** — parameters the file passes when invoking subcommands (e.g., `Skill("work-on:build:architect", args="... --files ...")`). Search for `Skill(` calls.
|
|
130
|
+
4. **Label state machine transitions** — `gh issue edit ... --add-label ... --remove-label ...` calls that define which label is set at the end of this phase.
|
|
131
|
+
|
|
132
|
+
**P2: Find downstream phases that consume these artefacts**
|
|
133
|
+
|
|
134
|
+
For each artefact identified in P1:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Find which pipeline files reference this comment marker or output field
|
|
138
|
+
grep -r "{MARKER_OR_FIELD}" /path/to/repo/commands/ \
|
|
139
|
+
--include="*.md" -l | grep -v {AFFECTED_FILE}
|
|
140
|
+
|
|
141
|
+
# Example: if FORGE:ARCHITECT is the marker
|
|
142
|
+
grep -r "FORGE:ARCHITECT" commands/ --include="*.md" -l
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For each consumer file found: note the file and the specific phase/section that reads the artefact.
|
|
146
|
+
|
|
147
|
+
**P3: Check for invocation signature changes**
|
|
148
|
+
|
|
149
|
+
If the change modifies what parameters a phase accepts (adds, removes, or renames a `--flag` in its Inputs section), find all callers:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
grep -r "Skill.*{SUBCOMMAND_NAME}" commands/ --include="*.md" -l
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For each caller: verify the invocation still matches the new signature. Flag any caller that passes a parameter that is being renamed or removed.
|
|
156
|
+
|
|
157
|
+
**P4: Emit phase-dependency checklist**
|
|
158
|
+
|
|
159
|
+
For each downstream phase identified in P2 and P3, emit a checklist item. These items are appended to the `### Consistency Checks` section of the `<!-- FORGE:ARCHITECT -->` comment output:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
- [ ] {DOWNSTREAM_FILE} Phase {N}: still reads `{ARTEFACT}` correctly after this change
|
|
163
|
+
- [ ] {CALLER_FILE} Phase {N}: invocation of `{SUBCOMMAND}` passes correct params after signature change
|
|
164
|
+
- [ ] Label state: `{LABEL}` set at end of changed phase matches what `{CONSUMER_FILE}` Phase {N} expects as entry condition
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
If no downstream phases are found (the change is additive only — new sections, new checklist items, no existing contract modified), emit:
|
|
168
|
+
```
|
|
169
|
+
- [ ] Phase-dependency check: ADDITIVE ONLY — no existing artefact contracts modified; no downstream updates required
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Phase A3: Consistency Rules
|
|
175
|
+
|
|
176
|
+
Identify invariants that ALL affected paths must satisfy. These become the builder's consistency checklist.
|
|
177
|
+
|
|
178
|
+
Common invariants to check:
|
|
179
|
+
- **Null handling**: All paths handle missing field the same way (None vs empty string vs omission)
|
|
180
|
+
- **Validation**: All paths apply the same size/type/format constraints
|
|
181
|
+
- **Logging**: All paths log the same fields at the same level
|
|
182
|
+
- **Error response**: All paths return the same error shape for the same failure mode
|
|
183
|
+
- **Auth check**: All paths enforce the same permission model
|
|
184
|
+
|
|
185
|
+
For each invariant: state the rule and note which files it applies to.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Phase A4: Sequence the Implementation
|
|
190
|
+
|
|
191
|
+
Order the changes to minimize breakage during implementation:
|
|
192
|
+
|
|
193
|
+
1. **Schema/type changes first** — any shared types, Pydantic models, TypeScript interfaces
|
|
194
|
+
2. **Core logic** — the primary path (usually the API router or main function)
|
|
195
|
+
3. **Secondary paths** — worker consumers, relay handlers, batch endpoints
|
|
196
|
+
4. **Tests** — update or add tests for each changed path
|
|
197
|
+
5. **Config/env** — any new environment variables or feature flags
|
|
198
|
+
|
|
199
|
+
Rules for ordering:
|
|
200
|
+
- A file that is imported by others must be changed before its importers
|
|
201
|
+
- Tests change last (after the code they test is stable)
|
|
202
|
+
- If two paths are independent, order by risk (higher risk first so review catches it early)
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Phase A5: Risk Assessment
|
|
207
|
+
|
|
208
|
+
For each non-obvious interaction or potential failure mode:
|
|
209
|
+
- State the risk in one sentence
|
|
210
|
+
- Rate it: HIGH / MEDIUM / LOW
|
|
211
|
+
- Suggest a mitigation or check
|
|
212
|
+
|
|
213
|
+
Focus on:
|
|
214
|
+
- Files that have changed recently (check `git log --oneline -10 -- {FILE}`)
|
|
215
|
+
- Paths that are called in both sync and async contexts
|
|
216
|
+
- Any place where the change touches a serialization boundary (JSON in/out, DB read/write)
|
|
217
|
+
- Unused or dormant code that the change might activate
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Output Format
|
|
222
|
+
|
|
223
|
+
Post the following as a GitHub comment on `{NUMBER}`:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:ARCHITECT -->
|
|
227
|
+
## Implementation Plan for #{NUMBER}
|
|
228
|
+
|
|
229
|
+
### Affected Paths (ALL must be updated)
|
|
230
|
+
| # | File | Function/Class | Change Required | Why |
|
|
231
|
+
|---|------|----------------|-----------------|-----|
|
|
232
|
+
| 1 | {FILE} | {FUNCTION} | {CHANGE} | {REASON} |
|
|
233
|
+
|
|
234
|
+
### Implementation Order
|
|
235
|
+
1. {FIRST_CHANGE} — {WHY_FIRST}
|
|
236
|
+
2. {SECOND_CHANGE} — {WHY_SECOND}
|
|
237
|
+
...
|
|
238
|
+
|
|
239
|
+
### Consistency Checks
|
|
240
|
+
<!-- Builder must verify each of these before committing -->
|
|
241
|
+
- [ ] {INVARIANT_1}
|
|
242
|
+
- [ ] {INVARIANT_2}
|
|
243
|
+
- [ ] {INVARIANT_3}
|
|
244
|
+
|
|
245
|
+
### Risk Assessment
|
|
246
|
+
| Risk | Severity | Mitigation |
|
|
247
|
+
|------|----------|------------|
|
|
248
|
+
| {RISK_DESCRIPTION} | HIGH/MEDIUM/LOW | {MITIGATION} |
|
|
249
|
+
|
|
250
|
+
### Files to Read Before Coding
|
|
251
|
+
<!-- Builder MUST read these files before writing any code -->
|
|
252
|
+
- \`{FILE}\` — {WHY_READ_IT}
|
|
253
|
+
|
|
254
|
+
<!-- FORGE:ARCHITECT:COMPLETE -->
|
|
255
|
+
"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Timing Rules
|
|
261
|
+
|
|
262
|
+
- Each file read: skip if the file exceeds 500 lines and only the first 100 lines are needed for structure
|
|
263
|
+
- Each `grep -r` call: timeout after 10s, skip if exceeded
|
|
264
|
+
- Total wall time budget: **3 minutes**. If budget exceeded, post partial results with `<!-- FORGE:ARCHITECT:PARTIAL -->` marker instead of `COMPLETE`.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Skip Conditions
|
|
269
|
+
|
|
270
|
+
Skip this entire step (post nothing, return empty plan to caller) if:
|
|
271
|
+
- Issue creates only **new files** with no callers to find (e.g. a new command file with no existing integration point yet)
|
|
272
|
+
- Issue is a 1-file config or docs edit with no code logic
|
|
273
|
+
- Issue title starts with "docs:" or "chore:"
|
|
274
|
+
- `{AFFECTED_FILES}` is empty
|
|
275
|
+
|
|
276
|
+
When skipped, the builder proceeds with investigation report + context briefing only.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Integration Point in work-on.md
|
|
281
|
+
|
|
282
|
+
This module runs at **Step 3C.6** — after Context Gathering, before Implement:
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
3C → Builder Contract posted
|
|
286
|
+
3C.5 → Context Gathering (FORGE:CONTEXT comment)
|
|
287
|
+
3C.6 → [THIS MODULE] Architecture Planning (FORGE:ARCHITECT comment)
|
|
288
|
+
3F → Implement (builder reads plan, implements ALL affected paths)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The builder agent reads the `<!-- FORGE:ARCHITECT -->` comment as its **primary input** before writing any code. The raw issue body is secondary context. If the architect step was skipped, the builder falls back to investigation report + contract.
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Pre-implementation context gathering — surfaces historical findings, bug patterns, and related code paths before the builder writes any code
|
|
3
|
+
argument-hint: [issue number] [affected_files...] [--functions function_names...]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# work-on/build/context — Pre-Implementation Context Gathering
|
|
7
|
+
|
|
8
|
+
**Invoked by**: `work-on.md` Step 3C.5, between Builder Contract and Implement.
|
|
9
|
+
**Time budget**: Max 2 minutes of queries. Skip any query that times out.
|
|
10
|
+
**Output**: Post `<!-- FORGE:CONTEXT -->` comment on the issue, then return structured briefing to caller.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Mission
|
|
15
|
+
|
|
16
|
+
Surface what went wrong in this area before the builder writes a single line of code. The builder starts with the investigator report and contract — this step adds institutional memory: what did review agents catch last time someone touched these files, what bugs recurred, what other paths must stay consistent. When prior investigation Gists are linked in the issue body, fetch and summarize them so the builder has cross-issue context without manual lookups. When a milestone-level index Gist exists, use it to discover all investigation Gists for the milestone — providing full cross-issue context from a single URL. <!-- Updated: forge#341 -->
|
|
17
|
+
|
|
18
|
+
**Principle**: A builder with context produces fewer review findings. Fewer findings = fewer fix cycles = lower token cost.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Inputs
|
|
23
|
+
|
|
24
|
+
Parse from `$ARGUMENTS`:
|
|
25
|
+
- `{NUMBER}` — issue number (positional, required)
|
|
26
|
+
- `--repo {GH_REPO}` — GitHub repo (e.g. `RapierCraft/AlterLab`)
|
|
27
|
+
- `--gh-flag {GH_FLAG}` — gh CLI repo flag (e.g. `-R RapierCraft/AlterLab`)
|
|
28
|
+
- `--repo-path {REPO_PATH}` — local filesystem path to the worktree (e.g. `/path/to/.claude/worktrees/fix/issue-121`); used by Phase C3 grep commands
|
|
29
|
+
- `{AFFECTED_FILES}` — space-separated file paths (positional, after `{NUMBER}`, before any `--functions` flag)
|
|
30
|
+
- `--functions {FUNCTION_NAMES}` — space-separated function/class names extracted from the Builder Contract deliverables table (optional)
|
|
31
|
+
|
|
32
|
+
**Graceful skip for empty FUNCTION_NAMES**: If `--functions` is absent or `{FUNCTION_NAMES}` is empty, Phase C3 produces zero for-loop iterations and is effectively skipped — no error, no output for that phase. This is expected behavior when the contract does not name specific functions.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Phase C0: Prior Investigation Findings (from Gists)
|
|
37
|
+
|
|
38
|
+
Scan the issue body for `<!-- FORGE:PRIOR_GIST: {url} -->` annotations embedded by the decompose or orchestrate phases (GIST-02). Also check for `<!-- FORGE:MILESTONE_INDEX: {url} -->` annotations — these reference a milestone-level index Gist (GIST-04) that aggregates all investigation Gist URLs for a milestone into a single reference. Both annotation types reference Knowledge Gists created during upstream investigation (GIST-01) and contain structured findings — verdict, root cause, recommendation, affected files — that the builder needs before writing code.
|
|
39
|
+
|
|
40
|
+
**Time budget**: 30 seconds total for all Gist fetches. Each individual fetch times out after 15 seconds.
|
|
41
|
+
|
|
42
|
+
**Skip if**: Issue body contains no `FORGE:PRIOR_GIST` or `FORGE:MILESTONE_INDEX` annotations, AND the issue's milestone description contains no `FORGE:MILESTONE_INDEX` annotation. Zero iterations, no output — this is expected for issues without prior investigation context.
|
|
43
|
+
|
|
44
|
+
### Step 0: Check for milestone index Gist
|
|
45
|
+
|
|
46
|
+
Before scanning individual Gist annotations, check if the issue's milestone has an index Gist. If so, fetch the index and extract individual Gist URLs from the table rows.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
ISSUE_BODY=$(gh issue view {NUMBER} -R {GH_REPO} --json body --jq '.body')
|
|
50
|
+
MILESTONE_NUM=$(gh issue view {NUMBER} -R {GH_REPO} --json milestone --jq '.milestone.number // empty')
|
|
51
|
+
|
|
52
|
+
MILESTONE_INDEX_URL=""
|
|
53
|
+
INDEX_GIST_URLS=""
|
|
54
|
+
|
|
55
|
+
# Check issue body for milestone index annotation
|
|
56
|
+
MILESTONE_INDEX_URL=$(echo "$ISSUE_BODY" \
|
|
57
|
+
| grep -oP '(?<=<!-- FORGE:MILESTONE_INDEX: )https://[^ ]+(?= -->)' \
|
|
58
|
+
| head -1)
|
|
59
|
+
|
|
60
|
+
# If not in issue body, check milestone description
|
|
61
|
+
if [ -z "$MILESTONE_INDEX_URL" ] && [ -n "$MILESTONE_NUM" ]; then
|
|
62
|
+
MILESTONE_DESC=$(gh api repos/{GH_REPO}/milestones/${MILESTONE_NUM} --jq '.description // ""' 2>/dev/null)
|
|
63
|
+
MILESTONE_INDEX_URL=$(echo "$MILESTONE_DESC" \
|
|
64
|
+
| grep -oP '(?<=<!-- FORGE:MILESTONE_INDEX: )https://[^ ]+(?= -->)' \
|
|
65
|
+
| head -1)
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# If found, fetch the index and extract individual Gist URLs from table rows
|
|
69
|
+
if [ -n "$MILESTONE_INDEX_URL" ]; then
|
|
70
|
+
INDEX_GIST_ID=$(echo "$MILESTONE_INDEX_URL" | grep -oP '[a-f0-9]{20,}' | tail -1)
|
|
71
|
+
if [ -n "$INDEX_GIST_ID" ]; then
|
|
72
|
+
INDEX_CONTENT=$(timeout 15 gh gist view "$INDEX_GIST_ID" --raw 2>/dev/null)
|
|
73
|
+
if [ -n "$INDEX_CONTENT" ]; then
|
|
74
|
+
# Extract Gist URLs from table rows (format: | ... | https://gist.github.com/... | ... |)
|
|
75
|
+
INDEX_GIST_URLS=$(echo "$INDEX_CONTENT" \
|
|
76
|
+
| grep -oP 'https://gist\.github\.com/[a-f0-9/]+' \
|
|
77
|
+
| head -10)
|
|
78
|
+
echo "Milestone index fetched: found $(echo "$INDEX_GIST_URLS" | wc -l) investigation Gist(s)"
|
|
79
|
+
else
|
|
80
|
+
echo "WARNING: Failed to fetch milestone index Gist — falling back to individual annotations"
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 1: Detect Gist URLs in issue body
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
GIST_URLS=$(echo "$ISSUE_BODY" \
|
|
90
|
+
| grep -oP '(?<=<!-- FORGE:PRIOR_GIST: )https://[^ ]+(?= -->)' \
|
|
91
|
+
| head -5)
|
|
92
|
+
|
|
93
|
+
# Merge with any URLs discovered from milestone index (deduplicate)
|
|
94
|
+
if [ -n "$INDEX_GIST_URLS" ]; then
|
|
95
|
+
GIST_URLS=$(echo -e "${GIST_URLS}\n${INDEX_GIST_URLS}" | sort -u | head -5)
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
if [ -z "$GIST_URLS" ]; then
|
|
99
|
+
echo "No FORGE:PRIOR_GIST or FORGE:MILESTONE_INDEX annotations found — skipping Phase C0"
|
|
100
|
+
# → Continue to Phase C1
|
|
101
|
+
fi
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Max Gists**: 5 per issue. If more than 5 are present (from combined individual + index sources), process only the first 5 to stay within time budget.
|
|
105
|
+
|
|
106
|
+
### Step 2: Fetch and summarize each Gist
|
|
107
|
+
|
|
108
|
+
For each Gist URL, extract the Gist ID (last path segment) and fetch the raw content:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
GIST_SUMMARIES=""
|
|
112
|
+
|
|
113
|
+
for url in $GIST_URLS; do
|
|
114
|
+
# Extract Gist ID from URL (last path segment, strip any trailing slash)
|
|
115
|
+
GIST_ID=$(echo "$url" | grep -oP '[a-f0-9]{20,}' | tail -1)
|
|
116
|
+
|
|
117
|
+
if [ -z "$GIST_ID" ]; then
|
|
118
|
+
echo "WARNING: Could not extract Gist ID from URL: $url — skipping"
|
|
119
|
+
continue
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Fetch Gist content with timeout
|
|
123
|
+
GIST_CONTENT=$(timeout 15 gh gist view "$GIST_ID" --raw 2>/dev/null)
|
|
124
|
+
|
|
125
|
+
if [ -z "$GIST_CONTENT" ]; then
|
|
126
|
+
echo "WARNING: Failed to fetch Gist $GIST_ID — skipping (deleted, private, or network error)"
|
|
127
|
+
GIST_SUMMARIES="${GIST_SUMMARIES}
|
|
128
|
+
- **Gist ${GIST_ID}** (${url}): _Fetch failed — Gist may be deleted or inaccessible_"
|
|
129
|
+
continue
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Extract key sections for summary (~2K chars target per Gist)
|
|
133
|
+
VERDICT=$(echo "$GIST_CONTENT" | grep -oP '(?<=verdict: )\w+' | head -1)
|
|
134
|
+
TASK_TYPE=$(echo "$GIST_CONTENT" | grep -oP '(?<=task_type: ).+' | head -1)
|
|
135
|
+
SEVERITY=$(echo "$GIST_CONTENT" | grep -oP '(?<=severity: )\w+' | head -1)
|
|
136
|
+
SOURCE_ISSUE=$(echo "$GIST_CONTENT" | grep -oP '(?<=issue: )\d+' | head -1)
|
|
137
|
+
|
|
138
|
+
# Extract structured sections: Root Cause, Recommendation, Affected Files
|
|
139
|
+
ROOT_CAUSE=$(echo "$GIST_CONTENT" \
|
|
140
|
+
| sed -n '/^### Root Cause/,/^### /p' \
|
|
141
|
+
| head -10 | tail -n +2 | head -8)
|
|
142
|
+
RECOMMENDATION=$(echo "$GIST_CONTENT" \
|
|
143
|
+
| sed -n '/^### Recommendation/,/^### /p' \
|
|
144
|
+
| head -10 | tail -n +2 | head -8)
|
|
145
|
+
AFFECTED_FILES=$(echo "$GIST_CONTENT" \
|
|
146
|
+
| sed -n '/^### Affected Files/,/^### /p' \
|
|
147
|
+
| head -10 | tail -n +2 | head -8)
|
|
148
|
+
|
|
149
|
+
GIST_SUMMARIES="${GIST_SUMMARIES}
|
|
150
|
+
|
|
151
|
+
#### Investigation #${SOURCE_ISSUE:-unknown} (${VERDICT:-unknown} / ${SEVERITY:-unknown})
|
|
152
|
+
**Source**: ${url}
|
|
153
|
+
**Task type**: ${TASK_TYPE:-unknown}
|
|
154
|
+
|
|
155
|
+
**Root Cause**:
|
|
156
|
+
${ROOT_CAUSE:-_Not extracted — read Gist directly_}
|
|
157
|
+
|
|
158
|
+
**Recommendation**:
|
|
159
|
+
${RECOMMENDATION:-_Not extracted — read Gist directly_}
|
|
160
|
+
|
|
161
|
+
**Affected Files**:
|
|
162
|
+
${AFFECTED_FILES:-_Not extracted — read Gist directly_}"
|
|
163
|
+
done
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Step 3: Store for output
|
|
167
|
+
|
|
168
|
+
If `GIST_SUMMARIES` is non-empty, it will be included in the `### Prior Investigation Findings` section of the FORGE:CONTEXT comment (see Output Format below). If empty (all fetches failed or no annotations found), the section is omitted from the output.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Phase C1: Past Review Findings on These Files
|
|
173
|
+
|
|
174
|
+
Query closed issues with `review-finding` label, searching by filename:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
for file in {AFFECTED_FILES}; do
|
|
178
|
+
basename=$(basename "$file" .py)
|
|
179
|
+
gh issue list -R {GH_REPO} \
|
|
180
|
+
--state closed \
|
|
181
|
+
--label "review-finding" \
|
|
182
|
+
--search "$basename" \
|
|
183
|
+
--limit 10 \
|
|
184
|
+
--json number,title,body \
|
|
185
|
+
--jq '.[] | {
|
|
186
|
+
number,
|
|
187
|
+
title,
|
|
188
|
+
pattern: (.body | capture("\\*\\*Pattern\\*\\*: *(?<p>[^\\n]+)").p // null),
|
|
189
|
+
prevention: (.body | capture("\\*\\*Prevention\\*\\*: *(?<v>[^\\n]+)").v // null),
|
|
190
|
+
root_cause: (.body | capture("\\*\\*Root cause\\*\\*: *(?<rc>[^\\n]+)").rc // (.body | capture("Root Cause[^\\n]*\\n(?<rc>[^\\n]+)").rc // "see body"))
|
|
191
|
+
}'
|
|
192
|
+
done
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Keep findings where the filename or function name appears in the title or body. Discard false matches (same word, different module).
|
|
196
|
+
|
|
197
|
+
**Pattern extraction note**: Issues created by `/review-pr` after the feedback-loop feature include structured `**Pattern**`, `**Root cause**`, and `**Prevention**` fields in the `## Pattern Metadata` section. Extract all three when present — they are the primary signal. Fall back to `root_cause` regex for older issues that predate this feature.
|
|
198
|
+
|
|
199
|
+
**Max results**: 10 findings total across all files.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Phase C2: Past Bugs in the Same Module
|
|
204
|
+
|
|
205
|
+
Mine git log for commit messages referencing issues, then fetch those issues:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Step 1: find issue numbers from git history on affected files
|
|
209
|
+
git log --oneline -30 -- {AFFECTED_FILES} \
|
|
210
|
+
| grep -oP '#\d+' \
|
|
211
|
+
| sort -u \
|
|
212
|
+
| head -8
|
|
213
|
+
|
|
214
|
+
# Step 2: for each issue number found, fetch title and any root cause annotation
|
|
215
|
+
gh issue view {RELATED_NUMBER} -R {GH_REPO} \
|
|
216
|
+
--json number,title,body,labels \
|
|
217
|
+
--jq '{number, title, labels: [.labels[].name], snippet: (.body[:300])}'
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Filter: keep only `bug`, `fix`, or `review-finding` labeled issues. Skip feature issues — they add noise without bug signal.
|
|
221
|
+
|
|
222
|
+
**Max results**: 5 issues.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Phase C3: Related Code Paths
|
|
227
|
+
|
|
228
|
+
Identify callers, importers, and sibling implementations that must stay consistent with the changed code:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Python: find importers of modified functions/classes
|
|
232
|
+
for fn in {FUNCTION_NAMES}; do
|
|
233
|
+
grep -r "$fn" {REPO_PATH} \
|
|
234
|
+
--include="*.py" \
|
|
235
|
+
-l \
|
|
236
|
+
| grep -v "__pycache__" \
|
|
237
|
+
| grep -v {AFFECTED_FILES} \
|
|
238
|
+
| head -5
|
|
239
|
+
done
|
|
240
|
+
|
|
241
|
+
# TypeScript: find usages
|
|
242
|
+
for fn in {FUNCTION_NAMES}; do
|
|
243
|
+
grep -r "$fn" {REPO_PATH}/web/src \
|
|
244
|
+
--include="*.ts" --include="*.tsx" \
|
|
245
|
+
-l \
|
|
246
|
+
| head -5
|
|
247
|
+
done
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
For each related file found: note the file path and the nature of the relationship (caller, sibling, test).
|
|
251
|
+
|
|
252
|
+
**Max results**: 8 related files.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Phase C4: Successful Similar Implementations
|
|
257
|
+
|
|
258
|
+
Find merged PRs that touched the same domain with a successful outcome — use as a positive pattern reference:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
gh pr list -R {GH_REPO} \
|
|
262
|
+
--state merged \
|
|
263
|
+
--search "{domain_keywords}" \
|
|
264
|
+
--limit 5 \
|
|
265
|
+
--json number,title,files \
|
|
266
|
+
--jq '.[] | {number, title, file_count: (.files | length)}'
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Use 2-3 keywords from the issue title. If no results, skip this phase — do not block on it.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Output Format
|
|
274
|
+
|
|
275
|
+
Post the following as a GitHub comment on `{NUMBER}`:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
gh issue comment {NUMBER} -R {GH_REPO} --body "<!-- FORGE:CONTEXT -->
|
|
279
|
+
## Implementation Context for #{NUMBER}
|
|
280
|
+
|
|
281
|
+
### Prior Investigation Findings
|
|
282
|
+
<!-- Summarized Knowledge Gist content from upstream investigations (Phase C0).
|
|
283
|
+
If no FORGE:PRIOR_GIST annotations were found in the issue body: omit this section entirely.
|
|
284
|
+
If Gist fetches failed: include the failure note so the builder knows context was attempted. -->
|
|
285
|
+
{GIST_SUMMARIES}
|
|
286
|
+
|
|
287
|
+
### Known Pitfalls for This Area
|
|
288
|
+
<!-- Structured prevention rules extracted from past review-finding issues (Pattern Metadata section).
|
|
289
|
+
If a finding has a Prevention field, list it here. Builder MUST read these before writing code.
|
|
290
|
+
If none: 'No structured pitfalls recorded — first time these files are touched or all findings predate the feedback loop.' -->
|
|
291
|
+
- **{PATTERN}** (`{FILE}`): {PREVENTION}
|
|
292
|
+
|
|
293
|
+
### Historical Findings on These Files
|
|
294
|
+
<!-- List of past review-finding issues from C1. If none: 'No prior findings.' -->
|
|
295
|
+
- #{NUM}: \"{TITLE}\" — root cause: {ROOT_CAUSE}
|
|
296
|
+
|
|
297
|
+
### Past Bugs in This Module
|
|
298
|
+
<!-- List of closed bug issues from git log mining. If none: 'No prior bugs found in git history.' -->
|
|
299
|
+
- #{NUM}: \"{TITLE}\" — root cause: {SNIPPET}
|
|
300
|
+
|
|
301
|
+
### Related Code Paths (must stay consistent)
|
|
302
|
+
<!-- Files that import or call the changed functions. Builder must read and validate these. -->
|
|
303
|
+
- \`{FILE}\` — {RELATIONSHIP}
|
|
304
|
+
|
|
305
|
+
### Patterns That Cause Bugs Here
|
|
306
|
+
<!-- Synthesize from C1+C2: recurring bug types (e.g. 'String/int coercion at JSON boundaries — 3 prior incidents'). If none: 'No recurring patterns identified.' -->
|
|
307
|
+
|
|
308
|
+
### Successful Similar Implementations
|
|
309
|
+
<!-- Positive patterns from C4. If none: 'No similar merged PRs found.' -->
|
|
310
|
+
- PR #{NUM}: \"{TITLE}\" — {FILE_COUNT} files, notes: {OBSERVATION}
|
|
311
|
+
|
|
312
|
+
<!-- FORGE:CONTEXT:COMPLETE -->
|
|
313
|
+
"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Timing Rules
|
|
319
|
+
|
|
320
|
+
- Phase C0 `gh gist view` calls: timeout after 15s each, 30s total budget for all Gist fetches
|
|
321
|
+
- Each `gh issue list` call: timeout after 20s, skip if exceeded
|
|
322
|
+
- Each `gh pr list` call: timeout after 20s, skip if exceeded
|
|
323
|
+
- Each `grep -r` call: timeout after 10s, skip if exceeded
|
|
324
|
+
- Total wall time budget: **2 minutes** (C0 through C4 combined). If budget exceeded, post partial results with `<!-- FORGE:CONTEXT:PARTIAL -->` marker instead of `COMPLETE`.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Skip Conditions
|
|
329
|
+
|
|
330
|
+
Skip this entire step (post nothing, return empty briefing) if:
|
|
331
|
+
- Issue is a 1-file config or docs edit with no code logic
|
|
332
|
+
- The affected files have zero git history (new files being created)
|
|
333
|
+
- `{AFFECTED_FILES}` is empty (investigation produced no file list)
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Integration Point in work-on.md
|
|
338
|
+
|
|
339
|
+
This module runs at **Step 3C.5** — after Builder Contract is posted, before Implement:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
3C → Builder Contract posted
|
|
343
|
+
3C.5 → [THIS MODULE] Context gathering (max 2 min)
|
|
344
|
+
3F → Implement (builder now has context briefing)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
The builder agent reads the `<!-- FORGE:CONTEXT -->` comment before writing any code. If the context step was skipped, the builder proceeds with investigation report + contract only.
|
|
348
|
+
|
|
349
|
+
When prior investigation Gists are available (Phase C0), the `### Prior Investigation Findings` section gives the builder cross-issue context — root causes, recommendations, and affected files from upstream investigations — without requiring manual Gist lookups. When a milestone-level index Gist exists (GIST-04), Phase C0 can resolve the index to discover all investigation Gists for the milestone from a single URL — providing full milestone-wide context automatically. <!-- Updated: forge#341 -->
|