@on-par/factory-cli 0.9.25-next.8 → 0.9.25

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.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/doctor-codex-sandbox.d.ts +8 -4
  3. package/dist/cli/doctor-codex-sandbox.d.ts.map +1 -1
  4. package/dist/cli/doctor-codex-sandbox.js +25 -5
  5. package/dist/cli/doctor-codex-sandbox.js.map +1 -1
  6. package/dist/cli/doctor-config.d.ts.map +1 -1
  7. package/dist/cli/doctor-config.js +13 -2
  8. package/dist/cli/doctor-config.js.map +1 -1
  9. package/dist/cli/doctor.d.ts +2 -0
  10. package/dist/cli/doctor.d.ts.map +1 -1
  11. package/dist/cli/doctor.js +5 -6
  12. package/dist/cli/doctor.js.map +1 -1
  13. package/dist/cli/index.d.ts +3 -9
  14. package/dist/cli/index.d.ts.map +1 -1
  15. package/dist/cli/index.js +58 -93
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/cli/json-contract.d.ts.map +1 -1
  18. package/dist/cli/json-contract.js +5 -1
  19. package/dist/cli/json-contract.js.map +1 -1
  20. package/dist/cli/land.d.ts +1 -3
  21. package/dist/cli/land.d.ts.map +1 -1
  22. package/dist/cli/land.js +2 -9
  23. package/dist/cli/land.js.map +1 -1
  24. package/dist/cli/program-run-work.d.ts.map +1 -1
  25. package/dist/cli/program-run-work.js +5 -4
  26. package/dist/cli/program-run-work.js.map +1 -1
  27. package/dist/cli/repo-router.js +3 -1
  28. package/dist/cli/repo-router.js.map +1 -1
  29. package/dist/cli/run-branch.d.ts +5 -1
  30. package/dist/cli/run-branch.d.ts.map +1 -1
  31. package/dist/cli/run-branch.js +7 -4
  32. package/dist/cli/run-branch.js.map +1 -1
  33. package/dist/cli/run-brief.d.ts +0 -7
  34. package/dist/cli/run-brief.d.ts.map +1 -1
  35. package/dist/cli/run-brief.js +47 -81
  36. package/dist/cli/run-brief.js.map +1 -1
  37. package/dist/cli/run-lane-deps.d.ts +0 -4
  38. package/dist/cli/run-lane-deps.d.ts.map +1 -1
  39. package/dist/cli/run-lane.d.ts.map +1 -1
  40. package/dist/cli/run-lane.js +3 -33
  41. package/dist/cli/run-lane.js.map +1 -1
  42. package/dist/cli/ship-options.d.ts +3 -1
  43. package/dist/cli/ship-options.d.ts.map +1 -1
  44. package/dist/cli/ship-options.js +3 -3
  45. package/dist/cli/ship-options.js.map +1 -1
  46. package/dist/cli/ship-runtime.d.ts +1 -2
  47. package/dist/cli/ship-runtime.d.ts.map +1 -1
  48. package/dist/cli/ship-runtime.js.map +1 -1
  49. package/dist/cli/ship-steps.d.ts +1 -7
  50. package/dist/cli/ship-steps.d.ts.map +1 -1
  51. package/dist/cli/ship-steps.js +3 -27
  52. package/dist/cli/ship-steps.js.map +1 -1
  53. package/dist/cli/ship.d.ts +4 -2
  54. package/dist/cli/ship.d.ts.map +1 -1
  55. package/dist/cli/ship.js +17 -6
  56. package/dist/cli/ship.js.map +1 -1
  57. package/dist/cli/slice-index.d.ts +1 -1
  58. package/dist/cli/slice-index.d.ts.map +1 -1
  59. package/dist/cli/slice-index.js +4 -8
  60. package/dist/cli/slice-index.js.map +1 -1
  61. package/dist/cli/stack-run.d.ts +27 -0
  62. package/dist/cli/stack-run.d.ts.map +1 -0
  63. package/dist/cli/stack-run.js +109 -0
  64. package/dist/cli/stack-run.js.map +1 -0
  65. package/dist/cli/status-json.d.ts +1 -2
  66. package/dist/cli/status-json.d.ts.map +1 -1
  67. package/dist/cli/status-json.js +2 -7
  68. package/dist/cli/status-json.js.map +1 -1
  69. package/dist/cli/status.d.ts.map +1 -1
  70. package/dist/cli/status.js +4 -23
  71. package/dist/cli/status.js.map +1 -1
  72. package/package.json +4 -4
  73. package/schemas/status.schema.json +3 -1
  74. package/dist/cli/run-children.d.ts +0 -24
  75. package/dist/cli/run-children.d.ts.map +0 -1
  76. package/dist/cli/run-children.js +0 -73
  77. package/dist/cli/run-children.js.map +0 -1
  78. package/dist/cli/run-lane-decompose.d.ts +0 -12
  79. package/dist/cli/run-lane-decompose.d.ts.map +0 -1
  80. package/dist/cli/run-lane-decompose.js +0 -27
  81. package/dist/cli/run-lane-decompose.js.map +0 -1
