@miller-tech/uap 1.150.2 → 1.151.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/cli/deliver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/cli/deliver.ts"],"names":[],"mappings":"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"}
@@ -94,7 +94,7 @@ export function resolveAcceptanceVerdict(r, acceptancePrimary) {
94
94
  import { createAgenticExecutor, noopApplier, selectExecutorMode, lockContractFiles } from '../delivery/agentic-executor.js';
95
95
  import { createRepairEscalation } from '../delivery/repair-escalation.js';
96
96
  import { clearStop, isStopRequested, loadRunState, newRunId, saveRunState } from '../delivery/run-state.js';
97
- import { parsePhaseArray, phaseInstruction, planDeliveryPhases, shouldDecompose } from '../delivery/decompose.js';
97
+ import { phaseInstruction, planDeliveryPhases, shouldDecompose } from '../delivery/decompose.js';
98
98
  import { runEpics } from '../delivery/epic-controller.js';
99
99
  import { initLedger, markItem } from '../delivery/completion-ledger.js';
100
100
  import { loadUapConfigRaw } from '../utils/config-loader.js';
@@ -112,16 +112,15 @@ function cfgRawEarlyForUvFactory(projectRoot) {
112
112
  };
113
113
  }
114
114
  import { resolveSessionTokenBudget, sessionWorkingBudget, discoverModelContextWindow, CONTEXT_BUDGET_MARKER } from '../delivery/context-budget.js';
115
- import { orchestrate } from '../delivery/task-orchestrator.js';
116
115
  import { preflightProject, formatPreflightFailure } from '../delivery/project-preflight.js';
117
116
  import { resolveFidelity } from '../delivery/fidelity.js';
118
117
  import { installRunExitRecorder } from '../delivery/run-exit.js';
119
118
  import { shouldDetach, relaunchDetached, isDetachedChild, canHostDetachLog, NO_DETACH_ENV, } from './deliver-detach.js';
120
- import { extractContract } from '../delivery/contract-extractor.js';
121
119
  import { completeDeliveryTask, openDeliveryTask, recordDeliveryOutcome, recordOrchestratorTaskOutcome, reopenDeliveryTask } from '../delivery/task-sync.js';
122
120
  import { autoMineHaloTraces, summarizeWeaknesses, weaknessGuidance, loadPersistedWeaknesses } from '../delivery/auto-mine.js';
123
121
  import { createGitWorktreeProvider } from '../delivery/candidate-workspace.js';
124
122
  import { createTaskWorkspaceManager, resolveParallelTasks } from '../delivery/task-workspace.js';
123
+ import { runOrchestratedMission as runOrchestratedMissionCore, foldDeliveryResult } from '../delivery/orchestrated-mission.js';
125
124
  import { createHaloDeliveryTracer } from '../delivery/halo-trace.js';
126
125
  import { haloTracePath, isHaloTracingEnabled } from '../observability/halo-exporter.js';
127
126
  import { createRunCoordinator } from '../delivery/run-coordinator.js';
