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.
@@ -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, plan waves, spawn agents, and report results. You NEVER read code, edit files, or implement fixes yourself.
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 wave, verify agents used `/work-on`.** Check that completed issues have `workflow:*` labels and structured comments. If an agent bypassed the pipeline, report it as a failure.
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 wave plan for the user's awareness, but NEVER act on it
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 wave planning — issues in the same domain likely touch the same files and should be sequential.
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 wave planning:**
295
- - Issues in the SAME domain (especially WORKER, BILLING, DATABASE) are more likely to touch the same files → prefer sequential within a wave or adjacent waves
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. Every DATABASE issue must be in its own wave. If 3 DATABASE issues are in a batch: Wave 1 runs issue A, Wave 2 runs issue B, Wave 3 runs issue C.
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 → they MUST be in separate waves (sequential)
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 wave plan: "#{A} and #{B} both modify `{file}` — serialized"
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 with the immediately preceding wave (safest default)
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 extra wave before starting). Always err toward serialization when uncertain.
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** | Serialize with prior wave |
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 execution plan
420
+ ### Step 3D: Build the dependency DAG
421
421
 
422
- Organize issues into **waves** (groups that can run in parallel):
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
- **Wave rules:**
425
- - Investigation issues already ran in Wave 0 (Phase 2) — they are NOT included in these waves
426
- - Issues with NO dependencies and NO file overlap → same wave (parallel)
427
- - Issues that depend on other issues in the set → later wave (after dependency completes)
428
- - **No artificial agent limit per wave** — spawn as many parallel agents as there are independent issues. The only constraint is file overlap and explicit dependencies.
429
- - Issues that touch the **same files** must be in separate waves (sequential) to avoid merge conflicts
430
- - If unsure about conflicts, err on the side of parallel — each agent works in its own worktree
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
- **Example plan:**
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
- Wave 0 (already done): #2644 (investigation) → spawned #2645, #2646, #2647
435
- Wave 1 (parallel): #2633 (orphaned queues), #2636 (invalidation sub), #2645 (new finding), #2646 (new finding)
436
- Wave 2 (after deps): #2634 (enable daemon — after #2633 fixes memory leak), #2647 (depends on #2645)
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
- **Estimated waves**: {wave_count} (Wave 0 = investigations, then implementation waves)
463
+ **Execution model**: Dependency-graph streaming (issues dispatch as predecessors complete)
447
464
 
448
465
  {IF investigations exist:}
449
- ### Wave 0 — Investigations (run first, may spawn new issues)
466
+ ### Investigations (run first, may spawn new issues)
450
467
  | # | Title | Expected Output |
451
468
  |---|-------|----------------|
452
- | #{INV1} | {title} | New issues → folded into subsequent waves |
469
+ | #{INV1} | {title} | New issues → folded into dependency graph |
453
470
 
454
- ### Implementation Waves (after investigations complete)
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 — prioritize in Wave 1} |
462
- | DATABASE | {N} | {Sequential — migration order matters} |
463
- | AUTH | {N} | {Critical — Wave 1} |
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
- ### Implementation Waves
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
- | Wave | Issues | Strategy |
473
- |------|--------|----------|
474
- | 1 | #{A}, #{B}, #{C} | Parallel (no deps, different domains) |
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**: Wave 0 investigations may create additional issues that will be automatically added to the implementation waves. The final wave plan will be confirmed after investigations complete.
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 Wave 0 exists, execute Phase 2B-E first. Then re-present the expanded plan (with newly spawned issues slotted into waves) for a quick confirmation before launching implementation waves.
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: Execute Waves
516
+ ## Phase 4: Streaming DAG Execution
493
517
 
494
- ### Step 4A-pre: Capture staging baseline (MANDATORY before each wave)
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. Capturing a line-count baseline before each wave and re-checking after allows early detection of any contamination by agents in that wave.
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**: Before launching EVERY wave in batches that target `staging` (fast-lane or milestone→staging). Skip only for pure milestone-branch batches where `{PR_BASE}` is `milestone/*` and staging is not involved.
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 launching the wave
525
+ # Capture initial staging baseline before first dispatch
502
526
  git fetch origin
503
527
  if [ "$DEFAULT_BRANCH" = "$STAGING_BRANCH" ]; then