package/dist/cli/index.js CHANGED
@@ -12,9 +12,10 @@ import { startupSweeps, warnQueueDiagnostics } from './queue-startup.js';
12
12
  import { proposeTriageQueue } from './triage-open-prs.js';
13
13
  import { makeQueuePreflightOps, preflightQueuedIssue, } from './queue-preflight.js';
14
14
  import { acquirePortLease, aggregateCosts, appendKpiHistoryLine, applyRepoConfig, buildPhase, checkPhase, clearProxyState, computeHealthKpis, ConstitutionLoader, createDefaultWorkSourceRegistry, createLogger, createLaneProxy, defaultFindPortListeners, describeEffectiveConfig, detectPostMergeDefects, diagnoseModels, probeDeclaredHarnesses, estimateTrailingSpend, fetchDefectSources, fetchSubscriptionUsage, formatUsageReport, getConstitutionsDir, getFactoryPaths, GITHUB_ISSUE_SOURCE, hasUnresolvedPark, InvalidWorkRequestInputError, isCommandAvailable, isProxyRunning, kpiBranchPrefixes, kpisToHistoryRecord, laneBaseUrl, laneEnv, laneHostLabel, loadFactoryConfigForRepo, loadModelsConfig, loadRepoConfig, loadRoutesConfig, joinClassifierOutcomes, mergeClassifierOutcomes, parseClassifierOutcomes, summarizeClassifierOutcomes, formatClassifierReport, mergedPrRefs, ModelRegistry, ModelRouter, parkReasonFor, parseKpiHistory, parseQueue, planPhase, readEvents, readPortLeases, readQueue, readUsage, reapOrphanProcesses, reconstructKpiEvents, recordLeasePgid, releasePortLease, renderKpiReport, renderKpiTrend, resolveDefectWindowDays, parseSizeGateMode, parseMaxSlices, SIZE_GATE_MODES, resolveEffectiveModelPins, resolveEnvironmentProxy, resolveMergePolicy, resolveSkipCI, resolveTimeouts, resolveUsageCap, resolveWatchdogPolicy, runAutoIngest, shipPhase, formatCostTotal, validateQueue, watchUsage, writeLocalRunReport, workKeyFromIssue, writeProxyState, } from '@on-par/factory-core';
