forgedock 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -33
- package/bin/cinema.mjs +23 -5
- package/bin/engine/invariants.mjs +361 -0
- package/bin/engine-cli.mjs +137 -11
- package/bin/env-detect.mjs +249 -0
- package/bin/forge-utils.mjs +364 -4
- package/bin/forgedock.mjs +1064 -135
- package/bin/hooks/pre-tool-use.mjs +182 -0
- package/bin/hooks/session-start.mjs +68 -3
- package/bin/init-detect.mjs +101 -12
- package/bin/journey.mjs +917 -16
- package/bin/labels.json +10 -0
- package/bin/recall.mjs +557 -0
- package/bin/registry.mjs +91 -3
- package/bin/runner.mjs +38 -2
- package/bin/tui.mjs +49 -3
- package/commands/adopt.md +1 -1
- package/commands/analytics.md +8 -8
- package/commands/audit.md +1 -1
- package/commands/autopilot.md +958 -77
- package/commands/ci-audit.md +1 -1
- package/commands/cleanup.md +139 -55
- package/commands/compat-audit.md +1 -1
- package/commands/deploy-info.md +1 -1
- package/commands/deploy-pr.md +1 -1
- package/commands/diagnose.md +1 -1
- package/commands/explain.md +1 -1
- package/commands/fix-ci.md +1 -1
- package/commands/forgedock-init.md +1 -1
- package/commands/incident-response.md +3 -3
- package/commands/issue.md +1 -1
- package/commands/optimize.md +586 -1
- package/commands/orchestrate/config.md +13 -3
- package/commands/orchestrate/phase-1-resolve.md +36 -26
- package/commands/orchestrate/phase-2-triage.md +1 -1
- package/commands/orchestrate/phase-2.5-synthesis.md +1 -1
- package/commands/orchestrate/phase-3-dependency.md +587 -48
- package/commands/orchestrate/phase-4-execution.md +1031 -57
- package/commands/orchestrate/phase-5-cleanup.md +1 -1
- package/commands/orchestrate/phase-6-report.md +248 -11
- package/commands/orchestrate/safety.md +2 -2
- package/commands/pipeline-health/phase-2-metrics.md +305 -1
- package/commands/pipeline-health/phase-4-proposals.md +127 -0
- package/commands/qa-sweep.md +1 -1
- package/commands/quality-gate.md +418 -1
- package/commands/recover-orphans.md +5 -5
- package/commands/replay.md +1 -1
- package/commands/review-pr-agents/api.md +2 -2
- package/commands/review-pr-agents/auth.md +2 -2
- package/commands/review-pr-agents/billing.md +2 -2
- package/commands/review-pr-agents/concurrency.md +2 -2
- package/commands/review-pr-agents/database.md +2 -2
- package/commands/review-pr-agents/frontend.md +2 -2
- package/commands/review-pr-agents/infra.md +2 -2
- package/commands/review-pr-agents/protocols.md +1 -1
- package/commands/review-pr-agents/scraper.md +2 -2
- package/commands/review-pr-agents/security.md +2 -2
- package/commands/review-pr-staging.md +41 -3
- package/commands/review-pr.md +462 -19
- package/commands/rollback.md +1 -1
- package/commands/scope.md +1 -1
- package/commands/security-audit.md +1 -1
- package/commands/spec-doctor.md +429 -0
- package/commands/test-gate.md +1 -1
- package/commands/validate.md +53 -1
- package/commands/work-on/build/architect.md +78 -1
- package/commands/work-on/build/context.md +360 -22
- package/commands/work-on/build/implement.md +3 -1
- package/commands/work-on/build/validate.md +29 -1
- package/commands/work-on/build.md +75 -6
- package/commands/work-on/close.md +624 -10
- package/commands/work-on/decompose.md +1 -1
- package/commands/work-on/investigate.md +235 -5
- package/commands/work-on/remediate.md +331 -0
- package/commands/work-on/review.md +1 -1
- package/commands/work-on-monolithic.md +1 -1
- package/commands/work-on.md +205 -66
- package/docs/CI.md +2 -2
- package/docs/CODEX.md +1 -1
- package/docs/CONFIG.md +186 -0
- package/docs/FORGE-PROTOCOL.md +101 -0
- package/docs/site/command-reference.md +31 -1
- package/docs/site/getting-started.md +9 -34
- package/docs/site/index.md +1 -1
- package/docs/spec/forge-protocol-v1.md +97 -5
- package/docs/spec/label-state-machine.md +6 -1
- package/package.json +3 -2
- package/packages/protocol/src/cli.js +374 -84
- package/packages/protocol/src/types.js +75 -1
- package/scripts/build-knowledge-index.mjs +1761 -0
- package/scripts/calibration.mjs +996 -0
- package/scripts/check-command-docs-drift.sh +4 -2
- package/scripts/danger-zones.mjs +789 -0
- package/scripts/doctor-pipeline-state.sh +88 -2
- package/scripts/select-fix-targets.sh +234 -0
- package/scripts/transition-label.sh +245 -6
- package/scripts/refresh-bot-token.sh +0 -97
package/commands/ci-audit.md
CHANGED
|
@@ -30,7 +30,7 @@ This command is designed to be run:
|
|
|
30
30
|
|
|
31
31
|
This is NOT a PR review — it does not approve or block. It creates issues for each CI gap found.
|
|
32
32
|
|
|
33
|
-
**Agent model policy**: `model: "
|
|
33
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
34
34
|
**NEVER use plan mode (EnterPlanMode).**
|
|
35
35
|
|
|
36
36
|
---
|
package/commands/cleanup.md
CHANGED
|
@@ -50,7 +50,7 @@ All `{GH_REPO}`, `{GH_FLAG}`, `{REPO_PATH}`, `{STAGING_BRANCH}`, `{PROJECT_BOARD
|
|
|
50
50
|
| `branches` | Prune worktrees and remote branches for merged PRs |
|
|
51
51
|
| `milestones` | Report milestones with 0 open issues (advisory — never closes) |
|
|
52
52
|
| `board` | Sync closed issues to Project board with correct terminal state |
|
|
53
|
-
| `batch-p3` | Sweep: fold stale unbatched P3 review findings into
|
|
53
|
+
| `batch-p3` | Sweep: fold stale unbatched P3 review findings into surface-area-grouped batch issues (same file, then leaf directory) |
|
|
54
54
|
| `all` | All of the above, in order |
|
|
55
55
|
|
|
56
56
|
---
|
|
@@ -68,6 +68,9 @@ gh issue list {GH_FLAG} --state closed --label "workflow:in-review" --limit 100
|
|
|
68
68
|
echo "=== Stale workflow:building ==="
|
|
69
69
|
gh issue list {GH_FLAG} --state closed --label "workflow:building" --limit 100 --json number,title --jq '.[] | "#\(.number) — \(.title)"'
|
|
70
70
|
|
|
71
|
+
echo "=== Stale workflow:awaiting-merge ==="
|
|
72
|
+
gh issue list {GH_FLAG} --state closed --label "workflow:awaiting-merge" --limit 100 --json number,title --jq '.[] | "#\(.number) — \(.title)"'
|
|
73
|
+
|
|
71
74
|
echo "=== Stale workflow:investigating ==="
|
|
72
75
|
gh issue list {GH_FLAG} --state closed --label "workflow:investigating" --limit 100 --json number,title --jq '.[] | "#\(.number) — \(.title)"'
|
|
73
76
|
|
|
@@ -79,11 +82,11 @@ gh issue list {GH_FLAG} --state closed --label "needs-validation" --limit 100 --
|
|
|
79
82
|
|
|
80
83
|
For each closed issue with a stale intermediate label:
|
|
81
84
|
|
|
82
|
-
**Stale `workflow:in-review`, `workflow:building`** — these were merged but label wasn't updated:
|
|
85
|
+
**Stale `workflow:in-review`, `workflow:building`, `workflow:awaiting-merge`** — these were merged but label wasn't updated:
|
|
83
86
|
```bash
|
|
84
87
|
for NUM in {stale_issue_numbers}; do
|
|
85
88
|
gh issue edit $NUM {GH_FLAG} --add-label "workflow:merged"
|
|
86
|
-
gh issue edit $NUM {GH_FLAG} --remove-label "workflow:in-review,workflow:building,needs-validation" 2>/dev/null || true
|
|
89
|
+
gh issue edit $NUM {GH_FLAG} --remove-label "workflow:in-review,workflow:building,workflow:awaiting-merge,needs-validation" 2>/dev/null || true
|
|
87
90
|
done
|
|
88
91
|
```
|
|
89
92
|
|
|
@@ -91,11 +94,58 @@ done
|
|
|
91
94
|
- If it has `workflow:invalid` already → just remove `workflow:investigating`
|
|
92
95
|
- If closed normally → add `workflow:merged`, remove `workflow:investigating`
|
|
93
96
|
|
|
94
|
-
**Stale `needs-validation`** —
|
|
97
|
+
**Stale `needs-validation`** — backfill from FORGE:INVESTIGATOR verdict where available; strip-only for issues with no verdict comment: <!-- Added: forge#1730 -->
|
|
98
|
+
|
|
99
|
+
This is the H1 backfill sweep from the Design Decision (#1730). For each closed finding-issue with `needs-validation`:
|
|
100
|
+
1. Fetch any `FORGE:INVESTIGATOR` comment on the issue
|
|
101
|
+
2. Extract the `**Verdict**: ...` line
|
|
102
|
+
3. `CONFIRMED` → apply `validated` + remove `needs-validation`
|
|
103
|
+
4. `NOT-CONFIRMED` / `INVALID` / `PARTIAL` → apply `false-positive` + remove `needs-validation`
|
|
104
|
+
5. No verdict comment (or unrecognized verdict) → strip `needs-validation` only (no label added — do not guess)
|
|
105
|
+
|
|
106
|
+
**H4 is forbidden**: Do NOT use file-overlap heuristics (whether a fix-PR touched the cited file) to infer validated/false-positive. H4 has ~10% error rate and poisons the corpus. If there is no FORGE:INVESTIGATOR comment, the issue goes to strip-only.
|
|
107
|
+
|
|
95
108
|
```bash
|
|
109
|
+
BACKFILL_VALIDATED=0
|
|
110
|
+
BACKFILL_FALSE_POSITIVE=0
|
|
111
|
+
BACKFILL_STRIP_ONLY=0
|
|
112
|
+
|
|
96
113
|
for NUM in {needs_validation_numbers}; do
|
|
97
|
-
|
|
114
|
+
# Fetch FORGE:INVESTIGATOR comment if any
|
|
115
|
+
INVESTIGATOR_COMMENT=$(gh api repos/{GH_REPO}/issues/$NUM/comments \
|
|
116
|
+
--jq '[.[] | select(.body | contains("FORGE:INVESTIGATOR"))] | last | .body // ""' 2>/dev/null || echo "")
|
|
117
|
+
|
|
118
|
+
if [ -n "$INVESTIGATOR_COMMENT" ]; then
|
|
119
|
+
# Extract verdict — matches "**Verdict**: CONFIRMED" etc.
|
|
120
|
+
VERDICT=$(echo "$INVESTIGATOR_COMMENT" | grep -oE '\*\*Verdict\*\*: [A-Za-z0-9_][A-Za-z0-9_-]*' | sed 's/^\*\*Verdict\*\*: //' | head -1)
|
|
121
|
+
|
|
122
|
+
case "$VERDICT" in
|
|
123
|
+
CONFIRMED)
|
|
124
|
+
gh issue edit $NUM {GH_FLAG} --add-label "validated" --remove-label "needs-validation" 2>/dev/null || true
|
|
125
|
+
echo "#$NUM: needs-validation → validated (verdict: CONFIRMED)"
|
|
126
|
+
BACKFILL_VALIDATED=$((BACKFILL_VALIDATED + 1))
|
|
127
|
+
;;
|
|
128
|
+
NOT-CONFIRMED|INVALID|PARTIAL)
|
|
129
|
+
gh issue edit $NUM {GH_FLAG} --add-label "false-positive" --remove-label "needs-validation" 2>/dev/null || true
|
|
130
|
+
echo "#$NUM: needs-validation → false-positive (verdict: $VERDICT)"
|
|
131
|
+
BACKFILL_FALSE_POSITIVE=$((BACKFILL_FALSE_POSITIVE + 1))
|
|
132
|
+
;;
|
|
133
|
+
*)
|
|
134
|
+
# Unrecognized or empty verdict — strip-only (no guessing)
|
|
135
|
+
gh issue edit $NUM {GH_FLAG} --remove-label "needs-validation" 2>/dev/null || true
|
|
136
|
+
echo "#$NUM: needs-validation stripped (no recognized verdict in INVESTIGATOR comment)"
|
|
137
|
+
BACKFILL_STRIP_ONLY=$((BACKFILL_STRIP_ONLY + 1))
|
|
138
|
+
;;
|
|
139
|
+
esac
|
|
140
|
+
else
|
|
141
|
+
# No INVESTIGATOR comment — strip-only
|
|
142
|
+
gh issue edit $NUM {GH_FLAG} --remove-label "needs-validation" 2>/dev/null || true
|
|
143
|
+
echo "#$NUM: needs-validation stripped (no FORGE:INVESTIGATOR comment found)"
|
|
144
|
+
BACKFILL_STRIP_ONLY=$((BACKFILL_STRIP_ONLY + 1))
|
|
145
|
+
fi
|
|
98
146
|
done
|
|
147
|
+
|
|
148
|
+
echo "Backfill complete: validated=$BACKFILL_VALIDATED false-positive=$BACKFILL_FALSE_POSITIVE strip-only=$BACKFILL_STRIP_ONLY"
|
|
99
149
|
```
|
|
100
150
|
|
|
101
151
|
### 1C: Report closed issues with NO workflow label
|
|
@@ -176,7 +226,7 @@ For each orphaned issue found:
|
|
|
176
226
|
```bash
|
|
177
227
|
gh issue close $NUM {GH_FLAG} --comment "Closed by cleanup — PR #$MERGED_PR was already merged."
|
|
178
228
|
gh issue edit $NUM {GH_FLAG} --add-label "workflow:merged"
|
|
179
|
-
gh issue edit $NUM {GH_FLAG} --remove-label "workflow:in-review" 2>/dev/null || true
|
|
229
|
+
gh issue edit $NUM {GH_FLAG} --remove-label "workflow:in-review,workflow:awaiting-merge" 2>/dev/null || true
|
|
180
230
|
```
|
|
181
231
|
|
|
182
232
|
Also check open issues with `workflow:building` — same pattern (search for merged PRs referencing them).
|
|
@@ -323,101 +373,132 @@ Do NOT call `gh api ... -X PATCH -f state=closed` on any milestone. This phase i
|
|
|
323
373
|
## Phase 4B: P3 Batch Sweep (if `batch-p3` or `all`)
|
|
324
374
|
|
|
325
375
|
<!-- Added: forge#1333 -->
|
|
376
|
+
<!-- Extended: forge#1828 — brought into lockstep with the P3 batching rule extension in orchestrate/phase-1-resolve.md and orchestrate/phase-4-execution.md (forge#1818): default-batchable eligibility, surface-area grouping, two-tier threshold, extended safety exclusions -->
|
|
326
377
|
|
|
327
|
-
**Purpose**: Fold stale unbatched P3 review findings into
|
|
378
|
+
**Purpose**: Fold stale unbatched P3 review findings into surface-area-grouped batch issues (same file first, leaf directory as broader fallback). Reduces pipeline overhead from individual per-finding full-pipeline runs. This sweep applies the same batching rule as `orchestrate/phase-1-resolve.md`'s "P3 Review-Finding Batching" section (the canonical definition) — this file is a periodic, cross-run pass over the same policy that Phase 1 (at `/orchestrate` start) and Phase 4C (mid-run cascade findings, `phase-4-execution.md`) already apply.
|
|
328
379
|
|
|
329
380
|
**Skip if**: Input is not `batch-p3` and not `all`.
|
|
330
381
|
|
|
331
382
|
### Step 4B.1: Fetch open batchable P3 findings
|
|
332
383
|
|
|
384
|
+
Eligibility is **default-batchable**: any open `review-finding` + `priority:P3` issue qualifies unless excluded below. The `<!-- FORGE:BATCHABLE -->` marker (still appended by `review-pr.md` at finding-creation time) is honored when present but is no longer required — matching `phase-1-resolve.md`'s eligibility rule. <!-- Changed: forge#1828 — marker was previously mandatory -->
|
|
385
|
+
|
|
333
386
|
```bash
|
|
334
|
-
# Find all open P3 review findings
|
|
335
|
-
#
|
|
387
|
+
# Find all open, unbatched P3 review findings. Excludes findings already
|
|
388
|
+
# claimed by a batch ("batch" label), and applies the same extended safety
|
|
389
|
+
# exclusions (security, billing, anti-bot, auth) as the other two batching
|
|
390
|
+
# sites, using the identical jq test() (Oniguruma) patterns so classification
|
|
391
|
+
# cannot diverge between the three sweep locations. <!-- Changed: forge#1828 -->
|
|
336
392
|
UNBATCHED_P3=$(gh issue list {GH_FLAG} \
|
|
337
393
|
--state open \
|
|
338
394
|
--label "review-finding,priority:P3" \
|
|
339
395
|
--limit 500 \
|
|
340
396
|
--json number,title,body,labels,createdAt \
|
|
341
|
-
--jq '.[] | select(.
|
|
342
|
-
| select((
|
|
343
|
-
| select(
|
|
344
|
-
| select((.
|
|
397
|
+
--jq '.[] | select(([.labels[].name] | any(. == "batch")) | not)
|
|
398
|
+
| select((.title | test("security|billing|anti-bot|auth"; "i")) | not)
|
|
399
|
+
| select(.body | test("## Problem[\\s\\S]{0,500}(security|billing|anti-bot|auth)"; "i") | not)
|
|
400
|
+
| select(([.labels[].name] | any(. == "security" or . == "billing" or . == "anti-bot" or . == "auth")) | not)')
|
|
345
401
|
|
|
346
402
|
echo "Unbatched batchable P3 findings: $(echo "$UNBATCHED_P3" | jq -s 'length')"
|
|
347
403
|
```
|
|
348
404
|
|
|
349
|
-
### Step 4B.2: Group by
|
|
405
|
+
### Step 4B.2: Group by surface area (same file, then leaf directory)
|
|
350
406
|
|
|
351
|
-
|
|
407
|
+
<!-- Changed: forge#1828 — was coarse domain grouping (`cut -d/ -f1,2,3`); now surface area, matching phase-1-resolve.md -->
|
|
352
408
|
|
|
353
|
-
|
|
354
|
-
# Domain = top-level directory of the first affected file
|
|
355
|
-
# e.g., "services/api/auth/login.py" → "services/api/auth"
|
|
356
|
-
# "commands/review-pr.md" → "commands"
|
|
357
|
-
# Exclude findings where the domain contains "billing" or "security"
|
|
409
|
+
For each finding, extract the exact affected-file path under `## Affected Files` (primary grouping key) and its leaf directory — `dirname` of that path — as a broader fallback key:
|
|
358
410
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
411
|
+
```bash
|
|
412
|
+
# Surface area = the exact affected file path listed first under "## Affected
|
|
413
|
+
# Files" (primary key). Leaf directory = dirname of that file (fallback key).
|
|
414
|
+
# e.g., "commands/orchestrate/phase-1-resolve.md" → file "commands/orchestrate/phase-1-resolve.md", leaf-dir "commands/orchestrate"
|
|
415
|
+
# "commands/review-pr.md" → file "commands/review-pr.md", leaf-dir "commands"
|
|
416
|
+
# (security/billing/anti-bot/auth paths are already excluded in Step 4B.1)
|
|
417
|
+
|
|
418
|
+
# Group findings by file (primary) and by leaf directory (fallback), tracking
|
|
419
|
+
# oldest creation timestamp per group
|
|
420
|
+
declare -A FILE_ISSUES
|
|
421
|
+
declare -A FILE_OLDEST
|
|
422
|
+
declare -A DIR_ISSUES
|
|
423
|
+
declare -A DIR_OLDEST
|
|
362
424
|
|
|
363
425
|
echo "$UNBATCHED_P3" | jq -c '.[]' | while read -r issue; do
|
|
364
426
|
NUM=$(echo "$issue" | jq -r '.number')
|
|
365
427
|
CREATED=$(echo "$issue" | jq -r '.createdAt')
|
|
366
428
|
BODY=$(echo "$issue" | jq -r '.body')
|
|
367
429
|
|
|
368
|
-
# Extract first affected file path from body
|
|
369
|
-
|
|
430
|
+
# Extract first affected file path from body. Uses POSIX ERE (`grep -oE`),
|
|
431
|
+
# NOT PCRE lookbehind (`grep -oP '(?<=...)'`) — the prior fallback line here
|
|
432
|
+
# used `-P`, which BSD grep on macOS does not support (forge#1767). This
|
|
433
|
+
# pattern matches the portable one already used in phase-4-execution.md's
|
|
434
|
+
# same-run surface-area batching. <!-- Changed: forge#1828 -->
|
|
435
|
+
FIRST_FILE=$(echo "$BODY" | sed -n '/^## Affected Files/,/^## /p' | grep -oE '`[^`]+`' | head -1 | tr -d '`')
|
|
370
436
|
if [ -z "$FIRST_FILE" ]; then
|
|
371
|
-
FIRST_FILE=$(echo "$BODY" | grep -
|
|
437
|
+
FIRST_FILE=$(echo "$BODY" | grep -oE '`[^`]+\.(py|tsx?|jsx?|sql|json|ya?ml|sh|md)`' | head -1 | tr -d '`')
|
|
372
438
|
fi
|
|
373
|
-
|
|
374
|
-
|
|
439
|
+
[ -z "$FIRST_FILE" ] && FIRST_FILE="unknown"
|
|
440
|
+
LEAF_DIR=$(dirname "$FIRST_FILE")
|
|
375
441
|
|
|
376
|
-
echo "${NUM}:${
|
|
442
|
+
echo "${NUM}:${FIRST_FILE}:${LEAF_DIR}:${CREATED}"
|
|
377
443
|
done
|
|
378
444
|
```
|
|
379
445
|
|
|
380
|
-
### Step 4B.3: Apply batching threshold
|
|
446
|
+
### Step 4B.3: Apply two-tier batching threshold
|
|
447
|
+
|
|
448
|
+
<!-- Changed: forge#1828 — added lower same-file tier, matching phase-1-resolve.md's two-tier threshold -->
|
|
381
449
|
|
|
382
|
-
|
|
383
|
-
- **
|
|
384
|
-
-
|
|
450
|
+
- **Same-file cluster** (primary, low threshold): **2+** unbatched batchable P3 findings share the exact same affected file → create a batch issue for that file cluster.
|
|
451
|
+
- **Leaf-directory cluster** (broader fallback, existing threshold preserved): among findings NOT already claimed by a same-file cluster above, **5+** share the same leaf directory, **OR** the oldest finding in that leaf directory is > 72 hours old → create a batch issue for that leaf-directory cluster.
|
|
452
|
+
- Form same-file clusters first; only findings left ungrouped after that pass are evaluated for leaf-directory clustering. A finding is claimed by at most one batch.
|
|
385
453
|
|
|
386
454
|
```bash
|
|
387
455
|
NOW_EPOCH=$(date +%s)
|
|
388
456
|
HOURS_72=$((72 * 3600))
|
|
457
|
+
MAX_MEMBERS=8 # Changed: forge#1828 — was 10, matching phase-1-resolve.md's cap
|
|
458
|
+
|
|
459
|
+
# Pass 1 — same-file clusters (2+ members). Claim member issue numbers into
|
|
460
|
+
# CLAIMED_BY_FILE so Pass 2 (leaf-directory) skips them.
|
|
461
|
+
CLAIMED_BY_FILE=""
|
|
462
|
+
echo "$FILE_ISSUES" | while IFS=: read -r file issue_list; do
|
|
463
|
+
COUNT=$(echo "$issue_list" | tr ',' '\n' | grep -c .)
|
|
464
|
+
if [ "$COUNT" -ge 2 ]; then
|
|
465
|
+
echo "Batching $COUNT P3 findings — same-file cluster: ${file}"
|
|
466
|
+
# Create batch issue(s) in chunks of <= MAX_MEMBERS members (see Batch
|
|
467
|
+
# creation below). Record consumed issue numbers in CLAIMED_BY_FILE.
|
|
468
|
+
fi
|
|
469
|
+
done
|
|
389
470
|
|
|
390
|
-
#
|
|
391
|
-
#
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
echo "$
|
|
395
|
-
|
|
471
|
+
# Pass 2 — leaf-directory clusters (5+ members, or oldest > 72h), excluding
|
|
472
|
+
# any issue already claimed by a same-file cluster in Pass 1
|
|
473
|
+
echo "$DIR_ISSUES" | while IFS=: read -r dir issue_list; do
|
|
474
|
+
REMAINING=$(echo "$issue_list" | tr ',' '\n' | grep -vxF -f <(printf '%s\n' "$CLAIMED_BY_FILE" | tr ',' '\n') || true)
|
|
475
|
+
COUNT=$(echo "$REMAINING" | grep -c . || echo 0)
|
|
476
|
+
[ "$COUNT" -eq 0 ] && continue
|
|
396
477
|
|
|
397
|
-
|
|
398
|
-
OLDEST_EPOCH=$(echo "$DOMAIN_OLDEST[$domain]" | date -d "$..." +%s 2>/dev/null || echo "$NOW_EPOCH")
|
|
478
|
+
OLDEST_EPOCH=$(echo "${DIR_OLDEST[$dir]}" | date -d "$..." +%s 2>/dev/null || echo "$NOW_EPOCH")
|
|
399
479
|
AGE_SECS=$((NOW_EPOCH - OLDEST_EPOCH))
|
|
400
480
|
|
|
401
481
|
if [ "$COUNT" -ge 5 ] || [ "$AGE_SECS" -ge "$HOURS_72" ]; then
|
|
402
|
-
echo "Batching $COUNT P3 findings
|
|
403
|
-
# Create batch
|
|
404
|
-
#
|
|
482
|
+
echo "Batching $COUNT P3 findings — leaf-directory cluster: ${dir}"
|
|
483
|
+
# Create batch issue(s) in chunks of <= MAX_MEMBERS members (see Batch
|
|
484
|
+
# creation below).
|
|
405
485
|
fi
|
|
406
486
|
done
|
|
407
487
|
```
|
|
408
488
|
|
|
409
|
-
**Batch creation** uses the same template as `orchestrate.md Phase 1 → P3 Review-Finding Batching
|
|
489
|
+
**Batch creation** uses the same template as `orchestrate.md Phase 1 → P3 Review-Finding Batching`, including its surface-area path sanitization (`tr -cd 'A-Za-z0-9._/-'` on the file/directory value before interpolating it into the batch issue's `--title`/`--body`). After creating the batch issue, add the `batch` label to each member issue to prevent re-batching on the next sweep.
|
|
410
490
|
|
|
411
491
|
### Step 4B.4: Report
|
|
412
492
|
|
|
413
493
|
```
|
|
414
494
|
## P3 Batch Sweep
|
|
415
495
|
|
|
416
|
-
|
|
|
417
|
-
|
|
418
|
-
| {
|
|
419
|
-
| {
|
|
420
|
-
| {
|
|
496
|
+
| Surface Area | Unbatched P3s | Threshold Met | Action |
|
|
497
|
+
|---------------|--------------|---------------|--------|
|
|
498
|
+
| {file} | {N} | ≥2 same-file | Created batch #{NUM} ({M} members) |
|
|
499
|
+
| {leaf-dir} | {N} | ≥5 issues | Created batch #{NUM} ({M} members) |
|
|
500
|
+
| {leaf-dir} | {N} | Oldest > 72h | Created batch #{NUM} ({M} members) |
|
|
501
|
+
| {leaf-dir} | {N} | Below threshold | No action |
|
|
421
502
|
|
|
422
503
|
Total batch issues created: {N}
|
|
423
504
|
Total P3 findings batched: {N}
|
|
@@ -465,7 +546,9 @@ fi
|
|
|
465
546
|
| workflow:in-review → workflow:merged | {N} |
|
|
466
547
|
| workflow:building → workflow:merged | {N} |
|
|
467
548
|
| workflow:investigating → cleaned | {N} |
|
|
468
|
-
| needs-validation
|
|
549
|
+
| needs-validation → validated (backfill H1) | {N} |
|
|
550
|
+
| needs-validation → false-positive (backfill H1) | {N} |
|
|
551
|
+
| needs-validation stripped (no verdict) | {N} |
|
|
469
552
|
|
|
470
553
|
### Stale-Open Intermediate Issues (Phase 1D)
|
|
471
554
|
| Issue | Label | Last Update | Action |
|
|
@@ -501,8 +584,9 @@ fi
|
|
|
501
584
|
{N} closed issues have no workflow label (closed outside pipeline — no action needed)
|
|
502
585
|
|
|
503
586
|
### P3 Batch Sweep Results
|
|
504
|
-
|
|
|
505
|
-
|
|
506
|
-
| {
|
|
507
|
-
| {
|
|
587
|
+
| Surface Area | Unbatched P3s | Action |
|
|
588
|
+
|---------------|--------------|--------|
|
|
589
|
+
| {file} | {N} | Created batch #{NUM} with {M} members (same-file, ≥2) |
|
|
590
|
+
| {leaf-dir} | {N} | Created batch #{NUM} with {M} members (leaf-directory, ≥5 or >72h) |
|
|
591
|
+
| {leaf-dir} | {N} | Below threshold — no action (< 5 findings, none > 72h, no same-file pair) |
|
|
508
592
|
```
|
package/commands/compat-audit.md
CHANGED
|
@@ -10,7 +10,7 @@ install: extras
|
|
|
10
10
|
|
|
11
11
|
You are the ForgeDock compatibility auditor. Produce a point-in-time advisory report that shows whether the user's installed Claude Code version is current and which ForgeDock features may behave differently on their runtime. This command is **non-blocking** — it never aborts the session. All output is advisory.
|
|
12
12
|
|
|
13
|
-
**Agent model policy**: `model: "
|
|
13
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
14
14
|
**NEVER use plan mode (EnterPlanMode).**
|
|
15
15
|
|
|
16
16
|
---
|
package/commands/deploy-info.md
CHANGED
|
@@ -16,7 +16,7 @@ install: extras
|
|
|
16
16
|
|
|
17
17
|
You are the pipeline's deploy awareness layer. Before the user merges staging → main (triggering CI/CD deployment), this command shows exactly what's going out: which PRs, which issues, what changed, and what risks exist.
|
|
18
18
|
|
|
19
|
-
**Agent model policy**: `model: "
|
|
19
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
20
20
|
|
|
21
21
|
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
22
22
|
|
package/commands/deploy-pr.md
CHANGED
|
@@ -13,7 +13,7 @@ allowed-tools: Bash, Read, Grep, Glob, Skill
|
|
|
13
13
|
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
14
14
|
**NEVER use the Agent tool** — deploy-pr dispatches sub-skills via `Skill(...)` only. The Agent tool bypasses the allowed-tools constraint and produces opaque output that cannot be structured into the deploy result.
|
|
15
15
|
|
|
16
|
-
**Agent model policy**: `model: "
|
|
16
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`.
|
|
17
17
|
|
|
18
18
|
<!-- FORGE:SPEC_LOADED — deploy-pr.md loaded and active. Agent is bound by this spec. -->
|
|
19
19
|
|
package/commands/diagnose.md
CHANGED
|
@@ -10,7 +10,7 @@ install: extras
|
|
|
10
10
|
|
|
11
11
|
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
12
12
|
|
|
13
|
-
**Agent model policy**: `model: "
|
|
13
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
14
14
|
|
|
15
15
|
You are the pipeline's diagnostic layer. Given a single GitHub issue number, you reconstruct the full FORGE annotation chain for that pipeline run, identify the exact failure point, and suggest specific remediation steps. This command is **read-only** — it never mutates GitHub state.
|
|
16
16
|
|
package/commands/explain.md
CHANGED
|
@@ -10,7 +10,7 @@ install: extras
|
|
|
10
10
|
|
|
11
11
|
You translate the FORGE pipeline's machine-readable annotations on a GitHub issue or PR into a clear, plain-English narrative that anyone can understand — no pipeline knowledge required. This is a read-only command: it never writes to GitHub, never changes labels, and never modifies any state.
|
|
12
12
|
|
|
13
|
-
**Agent model policy**: `model: "
|
|
13
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
14
14
|
**NEVER use plan mode (EnterPlanMode).**
|
|
15
15
|
|
|
16
16
|
---
|
package/commands/fix-ci.md
CHANGED
|
@@ -13,7 +13,7 @@ argument-hint: <PR number or URL> [--max-attempts N] [--repo owner/repo]
|
|
|
13
13
|
|
|
14
14
|
**Output**: Structured result — `{ pr, status, attempts, fixes_applied }` — printed to stdout and available to the calling skill.
|
|
15
15
|
|
|
16
|
-
**Agent model policy**: `model: "
|
|
16
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
17
17
|
**NEVER use plan mode (EnterPlanMode).**
|
|
18
18
|
**NEVER force-push or amend commits** — always create new commits.
|
|
19
19
|
|
|
@@ -11,7 +11,7 @@ argument-hint: [--preserve | --interactive | --section <name>]
|
|
|
11
11
|
|
|
12
12
|
You complete the `forge.yaml` configuration that `npx forgedock init` started. The CLI generates required sections (project, paths, branches) from auto-detection. Your job is to scan the codebase, query GitHub APIs, and produce a complete `forge.yaml` with every applicable optional section filled — using detected values directly, without asking for confirmation.
|
|
13
13
|
|
|
14
|
-
**Agent model policy**: `model: "
|
|
14
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
15
15
|
**NEVER use plan mode (EnterPlanMode).**
|
|
16
16
|
|
|
17
17
|
---
|
|
@@ -16,7 +16,7 @@ install: extras
|
|
|
16
16
|
|
|
17
17
|
You are the pipeline's incident response coordinator. When production goes down or a critical bug surfaces, this command orchestrates the response: validates the hotfix before deploy, reconstructs the incident timeline, and produces a post-incident analysis.
|
|
18
18
|
|
|
19
|
-
**Agent model policy**: `model: "
|
|
19
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
20
20
|
|
|
21
21
|
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
22
22
|
|
|
@@ -109,7 +109,7 @@ gh api repos/{owner}/{repo}/issues/{NUMBER}/comments \
|
|
|
109
109
|
Spawn a validation agent to check the proposed fix:
|
|
110
110
|
|
|
111
111
|
```
|
|
112
|
-
Agent(model="
|
|
112
|
+
Agent(model="{SUBAGENT_MODEL}", prompt="
|
|
113
113
|
You are validating a hotfix for a P0 production incident.
|
|
114
114
|
|
|
115
115
|
Issue: #{NUMBER} — {TITLE}
|
|
@@ -242,7 +242,7 @@ gh pr list --state merged --base main --json number,title,mergedAt \
|
|
|
242
242
|
Spawn an investigation agent:
|
|
243
243
|
|
|
244
244
|
```
|
|
245
|
-
Agent(model="
|
|
245
|
+
Agent(model="{SUBAGENT_MODEL}", prompt="
|
|
246
246
|
You are conducting a post-incident root cause analysis.
|
|
247
247
|
|
|
248
248
|
Incident: #{NUMBER} — {TITLE}
|
package/commands/issue.md
CHANGED
|
@@ -11,7 +11,7 @@ argument-hint: [description of the problem or feature]
|
|
|
11
11
|
|
|
12
12
|
You create GitHub issues with the exact structure the `/work-on` pipeline expects. Every issue you create must give the investigation agent enough context to find the right files on the first pass — no vague descriptions, no missing domains, no ambiguous scope.
|
|
13
13
|
|
|
14
|
-
**Agent model policy**: `model: "
|
|
14
|
+
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
15
15
|
**NEVER use plan mode (EnterPlanMode).**
|
|
16
16
|
|
|
17
17
|
---
|