issue-flow 0.11.1 → 0.13.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.
Files changed (180) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-BXRIEKVM.js +238 -0
  3. package/dist/agent-BXRIEKVM.js.map +1 -0
  4. package/dist/{analyze-XV3K25K3.js → analyze-WS47UYGN.js} +32 -15
  5. package/dist/analyze-WS47UYGN.js.map +1 -0
  6. package/dist/{apply-WUJHDD7A.js → apply-OS62UWRN.js} +15 -5
  7. package/dist/{apply-WUJHDD7A.js.map → apply-OS62UWRN.js.map} +1 -1
  8. package/dist/bench-SA3BOME5.js +906 -0
  9. package/dist/bench-SA3BOME5.js.map +1 -0
  10. package/dist/chunk-37N2RJW2.js +120 -0
  11. package/dist/chunk-37N2RJW2.js.map +1 -0
  12. package/dist/chunk-3XLCNVMD.js +180 -0
  13. package/dist/chunk-3XLCNVMD.js.map +1 -0
  14. package/dist/chunk-5TB6KLC2.js +72 -0
  15. package/dist/chunk-5TB6KLC2.js.map +1 -0
  16. package/dist/{chunk-OBLVLIUS.js → chunk-664Y3NDX.js} +25 -13
  17. package/dist/chunk-664Y3NDX.js.map +1 -0
  18. package/dist/chunk-6FDFRNXZ.js +357 -0
  19. package/dist/chunk-6FDFRNXZ.js.map +1 -0
  20. package/dist/chunk-7KD66LIM.js +658 -0
  21. package/dist/chunk-7KD66LIM.js.map +1 -0
  22. package/dist/chunk-7Z4Y3VKM.js +26 -0
  23. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  24. package/dist/chunk-ARFVHC2F.js +1111 -0
  25. package/dist/chunk-ARFVHC2F.js.map +1 -0
  26. package/dist/{chunk-RKTEV6EG.js → chunk-BHJCGWQX.js} +141 -12
  27. package/dist/chunk-BHJCGWQX.js.map +1 -0
  28. package/dist/chunk-BQDQTIM7.js +74 -0
  29. package/dist/chunk-BQDQTIM7.js.map +1 -0
  30. package/dist/chunk-CNBYCMSU.js +2709 -0
  31. package/dist/chunk-CNBYCMSU.js.map +1 -0
  32. package/dist/chunk-CRGIQFUQ.js +83 -0
  33. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  34. package/dist/chunk-DIG5XKQQ.js +298 -0
  35. package/dist/chunk-DIG5XKQQ.js.map +1 -0
  36. package/dist/chunk-FZDR7CGH.js +71 -0
  37. package/dist/chunk-FZDR7CGH.js.map +1 -0
  38. package/dist/chunk-HEF2RMKN.js +413 -0
  39. package/dist/chunk-HEF2RMKN.js.map +1 -0
  40. package/dist/{chunk-IVHZEYAX.js → chunk-HJGGNLWI.js} +25 -19
  41. package/dist/chunk-HJGGNLWI.js.map +1 -0
  42. package/dist/chunk-HQAHNIAR.js +283 -0
  43. package/dist/chunk-HQAHNIAR.js.map +1 -0
  44. package/dist/{chunk-GANSDJV7.js → chunk-IHIEXUTC.js} +46 -24
  45. package/dist/chunk-IHIEXUTC.js.map +1 -0
  46. package/dist/chunk-IV5SS4JN.js +84 -0
  47. package/dist/chunk-IV5SS4JN.js.map +1 -0
  48. package/dist/{chunk-HC2MT7BX.js → chunk-IYV6KNVF.js} +158 -592
  49. package/dist/chunk-IYV6KNVF.js.map +1 -0
  50. package/dist/{chunk-LVKQ2AKT.js → chunk-J62QSVP6.js} +10 -8
  51. package/dist/chunk-J62QSVP6.js.map +1 -0
  52. package/dist/chunk-KMMASOA6.js +134 -0
  53. package/dist/chunk-KMMASOA6.js.map +1 -0
  54. package/dist/chunk-KQHB7ZT3.js +559 -0
  55. package/dist/chunk-KQHB7ZT3.js.map +1 -0
  56. package/dist/chunk-L6HSKTQE.js +77 -0
  57. package/dist/chunk-L6HSKTQE.js.map +1 -0
  58. package/dist/{chunk-6N7LZZ5U.js → chunk-LZ6GFQAG.js} +474 -160
  59. package/dist/chunk-LZ6GFQAG.js.map +1 -0
  60. package/dist/{chunk-HQYXVIH6.js → chunk-MIVHK5YI.js} +5 -5
  61. package/dist/chunk-NEZZ6KDR.js +1217 -0
  62. package/dist/chunk-NEZZ6KDR.js.map +1 -0
  63. package/dist/{run-DBF2VWUN.js → chunk-OPNGPUKJ.js} +747 -594
  64. package/dist/chunk-OPNGPUKJ.js.map +1 -0
  65. package/dist/chunk-P3LRUNC6.js +16 -0
  66. package/dist/chunk-P3LRUNC6.js.map +1 -0
  67. package/dist/{chunk-BXCPXRBR.js → chunk-PIVGJM6K.js} +129 -32
  68. package/dist/chunk-PIVGJM6K.js.map +1 -0
  69. package/dist/{chunk-AAY6KM7N.js → chunk-PV4OX5TC.js} +167 -196
  70. package/dist/chunk-PV4OX5TC.js.map +1 -0
  71. package/dist/chunk-QCXPNSEL.js +141 -0
  72. package/dist/chunk-QCXPNSEL.js.map +1 -0
  73. package/dist/{chunk-34WNTK3K.js → chunk-QXDNBYQF.js} +53 -13
  74. package/dist/chunk-QXDNBYQF.js.map +1 -0
  75. package/dist/chunk-SNTTOQAD.js +30 -0
  76. package/dist/chunk-SNTTOQAD.js.map +1 -0
  77. package/dist/{chunk-EY6WMHV2.js → chunk-TM67EHSV.js} +67 -23
  78. package/dist/chunk-TM67EHSV.js.map +1 -0
  79. package/dist/chunk-TVN2JVOF.js +77 -0
  80. package/dist/chunk-TVN2JVOF.js.map +1 -0
  81. package/dist/chunk-TX5WIVYP.js +129 -0
  82. package/dist/chunk-TX5WIVYP.js.map +1 -0
  83. package/dist/{chunk-KQ4JQN7T.js → chunk-UJ7XWK7J.js} +83 -21
  84. package/dist/chunk-UJ7XWK7J.js.map +1 -0
  85. package/dist/{chunk-47VIN33V.js → chunk-UOCPC2Y2.js} +596 -17
  86. package/dist/chunk-UOCPC2Y2.js.map +1 -0
  87. package/dist/chunk-XEYH6ZZI.js +289 -0
  88. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  89. package/dist/cli.js +390 -40
  90. package/dist/cli.js.map +1 -1
  91. package/dist/config-MEM2IWWN.js +76 -0
  92. package/dist/contract-JH2WBIO6.js +8 -0
  93. package/dist/conventions-WV4NDXGH.js +143 -0
  94. package/dist/conventions-WV4NDXGH.js.map +1 -0
  95. package/dist/execute-NITIHHCK.js +31 -0
  96. package/dist/{generate-TBVTLMOP.js → generate-MVQI7A45.js} +39 -19
  97. package/dist/{generate-TBVTLMOP.js.map → generate-MVQI7A45.js.map} +1 -1
  98. package/dist/git-YRVRUN3C.js +31 -0
  99. package/dist/init-OKWEC3EV.js +21 -0
  100. package/dist/operations-LU6JA3BX.js +374 -0
  101. package/dist/operations-LU6JA3BX.js.map +1 -0
  102. package/dist/permissions-7NMDFU27.js +18 -0
  103. package/dist/plan-LEJJF3DE.js +31 -0
  104. package/dist/{policy-XQW5NUIE.js → policy-JSYEK5B2.js} +17 -4
  105. package/dist/policy-JSYEK5B2.js.map +1 -0
  106. package/dist/pr-HPVUZ7S3.js +36 -0
  107. package/dist/pr-review-R2QZBT3F.js +29 -0
  108. package/dist/pr-review-R2QZBT3F.js.map +1 -0
  109. package/dist/prd-5O6GYCC6.js +30 -0
  110. package/dist/prd-5O6GYCC6.js.map +1 -0
  111. package/dist/ps-TNE44R5V.js +90 -0
  112. package/dist/ps-TNE44R5V.js.map +1 -0
  113. package/dist/recorder-XGF55WXI.js +31 -0
  114. package/dist/recorder-XGF55WXI.js.map +1 -0
  115. package/dist/registry-LGPE53QD.js +15 -0
  116. package/dist/registry-LGPE53QD.js.map +1 -0
  117. package/dist/resume-QMEPMSZW.js +238 -0
  118. package/dist/resume-QMEPMSZW.js.map +1 -0
  119. package/dist/review-YKWD6SNN.js +32 -0
  120. package/dist/review-YKWD6SNN.js.map +1 -0
  121. package/dist/routing-2ZUMZPJB.js +91 -0
  122. package/dist/routing-2ZUMZPJB.js.map +1 -0
  123. package/dist/run-YU4TR62R.js +50 -0
  124. package/dist/run-YU4TR62R.js.map +1 -0
  125. package/dist/state-manager-X3PT3FGT.js +36 -0
  126. package/dist/state-manager-X3PT3FGT.js.map +1 -0
  127. package/dist/usage-VCFLDA5Y.js +174 -0
  128. package/dist/usage-VCFLDA5Y.js.map +1 -0
  129. package/dist/{web-ANQQTTRD.js → web-XVHLX62B.js} +43 -27
  130. package/dist/web-XVHLX62B.js.map +1 -0
  131. package/package.json +6 -2
  132. package/prompts/execute.md +7 -8
  133. package/prompts/plan.md +4 -5
  134. package/prompts/pr.md +13 -6
  135. package/web/AGENTS.md +3 -3
  136. package/web/public/app.css +38 -0
  137. package/web/public/app.js +132 -10
  138. package/web/public/index.html +24 -0
  139. package/dist/analyze-XV3K25K3.js.map +0 -1
  140. package/dist/chunk-34WNTK3K.js.map +0 -1
  141. package/dist/chunk-3BOHTH4V.js +0 -58
  142. package/dist/chunk-3BOHTH4V.js.map +0 -1
  143. package/dist/chunk-47VIN33V.js.map +0 -1
  144. package/dist/chunk-6N7LZZ5U.js.map +0 -1
  145. package/dist/chunk-AAY6KM7N.js.map +0 -1
  146. package/dist/chunk-BXCPXRBR.js.map +0 -1
  147. package/dist/chunk-EWDJENFW.js +0 -303
  148. package/dist/chunk-EWDJENFW.js.map +0 -1
  149. package/dist/chunk-EY6WMHV2.js.map +0 -1
  150. package/dist/chunk-GANSDJV7.js.map +0 -1
  151. package/dist/chunk-HC2MT7BX.js.map +0 -1
  152. package/dist/chunk-HDV3YDTG.js +0 -52
  153. package/dist/chunk-HDV3YDTG.js.map +0 -1
  154. package/dist/chunk-IVHZEYAX.js.map +0 -1
  155. package/dist/chunk-KQ4JQN7T.js.map +0 -1
  156. package/dist/chunk-LVKQ2AKT.js.map +0 -1
  157. package/dist/chunk-OBLVLIUS.js.map +0 -1
  158. package/dist/chunk-RKTEV6EG.js.map +0 -1
  159. package/dist/chunk-VQ5VN7DF.js +0 -1018
  160. package/dist/chunk-VQ5VN7DF.js.map +0 -1
  161. package/dist/config-4THHOXNN.js +0 -41
  162. package/dist/execute-5OEKLM5X.js +0 -15
  163. package/dist/init-PRMOTQ7N.js +0 -9
  164. package/dist/plan-Y2BYZD24.js +0 -17
  165. package/dist/policy-XQW5NUIE.js.map +0 -1
  166. package/dist/pr-H6GLOSXF.js +0 -21
  167. package/dist/pr-review-CK5FR6WX.js +0 -17
  168. package/dist/prd-4PWLCGH5.js +0 -17
  169. package/dist/review-QGVAHEZF.js +0 -15
  170. package/dist/run-DBF2VWUN.js.map +0 -1
  171. package/dist/web-ANQQTTRD.js.map +0 -1
  172. /package/dist/{chunk-HQYXVIH6.js.map → chunk-MIVHK5YI.js.map} +0 -0
  173. /package/dist/{config-4THHOXNN.js.map → config-MEM2IWWN.js.map} +0 -0
  174. /package/dist/{execute-5OEKLM5X.js.map → contract-JH2WBIO6.js.map} +0 -0
  175. /package/dist/{init-PRMOTQ7N.js.map → execute-NITIHHCK.js.map} +0 -0
  176. /package/dist/{plan-Y2BYZD24.js.map → git-YRVRUN3C.js.map} +0 -0
  177. /package/dist/{pr-H6GLOSXF.js.map → init-OKWEC3EV.js.map} +0 -0
  178. /package/dist/{pr-review-CK5FR6WX.js.map → permissions-7NMDFU27.js.map} +0 -0
  179. /package/dist/{prd-4PWLCGH5.js.map → plan-LEJJF3DE.js.map} +0 -0
  180. /package/dist/{review-QGVAHEZF.js.map → pr-HPVUZ7S3.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/bench.ts","../src/benchmark/corpus.ts","../src/benchmark/live.ts","../src/benchmark/real.ts","../src/benchmark/fixtures/materialize.ts","../src/benchmark/fixtures/templates.ts","../src/benchmark/stats.ts","../src/benchmark/tuple.ts","../src/benchmark/report.ts","../src/benchmark/synthetic.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { createInterface } from 'node:readline';\nimport { TASK_CLASSES, type TaskClass } from '../benchmark/corpus.js';\nimport { createLiveRepeatRunner } from '../benchmark/live.js';\nimport { type BenchCampaign, type RepeatRunner, runRealCorpus } from '../benchmark/real.js';\nimport { renderCampaignMarkdown } from '../benchmark/report.js';\nimport { runSyntheticCorpus } from '../benchmark/synthetic.js';\nimport { collectHarnessVersion } from '../benchmark/tuple.js';\nimport { printError, printInfo, printWarning } from '../ui/logger.js';\n\n/** p50 USD from the #79 before table — used only for the pre-flight estimate. */\nexport const BASELINE_COST_P50_USD: Record<TaskClass, number> = {\n trivial: 0.2,\n small: 3.17,\n medium: 6.08,\n analysis: 1.86,\n};\n\nexport class BenchConfirmationError extends Error {\n readonly exitCode = 1;\n constructor(message: string) {\n super(message);\n this.name = 'BenchConfirmationError';\n }\n}\n\nexport interface BenchOptions {\n mode?: 'synthetic' | 'real';\n task?: string[];\n arm?: string[];\n repeats?: number;\n maxCost?: number;\n maxDuration?: number;\n out?: string;\n yes?: boolean;\n repo?: string;\n json?: boolean;\n interactive?: boolean;\n stdin?: NodeJS.ReadableStream;\n stdout?: NodeJS.WritableStream;\n runPipeline?: (issue: string) => Promise<number>;\n runner?: RepeatRunner;\n harnessVersion?: string;\n}\n\nexport function estimateCampaignUsd(tasks: TaskClass[], arms: number, repeats: number): number {\n const perRepeat = tasks.reduce((sum, task) => sum + BASELINE_COST_P50_USD[task], 0);\n return perRepeat * arms * repeats;\n}\n\nfunction isInteractiveByDefault(): boolean {\n const ci = process.env.CI;\n const inCi = ci !== undefined && ci !== '' && ci !== '0' && ci.toLowerCase() !== 'false';\n return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY) && !inCi;\n}\n\nexport async function confirmRealCampaign(\n estimate: { cells: number; repeats: number; usd: number; maxCost?: number; maxDuration?: number },\n options: Pick<BenchOptions, 'yes' | 'interactive' | 'stdin' | 'stdout'> = {},\n): Promise<void> {\n printInfo(\n `Real campaign: ${estimate.cells} cells × ${estimate.repeats} repeats ≈ $${estimate.usd.toFixed(2)} (p50 of the #79 baseline).`,\n );\n if (estimate.maxCost !== undefined) {\n printInfo(`Cost ceiling: $${estimate.maxCost.toFixed(2)}.`);\n }\n if (estimate.maxDuration !== undefined) {\n printInfo(`Duration ceiling: ${estimate.maxDuration}ms.`);\n }\n if (options.yes === true) {\n printInfo('--yes: starting the campaign.');\n return;\n }\n const interactive = options.interactive ?? isInteractiveByDefault();\n if (!interactive) {\n throw new BenchConfirmationError(\n 'A real campaign spends money and the terminal is not interactive. Re-run with --yes.',\n );\n }\n const stdin = options.stdin ?? process.stdin;\n const stdout = options.stdout ?? process.stdout;\n const rl = createInterface({ input: stdin, output: stdout });\n try {\n const answer = await new Promise<string>((resolve) => {\n rl.question('Proceed with a paid campaign? [y/N] ', resolve);\n });\n if (!/^\\s*y(es)?\\s*$/i.test(answer)) {\n throw new BenchConfirmationError('Cancelled: the campaign was not confirmed.');\n }\n } finally {\n rl.close();\n }\n}\n\nfunction parseTasks(values: string[] | undefined): TaskClass[] {\n if (values === undefined || values.length === 0) return [...TASK_CLASSES];\n const tasks: TaskClass[] = [];\n for (const value of values) {\n if (!(TASK_CLASSES as readonly string[]).includes(value)) {\n throw new BenchConfirmationError(\n `Unknown task class '${value}'. Must be one of: ${TASK_CLASSES.join(', ')}.`,\n );\n }\n if (!tasks.includes(value as TaskClass)) tasks.push(value as TaskClass);\n }\n return tasks;\n}\n\nfunction printSynthetic(): void {\n const rows = runSyntheticCorpus();\n printInfo('Synthetic corpus (orchestration only; harness is a number).');\n for (const row of rows) {\n printInfo(\n `${row.task} duration=${row.taskDurationMs.toFixed(1)}ms overhead=${row.orchestrationOverheadMs.toFixed(1)}ms verdict=${row.verdict}`,\n );\n }\n}\n\nexport async function runBench(options: BenchOptions = {}): Promise<number> {\n const mode = options.mode ?? 'synthetic';\n if (mode !== 'synthetic' && mode !== 'real') {\n printError(`Unknown bench mode '${mode}'. Use synthetic or real.`);\n return 1;\n }\n if (mode === 'synthetic') {\n printSynthetic();\n return 0;\n }\n if (options.repo !== undefined) {\n printWarning(\n '--repo is an investigation escape: the row is not publishable. A disposable fixture is the only source of a comparable line.',\n );\n }\n\n let tasks: TaskClass[];\n try {\n tasks = parseTasks(options.task);\n } catch (error) {\n printError(error instanceof Error ? error.message : String(error));\n return 1;\n }\n const arms = options.arm !== undefined && options.arm.length > 0 ? options.arm : ['baseline'];\n const repeats = options.repeats ?? 5;\n const usd = estimateCampaignUsd(tasks, arms.length, repeats);\n\n try {\n await confirmRealCampaign(\n {\n cells: tasks.length * arms.length,\n repeats,\n usd,\n ...(options.maxCost === undefined ? {} : { maxCost: options.maxCost }),\n ...(options.maxDuration === undefined ? {} : { maxDuration: options.maxDuration }),\n },\n options,\n );\n } catch (error) {\n if (error instanceof BenchConfirmationError) {\n printError(error.message);\n return error.exitCode;\n }\n throw error;\n }\n\n const harnessVersion = options.harnessVersion ?? (await collectHarnessVersion('claude'));\n const runner =\n options.runner ??\n createLiveRepeatRunner({\n runPipeline:\n options.runPipeline ??\n (async (issue) => {\n const { runPipeline } = await import('./run.js');\n return runPipeline(issue, 'auto', undefined, true, false, { yes: true, only: true });\n }),\n });\n\n const campaign: BenchCampaign = await runRealCorpus({\n tasks,\n arms,\n repeats,\n tupleBase: {\n harness: 'claude',\n harnessVersion,\n model: 'default',\n modelVersion: null,\n effort: 'default',\n verification: 'none',\n strategy: 'pipeline',\n settingSourcesPinned: true,\n fallbackModelPassed: false,\n },\n ...(options.maxCost === undefined ? {} : { maxCostUsd: options.maxCost }),\n ...(options.maxDuration === undefined ? {} : { maxDurationMs: options.maxDuration }),\n runner,\n });\n\n if (campaign.stop.reason !== 'completed') {\n printWarning(\n `Campaign stopped on ${campaign.stop.reason} (spent ${campaign.stop.spent}, ceiling ${campaign.stop.ceiling}). Report is partial.`,\n );\n }\n\n const markdown = renderCampaignMarkdown(campaign, arms.join('-vs-'));\n if (options.out) {\n await mkdir(dirname(options.out), { recursive: true });\n await writeFile(options.out, markdown, 'utf-8');\n printInfo(`Wrote ${options.out}`);\n } else {\n (options.stdout ?? process.stdout).write(markdown);\n }\n if (options.json === true) {\n (options.stdout ?? process.stdout).write(`${JSON.stringify(campaign, null, 2)}\\n`);\n }\n return campaign.stop.reason === 'completed' ? 0 : 2;\n}\n","export const TASK_CLASSES = ['trivial', 'small', 'medium', 'analysis'] as const;\n\nexport type TaskClass = (typeof TASK_CLASSES)[number];\n\nexport interface CorpusTask {\n id: TaskClass;\n title: string;\n /** What a fixture repository should contain. */\n fixture: string;\n verification: 'none' | 'existing-tests' | 'tests-and-docs' | 'artifact-only';\n strategy: 'direct' | 'pipeline';\n}\n\n/**\n * Four representative tasks. The synthetic runner never opens a real repo;\n * `real` mode materializes a disposable git fixture per repetition via\n * `fixtures/materialize.ts`. `--repo` is an investigation escape and does\n * not produce a publishable row.\n */\nexport const CORPUS: readonly CorpusTask[] = [\n {\n id: 'trivial',\n title: 'Change one constant and its comment',\n fixture: '1–2 files, no test change',\n verification: 'none',\n strategy: 'direct',\n },\n {\n id: 'small',\n title: 'Fix a failing assertion in an existing test',\n fixture: 'correction against tests that already exist',\n verification: 'existing-tests',\n strategy: 'pipeline',\n },\n {\n id: 'medium',\n title: 'Add a function, tests and a README note',\n fixture: 'implementation plus tests plus documentation',\n verification: 'tests-and-docs',\n strategy: 'pipeline',\n },\n {\n id: 'analysis',\n title: 'Read the tree and write a short report',\n fixture: 'read-only artifact, no implementation',\n verification: 'artifact-only',\n strategy: 'direct',\n },\n];\n\nexport const BENCH_AXES = [\n 'task',\n 'harness',\n 'model',\n 'effort',\n 'verification',\n 'strategy',\n] as const;\n","import { setIssuesCliOverrides } from '../config.js';\nimport { loadTaskPlan } from '../core/state-manager.js';\nimport { GLOBAL_ROOT_ENV } from '../storage/paths.js';\nimport { resetStorageResolutionCache, resolveIssuePaths } from '../storage/resolve.js';\nimport { runAcceptance } from '../verify/run-issue.js';\nimport type { RepeatOutcome, RepeatRunner, RepeatRunnerInput } from './real.js';\n\n/**\n * Live repeats spend money. Unit tests must never take this path.\n * The only escape is an explicit `ISSUE_FLOW_E2E_BENCH=1`, matching the\n * `#80` Antigravity e2e gate.\n */\nexport function assertLiveBenchAllowed(env: NodeJS.ProcessEnv = process.env): void {\n if (env.VITEST && env.ISSUE_FLOW_E2E_BENCH !== '1') {\n throw new Error(\n 'issue-flow bench --mode real does not run under npm test. Set ISSUE_FLOW_E2E_BENCH=1 for a deliberate live campaign.',\n );\n }\n}\n\nexport interface LiveRepeatDeps {\n runPipeline: (issue: string) => Promise<number>;\n}\n\n/**\n * Isolate one repetition: own ISSUE_FLOW_HOME, local issues, no GitHub,\n * `--setting-sources` pinned, `--fallback-model` never passed.\n */\nexport function createLiveRepeatRunner(deps: LiveRepeatDeps): RepeatRunner {\n return async (input: RepeatRunnerInput): Promise<RepeatOutcome> => {\n assertLiveBenchAllowed();\n const previousHome = process.env[GLOBAL_ROOT_ENV];\n const previousCwd = process.cwd();\n process.env[GLOBAL_ROOT_ENV] = input.campaignHome;\n resetStorageResolutionCache();\n setIssuesCliOverrides({ preferredProvider: 'local' });\n process.chdir(input.fixture.root);\n const started = performance.now();\n try {\n await deps.runPipeline(input.fixture.issueRef);\n const paths = await resolveIssuePaths(input.fixture.issueRef, {\n projectRoot: input.fixture.root,\n });\n const plan = await loadTaskPlan(paths.tasksFile);\n const records = plan.executions ?? [];\n const acceptance = await runAcceptance({\n cwd: input.fixture.root,\n issueDir: paths.issueDir,\n declared: input.fixture.expectedVerification,\n executionId: records.at(-1)?.id ?? null,\n skipReviewer: input.arm !== 'L2',\n explicit: input.arm === 'L2',\n });\n const wall = performance.now() - started;\n const harness = records.reduce((sum, record) => sum + (record.durationMs ?? 0), 0);\n const reported = records.flatMap((record) =>\n record.cost.status === 'reported' ? [record.cost.amount] : [],\n );\n const cost =\n reported.length > 0\n ? {\n status: 'reported' as const,\n amount: reported.reduce((sum, amount) => sum + amount, 0),\n currency: 'USD' as const,\n }\n : ({ status: 'unknown' as const, reason: 'not_reported' as const } as const);\n return {\n records,\n verdict: acceptance.verdict,\n taskDurationMs: wall,\n harnessExecutionMs: harness,\n orchestrationOverheadMs: Math.max(0, wall - harness),\n attemptCount: records.reduce((max, record) => Math.max(max, record.attempt), 0) || 1,\n cost,\n };\n } finally {\n process.chdir(previousCwd);\n if (previousHome === undefined) delete process.env[GLOBAL_ROOT_ENV];\n else process.env[GLOBAL_ROOT_ENV] = previousHome;\n resetStorageResolutionCache();\n setIssuesCliOverrides({});\n }\n };\n}\n","import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { evaluateCeilings, spendFromCost } from '../routing/budget.js';\nimport { getGlobalRoot } from '../storage/paths.js';\nimport type { CostRecord, ExecutionRecord } from '../telemetry/types.js';\nimport type { VerdictStatus } from '../verify/types.js';\nimport { CORPUS, type TaskClass } from './corpus.js';\nimport { corpusTask, type FixtureHandle, materialize } from './fixtures/index.js';\nimport { p50, p95 } from './stats.js';\nimport {\n assertComparable,\n type ComparabilityTuple,\n isRowInvalid,\n type TupleField,\n tupleAxisForArm,\n} from './tuple.js';\n\nexport interface BenchRepeat {\n seed: number;\n taskDurationMs: number;\n harnessExecutionMs: number;\n orchestrationOverheadMs: number;\n timeToAcceptedResultMs: number | null;\n verdict: VerdictStatus;\n cost: CostRecord;\n attemptCount: number;\n executionIds: string[];\n invalid: boolean;\n}\n\nexport interface BenchCell {\n task: TaskClass;\n tuple: ComparabilityTuple;\n arm: string;\n repeats: BenchRepeat[];\n}\n\nexport interface PercentilePair {\n p50: number;\n p95: number;\n n: number;\n}\n\nexport interface CellSummary {\n n: number;\n taskDurationMs: PercentilePair;\n harnessExecutionMs: PercentilePair;\n orchestrationOverheadMs: PercentilePair;\n timeToAcceptedResultMs: { p50: number | null; p95: number | null; n: number };\n cost: {\n reportedP50: number | null;\n reportedP95: number | null;\n unknownRepeats: number;\n estimatedRepeats: number;\n };\n verdicts: Record<VerdictStatus, number>;\n}\n\nexport type CampaignStop =\n | { reason: 'completed' }\n | { reason: 'max_cost' | 'max_duration'; spent: number; ceiling: number; partial: true };\n\nexport interface BenchCampaign {\n id: string;\n home: string;\n cells: BenchCell[];\n stop: CampaignStop;\n}\n\nexport interface RepeatOutcome {\n records: ExecutionRecord[];\n verdict: VerdictStatus;\n taskDurationMs: number;\n harnessExecutionMs: number;\n orchestrationOverheadMs: number;\n attemptCount: number;\n cost: CostRecord;\n}\n\nexport interface RepeatRunnerInput {\n fixture: FixtureHandle;\n arm: string;\n tuple: ComparabilityTuple;\n campaignHome: string;\n}\n\nexport type RepeatRunner = (input: RepeatRunnerInput) => Promise<RepeatOutcome>;\n\nexport interface RealCorpusOptions {\n tasks?: TaskClass[];\n arms: string[];\n repeats: number;\n tupleBase: Omit<ComparabilityTuple, 'task' | 'strictMcpConfig' | 'fallbackModelPassed'> & {\n strictMcpConfig?: boolean;\n fallbackModelPassed?: boolean;\n };\n maxCostUsd?: number;\n maxDurationMs?: number;\n campaignId?: string;\n runner: RepeatRunner;\n now?: () => number;\n env?: NodeJS.ProcessEnv;\n}\n\nexport function campaignHome(campaignId: string, env?: NodeJS.ProcessEnv): string {\n return join(getGlobalRoot({ env }), 'bench', campaignId);\n}\n\nfunction combineCost(records: readonly ExecutionRecord[]): CostRecord {\n let reported = 0;\n let estimated = 0;\n let unknown = 0;\n for (const record of records) {\n if (record.cost.status === 'reported') reported += record.cost.amount;\n else if (record.cost.status === 'estimated') estimated += record.cost.amount;\n else unknown += 1;\n }\n if (reported > 0) return { status: 'reported', amount: reported, currency: 'USD' };\n if (estimated > 0) {\n return {\n status: 'estimated',\n amount: estimated,\n currency: 'USD',\n pricing: {\n tableVersion: 'bench',\n modelKey: 'aggregated',\n inputPerMillion: 0,\n outputPerMillion: 0,\n capturedAt: new Date(0).toISOString(),\n },\n };\n }\n return { status: 'unknown', reason: unknown > 0 ? 'not_reported' : 'not_reported' };\n}\n\nexport function summarizeCell(cell: BenchCell): CellSummary {\n const durations = cell.repeats.map((repeat) => repeat.taskDurationMs);\n const harness = cell.repeats.map((repeat) => repeat.harnessExecutionMs);\n const overhead = cell.repeats.map((repeat) => repeat.orchestrationOverheadMs);\n const accepted = cell.repeats\n .map((repeat) => repeat.timeToAcceptedResultMs)\n .filter((value): value is number => value !== null);\n const reported = cell.repeats\n .map((repeat) => (repeat.cost.status === 'reported' ? repeat.cost.amount : null))\n .filter((value): value is number => value !== null);\n const verdicts: Record<VerdictStatus, number> = { passed: 0, failed: 0, unverified: 0 };\n let unknownRepeats = 0;\n let estimatedRepeats = 0;\n for (const repeat of cell.repeats) {\n verdicts[repeat.verdict] += 1;\n if (repeat.cost.status === 'unknown') unknownRepeats += 1;\n if (repeat.cost.status === 'estimated') estimatedRepeats += 1;\n }\n return {\n n: cell.repeats.length,\n taskDurationMs: { p50: p50(durations), p95: p95(durations), n: durations.length },\n harnessExecutionMs: { p50: p50(harness), p95: p95(harness), n: harness.length },\n orchestrationOverheadMs: { p50: p50(overhead), p95: p95(overhead), n: overhead.length },\n timeToAcceptedResultMs: {\n p50: accepted.length === 0 ? null : p50(accepted),\n p95: accepted.length === 0 ? null : p95(accepted),\n n: accepted.length,\n },\n cost: {\n reportedP50: reported.length === 0 ? null : p50(reported),\n reportedP95: reported.length === 0 ? null : p95(reported),\n unknownRepeats,\n estimatedRepeats,\n },\n verdicts,\n };\n}\n\nfunction tupleForArm(\n task: TaskClass,\n arm: string,\n base: RealCorpusOptions['tupleBase'],\n): ComparabilityTuple {\n return {\n task,\n harness: base.harness,\n harnessVersion: base.harnessVersion,\n model: base.model,\n modelVersion: base.modelVersion,\n effort: base.effort,\n verification: base.verification,\n strategy: base.strategy,\n settingSourcesPinned: base.settingSourcesPinned,\n strictMcpConfig: arm === 'strict-mcp' ? true : (base.strictMcpConfig ?? false),\n fallbackModelPassed: base.fallbackModelPassed ?? false,\n };\n}\n\nfunction declaredIgnore(arms: readonly string[]): TupleField[] {\n const fields = new Set<TupleField>();\n for (const arm of arms) {\n const axis = tupleAxisForArm(arm);\n if (axis) fields.add(axis);\n }\n return [...fields];\n}\n\n/**\n * Run the real corpus. Arms are a parameter: new experiments do not add\n * runner code. Repeats of different arms are interleaved, not blocked.\n */\nexport async function runRealCorpus(options: RealCorpusOptions): Promise<BenchCampaign> {\n const tasks = options.tasks ?? CORPUS.map((entry) => entry.id);\n const campaignId = options.campaignId ?? `campaign-${Date.now()}`;\n const home = campaignHome(campaignId, options.env);\n await mkdir(home, { recursive: true });\n\n const cells = new Map<string, BenchCell>();\n const ignore = declaredIgnore(options.arms);\n const now = options.now ?? Date.now;\n const started = now();\n let reportedUsd = 0;\n let knownCost: CostRecord['status'] = 'unknown';\n let stop: CampaignStop = { reason: 'completed' };\n\n const schedule: Array<{ task: TaskClass; arm: string; seed: number }> = [];\n for (let seed = 0; seed < options.repeats; seed += 1) {\n for (const arm of options.arms) {\n for (const task of tasks) {\n schedule.push({ task, arm, seed });\n }\n }\n }\n\n for (const step of schedule) {\n const task = corpusTask(step.task);\n const tuple = tupleForArm(step.task, step.arm, {\n ...options.tupleBase,\n verification: task.verification,\n strategy: task.strategy,\n });\n const key = `${step.task}:${step.arm}`;\n const existing = cells.get(key);\n if (existing) {\n assertComparable(existing.tuple, tuple, { ignore });\n } else {\n for (const cell of cells.values()) {\n if (cell.task !== step.task) continue;\n assertComparable(cell.tuple, tuple, { ignore });\n }\n cells.set(key, { task: step.task, tuple, arm: step.arm, repeats: [] });\n }\n\n const fixture = await materialize(task, step.seed);\n try {\n const outcome = await options.runner({\n fixture,\n arm: step.arm,\n tuple,\n campaignHome: home,\n });\n const cost = outcome.cost.status !== undefined ? outcome.cost : combineCost(outcome.records);\n const spent = spendFromCost(cost);\n if (spent.costStatus === 'reported') {\n reportedUsd += spent.reportedUsd;\n knownCost = 'reported';\n }\n const cell = cells.get(key);\n if (!cell) throw new Error(`missing cell ${key}`);\n cell.repeats.push({\n seed: step.seed,\n taskDurationMs: outcome.taskDurationMs,\n harnessExecutionMs: outcome.harnessExecutionMs,\n orchestrationOverheadMs: outcome.orchestrationOverheadMs,\n timeToAcceptedResultMs: outcome.verdict === 'passed' ? outcome.taskDurationMs : null,\n verdict: outcome.verdict,\n cost,\n attemptCount: outcome.attemptCount,\n executionIds: outcome.records.map((record) => record.id),\n invalid: isRowInvalid(tuple),\n });\n } finally {\n await fixture.dispose();\n }\n\n const ceiling = evaluateCeilings({\n ceilings: {\n maxCostUsdPerIssue: options.maxCostUsd ?? null,\n maxDurationMsPerIssue: options.maxDurationMs ?? null,\n maxExecutionsPerIssue: null,\n onCeiling: 'block',\n },\n spent: {\n reportedUsd,\n costStatus: knownCost,\n durationMs: now() - started,\n executions: [...cells.values()].reduce((sum, cell) => sum + cell.repeats.length, 0),\n },\n });\n if (!ceiling.ok) {\n stop = {\n reason: ceiling.stopReason === 'max_attempts' ? 'max_duration' : ceiling.stopReason,\n spent: ceiling.numbers.spent,\n ceiling: ceiling.numbers.ceiling,\n partial: true,\n };\n break;\n }\n }\n\n return { id: campaignId, home, cells: [...cells.values()], stop };\n}\n","import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { ISSUES_DIR_NAME } from '../../storage/paths.js';\nimport { run } from '../../utils/shell.js';\nimport type { AcceptanceCheck } from '../../verify/types.js';\nimport type { CorpusTask } from '../corpus.js';\nimport { CORPUS } from '../corpus.js';\nimport { templateFor } from './templates.js';\n\nexport interface FixtureHandle {\n root: string;\n issueRef: string;\n expectedVerification: AcceptanceCheck[];\n seed: number;\n task: CorpusTask['id'];\n dispose(): Promise<void>;\n}\n\nconst GIT_IDENT = ['-c', 'user.name=issue-flow-bench', '-c', 'user.email=bench@issue-flow.test'];\n\nasync function git(cwd: string, args: string[]): Promise<void> {\n const result = await run('git', args, { cwd });\n if (result.exitCode !== 0) {\n throw new Error(\n `git ${args.join(' ')} failed (${result.exitCode}): ${result.stderr || result.stdout}`,\n );\n }\n}\n\nasync function writeTree(root: string, files: Record<string, string>): Promise<void> {\n for (const [relative, content] of Object.entries(files)) {\n const path = join(root, relative);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n }\n}\n\nasync function writeLocalIssue(root: string, title: string, body: string): Promise<void> {\n const issueDir = join(root, ISSUES_DIR_NAME, '1');\n await mkdir(issueDir, { recursive: true });\n await writeFile(join(issueDir, 'issue.md'), `# ${title}\\n\\n${body.trim()}\\n`, 'utf-8');\n await writeFile(\n join(issueDir, 'metadata.json'),\n `${JSON.stringify(\n {\n schemaVersion: 1,\n id: '1',\n number: 1,\n source: 'local',\n title,\n labels: ['bench'],\n state: 'open',\n createdAt: '2026-08-30T00:00:00.000Z',\n updatedAt: '2026-08-30T00:00:00.000Z',\n contentHash: 'sha256:fixture',\n },\n null,\n 2,\n )}\\n`,\n 'utf-8',\n );\n}\n\n/**\n * Materialize a disposable git repository for one corpus class and one seed.\n * A new call always starts from the same unfinished state — never from the\n * work of a previous repetition.\n */\nexport async function materialize(task: CorpusTask, seed: number): Promise<FixtureHandle> {\n const root = await mkdtemp(join(tmpdir(), `issue-flow-bench-${task.id}-${seed}-`));\n const template = templateFor(task.id, seed);\n await writeTree(root, template.files);\n await writeLocalIssue(root, template.issueTitle, template.issueBody);\n\n // An empty template skips sample hooks. Some sandboxes forbid writing\n // executable files under `.git/hooks/`.\n await git(root, ['-c', 'init.templateDir=', 'init']);\n await git(root, ['add', '.']);\n await git(root, [...GIT_IDENT, 'commit', '-m', `fixture ${task.id} seed=${seed}`]);\n\n return {\n root,\n issueRef: '1',\n expectedVerification: template.expectedVerification,\n seed,\n task: task.id,\n async dispose() {\n await rm(root, { recursive: true, force: true });\n },\n };\n}\n\nexport function corpusTask(id: CorpusTask['id']): CorpusTask {\n const task = CORPUS.find((entry) => entry.id === id);\n if (!task) throw new Error(`Unknown corpus class: ${id}`);\n return task;\n}\n","import type { AcceptanceCheck } from '../../verify/types.js';\nimport type { TaskClass } from '../corpus.js';\n\nexport interface FixtureTemplate {\n files: Record<string, string>;\n issueTitle: string;\n issueBody: string;\n expectedVerification: AcceptanceCheck[];\n}\n\nfunction withSeed(content: string, seed: number): string {\n return `${content}\\n// fixture-seed:${seed}\\n`;\n}\n\nexport function templateFor(task: TaskClass, seed: number): FixtureTemplate {\n switch (task) {\n case 'trivial':\n return {\n files: {\n 'src/answer.js': withSeed(\n [\n '/** The answer to life, the universe and everything. */',\n 'export const ANSWER = 41;',\n ].join('\\n'),\n seed,\n ),\n },\n issueTitle: 'Change one constant and its comment',\n issueBody: [\n 'Change `ANSWER` in `src/answer.js` from 41 to 42.',\n 'Update the comment so it no longer claims the wrong value.',\n 'Do not add tests.',\n ].join('\\n'),\n expectedVerification: [],\n };\n case 'small':\n return {\n files: {\n 'src/sum.js': withSeed('export function sum(a, b) {\\n return a - b;\\n}\\n', seed),\n 'src/sum.test.js': [\n \"import { sum } from './sum.js';\",\n \"import assert from 'node:assert/strict';\",\n 'assert.equal(sum(2, 2), 4);',\n '',\n ].join('\\n'),\n 'package.json': `${JSON.stringify({ name: 'bench-small', type: 'module', scripts: { test: 'node src/sum.test.js' } }, null, 2)}\\n`,\n },\n issueTitle: 'Fix a failing assertion in an existing test',\n issueBody: [\n '`src/sum.test.js` fails because `sum` subtracts instead of adding.',\n 'Fix `src/sum.js` so `node src/sum.test.js` exits 0.',\n 'Do not change the test.',\n ].join('\\n'),\n expectedVerification: [{ id: 'existing-tests', run: 'node src/sum.test.js', fatal: true }],\n };\n case 'medium':\n return {\n files: {\n 'src/greet.js': withSeed('// greet(name) is not implemented yet.\\n', seed),\n 'src/greet.test.js': [\n \"import { greet } from './greet.js';\",\n \"import assert from 'node:assert/strict';\",\n \"assert.equal(greet('Ada'), 'Hello, Ada');\",\n '',\n ].join('\\n'),\n 'README.md': ['# bench-medium', '', 'A tiny library.', ''].join('\\n'),\n 'package.json': `${JSON.stringify({ name: 'bench-medium', type: 'module', scripts: { test: 'node src/greet.test.js' } }, null, 2)}\\n`,\n },\n issueTitle: 'Add a function, tests and a README note',\n issueBody: [\n 'Implement `greet(name)` in `src/greet.js` so it returns Hello, <name>.',\n 'Keep `src/greet.test.js` as the contract.',\n 'Add an `## API` section to `README.md` documenting `greet`.',\n ].join('\\n'),\n expectedVerification: [\n { id: 'tests', run: 'node src/greet.test.js', fatal: true },\n { id: 'docs', expectFiles: ['README.md'], fatal: true },\n ],\n };\n case 'analysis':\n return {\n files: {\n 'src/alpha.js': withSeed('export const ALPHA = 1;\\n', seed),\n 'src/beta.js': withSeed(\n \"import { ALPHA } from './alpha.js';\\nexport const BETA = ALPHA + 1;\\n\",\n seed,\n ),\n 'src/gamma.js': withSeed(\n \"import { BETA } from './beta.js';\\nexport const GAMMA = BETA + 1;\\n\",\n seed,\n ),\n },\n issueTitle: 'Read the tree and write a short report',\n issueBody: [\n 'Read `src/` and write `report.md` describing the module graph.',\n 'Do not change the source files.',\n ].join('\\n'),\n expectedVerification: [{ id: 'artifact', expectFiles: ['report.md'], fatal: true }],\n };\n default: {\n const _exhaustive: never = task;\n throw new Error(`Unknown corpus class: ${_exhaustive}`);\n }\n }\n}\n","/** Shared percentiles. Used by both the synthetic CI guard and the real campaign. */\n\nfunction percentile(values: number[], p: number): number {\n const sorted = [...values].sort((a, b) => a - b);\n if (sorted.length === 0) return 0;\n const index = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[index] ?? 0;\n}\n\nexport function p50(values: number[]): number {\n return percentile(values, 50);\n}\n\nexport function p95(values: number[]): number {\n return percentile(values, 95);\n}\n","import { ensureHarnessVersion } from '../agents/registry.js';\nimport type { AgentProviderId } from '../agents/types.js';\nimport type { TaskClass } from './corpus.js';\n\nexport interface ComparabilityTuple {\n task: TaskClass;\n harness: string;\n harnessVersion: string;\n model: string;\n modelVersion: string | null;\n effort: string;\n verification: string;\n strategy: 'direct' | 'pipeline';\n settingSourcesPinned: boolean;\n strictMcpConfig: boolean;\n fallbackModelPassed: boolean;\n}\n\nexport type TupleField = keyof ComparabilityTuple;\n\nexport const TUPLE_FIELDS: readonly TupleField[] = [\n 'task',\n 'harness',\n 'harnessVersion',\n 'model',\n 'modelVersion',\n 'effort',\n 'verification',\n 'strategy',\n 'settingSourcesPinned',\n 'strictMcpConfig',\n 'fallbackModelPassed',\n] as const;\n\nexport class ComparabilityError extends Error {\n readonly field: TupleField;\n readonly left: unknown;\n readonly right: unknown;\n\n constructor(field: TupleField, left: unknown, right: unknown) {\n super(`ComparabilityTuple.${field} differs: ${String(left)} vs ${String(right)}`);\n this.name = 'ComparabilityError';\n this.field = field;\n this.left = left;\n this.right = right;\n }\n}\n\n/**\n * Two cells may be compared only when every field matches, except axes the\n * experiment declared (the arm). A silent mismatch is a bug.\n */\nexport function assertComparable(\n left: ComparabilityTuple,\n right: ComparabilityTuple,\n options: { ignore?: readonly TupleField[] } = {},\n): void {\n const ignored = new Set(options.ignore ?? []);\n for (const field of TUPLE_FIELDS) {\n if (ignored.has(field)) continue;\n if (left[field] !== right[field]) {\n throw new ComparabilityError(field, left[field], right[field]);\n }\n }\n}\n\n/** `--fallback-model` present means the measured model is not the one that ran. */\nexport function isRowInvalid(tuple: ComparabilityTuple): boolean {\n return tuple.fallbackModelPassed || !tuple.settingSourcesPinned;\n}\n\n/** Collect at campaign time. Never assume a version from a document. */\nexport async function collectHarnessVersion(provider: AgentProviderId): Promise<string> {\n const version = await ensureHarnessVersion(provider);\n return version ?? 'unknown';\n}\n\nexport function tupleAxisForArm(arm: string): TupleField | null {\n if (arm === 'strict-mcp') return 'strictMcpConfig';\n return null;\n}\n","import { hostname } from 'node:os';\nimport { getGlobalRoot } from '../storage/paths.js';\nimport { redactSecrets } from '../telemetry/redact.js';\nimport type { BenchCampaign, CellSummary } from './real.js';\nimport { summarizeCell } from './real.js';\nimport type { ComparabilityTuple } from './tuple.js';\n\nfunction formatMs(value: number | null): string {\n return value === null ? '—' : `${Math.round(value)}`;\n}\n\nfunction formatUsd(value: number | null): string {\n return value === null ? '—' : `$${value.toFixed(2)}`;\n}\n\nfunction tupleLine(tuple: ComparabilityTuple): string {\n return [\n tuple.task,\n tuple.harness,\n tuple.harnessVersion,\n tuple.model,\n tuple.modelVersion ?? '—',\n tuple.effort,\n tuple.verification,\n tuple.strategy,\n tuple.settingSourcesPinned ? 'setting-sources:pinned' : 'setting-sources:unpinned',\n tuple.strictMcpConfig ? 'strict-mcp' : 'mcp:default',\n tuple.fallbackModelPassed ? 'INVALID:fallback-model' : 'fallback:none',\n ].join(' × ');\n}\n\nfunction verdictCounts(summary: CellSummary): string {\n return `passed=${summary.verdicts.passed} failed=${summary.verdicts.failed} unverified=${summary.verdicts.unverified}`;\n}\n\nfunction scrubPaths(text: string): string {\n const home = getGlobalRoot();\n return text.split(home).join('<issue-flow-home>');\n}\n\nexport function renderCampaignMarkdown(campaign: BenchCampaign, subject: string): string {\n const lines: string[] = [\n `# Harness campaign — ${subject}`,\n '',\n `> **Research document.** Campaign \\`${campaign.id}\\`.`,\n `> Machine: \\`${hostname()}\\`. Node ${process.version}.`,\n campaign.stop.reason === 'completed'\n ? '> Status: complete.'\n : `> Status: **partial** — stopped on \\`${campaign.stop.reason}\\` (spent ${campaign.stop.spent}, ceiling ${campaign.stop.ceiling}). Results below are the repeats that finished; they are not a silently truncated table.`,\n '',\n '`time-to-accepted-result` is null when the verdict is not `passed`. Cost `unknown` is never summed as zero.',\n '',\n '## Cells',\n '',\n '| Task | Arm | n | duration p50/p95 (ms) | harness p50/p95 | overhead p50/p95 | accepted p50/p95 | cost p50/p95 | verdicts | invalid |',\n '|---|---|---:|---|---|---|---|---|---|---|',\n ];\n\n for (const cell of campaign.cells) {\n const summary = summarizeCell(cell);\n const invalid = cell.repeats.some((repeat) => repeat.invalid);\n lines.push(\n `| ${cell.task} | ${cell.arm} | ${summary.n} | ${formatMs(summary.taskDurationMs.p50)} / ${formatMs(summary.taskDurationMs.p95)} | ${formatMs(summary.harnessExecutionMs.p50)} / ${formatMs(summary.harnessExecutionMs.p95)} | ${formatMs(summary.orchestrationOverheadMs.p50)} / ${formatMs(summary.orchestrationOverheadMs.p95)} | ${formatMs(summary.timeToAcceptedResultMs.p50)} / ${formatMs(summary.timeToAcceptedResultMs.p95)} | ${formatUsd(summary.cost.reportedP50)} / ${formatUsd(summary.cost.reportedP95)} | ${verdictCounts(summary)} | ${invalid ? 'yes' : 'no'} |`,\n );\n }\n\n lines.push('', '## Comparability tuples', '');\n for (const cell of campaign.cells) {\n lines.push(`- **${cell.task} / ${cell.arm}**: \\`${tupleLine(cell.tuple)}\\``);\n }\n lines.push('');\n return redactSecrets(scrubPaths(lines.join('\\n')));\n}\n","import {\n createInitialSnapshot,\n reduceSessionEvent,\n type SessionEvent,\n} from '../core/session-state.js';\nimport { sessionSnapshotSchema } from '../schemas.js';\nimport { summarizePhaseTiming } from '../telemetry/timing.js';\nimport type { ExecutionRecord } from '../telemetry/types.js';\nimport { CORPUS } from './corpus.js';\nimport { p50, p95 } from './stats.js';\n\nexport { p50, p95 };\n\n/** Derived from the #79 investigation: orchestration must stay a rounding error. */\nexport const SYNTHETIC_BUDGETS = {\n /** p95 of reducing a short scripted run, in milliseconds. */\n reduceP95Ms: 50,\n /** p95 of parsing a snapshot through the lockstep schema. */\n parseP95Ms: 20,\n} as const;\n\nexport interface SyntheticResult {\n task: string;\n mode: 'synthetic';\n harness: 'mocked';\n model: 'none';\n effort: 'none';\n verification: string;\n strategy: string;\n taskDurationMs: number;\n harnessExecutionDurationMs: number;\n orchestrationOverheadMs: number;\n timeToFirstOutputMs: number | null;\n attemptCount: number;\n retryDurationMs: number;\n verdict: 'unverified';\n}\n\nfunction scriptedEvents(): SessionEvent[] {\n return [\n {\n type: 'session:start',\n at: '2026-08-30T03:00:00.000Z',\n sessionId: 'bench',\n issueNumber: 79,\n phases: ['prd', 'execute'],\n },\n { type: 'phase:start', at: '2026-08-30T03:00:01.000Z', phase: 'prd' },\n {\n type: 'phase:end',\n at: '2026-08-30T03:00:02.000Z',\n phase: 'prd',\n success: true,\n harnessExecutionMs: 800,\n orchestrationOverheadMs: 200,\n },\n { type: 'phase:start', at: '2026-08-30T03:00:02.000Z', phase: 'execute' },\n {\n type: 'phase:end',\n at: '2026-08-30T03:00:03.000Z',\n phase: 'execute',\n success: true,\n harnessExecutionMs: 900,\n orchestrationOverheadMs: 100,\n attemptCount: 1,\n },\n { type: 'session:end', at: '2026-08-30T03:00:03.000Z', status: 'completed' },\n ];\n}\n\nexport function reduceScriptedRun(): ReturnType<typeof reduceSessionEvent> {\n let snap = createInitialSnapshot();\n for (const event of scriptedEvents()) {\n snap = reduceSessionEvent(snap, event);\n }\n return snap;\n}\n\nexport function timeReduce(repeats = 20): number[] {\n const samples: number[] = [];\n for (let i = 0; i < repeats; i += 1) {\n const start = performance.now();\n reduceScriptedRun();\n samples.push(performance.now() - start);\n }\n return samples;\n}\n\nexport function timeParse(repeats = 20): number[] {\n const snap = reduceScriptedRun();\n const samples: number[] = [];\n for (let i = 0; i < repeats; i += 1) {\n const start = performance.now();\n sessionSnapshotSchema.parse(snap);\n samples.push(performance.now() - start);\n }\n return samples;\n}\n\nfunction mockedRecord(durationMs: number): ExecutionRecord {\n return {\n id: 'synthetic',\n sessionId: 'bench',\n purpose: 'execute',\n attempt: 1,\n trigger: 'initial',\n triggerReason: null,\n agent: {\n harness: 'mocked',\n provider: null,\n model: { requested: null, resolved: null, source: 'unavailable' },\n providerSessionId: null,\n },\n startedAt: '2026-08-30T03:00:00.000Z',\n finishedAt: '2026-08-30T03:00:01.000Z',\n durationMs,\n cliDurationMs: Math.max(0, durationMs - 5),\n harnessStartupMs: 5,\n ttftMs: null,\n usage: { source: 'unavailable' },\n cost: { status: 'unknown', reason: 'not_reported' },\n status: 'completed',\n failure: null,\n };\n}\n\n/** Orchestration-only measurement: the harness is a number, not a process. */\nexport function runSyntheticCorpus(): SyntheticResult[] {\n return CORPUS.map((task) => {\n const harnessMs = 1000;\n const orchestrateStart = performance.now();\n const snap = reduceScriptedRun();\n sessionSnapshotSchema.parse(snap);\n const orchestrationMs = performance.now() - orchestrateStart;\n const timing = summarizePhaseTiming(\n [mockedRecord(harnessMs)],\n 'execute',\n harnessMs + orchestrationMs,\n );\n return {\n task: task.id,\n mode: 'synthetic',\n harness: 'mocked',\n model: 'none',\n effort: 'none',\n verification: task.verification,\n strategy: task.strategy,\n taskDurationMs: harnessMs + orchestrationMs,\n harnessExecutionDurationMs: timing.harnessExecutionMs ?? harnessMs,\n orchestrationOverheadMs: timing.orchestrationOverheadMs ?? orchestrationMs,\n timeToFirstOutputMs: timing.ttftMs,\n attemptCount: timing.attemptCount ?? 1,\n retryDurationMs: timing.retryDurationMs ?? 0, // no retries in the mocked record\n verdict: 'unverified',\n };\n });\n}\n"],"mappings":"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","names":["mkdir","writeFile","dirname","mkdir","join","join","mkdir","mkdir","dirname","writeFile"]}
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ EXECUTION_PURPOSES,
4
+ getTelemetryContext
5
+ } from "./chunk-6FDFRNXZ.js";
6
+ import {
7
+ loadTaskPlan
8
+ } from "./chunk-DIG5XKQQ.js";
9
+
10
+ // src/telemetry/timing.ts
11
+ var EMPTY_TIMING = {
12
+ harnessExecutionMs: null,
13
+ orchestrationOverheadMs: null,
14
+ harnessStartupMs: null,
15
+ ttftMs: null,
16
+ attemptCount: null,
17
+ retryDurationMs: null,
18
+ cliDurationMs: null,
19
+ apiDurationMs: null,
20
+ numTurns: null,
21
+ outputTokens: null,
22
+ iteration: null
23
+ };
24
+ function isPurpose(phase) {
25
+ return EXECUTION_PURPOSES.includes(phase);
26
+ }
27
+ function sum(values) {
28
+ const known = values.filter((value) => typeof value === "number");
29
+ return known.length === 0 ? null : known.reduce((acc, value) => acc + value, 0);
30
+ }
31
+ function firstKnown(values) {
32
+ for (const value of values) {
33
+ if (typeof value === "number") return value;
34
+ }
35
+ return null;
36
+ }
37
+ function summarizePhaseTiming(records, phase, phaseWallMs) {
38
+ if (!isPurpose(phase)) return { ...EMPTY_TIMING };
39
+ const matched = records.filter((record) => record.purpose === phase);
40
+ if (matched.length === 0) return { ...EMPTY_TIMING };
41
+ const harnessExecutionMs = sum(
42
+ matched.map((record) => {
43
+ if (record.durationMs !== null && record.durationMs !== void 0) return record.durationMs;
44
+ const cli = record.cliDurationMs;
45
+ const startup = record.harnessStartupMs;
46
+ if (cli == null && startup == null) return null;
47
+ return (cli ?? 0) + (startup ?? 0);
48
+ })
49
+ );
50
+ const orchestrationOverheadMs = phaseWallMs !== null && phaseWallMs !== void 0 && harnessExecutionMs !== null ? Math.max(0, phaseWallMs - harnessExecutionMs) : null;
51
+ const retryDurationMs = sum(
52
+ matched.filter(
53
+ (record) => record.trigger === "retry" || record.trigger === "fallback" || record.attempt > 1
54
+ ).map((record) => record.durationMs)
55
+ );
56
+ return {
57
+ harnessExecutionMs,
58
+ orchestrationOverheadMs,
59
+ harnessStartupMs: sum(matched.map((record) => record.harnessStartupMs)),
60
+ ttftMs: firstKnown(matched.map((record) => record.ttftMs)),
61
+ attemptCount: matched.length,
62
+ retryDurationMs,
63
+ cliDurationMs: sum(matched.map((record) => record.cliDurationMs)),
64
+ apiDurationMs: sum(matched.map((record) => record.apiDurationMs)),
65
+ numTurns: sum(matched.map((record) => record.numTurns)),
66
+ outputTokens: sum(matched.map((record) => record.usage?.outputTokens)),
67
+ iteration: firstKnown(matched.map((record) => record.iteration))
68
+ };
69
+ }
70
+ async function loadPhaseTiming(phase, phaseWallMs) {
71
+ const ctx = getTelemetryContext();
72
+ if (ctx === null) return { ...EMPTY_TIMING };
73
+ try {
74
+ const plan = await loadTaskPlan(ctx.tasksPath);
75
+ return summarizePhaseTiming(plan.executions ?? [], phase, phaseWallMs);
76
+ } catch {
77
+ return { ...EMPTY_TIMING };
78
+ }
79
+ }
80
+ function formatSeconds(ms) {
81
+ if (ms === null) return "-";
82
+ const seconds = ms / 1e3;
83
+ if (seconds >= 10) return `${Math.round(seconds)}s`;
84
+ if (seconds >= 1) return `${seconds.toFixed(1)}s`;
85
+ return `${Math.round(ms)}ms`;
86
+ }
87
+ function formatPhaseLine(input) {
88
+ const iter = input.iteration == null ? "-" : String(input.iteration);
89
+ const turns = input.numTurns == null ? "-" : String(input.numTurns);
90
+ const out = input.outputTokens == null ? "-" : String(input.outputTokens);
91
+ return [
92
+ `task=${input.issueNumber}`,
93
+ `phase=${input.phase}`,
94
+ `iter=${iter}`,
95
+ `wall=${formatSeconds(input.wallMs)}`,
96
+ `cli=${formatSeconds(input.cliDurationMs)}`,
97
+ `startup=${formatSeconds(input.harnessStartupMs)}`,
98
+ `ttft=${formatSeconds(input.ttftMs)}`,
99
+ `turns=${turns}`,
100
+ `out=${out}`
101
+ ].join(" ");
102
+ }
103
+ function snapshotTimingFields(timing) {
104
+ return {
105
+ harnessExecutionMs: timing.harnessExecutionMs,
106
+ orchestrationOverheadMs: timing.orchestrationOverheadMs,
107
+ harnessStartupMs: timing.harnessStartupMs,
108
+ ttftMs: timing.ttftMs,
109
+ attemptCount: timing.attemptCount,
110
+ retryDurationMs: timing.retryDurationMs
111
+ };
112
+ }
113
+
114
+ export {
115
+ summarizePhaseTiming,
116
+ loadPhaseTiming,
117
+ formatPhaseLine,
118
+ snapshotTimingFields
119
+ };
120
+ //# sourceMappingURL=chunk-37N2RJW2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/telemetry/timing.ts"],"sourcesContent":["import { loadTaskPlan } from '../core/state-manager.js';\nimport { getTelemetryContext } from './recorder.js';\nimport { EXECUTION_PURPOSES, type ExecutionPurpose, type ExecutionRecord } from './types.js';\n\nexport interface PhaseTiming {\n harnessExecutionMs: number | null;\n orchestrationOverheadMs: number | null;\n harnessStartupMs: number | null;\n ttftMs: number | null;\n attemptCount: number | null;\n retryDurationMs: number | null;\n cliDurationMs: number | null;\n apiDurationMs: number | null;\n numTurns: number | null;\n outputTokens: number | null;\n iteration: number | null;\n}\n\nconst EMPTY_TIMING: PhaseTiming = {\n harnessExecutionMs: null,\n orchestrationOverheadMs: null,\n harnessStartupMs: null,\n ttftMs: null,\n attemptCount: null,\n retryDurationMs: null,\n cliDurationMs: null,\n apiDurationMs: null,\n numTurns: null,\n outputTokens: null,\n iteration: null,\n};\n\nfunction isPurpose(phase: string): phase is ExecutionPurpose {\n return (EXECUTION_PURPOSES as readonly string[]).includes(phase);\n}\n\nfunction sum(values: Array<number | null | undefined>): number | null {\n const known = values.filter((value): value is number => typeof value === 'number');\n return known.length === 0 ? null : known.reduce((acc, value) => acc + value, 0);\n}\n\nfunction firstKnown(values: Array<number | null | undefined>): number | null {\n for (const value of values) {\n if (typeof value === 'number') return value;\n }\n return null;\n}\n\n/**\n * Distinguishes harness wall time from orchestration leftover.\n *\n * `harnessExecutionMs` is the sum of invocation `durationMs` (or cli + startup\n * when wall is missing). `orchestrationOverheadMs` is the phase wall minus that\n * sum — absent when either side was not reported, never zero-filled.\n */\nexport function summarizePhaseTiming(\n records: readonly ExecutionRecord[],\n phase: string,\n phaseWallMs?: number | null,\n): PhaseTiming {\n if (!isPurpose(phase)) return { ...EMPTY_TIMING };\n\n const matched = records.filter((record) => record.purpose === phase);\n if (matched.length === 0) return { ...EMPTY_TIMING };\n\n const harnessExecutionMs = sum(\n matched.map((record) => {\n if (record.durationMs !== null && record.durationMs !== undefined) return record.durationMs;\n const cli = record.cliDurationMs;\n const startup = record.harnessStartupMs;\n if (cli == null && startup == null) return null;\n return (cli ?? 0) + (startup ?? 0);\n }),\n );\n\n const orchestrationOverheadMs =\n phaseWallMs !== null && phaseWallMs !== undefined && harnessExecutionMs !== null\n ? Math.max(0, phaseWallMs - harnessExecutionMs)\n : null;\n\n const retryDurationMs = sum(\n matched\n .filter(\n (record) =>\n record.trigger === 'retry' || record.trigger === 'fallback' || record.attempt > 1,\n )\n .map((record) => record.durationMs),\n );\n\n return {\n harnessExecutionMs,\n orchestrationOverheadMs,\n harnessStartupMs: sum(matched.map((record) => record.harnessStartupMs)),\n ttftMs: firstKnown(matched.map((record) => record.ttftMs)),\n attemptCount: matched.length,\n retryDurationMs,\n cliDurationMs: sum(matched.map((record) => record.cliDurationMs)),\n apiDurationMs: sum(matched.map((record) => record.apiDurationMs)),\n numTurns: sum(matched.map((record) => record.numTurns)),\n outputTokens: sum(matched.map((record) => record.usage?.outputTokens)),\n iteration: firstKnown(matched.map((record) => record.iteration)),\n };\n}\n\nexport async function loadPhaseTiming(\n phase: string,\n phaseWallMs?: number | null,\n): Promise<PhaseTiming> {\n const ctx = getTelemetryContext();\n if (ctx === null) return { ...EMPTY_TIMING };\n try {\n const plan = await loadTaskPlan(ctx.tasksPath);\n return summarizePhaseTiming(plan.executions ?? [], phase, phaseWallMs);\n } catch {\n return { ...EMPTY_TIMING };\n }\n}\n\nfunction formatSeconds(ms: number | null): string {\n if (ms === null) return '-';\n const seconds = ms / 1000;\n if (seconds >= 10) return `${Math.round(seconds)}s`;\n if (seconds >= 1) return `${seconds.toFixed(1)}s`;\n return `${Math.round(ms)}ms`;\n}\n\n/** One-line phase log: `task=63 phase=execute iter=3 wall=541s …`. */\nexport function formatPhaseLine(input: {\n issueNumber: number | string;\n phase: string;\n iteration?: number | null;\n wallMs: number | null;\n cliDurationMs: number | null;\n harnessStartupMs: number | null;\n ttftMs: number | null;\n numTurns: number | null;\n outputTokens: number | null;\n}): string {\n const iter = input.iteration == null ? '-' : String(input.iteration);\n const turns = input.numTurns == null ? '-' : String(input.numTurns);\n const out = input.outputTokens == null ? '-' : String(input.outputTokens);\n return [\n `task=${input.issueNumber}`,\n `phase=${input.phase}`,\n `iter=${iter}`,\n `wall=${formatSeconds(input.wallMs)}`,\n `cli=${formatSeconds(input.cliDurationMs)}`,\n `startup=${formatSeconds(input.harnessStartupMs)}`,\n `ttft=${formatSeconds(input.ttftMs)}`,\n `turns=${turns}`,\n `out=${out}`,\n ].join(' ');\n}\n\nexport function snapshotTimingFields(timing: PhaseTiming): {\n harnessExecutionMs: number | null;\n orchestrationOverheadMs: number | null;\n harnessStartupMs: number | null;\n ttftMs: number | null;\n attemptCount: number | null;\n retryDurationMs: number | null;\n} {\n return {\n harnessExecutionMs: timing.harnessExecutionMs,\n orchestrationOverheadMs: timing.orchestrationOverheadMs,\n harnessStartupMs: timing.harnessStartupMs,\n ttftMs: timing.ttftMs,\n attemptCount: timing.attemptCount,\n retryDurationMs: timing.retryDurationMs,\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ANTIGRAVITY_CAPABILITIES,
4
+ CLAUDE_CAPABILITIES,
5
+ CODEX_CAPABILITIES,
6
+ CURSOR_CAPABILITIES
7
+ } from "./chunk-NEZZ6KDR.js";
8
+
9
+ // src/routing/priors.ts
10
+ var PRIORS_VERSION = "1";
11
+ var PRIORS = {
12
+ bugfix: { "claude-code": 0.7, "codex-cli": 0.95, "cursor-cli": 0.65, "antigravity-cli": 0.6 },
13
+ feature: { "claude-code": 0.85, "codex-cli": 0.8, "cursor-cli": 0.7, "antigravity-cli": 0.65 },
14
+ refactor: { "claude-code": 0.75, "codex-cli": 0.9, "cursor-cli": 0.65, "antigravity-cli": 0.6 },
15
+ docs: { "claude-code": 0.8, "codex-cli": 0.7, "cursor-cli": 0.75, "antigravity-cli": 0.7 },
16
+ test: { "claude-code": 0.7, "codex-cli": 0.9, "cursor-cli": 0.65, "antigravity-cli": 0.6 },
17
+ infra: { "claude-code": 0.8, "codex-cli": 0.75, "cursor-cli": 0.6, "antigravity-cli": 0.55 },
18
+ analysis: { "claude-code": 0.95, "codex-cli": 0.6, "cursor-cli": 0.7, "antigravity-cli": 0.65 }
19
+ };
20
+ function priorFor(taskClass, harness) {
21
+ return PRIORS[taskClass][harness] ?? 0.5;
22
+ }
23
+
24
+ // src/routing/analyze.ts
25
+ var RISK_PATHS = [/auth/i, /migrat/i, /infra/i, /\.github\//i, /permission/i, /secret/i];
26
+ function analyzeTask(signals = {}) {
27
+ const hay = [
28
+ signals.title ?? "",
29
+ signals.body ?? "",
30
+ ...signals.labels ?? [],
31
+ ...signals.paths ?? []
32
+ ].join(" ").toLowerCase();
33
+ const taskClass = classify(hay, signals);
34
+ const risk = RISK_PATHS.some(
35
+ (pattern) => (signals.paths ?? []).some((path) => pattern.test(path))
36
+ ) ? "high" : /security|auth|migrat/.test(hay) ? "high" : /refactor|large|epic/.test(hay) ? "medium" : "low";
37
+ return { taskClass, risk };
38
+ }
39
+ function classify(hay, signals) {
40
+ if (/\bdocs?\b|readme|changelog/.test(hay)) return "docs";
41
+ if (/\btest|spec|coverage/.test(hay)) return "test";
42
+ if (/\bcie?|deploy|infra|workflow|docker/.test(hay)) return "infra";
43
+ if (/\banaly[sz]e|investigat|research/.test(hay)) return "analysis";
44
+ if (/\bbug|fix|regres+ion|crash/.test(hay)) return "bugfix";
45
+ if (/\brefactor|cleanup|extract/.test(hay)) return "refactor";
46
+ if (/\bfeat|feature|add |implement/.test(hay)) return "feature";
47
+ if ((signals.labels ?? []).some((label) => /bug/i.test(label))) return "bugfix";
48
+ if ((signals.labels ?? []).some((label) => /enhancement|feature/i.test(label))) return "feature";
49
+ return "feature";
50
+ }
51
+
52
+ // src/routing/capabilities.ts
53
+ function filterEligible(input) {
54
+ const reasons = [];
55
+ if (input.requiresExtraDirectories && input.capabilities.extraDirectories === "none") {
56
+ reasons.push("MISSING_CAPABILITY:extraDirectories");
57
+ }
58
+ return { eligible: reasons.length === 0, reasonCodes: reasons };
59
+ }
60
+
61
+ // src/routing/score.ts
62
+ var DELTA = 0.2;
63
+ var MIN_SAMPLE_SIZE = 8;
64
+ var PROFILE_MULTIPLIER = {
65
+ economy: 0.9,
66
+ balanced: 1,
67
+ quality: 1.05,
68
+ speed: 1.02
69
+ };
70
+ function clampLearned(value) {
71
+ return Math.max(-DELTA, Math.min(DELTA, value));
72
+ }
73
+ function scoreCandidates(inputs) {
74
+ const profile = inputs[0]?.profile ?? "balanced";
75
+ const scored = inputs.map((input) => {
76
+ const prior = priorFor(input.taskClass, input.harness);
77
+ const samples = input.samples ?? 0;
78
+ const rawLearned = samples >= MIN_SAMPLE_SIZE ? input.learned ?? 0 : 0;
79
+ const learned = clampLearned(rawLearned);
80
+ const multiplier = PROFILE_MULTIPLIER[profile];
81
+ const score = input.eligible ? (prior + learned) * multiplier : 0;
82
+ const reasonCodes = [...input.reasonCodes];
83
+ if (input.eligible && samples === 0) reasonCodes.push("COLD_START");
84
+ if (input.eligible && learned > 0) reasonCodes.push("HIGH_HISTORICAL_SUCCESS");
85
+ if (input.costStatus === "unknown") {
86
+ }
87
+ return {
88
+ harness: input.harness,
89
+ provider: input.provider,
90
+ model: input.model ?? null,
91
+ eligible: input.eligible,
92
+ prior,
93
+ learned,
94
+ samples,
95
+ score,
96
+ reasonCodes
97
+ };
98
+ });
99
+ return scored.sort((a, b) => {
100
+ if (b.score !== a.score) return b.score - a.score;
101
+ return a.harness.localeCompare(b.harness);
102
+ });
103
+ }
104
+ function pickSelected(candidates) {
105
+ const eligible = candidates.filter((candidate) => candidate.eligible);
106
+ if (eligible.length === 0) {
107
+ throw new Error(
108
+ `No eligible routing candidate: ${candidates.map((c) => `${c.harness} (${c.reasonCodes.join(",")})`).join("; ")}`
109
+ );
110
+ }
111
+ return eligible[0];
112
+ }
113
+
114
+ // src/routing/decide.ts
115
+ var CAPS = {
116
+ "claude-code": CLAUDE_CAPABILITIES,
117
+ "codex-cli": CODEX_CAPABILITIES,
118
+ "cursor-cli": CURSOR_CAPABILITIES,
119
+ "antigravity-cli": ANTIGRAVITY_CAPABILITIES
120
+ };
121
+ var PROVIDER = {
122
+ "claude-code": "claude",
123
+ "codex-cli": "codex",
124
+ "cursor-cli": "cursor",
125
+ "antigravity-cli": "antigravity"
126
+ };
127
+ function decideRouting(input) {
128
+ if (input.mode === "off") return null;
129
+ const analyzed = analyzeTask(input.signals ?? {});
130
+ const profile = input.profile ?? "balanced";
131
+ if (input.skipScore) {
132
+ return {
133
+ policyVersion: PRIORS_VERSION,
134
+ profile,
135
+ taskClass: analyzed.taskClass,
136
+ risk: analyzed.risk,
137
+ mode: input.mode,
138
+ candidates: [],
139
+ selected: input.actualHarness,
140
+ actual: input.actualHarness,
141
+ reasonCodes: ["EXPLICIT_CONFIG"]
142
+ };
143
+ }
144
+ const scored = scoreCandidates(
145
+ Object.keys(CAPS).map((harness) => {
146
+ const eligibility = filterEligible({
147
+ harness,
148
+ capabilities: CAPS[harness],
149
+ phase: input.phase,
150
+ requiresExtraDirectories: input.requiresExtraDirectories === true
151
+ });
152
+ return {
153
+ harness,
154
+ provider: PROVIDER[harness] ?? harness,
155
+ eligible: eligibility.eligible,
156
+ reasonCodes: eligibility.reasonCodes,
157
+ taskClass: analyzed.taskClass,
158
+ profile
159
+ };
160
+ })
161
+ );
162
+ const selected = pickSelected(scored);
163
+ return {
164
+ policyVersion: PRIORS_VERSION,
165
+ profile,
166
+ taskClass: analyzed.taskClass,
167
+ risk: analyzed.risk,
168
+ mode: input.mode,
169
+ candidates: scored,
170
+ selected: selected.harness,
171
+ actual: input.actualHarness,
172
+ reasonCodes: selected.reasonCodes.includes("COLD_START") ? ["HIGH_PRIOR", ...selected.reasonCodes] : selected.reasonCodes
173
+ };
174
+ }
175
+
176
+ export {
177
+ PRIORS_VERSION,
178
+ decideRouting
179
+ };
180
+ //# sourceMappingURL=chunk-3XLCNVMD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routing/priors.ts","../src/routing/analyze.ts","../src/routing/capabilities.ts","../src/routing/score.ts","../src/routing/decide.ts"],"sourcesContent":["import type { TaskClass } from './types.js';\n\n/** Bump when a cell's provenance changes. */\nexport const PRIORS_VERSION = '1';\n\n/**\n * Cold-start priors. Provenance: author judgement on 2026-08-30 from the\n * #79 baseline and the #76 capability matrix — not measured affinity.\n */\nexport const PRIORS: Record<TaskClass, Record<string, number>> = {\n bugfix: { 'claude-code': 0.7, 'codex-cli': 0.95, 'cursor-cli': 0.65, 'antigravity-cli': 0.6 },\n feature: { 'claude-code': 0.85, 'codex-cli': 0.8, 'cursor-cli': 0.7, 'antigravity-cli': 0.65 },\n refactor: { 'claude-code': 0.75, 'codex-cli': 0.9, 'cursor-cli': 0.65, 'antigravity-cli': 0.6 },\n docs: { 'claude-code': 0.8, 'codex-cli': 0.7, 'cursor-cli': 0.75, 'antigravity-cli': 0.7 },\n test: { 'claude-code': 0.7, 'codex-cli': 0.9, 'cursor-cli': 0.65, 'antigravity-cli': 0.6 },\n infra: { 'claude-code': 0.8, 'codex-cli': 0.75, 'cursor-cli': 0.6, 'antigravity-cli': 0.55 },\n analysis: { 'claude-code': 0.95, 'codex-cli': 0.6, 'cursor-cli': 0.7, 'antigravity-cli': 0.65 },\n};\n\nexport function priorFor(taskClass: TaskClass, harness: string): number {\n return PRIORS[taskClass][harness] ?? 0.5;\n}\n","import type { RiskLevel, TaskClass, TaskSignals } from './types.js';\n\nconst RISK_PATHS = [/auth/i, /migrat/i, /infra/i, /\\.github\\//i, /permission/i, /secret/i];\n\nexport interface AnalyzedTask {\n taskClass: TaskClass;\n risk: RiskLevel;\n}\n\n/** Deterministic. No model, no I/O. Every class is reachable. */\nexport function analyzeTask(signals: TaskSignals = {}): AnalyzedTask {\n const hay = [\n signals.title ?? '',\n signals.body ?? '',\n ...(signals.labels ?? []),\n ...(signals.paths ?? []),\n ]\n .join(' ')\n .toLowerCase();\n\n const taskClass = classify(hay, signals);\n const risk = RISK_PATHS.some((pattern) =>\n (signals.paths ?? []).some((path) => pattern.test(path)),\n )\n ? 'high'\n : /security|auth|migrat/.test(hay)\n ? 'high'\n : /refactor|large|epic/.test(hay)\n ? 'medium'\n : 'low';\n\n return { taskClass, risk };\n}\n\nfunction classify(hay: string, signals: TaskSignals): TaskClass {\n if (/\\bdocs?\\b|readme|changelog/.test(hay)) return 'docs';\n if (/\\btest|spec|coverage/.test(hay)) return 'test';\n if (/\\bcie?|deploy|infra|workflow|docker/.test(hay)) return 'infra';\n if (/\\banaly[sz]e|investigat|research/.test(hay)) return 'analysis';\n if (/\\bbug|fix|regres+ion|crash/.test(hay)) return 'bugfix';\n if (/\\brefactor|cleanup|extract/.test(hay)) return 'refactor';\n if (/\\bfeat|feature|add |implement/.test(hay)) return 'feature';\n if ((signals.labels ?? []).some((label) => /bug/i.test(label))) return 'bugfix';\n if ((signals.labels ?? []).some((label) => /enhancement|feature/i.test(label))) return 'feature';\n return 'feature';\n}\n","import type { AgentCapabilities, AgentPhase } from '../agents/types.js';\n\nexport interface EligibilityInput {\n harness: string;\n capabilities: AgentCapabilities;\n phase: AgentPhase;\n requiresExtraDirectories: boolean;\n}\n\nexport interface Eligibility {\n eligible: boolean;\n reasonCodes: string[];\n}\n\n/**\n * Restriction missing (`toolAllowlist`) is ignored. Enablement missing\n * (`extraDirectories`) is ineligible when the phase needs addDirs.\n */\nexport function filterEligible(input: EligibilityInput): Eligibility {\n const reasons: string[] = [];\n if (input.requiresExtraDirectories && input.capabilities.extraDirectories === 'none') {\n reasons.push('MISSING_CAPABILITY:extraDirectories');\n }\n return { eligible: reasons.length === 0, reasonCodes: reasons };\n}\n","import { priorFor } from './priors.js';\nimport type { Candidate, RoutingProfile, TaskClass } from './types.js';\n\nexport const DELTA = 0.2;\nexport const MIN_SAMPLE_SIZE = 8;\n\nconst PROFILE_MULTIPLIER: Record<RoutingProfile, number> = {\n economy: 0.9,\n balanced: 1,\n quality: 1.05,\n speed: 1.02,\n};\n\nexport interface ScoreInput {\n harness: string;\n provider: string;\n model?: string | null;\n eligible: boolean;\n reasonCodes: string[];\n taskClass: TaskClass;\n learned?: number;\n samples?: number;\n profile?: RoutingProfile;\n /** Cost status from #78. `unknown` never scores cost. */\n costStatus?: 'reported' | 'estimated' | 'unknown';\n}\n\nexport function clampLearned(value: number): number {\n return Math.max(-DELTA, Math.min(DELTA, value));\n}\n\nexport function scoreCandidates(inputs: readonly ScoreInput[]): Candidate[] {\n const profile = inputs[0]?.profile ?? 'balanced';\n const scored: Candidate[] = inputs.map((input) => {\n const prior = priorFor(input.taskClass, input.harness);\n const samples = input.samples ?? 0;\n const rawLearned = samples >= MIN_SAMPLE_SIZE ? (input.learned ?? 0) : 0;\n const learned = clampLearned(rawLearned);\n const multiplier = PROFILE_MULTIPLIER[profile];\n const score = input.eligible ? (prior + learned) * multiplier : 0;\n const reasonCodes = [...input.reasonCodes];\n if (input.eligible && samples === 0) reasonCodes.push('COLD_START');\n if (input.eligible && learned > 0) reasonCodes.push('HIGH_HISTORICAL_SUCCESS');\n if (input.costStatus === 'unknown') {\n // unknown (including subscription) is not $0 and does not score cost.\n }\n return {\n harness: input.harness,\n provider: input.provider,\n model: input.model ?? null,\n eligible: input.eligible,\n prior,\n learned,\n samples,\n score,\n reasonCodes,\n };\n });\n\n return scored.sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n return a.harness.localeCompare(b.harness);\n });\n}\n\nexport function pickSelected(candidates: readonly Candidate[]): Candidate {\n const eligible = candidates.filter((candidate) => candidate.eligible);\n if (eligible.length === 0) {\n throw new Error(\n `No eligible routing candidate: ${candidates.map((c) => `${c.harness} (${c.reasonCodes.join(',')})`).join('; ')}`,\n );\n }\n return eligible[0] as Candidate;\n}\n","import type { AgentPhase } from '../agents/types.js';\nimport {\n ANTIGRAVITY_CAPABILITIES,\n CLAUDE_CAPABILITIES,\n CODEX_CAPABILITIES,\n CURSOR_CAPABILITIES,\n} from '../agents/types.js';\nimport { analyzeTask } from './analyze.js';\nimport { filterEligible } from './capabilities.js';\nimport { PRIORS_VERSION } from './priors.js';\nimport { pickSelected, scoreCandidates } from './score.js';\nimport type { RoutingDecision, RoutingMode, RoutingProfile, TaskSignals } from './types.js';\n\nconst CAPS = {\n 'claude-code': CLAUDE_CAPABILITIES,\n 'codex-cli': CODEX_CAPABILITIES,\n 'cursor-cli': CURSOR_CAPABILITIES,\n 'antigravity-cli': ANTIGRAVITY_CAPABILITIES,\n} as const;\n\nconst PROVIDER: Record<string, string> = {\n 'claude-code': 'claude',\n 'codex-cli': 'codex',\n 'cursor-cli': 'cursor',\n 'antigravity-cli': 'antigravity',\n};\n\nexport function decideRouting(input: {\n signals?: TaskSignals;\n phase: AgentPhase;\n actualHarness: string;\n mode: RoutingMode;\n profile?: RoutingProfile;\n requiresExtraDirectories?: boolean;\n skipScore?: boolean;\n}): RoutingDecision | null {\n if (input.mode === 'off') return null;\n const analyzed = analyzeTask(input.signals ?? {});\n const profile = input.profile ?? 'balanced';\n\n if (input.skipScore) {\n return {\n policyVersion: PRIORS_VERSION,\n profile,\n taskClass: analyzed.taskClass,\n risk: analyzed.risk,\n mode: input.mode,\n candidates: [],\n selected: input.actualHarness,\n actual: input.actualHarness,\n reasonCodes: ['EXPLICIT_CONFIG'],\n };\n }\n\n const scored = scoreCandidates(\n (Object.keys(CAPS) as (keyof typeof CAPS)[]).map((harness) => {\n const eligibility = filterEligible({\n harness,\n capabilities: CAPS[harness],\n phase: input.phase,\n requiresExtraDirectories: input.requiresExtraDirectories === true,\n });\n return {\n harness,\n provider: PROVIDER[harness] ?? harness,\n eligible: eligibility.eligible,\n reasonCodes: eligibility.reasonCodes,\n taskClass: analyzed.taskClass,\n profile,\n };\n }),\n );\n const selected = pickSelected(scored);\n return {\n policyVersion: PRIORS_VERSION,\n profile,\n taskClass: analyzed.taskClass,\n risk: analyzed.risk,\n mode: input.mode,\n candidates: scored,\n selected: selected.harness,\n actual: input.actualHarness,\n reasonCodes: selected.reasonCodes.includes('COLD_START')\n ? ['HIGH_PRIOR', ...selected.reasonCodes]\n : selected.reasonCodes,\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readSessionFile
4
+ } from "./chunk-SNTTOQAD.js";
5
+ import {
6
+ isProcessAlive,
7
+ isRunLockStale,
8
+ readRunLock
9
+ } from "./chunk-NEZZ6KDR.js";
10
+ import {
11
+ PROJECTS_DIR_NAME,
12
+ RUN_LOCK_FILENAME,
13
+ getGlobalRoot,
14
+ getIssuePaths
15
+ } from "./chunk-TX5WIVYP.js";
16
+
17
+ // src/execution/registry.ts
18
+ import { readdir } from "fs/promises";
19
+ import { join } from "path";
20
+ function classifyRunLock(lock) {
21
+ if (!isProcessAlive(lock.pid)) return "orphan";
22
+ if (isRunLockStale(lock)) return "unsignaled";
23
+ return "running";
24
+ }
25
+ async function listLiveRuns(options = {}) {
26
+ const root = getGlobalRoot(options);
27
+ const projectsDir = join(root, PROJECTS_DIR_NAME);
28
+ let projectIds;
29
+ try {
30
+ const entries = await readdir(projectsDir, { withFileTypes: true });
31
+ projectIds = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
32
+ } catch {
33
+ return [];
34
+ }
35
+ const runs = await Promise.all(
36
+ projectIds.map(async (projectId) => {
37
+ const lockFile = join(projectsDir, projectId, RUN_LOCK_FILENAME);
38
+ const lock = await readRunLock(lockFile);
39
+ if (lock === null) return null;
40
+ return enrichRun(projectId, lockFile, lock, options);
41
+ })
42
+ );
43
+ return runs.filter((run) => run !== null).sort((a, b) => a.startedAt.localeCompare(b.startedAt));
44
+ }
45
+ async function enrichRun(projectId, lockFile, lock, options) {
46
+ const session = await readSessionFile(getIssuePaths(projectId, lock.target, options).sessionFile);
47
+ return {
48
+ projectId,
49
+ target: lock.target,
50
+ pid: lock.pid,
51
+ host: lock.host,
52
+ detached: lock.detached === true,
53
+ status: classifyRunLock(lock),
54
+ startedAt: lock.startedAt,
55
+ lastHeartbeatAt: lock.lastHeartbeatAt,
56
+ issue: session?.snapshot.issue.number ?? numericTarget(lock.target),
57
+ phase: session?.snapshot.currentPhase ?? null,
58
+ storiesCompleted: session?.snapshot.progress.storiesCompleted ?? null,
59
+ storiesTotal: session?.snapshot.progress.storiesTotal ?? null,
60
+ elapsedSeconds: session?.snapshot.elapsedSeconds ?? null,
61
+ lockFile
62
+ };
63
+ }
64
+ function numericTarget(target) {
65
+ return /^\d+$/.test(target) ? Number(target) : null;
66
+ }
67
+
68
+ export {
69
+ classifyRunLock,
70
+ listLiveRuns
71
+ };
72
+ //# sourceMappingURL=chunk-5TB6KLC2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/execution/registry.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { isProcessAlive, isRunLockStale, readRunLock } from '../storage/lock.js';\nimport {\n type GetGlobalRootOptions,\n getGlobalRoot,\n getIssuePaths,\n PROJECTS_DIR_NAME,\n RUN_LOCK_FILENAME,\n} from '../storage/paths.js';\nimport type { RunLock } from '../storage/schemas.js';\nimport { readSessionFile } from '../storage/session-file.js';\n\nexport type LiveRunStatus = 'running' | 'unsignaled' | 'orphan';\n\nexport interface LiveRun {\n projectId: string;\n target: string;\n pid: number;\n host: string;\n detached: boolean;\n status: LiveRunStatus;\n startedAt: string;\n lastHeartbeatAt: string;\n issue: number | null;\n phase: string | null;\n storiesCompleted: number | null;\n storiesTotal: number | null;\n elapsedSeconds: number | null;\n lockFile: string;\n}\n\nexport function classifyRunLock(lock: RunLock): LiveRunStatus {\n if (!isProcessAlive(lock.pid)) return 'orphan';\n if (isRunLockStale(lock)) return 'unsignaled';\n return 'running';\n}\n\n/**\n * Every run.lock under the global projects tree, enriched with session.json\n * when one exists. The lock is the source of truth for existence; the\n * snapshot only fills phase and progress.\n */\nexport async function listLiveRuns(options: GetGlobalRootOptions = {}): Promise<LiveRun[]> {\n const root = getGlobalRoot(options);\n const projectsDir = join(root, PROJECTS_DIR_NAME);\n let projectIds: string[];\n try {\n const entries = await readdir(projectsDir, { withFileTypes: true });\n projectIds = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n } catch {\n return [];\n }\n\n const runs = await Promise.all(\n projectIds.map(async (projectId) => {\n const lockFile = join(projectsDir, projectId, RUN_LOCK_FILENAME);\n const lock = await readRunLock(lockFile);\n if (lock === null) return null;\n return enrichRun(projectId, lockFile, lock, options);\n }),\n );\n\n return runs\n .filter((run): run is LiveRun => run !== null)\n .sort((a, b) => a.startedAt.localeCompare(b.startedAt));\n}\n\nasync function enrichRun(\n projectId: string,\n lockFile: string,\n lock: RunLock,\n options: GetGlobalRootOptions,\n): Promise<LiveRun> {\n const session = await readSessionFile(getIssuePaths(projectId, lock.target, options).sessionFile);\n\n return {\n projectId,\n target: lock.target,\n pid: lock.pid,\n host: lock.host,\n detached: lock.detached === true,\n status: classifyRunLock(lock),\n startedAt: lock.startedAt,\n lastHeartbeatAt: lock.lastHeartbeatAt,\n issue: session?.snapshot.issue.number ?? numericTarget(lock.target),\n phase: session?.snapshot.currentPhase ?? null,\n storiesCompleted: session?.snapshot.progress.storiesCompleted ?? null,\n storiesTotal: session?.snapshot.progress.storiesTotal ?? null,\n elapsedSeconds: session?.snapshot.elapsedSeconds ?? null,\n lockFile,\n };\n}\n\nfunction numericTarget(target: string): number | null {\n return /^\\d+$/.test(target) ? Number(target) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AA+Bd,SAAS,gBAAgB,MAA8B;AAC5D,MAAI,CAAC,eAAe,KAAK,GAAG,EAAG,QAAO;AACtC,MAAI,eAAe,IAAI,EAAG,QAAO;AACjC,SAAO;AACT;AAOA,eAAsB,aAAa,UAAgC,CAAC,GAAuB;AACzF,QAAM,OAAO,cAAc,OAAO;AAClC,QAAM,cAAc,KAAK,MAAM,iBAAiB;AAChD,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,aAAa,EAAE,eAAe,KAAK,CAAC;AAClE,iBAAa,QAAQ,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EACvF,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,OAAO,MAAM,QAAQ;AAAA,IACzB,WAAW,IAAI,OAAO,cAAc;AAClC,YAAM,WAAW,KAAK,aAAa,WAAW,iBAAiB;AAC/D,YAAM,OAAO,MAAM,YAAY,QAAQ;AACvC,UAAI,SAAS,KAAM,QAAO;AAC1B,aAAO,UAAU,WAAW,UAAU,MAAM,OAAO;AAAA,IACrD,CAAC;AAAA,EACH;AAEA,SAAO,KACJ,OAAO,CAAC,QAAwB,QAAQ,IAAI,EAC5C,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAC1D;AAEA,eAAe,UACb,WACA,UACA,MACA,SACkB;AAClB,QAAM,UAAU,MAAM,gBAAgB,cAAc,WAAW,KAAK,QAAQ,OAAO,EAAE,WAAW;AAEhG,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,MAAM,KAAK;AAAA,IACX,UAAU,KAAK,aAAa;AAAA,IAC5B,QAAQ,gBAAgB,IAAI;AAAA,IAC5B,WAAW,KAAK;AAAA,IAChB,iBAAiB,KAAK;AAAA,IACtB,OAAO,SAAS,SAAS,MAAM,UAAU,cAAc,KAAK,MAAM;AAAA,IAClE,OAAO,SAAS,SAAS,gBAAgB;AAAA,IACzC,kBAAkB,SAAS,SAAS,SAAS,oBAAoB;AAAA,IACjE,cAAc,SAAS,SAAS,SAAS,gBAAgB;AAAA,IACzD,gBAAgB,SAAS,SAAS,kBAAkB;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,cAAc,QAA+B;AACpD,SAAO,QAAQ,KAAK,MAAM,IAAI,OAAO,MAAM,IAAI;AACjD;","names":[]}