forgedock 1.0.19 → 1.0.20
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/commands/orchestrate.md +200 -150
- package/package.json +1 -1
package/commands/orchestrate.md
CHANGED
|
@@ -13,9 +13,9 @@ argument-hint: [milestone <slug> | #1 #2 #3 | next <N> | fast-lane | priority:P0
|
|
|
13
13
|
|
|
14
14
|
1. **Every agent MUST invoke `/work-on` via the Skill tool.** You do NOT write implementation prompts. You copy the Phase 4A template verbatim and fill in the `{VARIABLES}`. Nothing else. No custom prompts. No "just read and edit" shortcuts. The Skill tool invocation is what triggers labels, investigation comments, structured review, and trajectory tracking. Without it, the agent's work has no paper trail and is worthless.
|
|
15
15
|
|
|
16
|
-
2. **You are a dispatcher, not a builder.** You resolve issues,
|
|
16
|
+
2. **You are a dispatcher, not a builder.** You resolve issues, build the dependency DAG, spawn agents, and report results. You NEVER read code, edit files, or implement fixes yourself.
|
|
17
17
|
|
|
18
|
-
3. **After each
|
|
18
|
+
3. **After each agent completes, verify it used `/work-on`.** Check that completed issues have `workflow:*` labels and structured comments. If an agent bypassed the pipeline, report it as a failure.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -131,7 +131,7 @@ If a `workflow:decomposed` issue is found, automatically expand it to its open s
|
|
|
131
131
|
**What the orchestrator SHOULD do:**
|
|
132
132
|
- If two issues look related, add a note in the agent prompt: "Note: #{OTHER} has similar symptoms — investigate whether this is the same root cause or a different code path"
|
|
133
133
|
- Let both agents run independently — if one finds it's truly a duplicate, `/work-on`'s investigation phase will close it as invalid with evidence
|
|
134
|
-
- Flag potential overlap in the
|
|
134
|
+
- Flag potential overlap in the DAG plan for the user's awareness, but NEVER act on it
|
|
135
135
|
|
|
136
136
|
**Why**: Surface-level similarity hides critical differences. #3842 (api_key.id lazy load) and #4039 (user.id lazy load) had identical error messages but targeted completely different ORM objects. Closing #4039 as a "duplicate" would have left a customer-impacting P0 bug unfixed.
|
|
137
137
|
|
|
@@ -274,7 +274,7 @@ done
|
|
|
274
274
|
|
|
275
275
|
### Step 3B: Domain estimation
|
|
276
276
|
|
|
277
|
-
For each issue, estimate which domains it touches based on title, body, and labels. This improves
|
|
277
|
+
For each issue, estimate which domains it touches based on title, body, and labels. This improves DAG construction — issues in the same domain likely touch the same files and should be serialized (one becomes a predecessor of the other).
|
|
278
278
|
|
|
279
279
|
```bash
|
|
280
280
|
for NUM in {issue_numbers}; do
|
|
@@ -291,11 +291,11 @@ for NUM in {issue_numbers}; do
|
|
|
291
291
|
done
|
|
292
292
|
```
|
|
293
293
|
|
|
294
|
-
**Use domain info for
|
|
295
|
-
- Issues in the SAME domain (especially WORKER, BILLING, DATABASE) are more likely to touch the same files →
|
|
294
|
+
**Use domain info for DAG edge construction:**
|
|
295
|
+
- Issues in the SAME domain (especially WORKER, BILLING, DATABASE) are more likely to touch the same files → add predecessor edges to serialize them
|
|
296
296
|
- Issues in DIFFERENT domains are more likely independent → safe to parallelize
|
|
297
297
|
- BILLING + AUTH issues should be prioritized early (security-critical)
|
|
298
|
-
- **DATABASE issues are ALWAYS serialized — hard rule, no exceptions.** Multiple agents writing migrations simultaneously will produce duplicate migration numbers (e.g., two `0067_*.sql` files), which breaks the migration runner.
|
|
298
|
+
- **DATABASE issues are ALWAYS serialized — hard rule, no exceptions.** Multiple agents writing migrations simultaneously will produce duplicate migration numbers (e.g., two `0067_*.sql` files), which breaks the migration runner. DATABASE issues form a linear predecessor chain in the DAG. If 3 DATABASE issues are in a batch: A has no predecessors, B has {A} as predecessor, C has {B} as predecessor.
|
|
299
299
|
|
|
300
300
|
**Store domain tags per issue** for use in the plan presentation (Step 3E).
|
|
301
301
|
|
|
@@ -323,9 +323,9 @@ gh issue view $NUM --json body --jq '.body' | grep -oP '`[^`]*\.(py|tsx?|jsx?|sq
|
|
|
323
323
|
```
|
|
324
324
|
|
|
325
325
|
**Cross-reference all extracted file lists:**
|
|
326
|
-
- If two issues share ANY affected file →
|
|
326
|
+
- If two issues share ANY affected file → one MUST be a predecessor of the other (serialized)
|
|
327
327
|
- The issue with lower issue number goes first (stable ordering), unless an explicit `Depends on #` says otherwise
|
|
328
|
-
- Add a conflict note to the
|
|
328
|
+
- Add a conflict note to the DAG plan: "#{A} and #{B} both modify `{file}` — #{A} is predecessor of #{B}"
|
|
329
329
|
|
|
330
330
|
#### Layer 2: Directory-proximity detection
|
|
331
331
|
|
|
@@ -395,10 +395,10 @@ When file extraction yields **fewer than 2 file paths** for an issue (common for
|
|
|
395
395
|
|
|
396
396
|
**Rules:**
|
|
397
397
|
- If an issue has 0-1 extracted file paths AND shares a domain tag (from Step 3B) with another issue → serialize them
|
|
398
|
-
- If an issue has 0 extracted file paths AND no domain tag could be determined → serialize it
|
|
398
|
+
- If an issue has 0 extracted file paths AND no domain tag could be determined → add it as a predecessor of the next same-domain issue, or if no domain match exists, serialize it after the most recently added issue (safest default)
|
|
399
399
|
- Add a note to the plan: "#{N} — low file-extraction confidence, serialized conservatively"
|
|
400
400
|
|
|
401
|
-
**Rationale**: The cost of a false-negative (two agents conflict → one fails with merge error, wasting the full agent run) far exceeds the cost of a false-positive (an issue waits one
|
|
401
|
+
**Rationale**: The cost of a false-negative (two agents conflict → one fails with merge error, wasting the full agent run) far exceeds the cost of a false-positive (an issue waits for one predecessor before starting). Always err toward serialization when uncertain.
|
|
402
402
|
|
|
403
403
|
#### Combining all layers
|
|
404
404
|
|
|
@@ -413,29 +413,46 @@ Build the final conflict graph by merging signals from all four layers:
|
|
|
413
413
|
| Layer 3: High-fan-in file touched | **Probable conflict** | Serialize with same-service issues |
|
|
414
414
|
| Layer 3: Shared model/init pattern | **Probable conflict** | Serialize |
|
|
415
415
|
| Layer 4: Low confidence + same domain | **Conservative** | Serialize |
|
|
416
|
-
| Layer 4: Low confidence + no domain | **Conservative** |
|
|
416
|
+
| Layer 4: Low confidence + no domain | **Conservative** | Add predecessor edge to most recent issue |
|
|
417
417
|
|
|
418
418
|
**This supplements, not replaces, the domain keyword estimation.** Domain tags still help with broad sequencing decisions. Multi-layer conflict detection catches the specific cases keywords miss (e.g., two issues that both modify files in `services/api/app/models/` where one is labeled WORKER and the other BILLING — Layer 2 catches this even though Layer 1 shows no direct file overlap).
|
|
419
419
|
|
|
420
|
-
### Step 3D: Build the
|
|
420
|
+
### Step 3D: Build the dependency DAG
|
|
421
421
|
|
|
422
|
-
|
|
422
|
+
Build a **directed acyclic graph (DAG)** of per-issue dependencies. Each issue gets a `predecessors` set — the specific issues that must reach a terminal state before this issue can dispatch. This replaces the previous wave-grouping model where all issues in a wave had to complete before any issue in the next wave could start.
|
|
423
423
|
|
|
424
|
-
**
|
|
425
|
-
- Investigation issues already ran in
|
|
426
|
-
-
|
|
427
|
-
-
|
|
428
|
-
- **
|
|
429
|
-
-
|
|
430
|
-
-
|
|
424
|
+
**DAG construction rules:**
|
|
425
|
+
- Investigation issues already ran in Phase 2 — they are NOT included in this DAG
|
|
426
|
+
- Each issue starts with an empty predecessor set
|
|
427
|
+
- **Explicit dependencies**: If issue B says "Depends on #A" or "Blocked by #A", add A to B's predecessors
|
|
428
|
+
- **File-conflict edges**: If two issues share affected files (from Step 3C Layer 1), add a directed edge: lower issue number → higher issue number (unless explicit deps say otherwise). The later issue has the earlier issue in its predecessors.
|
|
429
|
+
- **Domain serialization edges**: DATABASE issues form a linear chain (each has the previous DATABASE issue as its predecessor). Same-small-directory issues (Layer 2) and high-fan-in file issues (Layer 3) get directed edges as per Step 3C rules.
|
|
430
|
+
- **Conservative fallback edges**: Low-confidence issues (Layer 4) get edges to same-domain issues as per Step 3C rules.
|
|
431
|
+
- **No artificial concurrency limit** — all issues with empty predecessor sets dispatch simultaneously. The only constraints are file overlap and explicit dependencies.
|
|
431
432
|
|
|
432
|
-
**
|
|
433
|
+
**Terminology:**
|
|
434
|
+
- **Ready issues**: Issues whose predecessor set is empty (all predecessors have reached terminal state or were never added)
|
|
435
|
+
- **Blocked issues**: Issues with one or more unresolved predecessors
|
|
436
|
+
- **Critical path**: The longest chain of dependent issues in the DAG — determines minimum wall-clock time
|
|
437
|
+
|
|
438
|
+
**Example DAG:**
|
|
433
439
|
```
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
440
|
+
Phase 2 (already done): #2644 (investigation) → spawned #2645, #2646, #2647
|
|
441
|
+
|
|
442
|
+
Dependency graph:
|
|
443
|
+
#2633 (orphaned queues) → predecessors: {} ← READY
|
|
444
|
+
#2636 (invalidation sub) → predecessors: {} ← READY
|
|
445
|
+
#2645 (new finding) → predecessors: {} ← READY
|
|
446
|
+
#2646 (new finding) → predecessors: {} ← READY
|
|
447
|
+
#2634 (enable daemon) → predecessors: {#2633} ← blocked until #2633 completes
|
|
448
|
+
#2647 (depends on #2645) → predecessors: {#2645} ← blocked until #2645 completes
|
|
449
|
+
|
|
450
|
+
Critical path: #2633 → #2634 (2 steps) or #2645 → #2647 (2 steps)
|
|
451
|
+
Initial dispatch: #2633, #2636, #2645, #2646 (all ready — launched simultaneously)
|
|
437
452
|
```
|
|
438
453
|
|
|
454
|
+
**Key advantage over waves**: When #2633 completes, #2634 dispatches immediately — it does not wait for #2636, #2645, or #2646 to finish. Similarly, when #2645 completes, #2647 dispatches immediately regardless of other issues' status.
|
|
455
|
+
|
|
439
456
|
### Step 3E: Present the plan to the user
|
|
440
457
|
|
|
441
458
|
```
|
|
@@ -443,39 +460,46 @@ Wave 2 (after deps): #2634 (enable daemon — after #2633 fixes memory leak), #2
|
|
|
443
460
|
|
|
444
461
|
**Scope**: {milestone name / "N issues" / "fast-lane"}
|
|
445
462
|
**Total issues**: {count} ({investigation_count} investigations + {implementation_count} implementations)
|
|
446
|
-
**
|
|
463
|
+
**Execution model**: Dependency-graph streaming (issues dispatch as predecessors complete)
|
|
447
464
|
|
|
448
465
|
{IF investigations exist:}
|
|
449
|
-
###
|
|
466
|
+
### Investigations (run first, may spawn new issues)
|
|
450
467
|
| # | Title | Expected Output |
|
|
451
468
|
|---|-------|----------------|
|
|
452
|
-
| #{INV1} | {title} | New issues → folded into
|
|
469
|
+
| #{INV1} | {title} | New issues → folded into dependency graph |
|
|
453
470
|
|
|
454
|
-
### Implementation
|
|
471
|
+
### Implementation (after investigations complete)
|
|
455
472
|
{END IF}
|
|
456
473
|
|
|
457
474
|
### Domain Distribution
|
|
458
475
|
| Domain | Issues | Notes |
|
|
459
476
|
|--------|--------|-------|
|
|
460
477
|
| FRONTEND | {N} | {Independent pages / Shared components} |
|
|
461
|
-
| BILLING | {N} | {Critical —
|
|
462
|
-
| DATABASE | {N} | {
|
|
463
|
-
| AUTH | {N} | {Critical —
|
|
478
|
+
| BILLING | {N} | {Critical — dispatches immediately} |
|
|
479
|
+
| DATABASE | {N} | {Serialized chain — migration order matters} |
|
|
480
|
+
| AUTH | {N} | {Critical — dispatches immediately} |
|
|
464
481
|
| WORKER | {N} | {High overlap risk within worker service} |
|
|
465
482
|
| AI | {N} | {Independent} |
|
|
466
483
|
| INFRA | {N} | {Independent} |
|
|
467
484
|
|
|
468
485
|
(Omit rows with 0 issues. Add project-specific domain rows from forge.yaml → review.domains.)
|
|
469
486
|
|
|
470
|
-
###
|
|
487
|
+
### Dependency Graph
|
|
488
|
+
|
|
489
|
+
| Issue | Predecessors | Domain | Status |
|
|
490
|
+
|-------|-------------|--------|--------|
|
|
491
|
+
| #{A} | — | FRONTEND | Ready (dispatches immediately) |
|
|
492
|
+
| #{B} | — | BILLING | Ready (dispatches immediately) |
|
|
493
|
+
| #{C} | — | WORKER | Ready (dispatches immediately) |
|
|
494
|
+
| #{D} | #{A} | FRONTEND | Blocked (waits for #{A} only) |
|
|
495
|
+
| #{E} | — | DATABASE | Ready (dispatches immediately) |
|
|
496
|
+
| #{F} | #{E} | DATABASE | Blocked (serialized — waits for #{E}) |
|
|
471
497
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
| 2 | #{D} (after #{A}), #{E} | Parallel (D waits for A) |
|
|
476
|
-
| 3 | #{F} (after #{D}) | Sequential |
|
|
498
|
+
**Critical path**: #{E} → #{F} (2 steps, determines minimum wall-clock time)
|
|
499
|
+
**Initial dispatch**: #{A}, #{B}, #{C}, #{E} (all predecessors resolved)
|
|
500
|
+
**Streaming**: #{D} dispatches as soon as #{A} completes — does NOT wait for #{B}, #{C}, or #{E}
|
|
477
501
|
|
|
478
|
-
**Note**:
|
|
502
|
+
**Note**: Investigations may create additional issues that will be automatically added to the dependency graph. The final graph will be confirmed after investigations complete.
|
|
479
503
|
|
|
480
504
|
**Excluded** (already in progress / ineligible):
|
|
481
505
|
- #{X} — {reason}
|
|
@@ -485,61 +509,56 @@ Proceed? (yes / adjust / pick specific issues)
|
|
|
485
509
|
|
|
486
510
|
**Wait for user confirmation before spawning agents.** This is the checkpoint — once agents launch, they run autonomously.
|
|
487
511
|
|
|
488
|
-
**After confirmation**: If
|
|
512
|
+
**After confirmation**: If investigations exist, execute Phase 2B-E first. Then re-present the expanded plan (with newly spawned issues added to the dependency graph) for a quick confirmation before launching implementation.
|
|
489
513
|
|
|
490
514
|
---
|
|
491
515
|
|
|
492
|
-
## Phase 4:
|
|
516
|
+
## Phase 4: Streaming DAG Execution
|
|
493
517
|
|
|
494
|
-
### Step 4A-pre:
|
|
518
|
+
### Step 4A-pre: Staging baseline tracking (MANDATORY — continuous)
|
|
495
519
|
|
|
496
|
-
**WHY THIS EXISTS**: Milestone-code-onto-staging contamination incidents (see issue #150) produce unexpected growth on the staging branch that is otherwise invisible until after a deploy.
|
|
520
|
+
**WHY THIS EXISTS**: Milestone-code-onto-staging contamination incidents (see issue #150) produce unexpected growth on the staging branch that is otherwise invisible until after a deploy. In the streaming DAG model, there are no discrete wave boundaries — instead, track a running baseline and check after each agent completion.
|
|
497
521
|
|
|
498
|
-
**When to run**:
|
|
522
|
+
**When to run**: Capture the initial baseline before the first dispatch. Then re-check after every agent that merges a PR targeting `staging`. Skip for pure milestone-branch batches where all issues target `milestone/*`.
|
|
499
523
|
|
|
500
524
|
```bash
|
|
501
|
-
# Capture staging baseline before
|
|
525
|
+
# Capture initial staging baseline before first dispatch
|
|
502
526
|
git fetch origin
|
|
503
527
|
if [ "$DEFAULT_BRANCH" = "$STAGING_BRANCH" ]; then
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
echo "Staging baseline before Wave {N}: skipped — single-branch repo (staging == default)"
|
|
528
|
+
STAGING_LINES_BASELINE=0
|
|
529
|
+
echo "Staging baseline: skipped — single-branch repo (staging == default)"
|
|
507
530
|
else
|
|
508
|
-
|
|
531
|
+
STAGING_LINES_BASELINE=$(git diff --stat origin/$DEFAULT_BRANCH...origin/$STAGING_BRANCH 2>/dev/null \
|
|
509
532
|
| tail -1 \
|
|
510
533
|
| grep -oP '\d+ insertion' \
|
|
511
534
|
| grep -oP '\d+' \
|
|
512
535
|
|| echo "0")
|
|
513
|
-
echo "Staging baseline
|
|
536
|
+
echo "Staging baseline: ${STAGING_LINES_BASELINE} lines ahead of $DEFAULT_BRANCH"
|
|
514
537
|
fi
|
|
538
|
+
|
|
539
|
+
# Track cumulative expected growth from merged PRs
|
|
540
|
+
CUMULATIVE_EXPECTED_DELTA=0
|
|
515
541
|
```
|
|
516
542
|
|
|
517
|
-
|
|
543
|
+
**Per-agent-completion integrity check** (run in Step 4B after each agent merges a PR targeting staging):
|
|
518
544
|
|
|
519
545
|
```bash
|
|
520
|
-
#
|
|
546
|
+
# After agent completes and its PR merges to staging:
|
|
521
547
|
git fetch origin
|
|
522
|
-
if [ "$DEFAULT_BRANCH"
|
|
523
|
-
|
|
524
|
-
STAGING_GROWTH=0
|
|
525
|
-
echo "Staging integrity check: skipped — single-branch repo (staging == default)"
|
|
526
|
-
else
|
|
527
|
-
STAGING_LINES_AFTER=$(git diff --stat origin/$DEFAULT_BRANCH...origin/$STAGING_BRANCH 2>/dev/null \
|
|
548
|
+
if [ "$DEFAULT_BRANCH" != "$STAGING_BRANCH" ]; then
|
|
549
|
+
STAGING_LINES_NOW=$(git diff --stat origin/$DEFAULT_BRANCH...origin/$STAGING_BRANCH 2>/dev/null \
|
|
528
550
|
| tail -1 \
|
|
529
551
|
| grep -oP '\d+ insertion' \
|
|
530
552
|
| grep -oP '\d+' \
|
|
531
553
|
|| echo "0")
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
# (Use 0 as threshold if no PRs merged — any growth is unexpected)
|
|
539
|
-
EXPECTED_DELTA={SUM_OF_PR_LINE_COUNTS_THIS_WAVE} # set from PR diffs collected in 4B
|
|
540
|
-
UNEXPECTED_GROWTH=$((STAGING_GROWTH - EXPECTED_DELTA))
|
|
554
|
+
STAGING_TOTAL_GROWTH=$((STAGING_LINES_NOW - STAGING_LINES_BASELINE))
|
|
555
|
+
|
|
556
|
+
# Add this PR's line count to cumulative expected delta
|
|
557
|
+
CUMULATIVE_EXPECTED_DELTA=$((CUMULATIVE_EXPECTED_DELTA + {THIS_PR_LINE_COUNT}))
|
|
558
|
+
|
|
559
|
+
UNEXPECTED_GROWTH=$((STAGING_TOTAL_GROWTH - CUMULATIVE_EXPECTED_DELTA))
|
|
541
560
|
if [ "$UNEXPECTED_GROWTH" -gt 500 ]; then
|
|
542
|
-
echo "ALERT: Staging grew by ${
|
|
561
|
+
echo "ALERT: Staging grew by ${STAGING_TOTAL_GROWTH} lines (+${UNEXPECTED_GROWTH} beyond expected ${CUMULATIVE_EXPECTED_DELTA})."
|
|
543
562
|
echo "This may indicate milestone-code contamination via agent merge commits."
|
|
544
563
|
echo "Review: git log --oneline --merges origin/$DEFAULT_BRANCH..origin/$STAGING_BRANCH"
|
|
545
564
|
echo "Do NOT merge $STAGING_BRANCH → $DEFAULT_BRANCH until the unexpected growth is investigated."
|
|
@@ -548,29 +567,29 @@ else
|
|
|
548
567
|
fi
|
|
549
568
|
```
|
|
550
569
|
|
|
551
|
-
If `UNEXPECTED_GROWTH > 500`, report the alert clearly before
|
|
570
|
+
If `UNEXPECTED_GROWTH > 500`, report the alert clearly before dispatching any more agents. The user confirms whether to continue.
|
|
552
571
|
|
|
553
572
|
---
|
|
554
573
|
|
|
555
|
-
### Step 4A.pre.0: Pre-create milestone branches for
|
|
574
|
+
### Step 4A.pre.0: Pre-create milestone branches for ready issues (MANDATORY before classify-lane) <!-- Added: forge#901 -->
|
|
556
575
|
|
|
557
|
-
**WHY THIS EXISTS**: Feature-lane milestone branches were created lazily — by whichever feature-lane agent reached its build phase first. When
|
|
576
|
+
**WHY THIS EXISTS**: Feature-lane milestone branches were created lazily — by whichever feature-lane agent reached its build phase first. When multiple agents are dispatched simultaneously, they each run the lane check at roughly the same time. Every agent that runs before the branch is first pushed observes "branch absent" and is misrouted (hard-fail / `needs-human`, or fallback to staging in older code paths). The result is a single milestone's PRs scattered across the milestone branch and staging — a branch-routing nondeterminism that recurs under parallelism.
|
|
558
577
|
|
|
559
|
-
The fix is deterministic: create every milestone branch the
|
|
578
|
+
The fix is deterministic: create every milestone branch the ready issues will target **once, up front, before any agent runs `classify-lane.sh`**. After this step, every agent's lane check sees the branch and routes consistently.
|
|
560
579
|
|
|
561
|
-
**When to run**: Before the classify-lane loop in Step 4A.pre, for every
|
|
580
|
+
**When to run**: Before the classify-lane loop in Step 4A.pre, for every dispatch group (initial ready set + each subsequent batch of newly unblocked issues). The step is a no-op for pure fast-lane issues (no issue in the group has a milestone).
|
|
562
581
|
|
|
563
|
-
**Requires bash 4+**: This snippet uses an associative array (`declare -A SEEN_MILESTONE_SLUG`) to de-dupe milestone slugs, so it must run under bash 4 or newer. Under a non-bash POSIX shell (`sh`/dash), `declare -A` fails and the de-dupe silently no-ops. This degrades gracefully — branch creation stays correct because the `git ls-remote --exit-code` exists-check below still skips any milestone branch that already exists; the only effect is redundant, idempotent `ls-remote`/`push` attempts for milestones referenced by more than one issue
|
|
582
|
+
**Requires bash 4+**: This snippet uses an associative array (`declare -A SEEN_MILESTONE_SLUG`) to de-dupe milestone slugs, so it must run under bash 4 or newer. Under a non-bash POSIX shell (`sh`/dash), `declare -A` fails and the de-dupe silently no-ops. This degrades gracefully — branch creation stays correct because the `git ls-remote --exit-code` exists-check below still skips any milestone branch that already exists; the only effect is redundant, idempotent `ls-remote`/`push` attempts for milestones referenced by more than one issue. Run this command's blocks under bash 4+. <!-- Added: forge#901 -->
|
|
564
583
|
|
|
565
584
|
```bash
|
|
566
|
-
# Pre-create the origin milestone branch for every distinct milestone referenced by
|
|
585
|
+
# Pre-create the origin milestone branch for every distinct milestone referenced by ready issues.
|
|
567
586
|
# Slugification MUST byte-match scripts/classify-lane.sh — otherwise a branch is created that
|
|
568
587
|
# the classifier will not select. Keep these two slug pipelines identical.
|
|
569
588
|
git fetch origin
|
|
570
589
|
|
|
571
|
-
# Collect distinct milestone titles among the
|
|
590
|
+
# Collect distinct milestone titles among the ready issues
|
|
572
591
|
declare -A SEEN_MILESTONE_SLUG
|
|
573
|
-
for NUM in {
|
|
592
|
+
for NUM in {ready_issue_numbers}; do
|
|
574
593
|
MILESTONE_TITLE=$(gh issue view "$NUM" -R {GH_REPO} --json milestone --jq '.milestone.title // empty' 2>/dev/null || echo "")
|
|
575
594
|
[ -z "$MILESTONE_TITLE" ] && continue # fast-lane issue — no milestone branch needed
|
|
576
595
|
|
|
@@ -615,11 +634,11 @@ for NUM in {wave_issue_numbers}; do
|
|
|
615
634
|
done
|
|
616
635
|
```
|
|
617
636
|
|
|
618
|
-
This step is the deterministic counterpart to fix #2 (atomic create-if-absent in the classifier): by guaranteeing the branch exists before the
|
|
637
|
+
This step is the deterministic counterpart to fix #2 (atomic create-if-absent in the classifier): by guaranteeing the branch exists before the lane checks run, no agent can observe a missing branch. `classify-lane.sh`'s hard-fail is intentionally preserved as the phantom-slug gate for any path that bypasses this step.
|
|
619
638
|
|
|
620
|
-
### Step 4A.pre: Classify lane for each issue (MANDATORY before
|
|
639
|
+
### Step 4A.pre: Classify lane for each issue (MANDATORY before dispatching agents)
|
|
621
640
|
|
|
622
|
-
Before building agent prompts, run `classify-lane.sh` for every issue in the current
|
|
641
|
+
Before building agent prompts, run `classify-lane.sh` for every issue in the current dispatch group to compute `{LANE}` and `{PR_BASE}` deterministically. The script output is authoritative — the LLM MUST NOT override or reason around it.
|
|
623
642
|
|
|
624
643
|
```bash
|
|
625
644
|
# Requires classify-lane.sh to be available at ~/.claude/scripts/classify-lane.sh
|
|
@@ -629,7 +648,7 @@ Before building agent prompts, run `classify-lane.sh` for every issue in the cur
|
|
|
629
648
|
declare -A ISSUE_LANE
|
|
630
649
|
declare -A ISSUE_PR_BASE
|
|
631
650
|
|
|
632
|
-
for NUM in {
|
|
651
|
+
for NUM in {ready_issue_numbers}; do
|
|
633
652
|
PR_BASE=$(bash ~/.claude/scripts/classify-lane.sh "$NUM" -R {GH_REPO}) || {
|
|
634
653
|
echo "ERROR: classify-lane.sh failed for #$NUM — adding needs-human label and skipping" >&2
|
|
635
654
|
gh issue edit "$NUM" -R {GH_REPO} --add-label "needs-human" 2>/dev/null || true
|
|
@@ -649,11 +668,11 @@ done
|
|
|
649
668
|
|
|
650
669
|
Use `${ISSUE_LANE[$NUM]}` and `${ISSUE_PR_BASE[$NUM]}` to populate `{LANE}` and `{PR_BASE}` in the agent template below. Never substitute prose guesses for these values — the script output is the only valid source. <!-- Added: forge#677 -->
|
|
651
670
|
|
|
652
|
-
### Step 4A:
|
|
671
|
+
### Step 4A: Dispatch ready issues
|
|
653
672
|
|
|
654
673
|
**REMINDER: You MUST use the template below verbatim. Only fill in `{VARIABLES}`. Do NOT rewrite the agent prompt. Do NOT write custom implementation instructions. The agent MUST invoke `/work-on` via the Skill tool — this is the HARD RULE from the top of this file.**
|
|
655
674
|
|
|
656
|
-
For each issue
|
|
675
|
+
For each **ready** issue (all predecessors resolved or no predecessors), spawn an Agent sub-agent that runs the full `/work-on` pipeline. On the initial dispatch, this is every issue with an empty predecessor set. On subsequent dispatches (triggered by agent completions in Step 4B), this is every newly-unblocked issue.
|
|
657
676
|
|
|
658
677
|
**One agent per issue.** Do NOT group multiple issues into a single agent. `/work-on` handles branching, labels, and PRs per-issue.
|
|
659
678
|
|
|
@@ -712,7 +731,7 @@ If the label is NOT terminal (e.g., `workflow:investigating`, `workflow:ready-to
|
|
|
712
731
|
)
|
|
713
732
|
```
|
|
714
733
|
|
|
715
|
-
**`{GIST_CONTEXT}` generation**: For each issue
|
|
734
|
+
**`{GIST_CONTEXT}` generation**: For each issue being dispatched, check if it was spawned by an investigation that has a Knowledge Gist (from Step 2C.5). If so, include the Gist URL(s) in the agent prompt:
|
|
716
735
|
|
|
717
736
|
```bash
|
|
718
737
|
# Build GIST_CONTEXT for an issue
|
|
@@ -739,12 +758,34 @@ fi
|
|
|
739
758
|
|
|
740
759
|
If `GIST_CONTEXT` is empty (no parent investigation or milestone index found), the variable resolves to a blank line in the template — no impact on the agent prompt. <!-- Updated: forge#341 -->
|
|
741
760
|
|
|
742
|
-
**Launch all agents
|
|
761
|
+
**Launch all ready agents simultaneously** by putting multiple Agent tool calls in a single message. Use `run_in_background=true` so they execute in parallel.
|
|
743
762
|
|
|
744
|
-
### Step 4B: Monitor
|
|
763
|
+
### Step 4B: Monitor completions and dispatch newly ready issues
|
|
745
764
|
|
|
746
765
|
You will be automatically notified when each background agent completes. **Do NOT use `sleep` loops to poll for completion.** Instead, wait for the automatic notification. When you receive a notification that an agent completed, immediately process it.
|
|
747
766
|
|
|
767
|
+
**Core streaming dispatch loop**: After processing each agent completion, check the DAG for newly unblocked issues. If any issue now has all predecessors in a terminal state, dispatch it immediately (run Steps 4A.pre.0, 4A.pre, and 4A for the newly ready issues). This is the key difference from the wave model — issues dispatch as soon as their specific predecessors complete, not after an entire group finishes.
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
# After each agent completion, check for newly ready issues:
|
|
771
|
+
for BLOCKED_NUM in {all_blocked_issue_numbers}; do
|
|
772
|
+
ALL_PREDS_DONE=true
|
|
773
|
+
for PRED in {predecessors_of_BLOCKED_NUM}; do
|
|
774
|
+
PRED_STATE=$(gh issue view $PRED -R {GH_REPO} --json labels,state --jq '{state: .state, workflow: [.labels[].name | select(startswith("workflow:"))]}')
|
|
775
|
+
# Terminal states: workflow:merged, workflow:invalid, needs-human, or state=CLOSED
|
|
776
|
+
if ! echo "$PRED_STATE" | grep -qE 'workflow:merged|workflow:invalid|needs-human|CLOSED'; then
|
|
777
|
+
ALL_PREDS_DONE=false
|
|
778
|
+
break
|
|
779
|
+
fi
|
|
780
|
+
done
|
|
781
|
+
if [ "$ALL_PREDS_DONE" = "true" ]; then
|
|
782
|
+
echo "#{BLOCKED_NUM} is now READY — all predecessors resolved. Dispatching."
|
|
783
|
+
# Add to dispatch batch for this completion cycle
|
|
784
|
+
fi
|
|
785
|
+
done
|
|
786
|
+
# Run Steps 4A.pre.0 → 4A.pre → 4A for newly ready issues (batch them in a single message)
|
|
787
|
+
```
|
|
788
|
+
|
|
748
789
|
**CRITICAL — Stall detection and recovery**: Background agents sometimes stop mid-pipeline (`stop_reason=end_turn`) after completing a sub-phase (e.g., investigation completes but build never starts). This causes the agent to "complete" from the Agent tool's perspective even though the `/work-on` pipeline is only partially done. When you receive a completion notification:
|
|
749
790
|
|
|
750
791
|
1. **Check if the agent completed the FULL pipeline** — not just one phase:
|
|
@@ -769,7 +810,11 @@ You will be automatically notified when each background agent completes. **Do NO
|
|
|
769
810
|
|
|
770
811
|
4. **Record completed results**: Success (PR merged), Invalid (issue closed), Blocked (needs human), or Error
|
|
771
812
|
|
|
772
|
-
5. **
|
|
813
|
+
5. **Check for newly unblocked issues** — run the DAG readiness check above. If any issues are now ready, dispatch them immediately (Steps 4A.pre.0 → 4A.pre → 4A). Batch all newly ready issues into a single dispatch message.
|
|
814
|
+
|
|
815
|
+
6. **Handle predecessor failures** — if a completed agent's issue FAILED (needs-human, invalid, or error), check for dependent issues in the DAG. Mark all transitive dependents as "skipped — dependency #{X} failed" and report them. Do NOT dispatch them.
|
|
816
|
+
|
|
817
|
+
7. **Verify pipeline compliance** — for each truly completed issue, check that the agent used `/work-on`:
|
|
773
818
|
```bash
|
|
774
819
|
LABELS=$(gh issue view $NUM -R {GH_REPO} --json labels --jq '[.labels[].name | select(startswith("workflow:"))] | length')
|
|
775
820
|
COMMENTS=$(gh api repos/{GH_REPO}/issues/${NUM}/comments --jq '[.[] | select(.body | test("FORGE:INVESTIGATOR|FORGE:BUILDER"))] | length')
|
|
@@ -779,19 +824,25 @@ You will be automatically notified when each background agent completes. **Do NO
|
|
|
779
824
|
```
|
|
780
825
|
If an agent bypassed the pipeline, report it as a **failure** regardless of whether a PR exists.
|
|
781
826
|
|
|
782
|
-
|
|
827
|
+
8. **Post a brief status update** to the user after each agent reaches terminal state:
|
|
783
828
|
```
|
|
784
829
|
✓ #{NUMBER} — {title} → PR #{PR} merged to {target}
|
|
785
830
|
✗ #{NUMBER} — {title} → {reason for failure}
|
|
786
831
|
⚠ #{NUMBER} — {title} → PIPELINE BYPASS (no /work-on — PR invalid)
|
|
787
|
-
⏳
|
|
832
|
+
⏳ Progress: {completed}/{total} complete, {active} active, {blocked} blocked
|
|
833
|
+
→ Dispatched #{NEWLY_READY} (predecessor #{PRED} completed)
|
|
788
834
|
```
|
|
789
835
|
|
|
836
|
+
9. **Run staging integrity check** (from Step 4A-pre) if the completed agent merged a PR targeting staging.
|
|
837
|
+
|
|
838
|
+
**Termination condition**: All issues in the DAG are in a terminal state (merged, invalid, needs-human, or skipped due to dependency failure). When this condition is met, proceed to Phase 5.
|
|
839
|
+
|
|
790
840
|
**Anti-pattern — DO NOT DO THIS:**
|
|
791
841
|
- `sleep 60/120/180/300` loops to check status — you will be notified automatically
|
|
792
842
|
- Spawning separate "progress check" agents — they waste tokens and add noise
|
|
793
843
|
- Reading agent JSONL output files to check progress — use GitHub labels as the source of truth
|
|
794
844
|
- Polling the same status check repeatedly on a timer
|
|
845
|
+
- Waiting for a "batch" of completions before checking for newly ready issues — check after EVERY completion
|
|
795
846
|
|
|
796
847
|
### Step 4B.5: Time-Based Stall Detection
|
|
797
848
|
|
|
@@ -799,7 +850,7 @@ You will be automatically notified when each background agent completes. **Do NO
|
|
|
799
850
|
|
|
800
851
|
**When to run** (NOT a sleep loop — two trigger points only):
|
|
801
852
|
1. On every background agent completion event (run BEFORE the terminal-state check in Step 4B)
|
|
802
|
-
2. Before posting any "waiting for
|
|
853
|
+
2. Before posting any "waiting for agents..." status update to the user
|
|
803
854
|
|
|
804
855
|
**Do NOT poll on a timer. Do NOT use sleep. Run at these two trigger points only.**
|
|
805
856
|
|
|
@@ -808,9 +859,9 @@ You will be automatically notified when each background agent completes. **Do NO
|
|
|
808
859
|
STALL_TIMEOUT=$(yq '.pipeline.stall_timeout_minutes // 15' forge.yaml 2>/dev/null || echo 15)
|
|
809
860
|
```
|
|
810
861
|
|
|
811
|
-
**For each non-terminal agent in the current
|
|
862
|
+
**For each non-terminal agent in the current batch**:
|
|
812
863
|
```bash
|
|
813
|
-
for NUM in {
|
|
864
|
+
for NUM in {active_issue_numbers}; do
|
|
814
865
|
# Skip issues already in terminal state
|
|
815
866
|
TERMINAL=$(gh issue view $NUM -R {GH_REPO} --json labels \
|
|
816
867
|
--jq '[.labels[].name | select(. == "workflow:merged" or . == "workflow:invalid" or . == "needs-human")] | length')
|
|
@@ -877,19 +928,19 @@ done
|
|
|
877
928
|
|
|
878
929
|
**Track stall resume cycles separately** from completion-event resumes (Step 4B). If the same issue accumulates ≥ 2 `FORGE:STALL_DETECTED` comments AND still hasn't reached terminal state, do not resume again — the `needs-human` label is already set.
|
|
879
930
|
|
|
880
|
-
### Step 4C: Collect review-finding issues from completed
|
|
931
|
+
### Step 4C: Collect review-finding issues from completed agents
|
|
881
932
|
|
|
882
|
-
|
|
933
|
+
After each agent reaches a terminal state, check if its `/work-on` run spawned review-finding issues during the review phase. These are new work items that should be added to the dependency DAG and dispatched when ready.
|
|
883
934
|
|
|
884
935
|
```bash
|
|
885
936
|
# Method 1: Read TRAJECTORY comments from completed issues for "Finding issues" row
|
|
886
|
-
for NUM in {
|
|
937
|
+
for NUM in {completed_issue_number}; do
|
|
887
938
|
gh api repos/{GH_REPO}/issues/${NUM}/comments \
|
|
888
939
|
--jq '.[] | select(.body | contains("FORGE:TRAJECTORY")) | .body' 2>/dev/null \
|
|
889
940
|
| grep -oP 'Finding issues\s*\|\s*#?\K\d+[^|]*' | grep -oP '\d+' | sort -u
|
|
890
941
|
done
|
|
891
942
|
|
|
892
|
-
# Method 2 (fallback): Check for recently created review-finding issues that reference PRs from this
|
|
943
|
+
# Method 2 (fallback): Check for recently created review-finding issues that reference PRs from this batch
|
|
893
944
|
gh issue list -R {GH_REPO} --state open --label "review-finding" --limit 20 \
|
|
894
945
|
--json number,title,body,createdAt \
|
|
895
946
|
--jq "[.[] | select(.createdAt > \"$(date -u -d '2 hours ago' +%Y-%m-%dT%H:%M:%SZ)\")]"
|
|
@@ -897,7 +948,7 @@ gh issue list -R {GH_REPO} --state open --label "review-finding" --limit 20 \
|
|
|
897
948
|
|
|
898
949
|
**If review-finding issues were spawned:**
|
|
899
950
|
|
|
900
|
-
**Cascade control (MANDATORY — run before folding findings into
|
|
951
|
+
**Cascade control (MANDATORY — run before folding findings into the DAG):**
|
|
901
952
|
|
|
902
953
|
For each spawned finding, determine whether it should be **executed** or **deferred**:
|
|
903
954
|
|
|
@@ -905,17 +956,17 @@ For each spawned finding, determine whether it should be **executed** or **defer
|
|
|
905
956
|
1. **Generation ≥ 2** (always defer, even for P1/P2): Finding was spawned by an issue that was itself a review-finding. Check the source issue's labels for `review-finding` — if the source has that label, the new finding is generation 2. Always defer. Rationale: gen-2+ cascade is theoretically unbounded — cap it here.
|
|
906
957
|
2. **Priority override** (P1 or P2 → always execute): If the finding is labeled P1 or P2, skip all remaining heuristics and execute. Rationale: high-priority findings must never be suppressed by keyword matching.
|
|
907
958
|
3. **Comment/typo heuristic** (P3 and below only): Finding title contains the word "comment" or "typo" (case-insensitive). These are 1-line cosmetic fixes that do not block other work.
|
|
908
|
-
4. **P3 + same-file overlap**: Finding is labeled `P3` AND the file it targets overlaps with ANY file already in the current or
|
|
959
|
+
4. **P3 + same-file overlap**: Finding is labeled `P3` AND the file it targets overlaps with ANY file already in the current batch (active or queued in the DAG). Rationale: same-file P3 findings add predecessor edges that serialize agents — one finding per original issue increases wall-clock time with no proportional value.
|
|
909
960
|
|
|
910
|
-
**Defer** (do NOT add to
|
|
961
|
+
**Defer** (do NOT add to the DAG) if rules 1, 3, or 4 match.
|
|
911
962
|
|
|
912
|
-
**Execute** (add to
|
|
963
|
+
**Execute** (add to the DAG) if:
|
|
913
964
|
- Rule 2 matches (P1 or P2)
|
|
914
965
|
- None of the defer rules matched (generation 1, P3 with no file overlap, not a keyword match)
|
|
915
966
|
|
|
916
967
|
**Before running the loop, build the batch file list (MANDATORY for Heuristic 3):**
|
|
917
968
|
|
|
918
|
-
Collect all file paths from every issue in the current batch — both completed
|
|
969
|
+
Collect all file paths from every issue in the current batch — both completed and remaining queued issues in the DAG. This produces `ALL_BATCH_FILES`, a newline-separated list of file paths used by Heuristic 3 to test same-file overlap.
|
|
919
970
|
|
|
920
971
|
```bash
|
|
921
972
|
# Build ALL_BATCH_FILES: collect file paths from ALL batch issues (completed + queued)
|
|
@@ -980,28 +1031,27 @@ done
|
|
|
980
1031
|
|
|
981
1032
|
**For queued (non-deferred) findings:**
|
|
982
1033
|
|
|
983
|
-
1. **Add them to the
|
|
1034
|
+
1. **Add them to the dependency DAG.** They are implementation issues — same as issues spawned by investigations in Phase 2. Compute their predecessor sets using the same conflict detection (Step 3C Layers 1-4) against all remaining blocked/active issues.
|
|
984
1035
|
2. **Respect source branch context.** Review-finding issues have `**Code branch**: \`{branch}\`` in their body — the `/work-on` agent will read this and branch from the right origin. No special handling needed from the orchestrator.
|
|
985
1036
|
3. **Report to user:**
|
|
986
1037
|
```
|
|
987
|
-
|
|
988
|
-
|
|
1038
|
+
Agent #{COMPLETED} spawned {count} new finding issues: #{A}, #{B}
|
|
1039
|
+
Added to DAG: #{A} (predecessors: {}), #{B} (predecessors: {#{X}})
|
|
989
1040
|
Deferred (cascade control): #{C} (P3 same-file), #{D} (comment heuristic)
|
|
990
|
-
Adding queued findings to Wave {N+1} (or new wave if no remaining waves).
|
|
991
1041
|
```
|
|
992
|
-
4. **Re-run file-overlap detection** (Step 3C) on the expanded issue set — finding issues may conflict with
|
|
1042
|
+
4. **Re-run file-overlap detection** (Step 3C) on the expanded issue set — finding issues may conflict with active or queued issues that touch the same files. Ready findings dispatch immediately via the standard Step 4B dispatch loop.
|
|
993
1043
|
|
|
994
1044
|
**For deferred findings:**
|
|
995
1045
|
|
|
996
1046
|
They remain open in GitHub — they will be picked up by future `/orchestrate` or `/work-on` runs. Log them in the final batch summary under "deferred" so they are visible. Do NOT close or label them — leave them for the next pipeline pass.
|
|
997
1047
|
|
|
998
|
-
**If no review-finding issues were spawned:** Continue
|
|
1048
|
+
**If no review-finding issues were spawned:** Continue monitoring for the next agent completion.
|
|
999
1049
|
|
|
1000
|
-
### Step 4C.5: Milestone lane-consistency check (
|
|
1050
|
+
### Step 4C.5: Milestone lane-consistency check (periodic) <!-- Added: forge#901 -->
|
|
1001
1051
|
|
|
1002
1052
|
**WHY THIS EXISTS**: A milestone's feature-lane PRs must all target the same milestone branch. If a branch-routing race ever scatters them — some on the milestone branch, some on staging — the milestone branch becomes incomplete relative to staging, and the split is otherwise invisible until the milestone tries to ship. Step 4A.pre.0 prevents the split deterministically; this check detects any residual split so it surfaces immediately instead of at ship time.
|
|
1003
1053
|
|
|
1004
|
-
**When to run**: After
|
|
1054
|
+
**When to run**: After every 3rd agent completion (or after all agents complete, whichever comes first), for any batch where at least one issue has a milestone. Skip for pure fast-lane batches. This check is **non-blocking** — it alerts; it does not auto-resolve or stop the pipeline.
|
|
1005
1055
|
|
|
1006
1056
|
```bash
|
|
1007
1057
|
# For each distinct milestone in the batch, assert all of its feature-lane PRs share one base.
|
|
@@ -1051,13 +1101,13 @@ for NUM in {all_batch_issue_numbers}; do
|
|
|
1051
1101
|
done
|
|
1052
1102
|
```
|
|
1053
1103
|
|
|
1054
|
-
Report any `ALERT` lines prominently before
|
|
1104
|
+
Report any `ALERT` lines prominently before dispatching more agents. Reconciliation of an existing split is a manual/`/milestone`-assisted step — this check only ensures the split is never silent.
|
|
1055
1105
|
|
|
1056
|
-
### Step 4D: Milestone integration build gate (MANDATORY
|
|
1106
|
+
### Step 4D: Milestone integration build gate (MANDATORY — periodic for milestone batches)
|
|
1057
1107
|
|
|
1058
|
-
**WHY THIS EXISTS**: Session Intelligence milestone shipped 116 PRs across multiple
|
|
1108
|
+
**WHY THIS EXISTS**: Session Intelligence milestone shipped 116 PRs across multiple dispatches with zero integration testing. Each PR built in isolation — type errors from cross-PR interactions (wrong prop types, missing components, incompatible interfaces) were invisible until the milestone→staging merge broke the build with 4 distinct errors. This gate catches those failures early.
|
|
1059
1109
|
|
|
1060
|
-
**When to run**: After
|
|
1110
|
+
**When to run**: After every 3rd milestone-targeted agent completion (or when all milestone issues are complete), IF the batch targets a milestone branch AND any `.tsx`/`.ts` files were changed by agents in the completed set. Running after every single agent would be too frequent — batch the check to reduce overhead while still catching integration errors before they accumulate.
|
|
1061
1111
|
|
|
1062
1112
|
All tool commands are read from `forge.yaml → verification.commands`; each step logs `SKIPPED — not configured` when the corresponding key is absent rather than silently passing.
|
|
1063
1113
|
|
|
@@ -1072,7 +1122,7 @@ MILESTONE_BRANCH="milestone/{milestone_slug}"
|
|
|
1072
1122
|
TS_CHANGED=$(git diff origin/{DEFAULT_BRANCH}...origin/${MILESTONE_BRANCH} --name-only | grep -E '\.(tsx?|jsx?)$' | head -1)
|
|
1073
1123
|
|
|
1074
1124
|
if [ -n "$TS_CHANGED" ]; then
|
|
1075
|
-
echo "=== Integration Build Gate (TypeScript):
|
|
1125
|
+
echo "=== Integration Build Gate (TypeScript): batch checkpoint ==="
|
|
1076
1126
|
cd {REPO_PATH}
|
|
1077
1127
|
git fetch origin ${MILESTONE_BRANCH}
|
|
1078
1128
|
git checkout origin/${MILESTONE_BRANCH} --detach 2>/dev/null
|
|
@@ -1096,18 +1146,18 @@ if [ -n "$TS_CHANGED" ]; then
|
|
|
1096
1146
|
git checkout - 2>/dev/null
|
|
1097
1147
|
|
|
1098
1148
|
if [ "$TSC_EXIT" -ne 0 ]; then
|
|
1099
|
-
echo "BLOCKING: TypeScript errors on ${MILESTONE_BRANCH} after
|
|
1100
|
-
echo "Fix type errors before
|
|
1149
|
+
echo "BLOCKING: TypeScript errors on ${MILESTONE_BRANCH} after batch checkpoint."
|
|
1150
|
+
echo "Fix type errors before dispatching more milestone agents."
|
|
1101
1151
|
elif [ "${BUILD_EXIT:-0}" -ne 0 ]; then
|
|
1102
|
-
echo "BLOCKING: build failed on ${MILESTONE_BRANCH} after
|
|
1103
|
-
echo "Build/prerender errors — fix before
|
|
1152
|
+
echo "BLOCKING: build failed on ${MILESTONE_BRANCH} after batch checkpoint."
|
|
1153
|
+
echo "Build/prerender errors — fix before dispatching more milestone agents."
|
|
1104
1154
|
fi
|
|
1105
1155
|
fi
|
|
1106
1156
|
|
|
1107
1157
|
# Python format check
|
|
1108
1158
|
PY_CHANGED=$(git diff origin/{DEFAULT_BRANCH}...origin/${MILESTONE_BRANCH} --name-only | grep -E '\.py$' | head -1)
|
|
1109
1159
|
if [ -n "$PY_CHANGED" ]; then
|
|
1110
|
-
echo "=== Integration Build Gate (Python):
|
|
1160
|
+
echo "=== Integration Build Gate (Python): batch checkpoint ==="
|
|
1111
1161
|
cd {REPO_PATH}
|
|
1112
1162
|
git checkout origin/${MILESTONE_BRANCH} --detach 2>/dev/null
|
|
1113
1163
|
|
|
@@ -1122,29 +1172,22 @@ if [ -n "$PY_CHANGED" ]; then
|
|
|
1122
1172
|
git checkout - 2>/dev/null
|
|
1123
1173
|
|
|
1124
1174
|
if [ "$FORMAT_EXIT" -ne 0 ]; then
|
|
1125
|
-
echo "WARNING: Python formatting issues on ${MILESTONE_BRANCH} after
|
|
1175
|
+
echo "WARNING: Python formatting issues on ${MILESTONE_BRANCH} after batch checkpoint."
|
|
1126
1176
|
echo "Not blocking but should be fixed before milestone→staging."
|
|
1127
1177
|
fi
|
|
1128
1178
|
fi
|
|
1129
1179
|
```
|
|
1130
1180
|
|
|
1131
|
-
**If the gate fails**: Report the errors to the user. Do NOT
|
|
1132
|
-
|
|
1133
|
-
### Step 4E: Advance to next wave
|
|
1134
|
-
|
|
1135
|
-
When wave results are processed, the integration gate passes (or is not applicable), and any new finding issues are folded in:
|
|
1136
|
-
|
|
1137
|
-
1. Check if any failures in the current wave block the next wave (dependency failures)
|
|
1138
|
-
2. If a dependency failed, skip dependent issues in the next wave and report them as "skipped — dependency #{X} failed"
|
|
1139
|
-
3. Launch the next wave (same process as Step 4A)
|
|
1181
|
+
**If the gate fails**: Report the errors to the user. Do NOT dispatch any more milestone-targeted agents until the integration errors are resolved. The accumulated milestone branch has integration errors that will only get worse with more PRs on top. Build failures are BLOCKING — SSG/prerender crashes are invisible to typecheck alone — configure `typescript.build` in `verification.commands` to catch them. Non-milestone (fast-lane) agents may continue dispatching normally.
|
|
1140
1182
|
|
|
1141
|
-
### Step
|
|
1183
|
+
### Step 4E: Handle individual agent failures
|
|
1142
1184
|
|
|
1143
1185
|
If an agent reports failure or error:
|
|
1144
1186
|
- **Merge conflict**: Report to user, mark issue as needing human attention
|
|
1145
1187
|
- **Invalid issue**: Already handled by the agent (closed with comment) — just report it
|
|
1146
1188
|
- **Build/test failure**: Report the error, suggest manual intervention
|
|
1147
1189
|
- **Agent timeout**: Report which issue timed out, suggest re-running with `/work-on #{N}`
|
|
1190
|
+
- **Dependency cascade**: Mark all transitive dependents in the DAG as "skipped — dependency #{X} failed"
|
|
1148
1191
|
|
|
1149
1192
|
**Do NOT retry failed agents automatically.** Report the failure and let the user decide.
|
|
1150
1193
|
|
|
@@ -1191,7 +1234,7 @@ Include the cleanup summary in the final report (Phase 6). If cleanup found prob
|
|
|
1191
1234
|
|
|
1192
1235
|
## Phase 6: Consolidated Report
|
|
1193
1236
|
|
|
1194
|
-
After ALL
|
|
1237
|
+
After ALL issues reach terminal state AND cleanup completes, present a final summary.
|
|
1195
1238
|
|
|
1196
1239
|
### Step 6A: Collect trajectory data
|
|
1197
1240
|
|
|
@@ -1212,7 +1255,7 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1212
1255
|
**Scope**: {milestone / issue list}
|
|
1213
1256
|
**Duration**: {approximate time}
|
|
1214
1257
|
|
|
1215
|
-
###
|
|
1258
|
+
### Investigations (Phase 2)
|
|
1216
1259
|
{IF investigations ran:}
|
|
1217
1260
|
| # | Investigation | Issues Created | Result |
|
|
1218
1261
|
|---|-------------|---------------|--------|
|
|
@@ -1232,10 +1275,10 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1232
1275
|
|
|
1233
1276
|
### Review-Spawned Issues
|
|
1234
1277
|
|
|
1235
|
-
{IF review findings were created during any
|
|
1278
|
+
{IF review findings were created during any agent run:}
|
|
1236
1279
|
| # | Finding | Source Issue | Source PR | Status |
|
|
1237
1280
|
|---|---------|-------------|-----------|--------|
|
|
1238
|
-
| #{F1} | {title} | #{A} | PR #{PR} | ✓ Merged (
|
|
1281
|
+
| #{F1} | {title} | #{A} | PR #{PR} | ✓ Merged (in-batch) / ⏳ Open (deferred) |
|
|
1239
1282
|
|
|
1240
1283
|
{ELSE: "No review findings created during this batch."}
|
|
1241
1284
|
|
|
@@ -1259,7 +1302,7 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1259
1302
|
|-------|-------|-------|--------|-------|---------|--------------|
|
|
1260
1303
|
{per-agent rows from audit}
|
|
1261
1304
|
|
|
1262
|
-
**
|
|
1305
|
+
**Batch efficiency**: {avg_idle_pct}% idle time
|
|
1263
1306
|
**Total resume cycles**: {sum_resumes} across {agent_count} agents
|
|
1264
1307
|
**Clean agents** (no stalls): {clean_count}/{agent_count}
|
|
1265
1308
|
|
|
@@ -1283,7 +1326,7 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1283
1326
|
**Systematic issues** (flag if detected):
|
|
1284
1327
|
- False positive rate > 30% → review agents may need tuning
|
|
1285
1328
|
- Invalidation rate < 10% or > 35% → investigation calibration off
|
|
1286
|
-
- Same-domain merge conflicts
|
|
1329
|
+
- Same-domain merge conflicts between concurrent agents → domain serialization edges too loose
|
|
1287
1330
|
- Contract divergences > 20% → investigation quality may need improvement
|
|
1288
1331
|
- **Idle% > 50%** → agents stalling at phase boundaries; check work-on routing loop
|
|
1289
1332
|
- **Avg resumes > 1** → orchestrator having to compensate for agent stops
|
|
@@ -1304,10 +1347,10 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1304
1347
|
4. **Always confirm with user before launching** — Step 3E is the mandatory checkpoint
|
|
1305
1348
|
5. **No retries** — if an agent fails, report it and move on
|
|
1306
1349
|
6. **Respect existing work** — skip issues already being worked on (`workflow:building`, `workflow:in-review`)
|
|
1307
|
-
7. **Dependency failures cascade** — if A fails and B depends on A,
|
|
1350
|
+
7. **Dependency failures cascade** — if A fails and B depends on A, all transitive dependents of A are skipped (not attempted)
|
|
1308
1351
|
8. **Always run post-batch cleanup** — Phase 5 is mandatory. Never skip `/cleanup all` after orchestration.
|
|
1309
1352
|
9. **NEVER close/skip issues as duplicates** — only `/work-on` investigation agents can make that call after examining the actual code. The orchestrator delegates, it does not adjudicate.
|
|
1310
|
-
10. **
|
|
1353
|
+
10. **Per-completion verification** — after each agent completes, check that it has `workflow:*` labels and structured comments. If an agent bypassed `/work-on`, report it as a pipeline failure.
|
|
1311
1354
|
|
|
1312
1355
|
---
|
|
1313
1356
|
|
|
@@ -1315,31 +1358,38 @@ Aggregate into the batch-level analytics for Step 6B.
|
|
|
1315
1358
|
|
|
1316
1359
|
### "orchestrate milestone api-expansion"
|
|
1317
1360
|
→ Fetches all open issues in "API Expansion v1" milestone
|
|
1318
|
-
→
|
|
1319
|
-
→
|
|
1361
|
+
→ Builds DAG: #1526 → #1527 → #1528 → #1529 (chain), #1530 (no predecessors)
|
|
1362
|
+
→ Confirms with user, dispatches #1526 + #1530 immediately
|
|
1363
|
+
→ When #1526 completes, dispatches #1527 immediately (doesn't wait for #1530)
|
|
1364
|
+
→ Streaming continues until all issues reach terminal state
|
|
1320
1365
|
|
|
1321
1366
|
### "orchestrate #1533 #1250"
|
|
1322
1367
|
→ Fetches those 2 issues, no deps between them
|
|
1323
|
-
→
|
|
1368
|
+
→ DAG: both have empty predecessor sets
|
|
1369
|
+
→ Confirms, dispatches both simultaneously
|
|
1324
1370
|
|
|
1325
1371
|
### "orchestrate next 5"
|
|
1326
|
-
→ Gets top 5 priority issues,
|
|
1327
|
-
→
|
|
1372
|
+
→ Gets top 5 priority issues, builds DAG
|
|
1373
|
+
→ Confirms, dispatches all ready issues immediately
|
|
1374
|
+
→ Dependent issues dispatch as predecessors complete
|
|
1328
1375
|
|
|
1329
1376
|
### "orchestrate P0"
|
|
1330
1377
|
→ Gets all P0 issues, runs them all (presumably urgent)
|
|
1331
|
-
→
|
|
1378
|
+
→ DAG: likely all independent — dispatches simultaneously
|
|
1379
|
+
→ Confirms, executes
|
|
1332
1380
|
|
|
1333
1381
|
### "orchestrate fast-lane"
|
|
1334
1382
|
→ Gets all unmilestoned bugs/fixes
|
|
1335
|
-
→
|
|
1383
|
+
→ Builds DAG from file-conflict and domain-serialization edges
|
|
1384
|
+
→ Dispatches all ready issues, streams dependent issues as predecessors complete
|
|
1336
1385
|
|
|
1337
1386
|
### "orchestrate milestone user-auth-v2"
|
|
1338
1387
|
→ Fetches all open issues in "User Auth v2" milestone
|
|
1339
1388
|
→ Detects #42 is an investigation issue (title: "Investigate: session expiry race condition under high concurrency")
|
|
1340
|
-
→
|
|
1389
|
+
→ Phase 2: Runs `/work-on 42` — investigation creates 3 new issues (#55-#57)
|
|
1341
1390
|
→ Re-fetches milestone issues, now includes #55-#57
|
|
1342
|
-
→
|
|
1343
|
-
→
|
|
1344
|
-
→
|
|
1345
|
-
→
|
|
1391
|
+
→ Builds DAG: #38, #41, #55, #56 have no predecessors (ready); #39 depends on #38; #57 depends on #55
|
|
1392
|
+
→ Dispatches #38, #41, #55, #56 simultaneously
|
|
1393
|
+
→ When #38 completes, #39 dispatches immediately (doesn't wait for #41, #55, or #56)
|
|
1394
|
+
→ When #55 completes, #57 dispatches immediately (doesn't wait for others)
|
|
1395
|
+
→ Final report shows investigation spawned issues and streaming execution results
|