504
- # Single-branch repo — staging and default are the same; diff is always zero
505
- STAGING_LINES_BEFORE=0
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
- STAGING_LINES_BEFORE=$(git diff --stat origin/$DEFAULT_BRANCH...origin/$STAGING_BRANCH 2>/dev/null \
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 before Wave {N}: ${STAGING_LINES_BEFORE} lines ahead of $DEFAULT_BRANCH"
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
- Store `STAGING_LINES_BEFORE` per wave. After the wave completes (after Step 4C), run the integrity check:
543
+ **Per-agent-completion integrity check** (run in Step 4B after each agent merges a PR targeting staging):
518
544
 
519
545
  ```bash
520
- # Check staging integrity after wave completes (run after Step 4C)
546
+ # After agent completes and its PR merges to staging:
521
547
  git fetch origin
522
- if [ "$DEFAULT_BRANCH" = "$STAGING_BRANCH" ]; then
523
- STAGING_LINES_AFTER=0
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
- STAGING_GROWTH=$((STAGING_LINES_AFTER - STAGING_LINES_BEFORE))
533
- echo "Staging after Wave {N}: ${STAGING_LINES_AFTER} lines (+${STAGING_GROWTH} vs baseline)"
534
-
535
- # Alert if growth exceeds expected delta
536
- # Expected: only the lines from PRs merged in this wave
537
- # Alert threshold: growth > 500 lines more than the sum of changed lines from wave PRs
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 ${STAGING_GROWTH} lines (+${UNEXPECTED_GROWTH} beyond expected ${EXPECTED_DELTA})."
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 launching the next wave. The user confirms whether to continue.
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 the wave (MANDATORY before classify-lane) <!-- Added: forge#901 -->
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 a wave launches N feature-lane agents in parallel, 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.
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 wave 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.
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 wave. The step is a no-op for pure fast-lane waves (no issue in the wave has a milestone).
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 in the wave. Run this command's blocks under bash 4+. <!-- Added: forge#901 -->
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 the wave.
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 wave's issues
590
+ # Collect distinct milestone titles among the ready issues
572
591
  declare -A SEEN_MILESTONE_SLUG
573
- for NUM in {wave_issue_numbers}; do
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 wave's 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.
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 spawning agents)
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 wave to compute `{LANE}` and `{PR_BASE}` deterministically. The script output is authoritative — the LLM MUST NOT override or reason around it.
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 {wave_issue_numbers}; do
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: Launch a wave
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 in the current wave, spawn an Agent sub-agent that runs the full `/work-on` pipeline.
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 in the wave, 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:
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 in the current wave simultaneously** by putting multiple Agent tool calls in a single message. Use `run_in_background=true` so they execute in parallel.
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 wave completion
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. **Verify pipeline compliance** — for each truly completed issue, check that the agent used `/work-on`:
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
- 6. **Post a brief status update** to the user after each agent reaches terminal state:
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
- ⏳ Wave 1: 2/3 complete (1 resumed after stall)...
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 wave..." status update to the user
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 wave**:
862
+ **For each non-terminal agent in the current batch**:
812
863
  ```bash
813
- for NUM in {active_wave_issue_numbers}; do
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 wave
931
+ ### Step 4C: Collect review-finding issues from completed agents
881
932
 
882
- When ALL agents in the current wave have completed, check if any `/work-on` runs spawned review-finding issues during their review phase. These are new work items that should be folded into the remaining waves.
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 {completed_issue_numbers_this_wave}; do
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 wave
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 waves):**
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 remaining batch waves. Rationale: same-file P3 findings serialize the entire remaining batch — one finding per original issue doubles wall-clock time with no proportional value.
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 wave queue) if rules 1, 3, or 4 match.
961
+ **Defer** (do NOT add to the DAG) if rules 1, 3, or 4 match.
911
962
 
912
- **Execute** (add to wave queue) if:
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 waves and remaining queued waves. This produces `ALL_BATCH_FILES`, a newline-separated list of file paths used by Heuristic 3 to test same-file overlap.
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 remaining wave plan.** They are implementation issues — same as issues spawned by investigations in Phase 2.
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
- Wave {N} review spawned {count} new finding issues: #{A}, #{B}
988
- Queued for execution: #{A}, #{B}
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 planned issues that touch the same files.
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 to next wave normally.
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 (run after each wave) <!-- Added: forge#901 -->
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 each wave completes, 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.
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 advancing to the next wave. Reconciliation of an existing split is a manual/`/milestone`-assisted step — this check only ensures the split is never silent.
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 between waves)
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 waves 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.
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 each wave completes, IF the batch targets a milestone branch AND any `.tsx`/`.ts` files were changed by agents in the completed wave.
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): Wave {N} ==="
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 Wave {N}."
1100
- echo "Fix type errors before starting next wave."
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 Wave {N}."
1103
- echo "Build/prerender errors — fix before starting next wave."
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): Wave {N} ==="
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 Wave {N}."
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 proceed to the next wave. 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.
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 4F: Handle individual agent failures
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 waves AND cleanup complete, present a final summary.
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
- ### Wave 0: Investigations
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 wave:}
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 (wave {N}) / ⏳ Open (deferred) |
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
- **Wave efficiency**: {avg_idle_pct}% idle time
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 in 2+ waves → domain sequencing too aggressive
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, B is skipped (not attempted)
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. **Post-wave verification** — after each wave, check that every completed issue has `workflow:*` labels and structured comments. If an agent bypassed `/work-on`, report it as a pipeline failure.
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
- → Analyzes deps (#1526 → #1527 → #1528 → #1529, #1530 independent)
1319
- → Plans 3 waves, confirms with user, executes
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
- → Single wave, both parallel, confirms, executes
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, checks deps
1327
- → Plans waves, confirms, executes
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
- → Single wave if possible, confirms, executes
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
- → Groups by independence, runs in waves
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
- → Wave 0: Runs `/work-on 42` — investigation creates 3 new issues (#55-#57)
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
- → Wave 1: #38 (P0 token refresh bug), #41 (session store migration), #55, #56 (all independent)
1343
- → Wave 2: #39 (enable refresh rotation — after #38 fixes token bug), #57 (depends on #55)
1344
- → Wave 3: remaining issues
1345
- → Final report shows investigation spawned issues and their results
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgedock",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "GitHub as a knowledge graph for AI agents. Autonomous dev pipeline for Claude Code.",
5
5
  "bin": {
6
6
  "forgedock": "bin/forgedock.mjs"