15
- import { acquirePidFile, createCheckResumeStore, DEFAULT_GARDEN_MAX_CLUSTERS, DEFAULT_GARDEN_SINCE, capGardenClusters, clusterGarden, dedupGardenClusters, filterGardenOnlyNew, filterGardenWindow, markGardenTrackingUnknown, parseGardenDuration, readHarvestEvents, renderGardenJson, renderGardenReport, laneWorktreePath, migrateRepoConfigToYaml, readRepoConfigFile, rewriteRepoConfigFile, REPO_CONFIG_YAML_HEADER, claudeConfigDirOverride, claudeKeychainService, cleanupWorktree, createDaemonLogSink, factoryBranchIssue, factoryBranchPrefixes, createFactorydServer, createRunRuntime, createShipExecutor, createGithubQueue, createLocalSmallDryRun, createOctokitFilingClient, createOctokitGreenPrClient, createOctokitQueueClient, daemonRuntimePaths, defaultRegistryPath, ensureDir, fetchHumanEventSourcesCached, FACTORY_RUNTIME_CONFIG_KEYS, findUnmergedGreenPrs, listStatelessLaneIssues, formatGcReport, gitFetch, listMicroVms, listOrphanContainers, logCost, logEvent, planQueueMigration, pollBlockedParks, readCosts, readGithubQueueSnapshot, reapCleanShipWorktree, reapLaneWorktree, reapOrphanContainers, reapOrphanMicroVm, releaseRuntimeFiles, releaseStaleClaims, resolveBranchPrefix, resolveEffectiveConfig, resolveExperimental, resolveLocalOnly, describeDraftPrPolicy, resolveDraftPrPolicy, resolvePrClassifierPolicy, resolveReviewFloorRules, runOvernightQueue, parseRemoteSlug, setupWorktree, shellEscape, listBuiltInCheckers, sweepWorktrees, watchChecks, withFileLock, withGitLock, writePortFile, buildTriagePrompt, parseTriageCandidates, laneSlug, formatStopMarker, readStopMarker, detectClaudePlan, } from '@on-par/factory-core/internal';
15
+ import { acquirePidFile, createCheckResumeStore, DEFAULT_GARDEN_MAX_CLUSTERS, DEFAULT_GARDEN_SINCE, capGardenClusters, clusterGarden, dedupGardenClusters, filterGardenOnlyNew, filterGardenWindow, markGardenTrackingUnknown, parseGardenDuration, readHarvestEvents, renderGardenJson, renderGardenReport, laneWorktreePath, migrateRepoConfigToYaml, readRepoConfigFile, rewriteRepoConfigFile, REPO_CONFIG_YAML_HEADER, claudeConfigDirOverride, claudeKeychainService, cleanupWorktree, createDaemonLogSink, factoryBranchIssue, factoryBranchPrefixes, createFactorydServer, createRunRuntime, createShipExecutor, createGithubQueue, createLocalSmallDryRun, createOctokitFilingClient, createOctokitGreenPrClient, createOctokitQueueClient, daemonRuntimePaths, defaultRegistryPath, ensureDir, fetchHumanEventSourcesCached, FACTORY_RUNTIME_CONFIG_KEYS, findUnmergedGreenPrs, listStatelessLaneIssues, formatGcReport, gitFetch, listMicroVms, listOrphanContainers, logCost, logEvent, planQueueMigration, pollBlockedParks, readCosts, readGithubQueueSnapshot, reapCleanShipWorktree, reapLaneWorktree, reapOrphanContainers, reapOrphanMicroVm, releaseRuntimeFiles, releaseStaleClaims, resolveBranchPrefix, resolveEffectiveConfig, resolveExperimental, resolveLocalOnly, describeDraftPrPolicy, resolveDraftPrPolicy, resolvePrClassifierPolicy, resolveReviewFloorRules, runOvernightQueue, parseRemoteSlug, setupWorktree, shellEscape, listBuiltInCheckers, sweepWorktrees, watchChecks, withFileLock, withGitLock, writePortFile, buildTriagePrompt, parseTriageCandidates, laneSlug, formatStopMarker, readStopMarker, detectClaudePlan, findSlicePlanComment, listBlockedBy, aliasDeprecatedSizeGateMode, } from '@on-par/factory-core/internal';
16
16
  import { CliExitError } from './errors.js';
17
17
  import { baseBranchConflict, baseBranchOrExit } from './ship-options.js';
18
+ import { runIssueStack } from './stack-run.js';
18
19
  import { withRepoRunLock } from './repo-run-lock.js';
19
20
  export { CliExitError, withRepoRunLock };
20
21
  import { formatSteerabilityReport } from '@on-par/factory-core/internal';