@@ -1617,154 +1616,61 @@ async function runDeliver(instruction, options) {
1617
1616
  * the per-task executor; a completed task publishes a compact summary its
1618
1617
  * dependents read instead of source.
1619
1618
  */
1620
- const runOrchestratedMission = async () => {
1621
- const all = {
1622
- success: true, alreadyDelivered: false, turns: 0, bestScore: 0, bestTurn: 0,
1623
- history: [], finalFeedback: '', finalOutput: '', totalDurationMs: 0,
1624
- };
1625
- const tasks = phases.map((ph) => ({
1626
- id: ph.id, title: ph.title, goal: ph.goal, ...(ph.deps ? { deps: ph.deps } : {}),
1627
- }));
1628
- // -- Worktree-isolated parallel dispatch --
1629
- // `.uap.json` deliver.parallelTasks (config-only BY DESIGN - no env; see
1630
- // the concurrency notes in task-orchestrator.ts) dispatches independent
1631
- // READY tasks concurrently, EACH in its own detached git worktree seeded
1632
- // with the main tree's current uncommitted state and judged against its
1633
- // own spec. Merge-backs are SERIALIZED under a lock; a conflicting merge
1634
- // fails the task, and the orchestrator's minimal repair retries it in a
1635
- // fresh workspace seeded with the updated baseline - conflicts resolve
1636
- // through the ATG repair path instead of corrupting the tree.
1637
- const parallelTasks = resolveParallelTasks(cfgRaw.deliver?.parallelTasks);
1638
- const wsManager = parallelTasks > 1 ? createTaskWorkspaceManager(projectRoot) : null;
1639
- if (parallelTasks > 1 && !wsManager) {
1640
- console.log(chalk.yellow(' ⇉ parallel tasks: worktree isolation unavailable (not a git repo?) - running sequentially'));
1641
- }
1642
- else if (wsManager) {
1643
- console.log(chalk.cyan(` ⇉ parallel tasks: up to ${parallelTasks} independent tasks in isolated worktrees`));
1644
- }
1645
- // Merge-boundary defense-in-depth: refuse a delta touching protected
1646
- // tests/gate configs at the boundary, instead of trusting the in-worktree
1647
- // layers transitively (mode-only changes and capture-skipped files would
1648
- // otherwise ride the patch back).
1649
- const mergeProtected = new Set(options.protectTests !== false
1650
- ? [...snapshotProtection(projectRoot).protectedFiles, ...listGateConfigFiles(projectRoot)].map((f) => f.toLowerCase())
1651
- : []);
1652
- let mergeChain = Promise.resolve();
1653
- const withMergeLock = (fn) => {
1654
- const next = mergeChain.then(fn, fn);
1655
- mergeChain = next.then(() => undefined, () => undefined);
1656
- return next;
1657
- };
1658
- // Regexes built from strings so policy hooks never mistake a literal for a path.
1659
- const SOURCE_FILE_RE = new RegExp('[.](js|mjs|cjs|ts|tsx|jsx|py)$');
1660
- const NEW_TASKS_RE = new RegExp('NEW_TASKS:\\s*(\\[[\\s\\S]*?\\])');
1661
- /** Run one task's convergence loop against `root` with executor `exec` -
1662
- * the historic in-tree body, parameterized so isolated workspaces reuse it
1663
- * verbatim. Turns/history flow into the mission aggregate as before. */
1664
- const runTaskAt = async (ctx, task, root, exec) => {
1665
- const taskRecord = await openDeliveryTask(`${task.title} — ${task.goal.slice(0, 120)}`, projectRoot, missionTask?.id);
1666
- acceptanceSpecByRoot.set(root, ctx.prompt);
1667
- if (root === projectRoot)
1668
- acceptanceSpec = ctx.prompt;
1669
- evidenceFor(root).writes = 0;
1670
- try {
1671
- const loop = new ConvergenceLoop({
1672
- ...loopConfig,
1673
- projectRoot: root,
1674
- baselineCheck: false,
1675
- resumeFrom: undefined,
1676
- // Checkpoints describe THE mission tree; isolated roots must not
1677
- // clobber the durable run state.
1678
- // The inherited explorer's workspaceProvider is bound to the MAIN
1679
- // projectRoot; inside an isolated task it must not run at all.
1680
- ...(root !== projectRoot ? { onCheckpoint: undefined, explorer: undefined } : {}),
1681
- onIteration: makeIterationHook(root),
1682
- }, exec, seams);
1683
- const r = await loop.deliver(ctx.prompt);
1684
- all.turns += r.turns;
1685
- all.history.push(...r.history);
1686
- all.totalDurationMs += r.totalDurationMs;
1687
- if (r.bestScore > all.bestScore) {
1688
- all.bestScore = r.bestScore;
1689
- all.bestTurn = r.bestTurn;
1690
- }
1691
- all.finalFeedback = r.finalFeedback;
1692
- all.finalOutput = r.finalOutput;
1693
- completeDeliveryTask(taskRecord, r);
1694
- const files = [...new Set(r.history.flatMap((h) => h.filesApplied ?? []))];
1695
- // P4 - extract the VERIFIED public contract of what this task built so
1696
- // dependents load the interface (a few hundred chars), not the source.
1697
- let contract;
1698
- if (r.success && files.length > 0) {
1699
- try {
1700
- const { readFileSync } = await import('fs');
1701
- const { join } = await import('path');
1702
- const srcs = files
1703
- .filter((f) => SOURCE_FILE_RE.test(f))
1704
- .map((f) => {
1705
- try {
1706
- return { path: f, content: readFileSync(join(root, f), 'utf-8') };
1707
- }
1708
- catch {
1709
- return null;
1710
- }
1711
- })
1712
- .filter((x) => x !== null);
1713
- contract = extractContract(srcs).contract || undefined;
1714
- }
1715
- catch {
1716
- contract = undefined;
1717
- }
1718
- }
1719
- // P5 - adaptive re-planning feed: a task may surface work the initial
1720
- // plan missed by emitting a `NEW_TASKS: [ {id,title,goal,deps} ]` JSON
1721
- // array in its output. Parsed through the same validator as the planner
1722
- // (well-formed only), then folded into the DAG by orchestrate() (which
1723
- // dedupes, topo-resorts, and caps at maxTasks). Only structural fields
1724
- // are used - never free-form model text as durable memory.
1725
- let newTasks;
1726
- if (r.success) {
1727
- try {
1728
- const marker = NEW_TASKS_RE.exec(r.finalOutput || r.finalFeedback || '');
1729
- if (marker) {
1730
- const parsed = parsePhaseArray(marker[1]).filter((t) => t.id !== task.id);
1731
- if (parsed.length > 0) {
1732
- newTasks = parsed.map((t) => ({
1733
- id: t.id, title: t.title, goal: t.goal,
1734
- ...(t.deps ? { deps: t.deps } : {}),
1735
- }));
1736
- console.log(chalk.dim(` ↳ re-planning: task ${task.id} discovered ${newTasks.length} follow-up task(s)`));
1737
- }
1738
- }
1739
- }
1740
- catch {
1741
- newTasks = undefined;
1742
- }
1743
- }
1744
- return {
1745
- taskId: task.id,
1746
- success: r.success,
1747
- turns: r.turns,
1748
- // ATG minimal repair: a FAILED task's summary must carry the failure
1749
- // (the retry's only new information), never a goal restatement.
1750
- summary: r.success
1751
- ? `${task.goal.slice(0, 160)}${files.length ? ` [files: ${files.join(', ')}]` : ''}`
1752
- : `${task.goal.slice(0, 120)} — FAILED: ${(r.finalFeedback || 'gates did not pass').slice(0, 280)}`,
1753
- ...(contract ? { contract } : {}),
1754
- ...(newTasks && newTasks.length > 0 ? { newTasks } : {}),
1755
- };
1756
- }
1757
- finally {
1758
- acceptanceSpecByRoot.delete(root);
1759
- }
1760
- };
1761
- const orchResult = await orchestrate({
1762
- mission: instruction,
1763
- tasks,
1619
+ /**
1620
+ * Wire deliver's ambient context (loop config, executors, judge state, task
1621
+ * records, gates) into the extracted orchestrated-mission runner
1622
+ * (src/delivery/orchestrated-mission.ts). Shared by the top-level
1623
+ * orchestrated path and the epic controller's inner missions — and, because
1624
+ * the runner is seam-injected, the orchestrate() wiring is finally
1625
+ * unit-testable (the PR #516 inert-concurrency critical could not recur
1626
+ * unobserved).
1627
+ */
1628
+ const buildOrchestratedDeps = (missionText, taskPhases, parallelTasks, parentTaskId = missionTask?.id) => {
1629
+ const mergeProtected = new Set([
1630
+ ...(options.protectTests !== false
1631
+ ? [...snapshotProtection(projectRoot).protectedFiles, ...listGateConfigFiles(projectRoot)]
1632
+ : []),
1633
+ // Locked contract files are read-only for later epics; the merge
1634
+ // boundary re-checks them like the other protected surfaces instead
1635
+ // of trusting the in-worktree write_file guard transitively.
1636
+ ...contractLock,
1637
+ ].map((f) => f.toLowerCase()));
1638
+ return {
1639
+ instruction: missionText,
1640
+ projectRoot,
1641
+ tasks: taskPhases.map((ph) => ({
1642
+ id: ph.id,
1643
+ title: ph.title,
1644
+ goal: ph.goal,
1645
+ ...(ph.deps ? { deps: ph.deps } : {}),
1646
+ })),
1647
+ parallelTasks,
1764
1648
  contextBudgetChars: Number(process.env.UAP_DELIVER_CONTEXT_BUDGET ?? 6000),
1765
1649
  maxTasks: Number(process.env.UAP_DELIVER_MAX_TASKS ?? 40),
1766
- // Dependency-aware parallel dispatch only with worktree isolation.
1767
- concurrency: wsManager ? parallelTasks : 1,
1650
+ workspaceManager: parallelTasks > 1 ? createTaskWorkspaceManager(projectRoot) : null,
1651
+ note: (line) => console.log(line.startsWith('▶')
1652
+ ? chalk.bold(line)
1653
+ : line.includes('unavailable') || line.includes('conflicted')
1654
+ ? chalk.yellow(line)
1655
+ : line.includes('parallel tasks:') || line.includes('post-merge verification')
1656
+ ? chalk.cyan(line)
1657
+ : chalk.dim(line)),
1658
+ beginTaskSpec: (root, spec) => {
1659
+ acceptanceSpecByRoot.set(root, spec);
1660
+ if (root === projectRoot)
1661
+ acceptanceSpec = spec;
1662
+ evidenceFor(root).writes = 0;
1663
+ },
1664
+ endTaskSpec: (root) => {
1665
+ acceptanceSpecByRoot.delete(root);
1666
+ // An in-tree task re-pointed the shared spec; restore the mission-
1667
+ // level spec so a later watch-ci re-converge never judges against a
1668
+ // stale task prompt.
1669
+ if (root === projectRoot)
1670
+ acceptanceSpec = missionText;
1671
+ },
1672
+ openTask: (title) => openDeliveryTask(title, projectRoot, parentTaskId),
1673
+ completeTask: (record, r) => completeDeliveryTask(record, r),
1768
1674
  // P3 — per-task memory retrieval: pull the few most relevant established
1769
1675
  // decisions/patterns/gotchas for THIS task's goal (a small semantic
1770
1676
  // query, not the full spec), so a fresh-context task reconstructs "what
@@ -1794,85 +1700,62 @@ async function runDeliver(instruction, options) {
1794
1700
  return;
1795
1701
  await recordOrchestratorTaskOutcome(task.id, task.title, outcome.contract ?? outcome.summary, projectRoot);
1796
1702
  },
1797
- runTask: async (ctx, task) => {
1798
- console.log(chalk.bold(`▶ task ${task.id}: ${task.title}`) +
1799
- chalk.dim(` (ctx ${ctx.prompt.length} chars, deps: ${ctx.includedDeps.join(',') || 'none'})`));
1800
- // Workspace acquisition mutates git state (worktree add) - serialize
1801
- // it behind the same lock the merges use.
1802
- const ws = wsManager ? await withMergeLock(() => wsManager.acquire(task.id)) : null;
1803
- if (!ws) {
1804
- if (wsManager) {
1805
- console.log(chalk.yellow(` ⇉ task ${task.id}: workspace unavailable - running in-tree (serialized)`));
1806
- // In-tree execution mutates the shared tree; hold the lock for the
1807
- // WHOLE run so it never races an isolated task's merge-back.
1808
- return withMergeLock(() => runTaskAt(ctx, task, projectRoot, executor));
1809
- }
1810
- return runTaskAt(ctx, task, projectRoot, executor);
1811
- }
1703
+ isMergeBlocked: (f) => mergeProtected.has(f.toLowerCase()),
1704
+ verifyCombined: () => {
1705
+ // Mirror the loop's redetect-merge: redetection REASSIGNS the loop's
1706
+ // local rungs and never mutates this captured t0 array, so a
1707
+ // from-scratch build's mid-mission gates must be re-merged here or
1708
+ // the combined tree is verified against stale t0 gates only.
1709
+ let combinedRungs = rungs;
1812
1710
  try {
1813
- // The agentic executor binds tools to a root at construction - give
1814
- // the isolated task its own, with the same protections re-derived
1815
- // for its tree. The blind executor is root-free (the per-task loop's
1816
- // projectRoot directs the applier and gates).
1817
- const taskExecutor = agentic
1818
- ? createAgenticExecutor(model, {
1819
- projectRoot: ws.root,
1820
- endpoint: agenticEndpoint,
1821
- temperature,
1822
- contextTokenBudget: sessionBudget,
1823
- contractFiles: contractLock,
1824
- protectedFiles: options.protectTests !== false ? snapshotProtection(ws.root).protectedFiles : new Set(),
1825
- protectGateConfigs: options.protectTests !== false,
1826
- allowBash: options.allowBash === true || process.env.UAP_DELIVER_ALLOW_BASH === '1',
1827
- onEvent: (e) => console.log(chalk.dim(` [${task.id} r${e.round} ${e.kind}${e.tool ? `:${e.tool}` : ''}] ${e.detail ?? ''}`)),
1828
- })
1829
- : executor;
1830
- const outcome = await runTaskAt(ctx, task, ws.root, taskExecutor);
1831
- if (!outcome.success)
1832
- return outcome;
1833
- const merged = await withMergeLock(() => ws.mergeBack((f) => mergeProtected.has(f.toLowerCase())));
1834
- if (!merged.ok) {
1835
- console.log(chalk.yellow(` ⇉ task ${task.id}: merge-back conflicted (${merged.reason ?? 'apply failed'}) - minimal repair retries on the updated tree`));
1836
- return {
1837
- taskId: task.id,
1838
- success: false,
1839
- turns: 0,
1840
- summary: `${task.goal.slice(0, 120)} — FAILED: the tree changed underneath this task (parallel merge conflict) — rebuild it against the CURRENT state of the repository. Detail: ${(merged.reason ?? 'could not apply the task delta').slice(0, 200)}`,
1841
- };
1842
- }
1843
- if (merged.files.length > 0) {
1844
- console.log(chalk.dim(` ⇉ task ${task.id}: merged ${merged.files.length} file(s) into the main tree`));
1845
- }
1846
- return outcome;
1711
+ const detected = detectRungs(projectRoot);
1712
+ const have = new Set(rungs.map((r) => r.id));
1713
+ const allow = loopConfig.redetectFilter ?? ((r) => tierOf(r) === 'fast' || tierOf(r) === 'runtime');
1714
+ const added = detected.filter((r) => !have.has(r.id) && allow(r));
1715
+ if (added.length > 0)
1716
+ combinedRungs = [...rungs, ...added];
1847
1717
  }
1848
- finally {
1849
- ws.cleanup();
1718
+ catch {
1719
+ // detection unavailable - verify against the t0 rungs
1850
1720
  }
1721
+ return Promise.resolve(tieredRunner(combinedRungs, projectRoot, {}));
1851
1722
  },
1852
- });
1853
- // Post-merge verification: every gate passed in SOME tree, but 3-way
1854
- // resolution can produce a combined main tree no gate ever saw. One
1855
- // ladder run on the merged result closes that. Fail-soft on runner
1856
- // errors; hard on gate failures.
1857
- if (wsManager && orchResult.success) {
1858
- try {
1859
- console.log(chalk.cyan(' ⇉ post-merge verification: gate ladder on the merged main tree…'));
1860
- const combined = await tieredRunner(rungs, projectRoot, {});
1861
- if (!combined.passed) {
1862
- orchResult.success = false;
1863
- orchResult.failed.push('post-merge-verification');
1864
- all.finalFeedback = `post-merge verification FAILED on the combined tree:\n${combined.feedback}`.slice(0, 4000);
1865
- }
1866
- }
1867
- catch {
1868
- // verification unavailable — keep the per-task verdicts
1869
- }
1870
- }
1871
- all.success = orchResult.success;
1872
- if (!orchResult.success) {
1873
- all.finalFeedback = `orchestration incomplete — failed tasks: ${orchResult.failed.join(', ')}\n${all.finalFeedback}`;
1874
- }
1875
- return all;
1723
+ runLoop: async ({ root, prompt, taskId, isolated }) => {
1724
+ // The agentic executor binds tools to a root at construction — give
1725
+ // an isolated task its own, with the same protections re-derived for
1726
+ // its tree. The blind executor is root-free (the per-task loop's
1727
+ // projectRoot directs the applier and gates).
1728
+ const exec = isolated && agentic
1729
+ ? createAgenticExecutor(model, {
1730
+ projectRoot: root,
1731
+ endpoint: agenticEndpoint,
1732
+ temperature,
1733
+ contextTokenBudget: sessionBudget,
1734
+ contractFiles: contractLock,
1735
+ protectedFiles: options.protectTests !== false ? snapshotProtection(root).protectedFiles : new Set(),
1736
+ protectGateConfigs: options.protectTests !== false,
1737
+ allowBash: options.allowBash === true || process.env.UAP_DELIVER_ALLOW_BASH === '1',
1738
+ onEvent: (e) => console.log(chalk.dim(` [${taskId} r${e.round} ${e.kind}${e.tool ? `:${e.tool}` : ''}] ${e.detail ?? ''}`)),
1739
+ })
1740
+ : executor;
1741
+ const loop = new ConvergenceLoop({
1742
+ ...loopConfig,
1743
+ projectRoot: root,
1744
+ baselineCheck: false,
1745
+ resumeFrom: undefined,
1746
+ // Checkpoints describe THE mission tree, and the inherited
1747
+ // explorer's workspaceProvider is bound to the MAIN projectRoot —
1748
+ // neither may run inside an isolated task.
1749
+ ...(isolated ? { onCheckpoint: undefined, explorer: undefined } : {}),
1750
+ onIteration: makeIterationHook(root),
1751
+ }, exec, seams);
1752
+ return loop.deliver(prompt);
1753
+ },
1754
+ };
1755
+ };
1756
+ const runOrchestratedMission = async () => {
1757
+ const parallelTasks = resolveParallelTasks(cfgRaw.deliver?.parallelTasks);
1758
+ return runOrchestratedMissionCore(buildOrchestratedDeps(instruction, phases, parallelTasks));
1876
1759
  };
1877
1760
  const runPhasedMission = async () => {
1878
1761
  const all = {
@@ -1940,6 +1823,7 @@ async function runDeliver(instruction, options) {
1940
1823
  success: true, alreadyDelivered: false, turns: 0, bestScore: 0, bestTurn: 0,
1941
1824
  history: [], finalFeedback: '', finalOutput: '', totalDurationMs: 0,
1942
1825
  };
1826
+ const epicParallelTasks = resolveParallelTasks(cfgRaw.deliver?.parallelTasks);
1943
1827
  const contractsFirst = process.env.UAP_DELIVER_CONTRACTS !== '0';
1944
1828
  const scaffoldFirst = process.env.UAP_DELIVER_SCAFFOLD !== '0';
1945
1829
  const planned = await planDeliveryPhases(instruction, verdictExecutor, undefined, {
@@ -2032,14 +1916,90 @@ async function runDeliver(instruction, options) {
2032
1916
  // prompt carries process instructions ("read X first"), prior-epic
2033
1917
  // summaries, and retry feedback — none verifiable from code, so a
2034
1918
  // small judge rejects objectively-green turns against them forever.
2035
- acceptanceSpec =
2036
- `EPIC ${epic.title}:\n${epic.goal}` +
2037
- (epic.criteria?.length ? `\nAcceptance criteria:\n${epic.criteria.map((c) => `- ${c}`).join('\n')}` : '') +
2038
- (!epic.contracts && contractLock.size > 0 ? `\n(Builds against locked contracts: ${[...contractLock].join(', ')})` : '') +
2039
- (fillsScaffold ? '\n(FILL epic: no todo!()/NotImplementedError/TODO-throw stub markers may remain in the files it implements; signatures must be unchanged.)' : '') +
2040
- (epic.scaffold ? '\n(SCAFFOLD epic: complete compiling signatures with stub bodies are the DELIVERABLE — unimplemented logic is expected and correct here.)' : '');
1919
+ const epicSpec = `EPIC — ${epic.title}:\n${epic.goal}` +
1920
+ (epic.criteria?.length ? `\nAcceptance criteria:\n${epic.criteria.map((c) => `- ${c}`).join('\n')}` : '') +
1921
+ (!epic.contracts && contractLock.size > 0 ? `\n(Builds against locked contracts: ${[...contractLock].join(', ')})` : '') +
1922
+ (fillsScaffold ? '\n(FILL epic: no todo!()/NotImplementedError/TODO-throw stub markers may remain in the files it implements; signatures must be unchanged.)' : '') +
1923
+ (epic.scaffold ? '\n(SCAFFOLD epic: complete compiling signatures with stub bodies are the DELIVERABLE unimplemented logic is expected and correct here.)' : '');
1924
+ acceptanceSpec = epicSpec;
2041
1925
  specChangeEvidence.writes = 0; // fresh epic — breaker needs fresh diff evidence
2042
1926
  const epicTask = await openDeliveryTask(`${epic.title} \u2014 ${epic.goal.slice(0, 120)}`, projectRoot, missionTask?.id);
1927
+ // Epic-path parallel dispatch (PR #516 follow-up): with
1928
+ // deliver.parallelTasks > 1, an epic whose goal itself decomposes
1929
+ // runs as an orchestrated task DAG — worktree-isolated parallel
1930
+ // dispatch inside the DEFAULT (epics-on) path. Only the PLANNER call
1931
+ // is fail-soft (a miss falls through to the classic single loop); a
1932
+ // runner exception must propagate — swallowing it would silently
1933
+ // restart the epic on a partially-merged tree.
1934
+ if (epicParallelTasks > 1) {
1935
+ // Retry feedback must reach the decomposition (fresh tasks that fix
1936
+ // the failure) — mirroring splitEpic — because the orchestrator's
1937
+ // 300-char mission snippet cannot carry it into every task.
1938
+ const epicPlanGoal = `${epic.title}: ${epic.goal}` +
1939
+ (ctx.lastFailure
1940
+ ? `\n\n(The previous attempt did not complete: ${ctx.lastFailure.slice(0, 300)}. The tasks you produce must FIX this.)`
1941
+ : '');
1942
+ let epicPlan = [];
1943
+ try {
1944
+ epicPlan = await planDeliveryPhases(epicPlanGoal, verdictExecutor, undefined,
1945
+ // The mission-level plan already passed validation and each
1946
+ // task converges against real gates — skip the judge call here.
1947
+ { sessionTokenBudget: sessionBudget, thoughtExperiment: false });
1948
+ }
1949
+ catch {
1950
+ epicPlan = [];
1951
+ }
1952
+ if (epicPlan.length < 2) {
1953
+ console.log(chalk.dim(` ⇉ epic ${epic.id}: no usable task decomposition — classic single-loop epic`));
1954
+ }
1955
+ else {
1956
+ console.log(chalk.cyan(` ⇉ epic ${epic.id}: decomposed into ${epicPlan.length} tasks — orchestrated parallel dispatch`));
1957
+ // The orchestrator's mission snippet carries the HEAD of this
1958
+ // text — lead with the epic essence, then retry + steering.
1959
+ const epicMissionText = `EPIC — ${epic.title}: ${epic.goal}` +
1960
+ (ctx.lastFailure ? `\nPREVIOUS ATTEMPT FEEDBACK (address this): ${ctx.lastFailure}` : '') +
1961
+ `${contractsNote}${scaffoldNote}${priors}`;
1962
+ const r = await runOrchestratedMissionCore(buildOrchestratedDeps(epicMissionText, epicPlan, epicParallelTasks, epicTask?.id));
1963
+ foldDeliveryResult(all, r);
1964
+ completeDeliveryTask(epicTask, r);
1965
+ const files = [...new Set(r.history.flatMap((h) => h.filesApplied ?? []))];
1966
+ if (epic.contracts)
1967
+ lastContractEpicFiles = files;
1968
+ // Epic-level acceptance parity: the classic path judges every
1969
+ // green turn against the EPIC spec (criteria, FILL "no stub
1970
+ // markers remain", locked contracts). Green tasks + a green
1971
+ // combined tree still must satisfy it — one judge call.
1972
+ // Fail-soft on judge availability; hard on a completed verdict.
1973
+ if (r.success && options.acceptance && !skipJudgeForSimple) {
1974
+ try {
1975
+ const judged = await runAcceptanceGate({
1976
+ spec: epicSpec,
1977
+ projectRoot,
1978
+ executor: verdictExecutor,
1979
+ runtimeNote: 'Objective project gates ALL PASSED for every task and on the combined tree — treat build/test requirements as objectively verified.',
1980
+ });
1981
+ const verdict = resolveAcceptanceVerdict(judged, acceptancePrimary);
1982
+ if (!verdict.passed) {
1983
+ return {
1984
+ success: false,
1985
+ turns: r.turns,
1986
+ summary: `${epic.goal.slice(0, 120)} — tasks green but EPIC acceptance failed: ${(verdict.feedback ?? '').slice(0, 240)}`,
1987
+ };
1988
+ }
1989
+ }
1990
+ catch {
1991
+ // judge unavailable — the objective verdicts stand
1992
+ }
1993
+ }
1994
+ const budgetHit = !r.success && r.history.some((h) => h.budgetStopped);
1995
+ return {
1996
+ success: r.success,
1997
+ turns: r.turns,
1998
+ summary: `${epic.goal.slice(0, 140)}${files.length ? ` [files: ${files.join(', ')}]` : ''}` +
1999
+ (budgetHit ? ` ${CONTEXT_BUDGET_MARKER} session(s) exceeded the context budget — scope is too large for one session` : ''),
2000
+ };
2001
+ }
2002
+ }
2043
2003
  const loop = new ConvergenceLoop({ ...loopConfig, baselineCheck: false, resumeFrom: undefined, onIteration: makeIterationHook() }, executor, seams);
2044
2004
  const r = await loop.deliver(scoped);
2045
2005
  all.turns += r.turns;