@adlc/merge-forecast
v1.12.0
Published
Conflict forecast and dispatch schedule for parallel ticket execution (D2).
Maintainers
Readme
@adlc/merge-forecast
ADLC phase: D2 — The time dial / fan-out mechanics
Conflict forecast + dispatch schedule for parallel ticket execution. Predicts merge conflicts before any agent runs, certifies the safe fan-out width, and emits a foundation-first merge schedule.
Usage
merge-forecast [options]
Options:
--tickets <path> Path to tickets JSON (default: .adlc/tickets.json)
--width <N> Desired fan-out width; gate fails (exit 2) if > firstWaveWidth
--build-min <X> Mean ticket build time in minutes (for backpressure width)
--merge-min <Y> Mean merge-rebase-regreen time in minutes
--co-change-limit <N> Git log depth for co-change mining (default: 500)
--conflict-threshold <F> Score >= this triggers SEQUENCE verdict (default: 0.5)
--graph-coupling <path> Path to semantic call/symbol graph coupling JSON
--json Machine-readable JSON output
--help Show this helpThe forecast walks the tree and mines co-change from the git repository root, so it gives the same result from any subdirectory; --tickets and --graph-coupling paths resolve from the working directory. Outside a git repository the working directory is the root and co-change is skipped with a warning.
Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Gate passes — schedule is safe at the recommended width |
| 1 | Operational error — bad tickets file, unresolvable input |
| 2 | Gate fails — --width exceeds firstWaveWidth, or vetoed/high-risk pair scheduled concurrently |
Signals
Each parallel-eligible ticket pair (neither is an ancestor of the other in the DAG) is scored by five signals. Combined score = max of individual signals.
| Score | Signal | Description |
|-------|--------|-------------|
| 1.0 | scope-overlap | HARD VETO — tickets' declared scope globs overlap. These must serialize. |
| 0.8 | namespace-collision | Dynamic route segments conflict ([pk] vs [voteKey] at same path depth) or migration prefix collision (drizzle/0005_* vs migrations/0005_*). |
| 0.7 | graph-coupling | Semantic call/symbol graph coupling (e.g. Spanner Graph, mcp__spannercg, or exported graph coupling). |
| 0.6 | import-radius | Files matching ticket A's scope import from ticket B's scope or vice versa. |
| 0–0.5 | co-change | Historical co-commit coupling: pairCount / min(fileCountA, fileCountB) × 0.5. |
Pairs at or above --conflict-threshold get a SEQUENCE verdict. Below threshold: PARALLEL.
The --co-change-limit option must be an integer >= 1. When git history yields zero commits or empty co-change pairs, merge-forecast outputs a descriptive warning in warnings.
Tickets with no scope or an empty scope emit a warning (ticket "<id>" has no scope defined), and tickets whose declared scope matches zero files in the repository emit a warning (ticket "<id>" scope matches 0 files in repo). Any pair involving an unscoped or zero-match ticket is treated as SEQUENCE (score 1.0, signal unscoped) and excluded from parallel wave width calculations.
Width Analysis
- firstWaveWidth — greedy largest independent set among wave-1 tickets (tickets where all pairs are below threshold). Answers how wide can I dispatch right now. This is the number
--widthis gated against. - scheduleWidth — the same computation applied to every wave, taking the widest. Answers how wide can this schedule ever go. For a foundation-first DAG, wave 1 holds a single ticket, so
firstWaveWidthis 1 whilescheduleWidthreports the fan-out behind it. - certifiedWidth — deprecated alias of
firstWaveWidth, retained for existing consumers. It tracks wave 1, notscheduleWidth. - backpressureWidth —
round(buildMin / mergeMin)when both flags are given. Derived from integrator-lane throughput: if builds complete faster than merges absorb them, queue depth compounds. - recommendedWidth —
min(firstWaveWidth, backpressureWidth?, --width?).
Schedule
The schedule is derived from the ticket DAG via Kahn topological waves. All tickets in the same wave are ready to build concurrently (their dependencies completed in earlier waves). The merge order is foundation-first (ticket dependencies merge before their dependants; within a tier, first-done-first-merged).
Examples
# Basic forecast (auto-detect .adlc/tickets.json)
merge-forecast
# Gate against fan-out width
merge-forecast --width 4
# With backpressure — 20-min builds, 4-min merges
merge-forecast --width 5 --build-min 20 --merge-min 4
# JSON output for orchestrators
merge-forecast --json
# Custom tickets path + looser threshold
merge-forecast --tickets plan/tickets.json --conflict-threshold 0.7
# Deep co-change history
merge-forecast --co-change-limit 1000Relation to Sibling Tools
- Upstream: Tickets are produced by
model-router(P2 phase). This tool validates the partition quality before agents run. - Downstream:
rails-guardenforces the contract rails thatmerge-forecastidentifies as conflict surfaces. - Complement: After completing parallel branches,
merge-forecastcan be re-run against the updated main to confirm rebase safety.
Core Gaps
@adlc/core provides activeTickets to filter completed tickets (drop completed
tickets and strip edges pointing to them, keeping the remaining DAG valid) so
backlog enumerators do not schedule finished work.