@@ -67,7 +68,6 @@ import { selectOctokit } from './github-stub.js';
67
68
  import { createFactoryOctokit } from './octokit.js';
68
69
  import { runDraftCommand } from './draft-command.js';
69
70
  import { checkErrorExit, checkReportExit, createDeepModelRunner, runIssueCheck } from './ready-check.js';
70
- import { childRunSucceeded, formatChildRunSummary, runChildrenInOrder } from './run-children.js';
71
71
  import { cmdRunBrief as cmdRunBriefWith } from './run-brief.js';
72
72
  import { readRunFlagOverrides, recordDraftPrFlag } from './run-flags.js';
73
73
  import { runStalenessGuard } from './staleness.js';
@@ -359,7 +359,6 @@ setShipRuntime(() => ({
359
359
  LaneParkError,
360
360
  LaneEnvironmentPauseError,
361
361
  IssueSkippedError,
362
- IssueDecomposedError,
363
362
  }));
364
363
  export { LaneEnvironmentPauseError, shipIssue };
365
364
  export function hasGitHubToken(env = process.env, tryToken) {
@@ -665,7 +664,7 @@ function branchPrefixOrExit(raw, configPath) {
665
664
  function sizeGateOrExit(raw) {
666
665
  if (raw === undefined)
667
666
  return undefined;
668
- const mode = parseSizeGateMode(raw);
667
+ const mode = parseSizeGateMode(aliasDeprecatedSizeGateMode(raw));
669
668
  if (mode === undefined) {
670
669
  throw new CliExitError(`factory: invalid --size-gate '${raw}' — expected one of: ${SIZE_GATE_MODES.join(', ')}`, 2);
671
670
  }
@@ -1108,7 +1107,9 @@ async function cmdClassifierBacktestEntry(opts) {
1108
1107
  const repoConfig = configLoaders.loadRepoConfig(repoRoot);
1109
1108
  const effective = resolveEffectiveConfig(repoConfig);
1110
1109
  const router = new coreOps.ModelRouter(applyRepoConfig(configLoaders.loadModelsConfig(), repoConfig), configLoaders.loadRoutesConfig(), false, undefined, effective.allowExperimental, effective.localOnly);
1111
- router.setCodexFullAccessTasks?.(configLoaders.loadFactoryConfigForRepo(paths.config).sandbox.codexFullAccessTasks);
1110
+ const sandbox = configLoaders.loadFactoryConfigForRepo(paths.config).sandbox;
1111
+ router.setCodexFullAccessTasks?.(sandbox.codexFullAccessTasks);
1112
+ router.setCodexSandbox?.(sandbox.codexSandbox);
1112
1113
  applyRouterGuards(router);
1113
1114
  try {
1114
1115
  await cmdClassifierBacktest({ ...opts, branchPrefix }, {
@@ -1359,7 +1360,9 @@ async function cmdTui(opts = {}, runTuiImpl = runTui) {
1359
1360
  const routesConfig = configLoaders.loadRoutesConfig();
1360
1361
  const effective = resolveEffectiveConfig(repoConfig);
1361
1362
  const router = new coreOps.ModelRouter(modelsConfig, routesConfig, false, undefined, effective.allowExperimental, effective.localOnly);
1362
- router.setCodexFullAccessTasks?.(configLoaders.loadFactoryConfigForRepo(paths.config).sandbox.codexFullAccessTasks);
1363
+ const sandbox = configLoaders.loadFactoryConfigForRepo(paths.config).sandbox;
1364
+ router.setCodexFullAccessTasks?.(sandbox.codexFullAccessTasks);
1365
+ router.setCodexSandbox?.(sandbox.codexSandbox);
1363
1366
  applyRouterGuards(router);
1364
1367
  const effectiveConfigLines = describeEffectiveConfig({
1365
1368
  router,
@@ -1601,6 +1604,8 @@ async function cmdShip(issueNum, opts) {
1601
1604
  }, { scope: { kind: 'issue', key: workKeyFromIssue(issueNum) } });
1602
1605
  }
1603
1606
  async function cmdRunIssue(issueNum, opts) {
1607
+ if (opts.runChildren)
1608
+ throw new CliExitError('--run-children was removed; oversized issues stack with --stack', 2);
1604
1609
  if (availableAgentClis(coreOps.isCommandAvailable).length === 0) {
1605
1610
  throw new CliExitError(`factory: ${missingAgentCliMessage()}`, 2);
1606
1611
  }
@@ -1609,16 +1614,24 @@ async function cmdRunIssue(issueNum, opts) {
1609
1614
  if (!existsSync(paths.root)) {
1610
1615
  throw new CliExitError(`factory: ${notInitializedMessage()}`, 2);
1611
1616
  }
1612
- const { runChildren, sizeGate: rawSizeGate, maxSlices: rawMaxSlices, ...shipOpts } = opts;
1617
+ const { runChildren: _removed, sizeGate: rawSizeGate, maxSlices: rawMaxSlices, stack, ...shipOpts } = opts;
1613
1618
  const branchPrefix = branchPrefixOrExit(opts.branchPrefix, paths.config);
1614
- const sizeGate = sizeGateOrExit(rawSizeGate);
1619
+ const parsedSizeGate = sizeGateOrExit(rawSizeGate);
1620
+ if (stack && parsedSizeGate !== undefined && parsedSizeGate !== 'stack') {
1621
+ throw new CliExitError('factory: --stack is --size-gate stack — drop one of them', 2);
1622
+ }
1623
+ const sizeGate = stack ? 'stack' : parsedSizeGate;
1624
+ const explicitStack = stack === true || rawSizeGate === 'stack';
1615
1625
  const maxSlices = maxSlicesOrExit(rawMaxSlices);
1616
1626
  const baseBranch = baseBranchOrExit(opts.baseBranch);
1617
- const conflict = baseBranchConflict({ baseBranch, sizeGate: rawSizeGate, runChildren });
1627
+ const conflict = baseBranchConflict({ baseBranch, sizeGate });
1618
1628
  if (conflict)
1619
1629
  throw new CliExitError(conflict, 2);
1620
- if (opts.pr === false && ((sizeGate !== undefined && sizeGate !== 'off') || runChildren)) {
1621
- throw new CliExitError('factory: --no-pr runs with the size gate off — drop --size-gate/--run-children or drop --no-pr', 2);
1630
+ if (sizeGate === 'stack' && opts.pr === false) {
1631
+ throw new CliExitError('factory: --stack opens a PR per slice — drop --no-pr or drop --stack', 2);
1632
+ }
1633
+ if (opts.pr === false && sizeGate !== undefined && sizeGate !== 'off') {
1634
+ throw new CliExitError('factory: --no-pr runs with the size gate off — drop --size-gate or drop --no-pr', 2);
1622
1635
  }
1623
1636
  await withRepoRunLock(paths, 'factory run-issue', async () => {
1624
1637
  recordDraftPrFlag(paths.runFlags, opts.draftPr);
@@ -1648,84 +1661,45 @@ async function cmdRunIssue(issueNum, opts) {
1648
1661
  });
1649
1662
  }
1650
1663
  try {
1651
- await shipIssue(issueNum, { ...shipOpts, branchPrefix, sizeGate, maxSlices }, { repoRoot, ghRepo, workRequest: work });
1664
+ if (sizeGate === 'stack') {
1665
+ await runIssueStack(issueNum, baseBranch, {
1666
+ repo: ghRepo,
1667
+ list: (issue) => listBlockedBy({ octokit: getOctokit(), repo: ghRepo }, issue),
1668
+ shipMember: async (issue, base, onOutcome) => {
1669
+ const memberWork = issue === issueNum
1670
+ ? work
1671
+ : await workSources.resolve(GITHUB_ISSUE_SOURCE, { repo: ghRepo, issue });
1672
+ await shipIssue(issue, {
1673
+ ...shipOpts,
1674
+ branchPrefix,
1675
+ sizeGate,
1676
+ explicitStack,
1677
+ maxSlices,
1678
+ baseBranch: base,
1679
+ parkOverBudget: true,
1680
+ }, { repoRoot, ghRepo, workRequest: memberWork, onOutcome });
1681
+ },
1682
+ readSlicePlan: async () => {
1683
+ const lookup = await findSlicePlanComment({ octokit: getOctokit(), repo: ghRepo, issue: issueNum });
1684
+ return lookup.status === 'found' ? lookup.plan : undefined;
1685
+ },
1686
+ ship: async (base, onOutcome) => {
1687
+ await shipIssue(issueNum, { ...shipOpts, branchPrefix, sizeGate, explicitStack, maxSlices, baseBranch: base }, { repoRoot, ghRepo, workRequest: work, onOutcome });
1688
+ },
1689
+ });
1690
+ return;
1691
+ }
1692
+ await shipIssue(issueNum, { ...shipOpts, branchPrefix, sizeGate, explicitStack, maxSlices }, { repoRoot, ghRepo, workRequest: work });
1652
1693
  }
1653
1694
  catch (err) {
1695
+ if (err instanceof CliExitError)
1696
+ throw err;
1654
1697
  if (err instanceof IssueSkippedError)
1655
1698
  return;
1656
- if (err instanceof IssueDecomposedError && runChildren) {
1657
- await runDecomposedChildren(issueNum, err.childIssues, { ...shipOpts, branchPrefix, sizeGate, maxSlices }, { repoRoot, ghRepo, workSources });
1658
- return;
1659
- }
1660
- if (err instanceof IssueDecomposedError && !runChildren) {
1661
- const children = err.childIssues.map((n) => `#${n}`).join(', ');
1662
- throw new CliExitError(`Run failed for issue #${issueNum}: the size gate decomposed it into ${children} — no child issue was run. ` +
1663
- `Re-run with \`factory run-issue ${issueNum} --run-children\` to run them.`, 1);
1664
- }
1665
1699
  throw new CliExitError(`Run failed for issue #${issueNum}: ${err.message}`, 1);
1666
1700
  }
1667
1701
  }, { scope: { kind: 'issue', key: workKeyFromIssue(issueNum) } });
1668
1702
  }
1669
- /** Runs each decomposed child through the one-shot pipeline in build order, inside the caller's
1670
- * run lock, then prints a per-child summary. Nested decompositions expand in place and closed
1671
- * children are skipped. A failed or escalated child is recorded and the next one still runs;
1672
- * `.factory/STOP` is checked before each child starts (read only, ADR-0111). Throws CliExitError(1)
1673
- * unless every child is ready or skipped (#1747, #1748, #1749). */
1674
- async function runDecomposedChildren(parent, children, opts, env) {
1675
- const list = children.map((n) => `#${n}`).join(', ');
1676
- console.log(styleText('cyan', `run-children: #${parent} decomposed into ${list} — running them in build order`));
1677
- const paths = getFactoryPaths(env.repoRoot);
1678
- const results = await runChildrenInOrder(children, async (child) => {
1679
- let work;
1680
- try {
1681
- work = await env.workSources.resolve(GITHUB_ISSUE_SOURCE, {
1682
- repo: env.ghRepo,
1683
- issue: child,
1684
- });
1685
- }
1686
- catch (err) {
1687
- return { issue: child, status: 'failed', detail: `could not resolve issue #${child} (${errorDetail(err)})` };
1688
- }
1689
- console.log(styleText('cyan', `one-shot: resolved ${work.id} — running the pipeline (queue untouched)`));
1690
- let outcome;
1691
- try {
1692
- await withRepoRunLock(paths, 'factory run-issue', () => shipIssue(child, opts, {
1693
- repoRoot: env.repoRoot,
1694
- ghRepo: env.ghRepo,
1695
- workRequest: work,
1696
- onOutcome: (o) => {
1697
- outcome = o;
1698
- },
1699
- }), { scope: { kind: 'issue', key: workKeyFromIssue(child) } });
1700
- }
1701
- catch (err) {
1702
- if (err instanceof IssueDecomposedError) {
1703
- const again = err.childIssues.map((n) => `#${n}`).join(', ');
1704
- console.log(styleText('cyan', `run-children: #${child} decomposed into ${again} — running them in its place`));
1705
- return { issue: child, status: 'decomposed', children: err.childIssues };
1706
- }
1707
- if (err instanceof IssueSkippedError) {
1708
- return { issue: child, status: 'skipped', detail: err.message };
1709
- }
1710
- return { issue: child, status: 'failed', detail: err instanceof Error ? err.message : String(err) };
1711
- }
1712
- const done = outcome;
1713
- return { issue: child, status: 'ready', prNumber: done && 'prNumber' in done ? done.prNumber : undefined };
1714
- }, [parent], (next) => {
1715
- if (!existsSync(paths.stop))
1716
- return false;
1717
- logEvent(paths.events, 'stopped', next, 'STOP file present');
1718
- console.log(styleText('yellow', `run-children: .factory/STOP present — not starting #${next} or any later child`));
1719
- return true;
1720
- });
1721
- const ok = childRunSucceeded(results);
1722
- for (const line of formatChildRunSummary(parent, results)) {
1723
- console.log(ok ? styleText('green', line) : styleText('yellow', line));
1724
- }
1725
- if (!ok) {
1726
- throw new CliExitError(`Run failed for issue #${parent}: not every decomposed child reached ready-for-review or was skipped as closed (failed or not-run children are listed above)`, 1);
1727
- }
1728
- }
1729
1703
  async function cmdLocalSmallDryRun(issueNum, opts) {
1730
1704
  const repoRoot = await getRepoRoot();
1731
1705
  const ghRepo = await getGitHubRepo();
@@ -1976,7 +1950,9 @@ async function cmdTriage(opts) {
1976
1950
  const routesConfig = configLoaders.loadRoutesConfig();
1977
1951
  const effective = resolveEffectiveConfig(repoConfig);
1978
1952
  const router = new coreOps.ModelRouter(modelsConfig, routesConfig, false, undefined, effective.allowExperimental, effective.localOnly);
1979
- router.setCodexFullAccessTasks?.(configLoaders.loadFactoryConfigForRepo(paths.config).sandbox.codexFullAccessTasks);
1953
+ const sandbox = configLoaders.loadFactoryConfigForRepo(paths.config).sandbox;
1954
+ router.setCodexFullAccessTasks?.(sandbox.codexFullAccessTasks);
1955
+ router.setCodexSandbox?.(sandbox.codexSandbox);
1980
1956
  applyRouterGuards(router);
1981
1957
  router.skipMissingHarnessClis(coreOps.isCommandAvailable);
1982
1958
  router.setCostSink((entry) => logCost(paths.costs, { ...entry, issue: '-' }));
@@ -2527,7 +2503,6 @@ export function laneQueueDeps(queue, lane) {
2527
2503
  releaseIssue: (issue, outcome) => queue.release(issue, outcome),
2528
2504
  heartbeat: (issue) => queue.heartbeat(issue),
2529
2505
  countRemaining: async () => (await queue.list(lane)).length,
2530
- queueChildren: (parent, children) => queue.enqueueAfter(lane, parent, children),
2531
2506
  };
2532
2507
  }
2533
2508
  export { preflightQueuedIssue };
@@ -2571,16 +2546,6 @@ export class IssueSkippedError extends Error {
2571
2546
  this.reason = reason;
2572
2547
  }
2573
2548
  }
2574
- /** The target issue tripped the PLAN pre-flight size gate and was decomposed into real
2575
- * filed sub-issues; the queue was rewritten. Not a park — the lane continues with the
2576
- * children in place of the oversized issue. (#823) */
2577
- export class IssueDecomposedError extends Error {
2578
- childIssues;
2579
- constructor(message, childIssues) {
2580
- super(message);
2581
- this.childIssues = childIssues;
2582
- }
2583
- }
2584
2549
  export function issueFromFactoryBranch(branch, prefix) {
2585
2550
  return factoryBranchIssue(branch, prefix) ?? undefined;
2586
2551
  }