@robmclarty/volley 0.5.4 → 0.6.1
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.
- package/CHANGELOG.md +20 -0
- package/README.md +5 -1
- package/dist/cli.js +57 -42
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +86 -3
- package/dist/index.js +198 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/changes.ts","../src/types.ts","../src/orchestrator.ts","../src/engine.ts","../src/flow.ts","../src/builder.ts","../src/builder/context_check.ts","../src/builder/tools.ts","../src/workspace_tools.ts","../src/cost.ts","../src/prewarm.ts","../src/worktree.ts","../src/workspace.ts","../src/critic/run.ts","../src/critic/prompt.ts","../src/loop_state.ts","../src/check/checkride.ts","../src/check/command.ts","../src/iteration.ts","../src/summary.ts","../src/phases.ts","../src/render/format.ts","../src/render/renderer.ts","../src/exit_codes.ts"],"sourcesContent":["/**\n * Config resolution: merge CLI flags over an optional config file\n * over defaults, expand `@file` references, validate, and produce the\n * immutable `ResolvedConfig` that `.volley/config.json` records.\n */\nimport { accessSync, constants, existsSync, readFileSync, statSync } from 'node:fs';\nimport { isAbsolute, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { randomUUID } from 'node:crypto';\nimport { DEFAULT_GATE_PATTERNS } from './changes.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CriticPreset,\n CriticProvider,\n ResolvedConfig,\n VolleyConfig,\n} from './types.js';\n\nexport const DEFAULT_BUILDER_MODEL = 'opus';\nconst DEFAULT_CRITIC_MODEL = 'opus';\nexport const DEFAULT_MAX_ITERATIONS = 10;\nexport const DEFAULT_BUILDER_MAX_STEPS = 50;\nexport const DEFAULT_CHECK = 'auto';\nconst DEFAULT_CRITIC = 'reviewer';\nconst DEFAULT_BUILDER_PROVIDER: BuilderProvider = 'claude_cli';\nconst DEFAULT_CRITIC_PROVIDER: CriticProvider = 'claude_cli';\nconst DEFAULT_PERMISSION_MODE: BuilderPermissionMode = 'acceptEdits';\n/** The image volley's own `Dockerfile` builds; the local-builder sandbox runs\n * it unless `--sandbox-image` / `VOLLEY_SANDBOX_IMAGE` overrides it. */\nexport const DEFAULT_SANDBOX_IMAGE = 'volley-sandbox:latest';\n\nconst BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n];\n\n/** Builder providers that run a local model through volley's own tool loop —\n * a real `bash` (write + exec). Refused unless volley is running\n * inside a container (the correct blast-radius default) or the operator\n * explicitly opts out; `claude_cli` has its own permission model and is\n * exempt. */\nconst LOCAL_BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'ollama',\n 'lmstudio',\n];\n\nconst CRITIC_PROVIDERS: ReadonlyArray<CriticProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n];\n\nconst CRITIC_PRESETS: ReadonlyArray<CriticPreset> = [\n 'reviewer',\n 'optimizer',\n 'researcher',\n];\n\nconst PERMISSION_MODES: ReadonlyArray<BuilderPermissionMode> = [\n 'acceptEdits',\n 'bypassPermissions',\n];\n\n/** `@path/to/file` reads the file; any other string passes through. */\nexport function expand_at_file(value: string, cwd: string): string {\n if (!value.startsWith('@')) return value;\n const path = resolve(cwd, value.slice(1));\n if (!existsSync(path)) {\n throw config_error(`file not found: ${path} (from ${value})`);\n }\n return readFileSync(path, 'utf8');\n}\n\nfunction is_critic_preset(value: string): value is CriticPreset {\n return (CRITIC_PRESETS as ReadonlyArray<string>).includes(value);\n}\n\n/** Load a `volley.config.ts` / `.js` file's default export. */\nexport async function load_config_file(path: string): Promise<VolleyConfig> {\n const abs = resolve(path);\n if (!existsSync(abs)) {\n throw config_error(`config file not found: ${abs}`);\n }\n let loaded: unknown;\n try {\n const mod = (await import(pathToFileURL(abs).href)) as {\n default?: unknown;\n };\n loaded = mod.default;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw config_error(`failed to load config file ${abs}: ${detail}`);\n }\n if (typeof loaded !== 'object' || loaded === null) {\n throw config_error(`config file ${abs} must default-export a VolleyConfig object`);\n }\n return loaded as VolleyConfig;\n}\n\nfunction validate_workspace(workspace: string): string {\n const abs = isAbsolute(workspace) ? workspace : resolve(workspace);\n if (!existsSync(abs)) {\n throw config_error(`workspace not found: ${abs}`);\n }\n if (!statSync(abs).isDirectory()) {\n throw config_error(`workspace is not a directory: ${abs}`);\n }\n try {\n accessSync(abs, constants.W_OK);\n } catch {\n throw config_error(`workspace not writable: ${abs}`);\n }\n return abs;\n}\n\nfunction resolve_critic(\n critic: string,\n cwd: string,\n): { critic_preset: CriticPreset | 'custom'; critic_prompt_path: string | null } {\n if (is_critic_preset(critic)) {\n return { critic_preset: critic, critic_prompt_path: null };\n }\n const path = resolve(cwd, critic);\n if (!existsSync(path)) {\n throw config_error(\n `--critic must be one of ${CRITIC_PRESETS.join(', ')} or a path to a prompt file; got: ${critic}`,\n );\n }\n return { critic_preset: 'custom', critic_prompt_path: path };\n}\n\nexport type ResolveOptions = {\n cwd?: string;\n run_id?: string;\n started_at?: string;\n env?: Record<string, string | undefined>;\n};\n\n/** `--builder-max-steps` (a merged flag/config value) wins over the\n * `VOLLEY_BUILDER_MAX_STEPS` env var, which wins over the default. Local\n * builder only; ignored by the `claude_cli` arm. */\nfunction resolve_builder_max_steps(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): number {\n if (raw.builder_max_steps !== undefined) {\n return validate_builder_max_steps(raw.builder_max_steps, raw.builder_max_steps);\n }\n const env_value = env['VOLLEY_BUILDER_MAX_STEPS'];\n if (env_value !== undefined && env_value !== '') {\n return validate_builder_max_steps(Number(env_value), env_value);\n }\n return DEFAULT_BUILDER_MAX_STEPS;\n}\n\nfunction validate_builder_max_steps(value: number, original: unknown): number {\n if (!Number.isInteger(value) || value < 1) {\n throw config_error(\n `--builder-max-steps / VOLLEY_BUILDER_MAX_STEPS must be a positive integer; got: ${String(original)}`,\n );\n }\n return value;\n}\n\n/** `--sandbox-image` (a merged flag/config value) wins over the\n * `VOLLEY_SANDBOX_IMAGE` env var, which wins over the default image. Used only\n * on the local-builder Docker sandbox path; the `claude_cli` path never\n * runs Docker. */\nfunction resolve_sandbox_image(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): string {\n if (raw.sandbox_image !== undefined && raw.sandbox_image !== '') {\n return raw.sandbox_image;\n }\n const env_value = env['VOLLEY_SANDBOX_IMAGE'];\n if (env_value !== undefined && env_value !== '') {\n return env_value;\n }\n return DEFAULT_SANDBOX_IMAGE;\n}\n\n/** The `--allow-unsandboxed-builder` flag/config value wins; otherwise\n * `VOLLEY_ALLOW_UNSANDBOXED_BUILDER=1` (or `=true`) opts out. Any other value\n * (incl. `0`/`false`/unset) leaves the local builder refused unless contained. */\nfunction resolve_allow_unsandboxed_builder(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): boolean {\n if (raw.allow_unsandboxed_builder === true) return true;\n const env_value = env['VOLLEY_ALLOW_UNSANDBOXED_BUILDER'];\n return env_value === '1' || env_value === 'true';\n}\n\n/** volley *detects* it is running inside its sandbox container rather than\n * starting the container itself. The signal is the `VOLLEY_CONTAINED=1` marker\n * volley's own image bakes in (`Dockerfile` `ENV`), so a `docker run <hardened\n * flags> <image> volley run …` is recognized as contained out of the box. Kept\n * env-only — no ambient `/.dockerenv` probe — so the safety gate is deterministic\n * and testable, and so a CI job that itself runs in an unrelated container does\n * not silently satisfy the gate; a hand-rolled sandbox must set the marker (or\n * the operator uses `--allow-unsandboxed-builder`). */\nexport function detect_containment(env: Record<string, string | undefined>): boolean {\n const value = env['VOLLEY_CONTAINED'];\n return value === '1' || value === 'true';\n}\n\n/** Merge, expand, and validate a raw `VolleyConfig` into a `ResolvedConfig`.\n * `check_resolved` is filled in later by check detection (workspace-relative);\n * it starts as `none` and `resolve_check_runner` overrides it. */\nexport function resolve_config(\n raw: VolleyConfig,\n options: ResolveOptions = {},\n): ResolvedConfig {\n const cwd = options.cwd ?? process.cwd();\n const env = options.env ?? process.env;\n\n if (typeof raw.prompt !== 'string' || raw.prompt.length === 0) {\n throw config_error('missing required option: --prompt');\n }\n if (typeof raw.workspace !== 'string' || raw.workspace.length === 0) {\n throw config_error('missing required option: --workspace');\n }\n if (typeof raw.criteria !== 'string' || raw.criteria.length === 0) {\n throw config_error('missing required option: --criteria');\n }\n\n const workspace = validate_workspace(resolve(cwd, raw.workspace));\n const prompt = expand_at_file(raw.prompt, cwd);\n const criteria = expand_at_file(raw.criteria, cwd);\n\n const max_iterations = raw.max_iterations ?? DEFAULT_MAX_ITERATIONS;\n if (!Number.isInteger(max_iterations) || max_iterations < 1) {\n throw config_error(`--max-iterations must be a positive integer; got: ${String(raw.max_iterations)}`);\n }\n\n const max_cost_usd = raw.max_cost_usd ?? null;\n if (max_cost_usd !== null && !(typeof max_cost_usd === 'number' && max_cost_usd > 0)) {\n throw config_error(`--max-cost-usd must be a positive number; got: ${String(raw.max_cost_usd)}`);\n }\n\n const builder_permission_mode = raw.builder_permission_mode ?? DEFAULT_PERMISSION_MODE;\n if (!PERMISSION_MODES.includes(builder_permission_mode)) {\n throw config_error(\n `--builder-permission-mode must be one of ${PERMISSION_MODES.join(', ')}; got: ${String(raw.builder_permission_mode)}`,\n );\n }\n\n const { critic_preset, critic_prompt_path } = resolve_critic(\n raw.critic ?? DEFAULT_CRITIC,\n cwd,\n );\n\n const builder_provider = raw.builder_provider ?? DEFAULT_BUILDER_PROVIDER;\n if (!BUILDER_PROVIDERS.includes(builder_provider)) {\n throw config_error(\n `--builder-provider must be one of ${BUILDER_PROVIDERS.join(', ')}; got: ${String(raw.builder_provider)}`,\n );\n }\n\n // Safety gate: a local builder gets a real `bash` (write + exec),\n // so refuse it — before any model spend — unless volley is running *inside* a\n // container (the correct blast-radius default) or the operator explicitly\n // opts out to run uncontained on the host.\n const allow_unsandboxed_builder = resolve_allow_unsandboxed_builder(raw, env);\n const contained = detect_containment(env);\n if (\n LOCAL_BUILDER_PROVIDERS.includes(builder_provider) &&\n !contained &&\n !allow_unsandboxed_builder\n ) {\n throw config_error(\n `builder-provider '${builder_provider}' runs a local model with a real bash ` +\n `(write + exec) — refused unless contained. Launch volley inside its sandbox container ` +\n `(docker run <hardened flags> <image> volley run …, which sets VOLLEY_CONTAINED=1), or pass ` +\n `--allow-unsandboxed-builder (VOLLEY_ALLOW_UNSANDBOXED_BUILDER=1) to run uncontained on the host.`,\n );\n }\n\n const builder_max_steps = resolve_builder_max_steps(raw, env);\n\n const critic_provider = raw.critic_provider ?? DEFAULT_CRITIC_PROVIDER;\n if (!CRITIC_PROVIDERS.includes(critic_provider)) {\n throw config_error(\n `--critic-provider must be one of ${CRITIC_PROVIDERS.join(', ')}; got: ${String(raw.critic_provider)}`,\n );\n }\n\n // Containment auth gate: `claude_cli`'s subscription/OAuth credentials\n // do not survive containerization — the token is mangled inside the container —\n // so a contained run may drive Claude only by API key (a plain env var that\n // travels the boundary). Refuse a contained `claude_cli` role (builder and/or\n // critic) that is not explicitly in `api_key` mode; the all-Claude path stays\n // on the host and Docker-free by design, where subscription auth works.\n if (contained) {\n const claude_roles = [\n builder_provider === 'claude_cli' ? 'builder' : null,\n critic_provider === 'claude_cli' ? 'critic' : null,\n ].filter((role): role is string => role !== null);\n const auth_mode = env['VOLLEY_AUTH_MODE'] ?? 'auto';\n if (claude_roles.length > 0 && auth_mode !== 'api_key') {\n throw config_error(\n `claude_cli (${claude_roles.join(', ')}) cannot use its subscription/OAuth token inside a ` +\n `container — it is mangled there. Set VOLLEY_AUTH_MODE=api_key (with ANTHROPIC_API_KEY) to ` +\n `drive Claude contained, or run claude_cli on the host uncontained.`,\n );\n }\n }\n\n if (raw.git_checkpoints === true && !existsSync(resolve(workspace, '.git'))) {\n throw config_error(`--git requires the workspace to be a git repository: ${workspace}`);\n }\n\n // A worktree is checked out from the workspace's git history, so refuse the\n // flag before any model spend when the workspace is not a repository.\n const worktree = raw.worktree ?? false;\n if (worktree && !existsSync(resolve(workspace, '.git'))) {\n throw config_error(`--worktree requires the workspace to be a git repository: ${workspace}`);\n }\n\n // `--discard-worktree`: opt in to the throw-away mode — a converged run's\n // effects go away with its branch instead of being kept on it. Only meaningful\n // under `--worktree`, so a lone flag is refused rather than silently ignored:\n // it would otherwise read as isolation the run does not have.\n const discard_worktree = raw.discard_worktree ?? false;\n if (discard_worktree && !worktree) {\n throw config_error(\n '--discard-worktree applies only to a --worktree run: there is no worktree to discard',\n );\n }\n\n // What counts as the gate is the task's call, so a config's own list replaces\n // the defaults outright rather than extending them: a test-writing task owns\n // its tests, and an empty list turns the report off entirely.\n const gate_paths = raw.gate_paths ?? DEFAULT_GATE_PATTERNS;\n if (!Array.isArray(gate_paths) || gate_paths.some((glob) => typeof glob !== 'string')) {\n throw config_error('gate_paths must be an array of glob strings');\n }\n\n const sandbox_image = resolve_sandbox_image(raw, env);\n\n return {\n version: 2,\n run_id: options.run_id ?? randomUUID(),\n started_at: options.started_at ?? new Date().toISOString(),\n prompt,\n criteria,\n check: raw.check ?? DEFAULT_CHECK,\n check_resolved: 'none',\n builder_model: raw.builder_model ?? DEFAULT_BUILDER_MODEL,\n builder_provider,\n builder_max_steps,\n allow_unsandboxed_builder,\n critic_model: raw.critic_model ?? DEFAULT_CRITIC_MODEL,\n critic_provider,\n builder_permission_mode,\n critic_preset,\n critic_prompt_path,\n max_iterations,\n max_cost_usd,\n git_checkpoints: raw.git_checkpoints ?? false,\n worktree,\n discard_worktree,\n gate_paths: [...gate_paths],\n fail_on_gate_edit: raw.fail_on_gate_edit ?? false,\n sandbox_image,\n workspace,\n verbose: raw.verbose ?? false,\n quiet: raw.quiet ?? false,\n json: raw.json ?? false,\n show_thinking: raw.show_thinking ?? true,\n };\n}\n","/**\n * What the builder changed, and whether it touched the gate.\n *\n * Until now the harness's only view of a builder's work was \"the check exited\n * 0\" — which is exactly the thing a builder can arrange by editing the check.\n * The reckon run (`research/reckon-local-run-finding.md`) closed that hole by\n * hand: after a green all-local run, the salvage commit was inspected to confirm\n * it touched only the four source modules and no test, fixture, or manifest.\n * This module is that inspection, mechanized — diff the build root against a\n * baseline captured before the first iteration, classify every changed path\n * against the gate patterns, and hand the result to the critic prompt, the run\n * summary, and (opt-in) the loop's stopping condition.\n *\n * Everything here is best-effort and non-throwing. A build root that is not a\n * git repository simply has no change set (`null`) and the loop behaves exactly\n * as it did before: change detection is evidence, never a precondition.\n *\n * Deliberately *not* collected: diff hunks. The changed-path list is bounded and\n * cheap, while inlined content would blow a local critic's context (32k on the\n * reckon seats) for the one part of the picture its read tools can already\n * fetch — the critic learns *where* to look, then looks.\n */\nimport { spawnSync } from 'node:child_process';\nimport type { ChangeSet, ChangeStatus, ChangedFile } from './types.js';\n\n/**\n * The default gate: paths whose edits change *what passing means* rather than\n * whether the work passes. Tests and fixtures are the executable half of the\n * spec; the check configuration and manifest decide which tests run at all.\n *\n * Deliberately broad and language-general — a false positive costs one line in\n * the critic's prompt, while a miss is the failure mode this exists to prevent.\n * A config's own `gate_paths` replaces the list outright (spec-writing tasks\n * legitimately own their tests).\n */\nexport const DEFAULT_GATE_PATTERNS: string[] = [\n '**/*.test.*',\n '**/*.spec.*',\n '**/*_test.*',\n '**/test/**',\n '**/tests/**',\n '**/__tests__/**',\n '**/spec/**',\n '**/fixtures/**',\n '**/checkride.config.*',\n '**/vitest.config.*',\n '**/jest.config.*',\n '**/playwright.config.*',\n '**/package.json',\n '.github/workflows/**',\n];\n\n/** Harness state, toolchain, and VCS internals: never the builder's work, even\n * when they sit in the build root and show up dirty. `.volley/` is the control\n * plane, `.check/` is the check's own artifacts, `node_modules/` rides in on the\n * worktree symlink. */\nconst EXCLUDED_PREFIXES = ['.volley/', '.volley.bak.', '.check/', '.git/', 'node_modules/'];\n\n/** How many changed paths the set carries. The cap bounds the critic prompt and\n * the archived summary on a sweeping refactor; `gate_edits` and `total` are\n * always computed over the full list, so nothing load-bearing is truncated. */\nconst DEFAULT_LIMIT = 200;\n\ntype GitResult = { status: number; stdout: string };\n\n/** Run git in `root`, best-effort: a missing binary, a broken repo, or a\n * non-zero exit all read as \"no output\". Change detection reports what it can\n * and never fails a run over what it cannot (unlike `worktree.ts`, where git is\n * a precondition the operator asked for). */\nfunction git(root: string, args: string[]): GitResult {\n try {\n const result = spawnSync('git', args, {\n cwd: root,\n encoding: 'utf8',\n maxBuffer: 32 * 1024 * 1024,\n });\n return { status: result.status ?? -1, stdout: result.stdout ?? '' };\n } catch {\n return { status: -1, stdout: '' };\n }\n}\n\n/** Is this directory inside a git repository? Asked of git rather than by\n * looking for `.git`, so a workspace nested under a repo root — and a linked\n * worktree, whose `.git` is a file — both answer correctly. */\nfunction in_git_repo(root: string): boolean {\n return git(root, ['rev-parse', '--git-dir']).status === 0;\n}\n\n/**\n * The commit a run's changes are measured against: the build root's HEAD, read\n * once before the first iteration. Null when the root is not a repository or has\n * no commits yet — in the latter case `collect_changes` still reports untracked\n * files, which is the whole of a from-scratch build.\n */\nexport function capture_baseline(root: string): string | null {\n const head = git(root, ['rev-parse', 'HEAD']);\n if (head.status !== 0) return null;\n const sha = head.stdout.trim();\n return sha.length > 0 ? sha : null;\n}\n\n/** git's status letters, folded onto the four cases worth naming. Rename and\n * copy both record the destination path — where the content lives now. */\nfunction change_status(code: string): ChangeStatus {\n const letter = code.charAt(0);\n if (letter === 'A') return 'added';\n if (letter === 'M' || letter === 'T') return 'modified';\n if (letter === 'D') return 'deleted';\n if (letter === 'R' || letter === 'C') return 'renamed';\n return 'unknown';\n}\n\ntype RawChange = { path: string; status: ChangeStatus };\n\n/**\n * Parse `git diff --name-status -z`: a flat NUL-separated stream of\n * `status, path` pairs, except renames and copies, which carry `status, source,\n * destination`. NUL separation (rather than lines) is what makes paths with\n * spaces or newlines in them safe to read.\n */\nfunction parse_name_status(stdout: string): RawChange[] {\n const tokens = stdout.split('\\0').filter((token) => token.length > 0);\n const changes: RawChange[] = [];\n let index = 0;\n while (index < tokens.length) {\n const code = tokens[index] ?? '';\n const paired = code.startsWith('R') || code.startsWith('C');\n const path = tokens[index + (paired ? 2 : 1)];\n if (path !== undefined) changes.push({ path, status: change_status(code) });\n index += paired ? 3 : 2;\n }\n return changes;\n}\n\n/** Parse a NUL-separated path list (`git ls-files -z`). */\nfunction parse_paths(stdout: string): string[] {\n return stdout.split('\\0').filter((path) => path.length > 0);\n}\n\nfunction excluded(path: string): boolean {\n return EXCLUDED_PREFIXES.some((prefix) => path.startsWith(prefix));\n}\n\n/**\n * Compile one glob to an anchored regular expression. Supports the three forms\n * the gate patterns need — `**` across separators, `*` within a segment, `?` for\n * one character — in a single pass, because sequential string replacement would\n * re-process the regex syntax its own earlier passes emit.\n *\n * A leading globstar-plus-separator collapses to \"any number of leading\n * segments, including none\", so one `test` pattern matches `test/a.mjs` and\n * `src/test/a.mjs` alike instead of needing a rule per depth.\n */\nfunction glob_to_regexp(pattern: string): RegExp {\n let source = '';\n let index = 0;\n while (index < pattern.length) {\n const char = pattern.charAt(index);\n if (char === '*' && pattern.charAt(index + 1) === '*') {\n const slashed = pattern.charAt(index + 2) === '/';\n source += slashed ? '(?:.*/)?' : '.*';\n index += slashed ? 3 : 2;\n continue;\n }\n if (char === '*') {\n source += '[^/]*';\n index += 1;\n continue;\n }\n if (char === '?') {\n source += '[^/]';\n index += 1;\n continue;\n }\n source += /[.+^${}()|[\\]\\\\]/.test(char) ? `\\\\${char}` : char;\n index += 1;\n }\n return new RegExp(`^${source}$`);\n}\n\n/** Does this path match any of these glob patterns? Exported for the gate-path\n * unit tests, which pin the matcher's semantics independently of git. */\nexport function matches_any(path: string, patterns: string[]): boolean {\n return patterns.some((pattern) => glob_to_regexp(pattern).test(path));\n}\n\nexport type CollectChangesOptions = {\n /** Where the builder's effects land — the worktree under `--worktree`, else\n * the workspace (`build_root`). */\n root: string;\n /** The run's baseline commit, from `capture_baseline`. */\n baseline: string | null;\n gate_patterns: string[];\n limit?: number;\n};\n\nfunction by_path(left: ChangedFile, right: ChangedFile): number {\n if (left.path < right.path) return -1;\n return left.path > right.path ? 1 : 0;\n}\n\n/**\n * Everything the builder changed in `root` since `baseline`, classified against\n * the gate patterns. Tracked edits come from the diff, brand-new files from the\n * untracked list — together they cover both checkpoint styles, since `--git`\n * commits the builder's work as it goes while a plain run leaves it dirty.\n *\n * Returns null when `root` is not a git repository: the one honest answer, and\n * the signal every consumer uses to omit the section rather than claim the\n * builder changed nothing.\n */\nexport function collect_changes(options: CollectChangesOptions): ChangeSet | null {\n const { root, baseline } = options;\n if (!in_git_repo(root)) return null;\n const limit = options.limit ?? DEFAULT_LIMIT;\n\n // `--relative` + `-- .` keep both halves scoped to the build root and its own\n // path vocabulary, for the case where the workspace sits under a repo root.\n const tracked =\n baseline === null\n ? []\n : parse_name_status(\n git(root, ['diff', '--name-status', '--relative', '-z', baseline, '--', '.']).stdout,\n );\n const untracked: RawChange[] = parse_paths(\n git(root, ['ls-files', '--others', '--exclude-standard', '-z']).stdout,\n ).map((path) => ({ path, status: 'added' }));\n\n const seen = new Set<string>();\n const files: ChangedFile[] = [];\n for (const change of [...tracked, ...untracked]) {\n if (excluded(change.path) || seen.has(change.path)) continue;\n seen.add(change.path);\n files.push({ ...change, gate: matches_any(change.path, options.gate_patterns) });\n }\n const sorted = files.toSorted(by_path);\n\n return {\n baseline,\n // Over the full list, before the cap: truncation must never hide a gate edit.\n gate_edits: sorted.filter((file) => file.gate).map((file) => file.path),\n total: sorted.length,\n files: sorted.slice(0, limit),\n truncated: sorted.length > limit,\n };\n}\n","/**\n * Shared value and type contracts for volley.\n *\n * Type aliases are PascalCase; value-level identifiers are snake_case.\n * Fascicle's usage/cost types are used verbatim so summaries carry the\n * substrate's shapes, not a re-derivation.\n */\nimport type { FinishReason, Throughput, UsageTotals } from 'fascicle';\n\nexport type Verdict = 'approved' | 'changes_requested';\n\nexport type CriticPreset = 'reviewer' | 'optimizer' | 'researcher';\n\n/** Transport for the critic role. The critic is read-only + schema-constrained,\n * so it has always been able to run on a local model. */\nexport type CriticProvider = 'claude_cli' | 'ollama' | 'lmstudio';\n\n/** Transport for the builder role. `claude_cli` is a full agentic Claude Code\n * session; the local providers run the builder as a volley-driven tool loop\n * (write/exec tools supplied by the harness). The execution path for the local\n * providers lands with the builder tool/termination work; this type and its\n * plumbing exist so that work has somewhere to attach (spec v3). */\nexport type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio';\n\nexport type BuilderPermissionMode = 'acceptEdits' | 'bypassPermissions';\n\n/** `auto`, `none`, or any shell command (the `string & {}` keeps the literal\n * hints in editor completions without collapsing the union). */\nexport type CheckMode = 'auto' | 'none' | (string & {});\n\nexport type CheckRunnerKind = 'checkride' | 'command' | 'none';\n\nexport type CostSource = 'provider_reported' | 'engine_derived' | 'unknown';\n\n/** Fascicle's `provider_error.cause_kind` discriminant — why a provider call\n * died. Recorded alongside a critic retry so a degraded run says\n * *what* failed, not just that it retried. */\nexport type CauseKind = 'provider_5xx' | 'network' | 'unknown';\n\nexport type RunStatus =\n | 'running'\n | 'success'\n | 'budget_exhausted'\n | 'cost_cap_reached'\n /** The builder edited the gate that judges it, under `--fail-on-gate-edit`:\n * the run halts on the spot rather than iterating, because a check the builder\n * can rewrite is not evidence the work is done. */\n | 'gate_edit_blocked'\n | 'interrupted'\n | 'error';\n\n/** User-facing configuration, before resolution (config file / flags). */\nexport type VolleyConfig = {\n prompt: string;\n workspace: string;\n criteria: string;\n check?: CheckMode;\n builder_model?: string;\n builder_provider?: BuilderProvider;\n builder_max_steps?: number;\n allow_unsandboxed_builder?: boolean;\n critic_model?: string;\n critic_provider?: CriticProvider;\n builder_permission_mode?: BuilderPermissionMode;\n critic?: CriticPreset | (string & {});\n max_iterations?: number;\n max_cost_usd?: number | null;\n git_checkpoints?: boolean;\n worktree?: boolean;\n discard_worktree?: boolean;\n gate_paths?: string[];\n fail_on_gate_edit?: boolean;\n sandbox_image?: string;\n verbose?: boolean;\n quiet?: boolean;\n json?: boolean;\n show_thinking?: boolean;\n dry_run?: boolean;\n};\n\n/** Fully resolved run configuration; `.volley/config.json` mirrors this. */\nexport type ResolvedConfig = {\n version: 2;\n run_id: string;\n started_at: string;\n prompt: string;\n criteria: string;\n check: CheckMode;\n check_resolved: CheckRunnerKind;\n builder_model: string;\n builder_provider: BuilderProvider;\n builder_max_steps: number;\n /** Operator opt-out permitting a local (non-`claude_cli`) builder to run\n * without a sandbox — it gets a real host bash. Refused by default. */\n allow_unsandboxed_builder: boolean;\n critic_model: string;\n critic_provider: CriticProvider;\n builder_permission_mode: BuilderPermissionMode;\n critic_preset: CriticPreset | 'custom';\n critic_prompt_path: string | null;\n max_iterations: number;\n max_cost_usd: number | null;\n git_checkpoints: boolean;\n /** Isolate the builder run's effects in a per-run git worktree: the\n * builder/critic file tools' containment root moves to the worktree, while\n * `.volley/` state stays under `workspace` (the control plane). Off by\n * default; requires the workspace to be a git repository. */\n worktree: boolean;\n /** Throw a `--worktree` run's effects away at teardown even when it converged:\n * the run branch is force-deleted rather than kept, because only the\n * verdicts are wanted. This is what `volley matrix` sweeps with — one config,\n * many builder×critic seats, no per-seat commits or branches left anywhere.\n * Refused without `--worktree`; `--git` still wins, so a `--worktree --git`\n * run integrates exactly as it always has. */\n discard_worktree: boolean;\n /** Glob patterns naming the *gate*: the tests, fixtures, and check\n * configuration that decide whether the builder's work passes. An edit to one\n * is reported to the critic and recorded in the summary — and refused outright\n * under `fail_on_gate_edit`. Defaults to `DEFAULT_GATE_PATTERNS`; a config's\n * own list replaces it, because what counts as the gate is the task's call\n * (a test-writing task edits tests by design). */\n gate_paths: string[];\n /** Halt the run when the builder edits a `gate_paths` match, instead of\n * reporting it and continuing. Off by default: a gate edit is legitimate often\n * enough that refusing it by default would break honest tasks, and the mark on\n * the summary already makes it impossible to miss. */\n fail_on_gate_edit: boolean;\n /** Container image the local-builder Docker sandbox runs. Defaults to\n * volley's own `Dockerfile`-built image; `--sandbox-image <tag>` /\n * `VOLLEY_SANDBOX_IMAGE` override it. Meaningful only for a local builder —\n * the `claude_cli` path never uses Docker. */\n sandbox_image: string;\n workspace: string;\n verbose: boolean;\n quiet: boolean;\n json: boolean;\n show_thinking: boolean;\n};\n\n/** One failing check slot's raw artifact, for the critic prompt. */\nexport type CheckArtifact = {\n slot: string;\n path: string | null;\n content: string;\n truncated: boolean;\n};\n\nexport type CheckResult = {\n ran: boolean;\n runner: CheckRunnerKind;\n ok: boolean;\n exit_code: number | null;\n duration_ms: number;\n failing_slots: string[];\n detail: CheckArtifact[];\n /** Raw checkride summary JSON (when the runner is checkride). */\n summary?: unknown;\n /** Captured combined output (when the runner is a shell command). */\n log?: string;\n};\n\n/** How one path changed between the run's baseline and the builder's output.\n * `renamed` covers git's rename/copy detection (the destination path is the one\n * recorded); `unknown` is any status git reports that none of these name. */\nexport type ChangeStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'unknown';\n\n/** One path the builder changed, and whether that path is part of the *gate* —\n * the tests, fixtures, and check configuration that decide whether the work\n * passes. A gate edit is not misconduct by itself (some tasks are *about* the\n * tests); it is the fact that makes a green check prove less. */\nexport type ChangedFile = {\n path: string;\n status: ChangeStatus;\n gate: boolean;\n};\n\n/** What the builder changed since the run's baseline, as the harness sees it\n * (`src/changes.ts`). Null in `LoopState` when the build root is not a git\n * repository — change detection is evidence, never a precondition. */\nexport type ChangeSet = {\n /** The commit the changes are measured against — the build root's HEAD before\n * the first iteration. Null in a repository with no commits yet, where only\n * untracked files can be reported. */\n baseline: string | null;\n /** The changed paths, sorted, capped at the collection limit. */\n files: ChangedFile[];\n /** Every gate-matching path — computed over the *full* list before the cap,\n * so truncation can never hide a gate edit. */\n gate_edits: string[];\n /** How many paths changed in total, before the cap. */\n total: number;\n truncated: boolean;\n};\n\n/** Per-phase record for iteration summaries. */\nexport type PhaseRecord = {\n provider: string;\n model: string;\n session_id: string | null;\n /** Wall-clock of the phase's model work, the same measure for every provider\n * so an all-local run and an all-Claude run compare directly. The builder's is\n * fascicle's `GenerateResult.timing`: the whole call, every turn and the tools\n * between them. The critic's spans its whole degradation ladder, failed\n * attempts included, since no one result's timing covers the attempts before\n * it. Neither counts the Ollama prewarm. */\n duration_ms: number;\n usage: UsageTotals;\n cost_usd: number | null;\n cost_source: CostSource;\n /** How the phase's generate call ended. For a local builder,\n * `'max_steps'` is a budget cutoff surfaced as a warning, not an error. */\n finish_reason: FinishReason;\n /** Tool calls fascicle executed in this phase, and how many were recovered\n * from assistant text rather than returned structurally — the raw\n * counts behind the salvage-rate health metric. */\n tool_calls: number;\n salvaged_tool_calls: number;\n /** Provider-error retries that preceded this phase's successful call\n * — the local-critic degradation ladder's first rung: a stochastic\n * Ollama stream death is retried once before falling back. Set on the critic\n * record (0 when the first call succeeded); absent on the builder, which is\n * not retried this build. Additive — old summary consumers ignore it. */\n retries?: number;\n /** The `cause_kind` of the retried provider error, recorded with `retries`.\n * Absent when no retry happened. */\n retry_cause_kind?: CauseKind;\n /** This local-critic verdict was rendered by the tool-less fallback rung:\n * the tool-bearing critique kept dying on the provider's stream\n * even after the bounded retry, so the critic judged with no read access —\n * grounded only by the criteria, the raw check artifacts, and a workspace file\n * inventory. Set (true) on a degraded critic record; absent on a full\n * critique and on the builder. Additive, and a degraded verdict is *always*\n * marked so it never passes silently as a full one. */\n critic_degraded?: boolean;\n /** Output tokens per second over the model's own turns (tool execution and\n * retry backoff excluded), from fascicle's per-step timing. `basis` is\n * `decode` when every turn streamed, `blended` when any round trip counted\n * prefill and network too — always the case for `claude_cli`, whose rate\n * fascicle derives from the CLI's reported API time. Absent when no turn\n * carried timing. Additive. */\n throughput?: Throughput;\n};\n\nexport type HaltReason = 'cost_cap' | 'gate_edit' | null;\n\n/** Carry-state threaded through the fascicle loop. */\nexport type LoopState = {\n iteration: number;\n iteration_started_at: string;\n feedback: string | null;\n verdict: Verdict | null;\n unmet_criteria: string[];\n check: CheckResult | null;\n /** What the builder changed this iteration, measured against the run's\n * baseline (`src/changes.ts`). Null when the build root is not a git\n * repository, and before the first `build` step of a run. */\n changes: ChangeSet | null;\n builder: PhaseRecord | null;\n critic: PhaseRecord | null;\n total_usage: UsageTotals;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n check_duration_ms: number;\n iteration_cost_usd: number;\n halt: HaltReason;\n cost_warned: boolean;\n};\n\nexport type RunInput = {\n resume_from: LoopState | null;\n};\n\n/** Projection of final loop state; `.volley/summary.json` mirrors this. */\nexport type RunResult = {\n run_id: string;\n status: RunStatus;\n started_at: string;\n completed_at: string | null;\n iterations_completed: number;\n total_usage: UsageTotals;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n check_duration_ms: number;\n final_verdict: Verdict | null;\n /** The run branch teardown left behind because this run's work was never\n * integrated: under `--worktree` without `--git` a converged run has no\n * other copy of its effects, so teardown commits them onto `volley/<run id>`\n * and keeps the branch instead of force-deleting it. Null whenever nothing\n * survived — every non-worktree run, every integrated run, every discarded\n * one. `--json` consumers read it here; `.volley/summary.json` mirrors it. */\n salvaged_branch: string | null;\n};\n\nexport type VolleyPhase = 'builder' | 'critic' | 'check';\n\n/** Recoverable domain failures surface as `kind`-tagged Error values (the\n * same discrimination style as fascicle's error taxonomy) so the top-level\n * handler maps them to exit codes without string matching or instanceof. */\nexport type ConfigError = Error & { kind: 'config_error' };\n\nexport type CheckError = Error & { kind: 'check_error' };\n\nexport type PhaseError = Error & {\n kind: 'phase_error';\n phase: VolleyPhase;\n iteration: number;\n cause: unknown;\n};\n\nexport function config_error(message: string): ConfigError {\n return Object.assign(new Error(message), { kind: 'config_error' as const });\n}\n\nexport function check_error(message: string): CheckError {\n return Object.assign(new Error(message), { kind: 'check_error' as const });\n}\n\n/** Wraps a provider/schema failure with the phase and iteration it hit. */\nexport function phase_error(\n phase: VolleyPhase,\n iteration: number,\n cause: unknown,\n): PhaseError {\n const detail = cause instanceof Error ? cause.message : String(cause);\n return Object.assign(\n new Error(`${phase} failed on iteration ${iteration}: ${detail}`),\n { kind: 'phase_error' as const, phase, iteration, cause },\n );\n}\n\nexport function error_kind(err: unknown): string | null {\n if (typeof err === 'object' && err !== null && 'kind' in err) {\n const kind = (err as { kind: unknown }).kind;\n return typeof kind === 'string' ? kind : null;\n }\n return null;\n}\n","/**\n * The shell around the volley flow (`./flow.ts`): set up the workspace, wrap\n * the run in the worktree lifecycle, execute the flow with a single `run` call,\n * and turn its outcome into the run summary. No hand-rolled runner — rounds,\n * abort threading, signal handlers, and cleanup order all belong to the\n * substrate.\n *\n * run_volley\n * ├─ initialize the workspace (or preserve it, on resume)\n * ├─ with_worktree off unless --worktree\n * │ ├─ capture the change baseline\n * │ ├─ run_loop run(build_flow(...)), then the final summary\n * │ └─ integrate a successful --worktree --git run only\n * └─ report a kept checkout, or a salvaged branch (re-stamping the summary)\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { run } from 'fascicle';\nimport { filesystem_logger } from 'fascicle/adapters';\nimport type { Engine } from 'fascicle';\nimport type { BashExecutor } from './builder/tools.js';\nimport { capture_baseline } from './changes.js';\nimport { create_volley_engine } from './engine.js';\nimport { build_flow } from './flow.js';\nimport { run_result_from_state } from './iteration.js';\nimport { initial_state, status_of } from './loop_state.js';\nimport { write_run_summary } from './summary.js';\nimport type { Renderer } from './render/renderer.js';\nimport { error_kind } from './types.js';\nimport type { LoopState, ResolvedConfig, RunResult, RunStatus } from './types.js';\nimport {\n initialize_workspace,\n integrate_worktree,\n volley_path,\n write_resolved_config,\n} from './workspace.js';\nimport {\n build_root,\n report_worktree_fate,\n with_worktree,\n worktree_branch,\n worktree_fate,\n} from './worktree.js';\n\nexport type OrchestratorDeps = {\n renderer: Renderer;\n engine?: Engine;\n abort?: AbortSignal;\n install_signal_handlers?: boolean;\n};\n\nexport async function run_volley(\n config: ResolvedConfig,\n deps: OrchestratorDeps,\n resume_from: LoopState | null = null,\n): Promise<RunResult> {\n const { renderer } = deps;\n\n if (resume_from === null) {\n initialize_workspace(config.workspace);\n write_resolved_config(config);\n } else {\n initialize_workspace(config.workspace, { preserve: true });\n }\n\n // Say what this run will do with its effects before it spends anything — the\n // same notice `--dry-run` prints, repeated here so a run started without a dry\n // run still hears it (the same predict-then-warn shape).\n report_worktree_fate(config, renderer);\n\n // The worktree lifecycle wraps the whole builder loop: created before the\n // first iteration, torn down after the last. Off unless `--worktree` is set\n // (config.worktree), so the default path never touches git here.\n const branch = worktree_branch(config.run_id);\n const fate = worktree_fate(config);\n const outcome = await with_worktree<RunResult>(\n {\n enabled: config.worktree,\n workspace: config.workspace,\n branch,\n log: (message) => renderer.info(message),\n // The one case teardown must keep rather than force-delete: a converged run\n // that integrated nothing, whose only copy of its work is the worktree.\n salvage: (result) => fate === 'salvage' && result.status === 'success',\n },\n async () => {\n // Whole-process containment: volley runs *inside* its hardened\n // container already — the operator/example's `docker run … <volley args>`\n // launched it — so there is no container lifecycle to orchestrate here. `bash`\n // is the local `host_bash_executor` running in-container (null executor,\n // the host `spawnSync` default) and the file tools write straight to the\n // bind-mounted worktree; the retired `docker exec` path is gone. The\n // hardened `docker run` invocation spec the example uses lives in\n // `src/sandbox.ts`.\n // The commit every iteration's change set is measured against, read after\n // the worktree exists and before the builder writes anything. Null when the\n // build root is not a git repo — then the run reports no changes at all\n // rather than guessing at them.\n const baseline = capture_baseline(build_root(config.workspace, config.worktree));\n const result = await run_loop(config, deps, resume_from, null, baseline);\n // Integration: a *successful* `--worktree --git` run squash-merges the\n // phase branch's checkpoints onto the workspace branch before teardown\n // discards it. Any non-success outcome (cost cap, budget, interrupt,\n // error) is abandoned — teardown discards the branch wholesale, nothing\n // integrated. Gated on `--git` too (`fate === 'integrate'`), so volley only\n // commits to the workspace branch when the operator opted into checkpoints;\n // without it the same work is salvaged onto its own branch instead.\n if (fate === 'integrate' && result.status === 'success') {\n integrate_worktree(config.workspace, branch, `volley run ${config.run_id}: integrate worktree (squash)`);\n renderer.info(`worktree: squash-merged ${branch} onto the workspace branch`);\n }\n return result;\n },\n );\n\n if (outcome.kept_path !== null) {\n renderer.warn(\n `worktree: could not commit this run's work onto ${branch}, so the checkout at ` +\n `${outcome.kept_path} was left standing rather than deleted — its files are intact, and ` +\n 'the next --worktree run rotates the directory aside instead of destroying it.',\n );\n }\n if (outcome.salvaged_branch === null) return outcome.value;\n renderer.info(\n `worktree: this run was not integrated; its work is preserved on branch ` +\n `${outcome.salvaged_branch} (git switch ${outcome.salvaged_branch}, or cherry-pick it).`,\n );\n // Teardown salvaged the branch *after* `run_loop` wrote the final summary, so\n // re-stamp it: `.volley/summary.json` and `--json` both name the survivor.\n const salvaged: RunResult = { ...outcome.value, salvaged_branch: outcome.salvaged_branch };\n write_run_summary(config, salvaged);\n return salvaged;\n}\n\nasync function run_loop(\n config: ResolvedConfig,\n deps: OrchestratorDeps,\n resume_from: LoopState | null,\n bash_executor: BashExecutor | null,\n baseline: string | null,\n): Promise<RunResult> {\n const { renderer } = deps;\n\n const engine =\n deps.engine ??\n create_volley_engine({\n workspace: config.workspace,\n builder_provider: config.builder_provider,\n critic_provider: config.critic_provider,\n });\n\n const flow = build_flow({ engine, config, renderer, bash_executor, baseline }, resume_from);\n\n try {\n const { value, converged } = await run(\n flow,\n { resume_from },\n {\n trajectory: filesystem_logger({\n output_path: volley_path(config.workspace, 'trajectory.jsonl'),\n }),\n ...(deps.abort !== undefined ? { abort: deps.abort } : {}),\n ...(deps.install_signal_handlers !== undefined\n ? { install_signal_handlers: deps.install_signal_handlers }\n : {}),\n },\n );\n const status = status_of(value, converged);\n const result = run_result_from_state(config, value, status, new Date().toISOString());\n write_run_summary(config, result);\n return result;\n } catch (err) {\n finalize_failed_run(config, err);\n throw err;\n } finally {\n await engine.dispose();\n }\n}\n\n/** Best-effort status stamp on the run summary when the loop threw; the\n * on-disk iteration state is already consistent (record runs per round). */\nfunction finalize_failed_run(config: ResolvedConfig, err: unknown): void {\n const kind = error_kind(err);\n const cause = kind === 'phase_error' ? error_kind((err as { cause?: unknown }).cause) : null;\n const status: RunStatus =\n kind === 'aborted_error' || cause === 'aborted_error' ? 'interrupted' : 'error';\n try {\n // Preserve accumulated totals when `record` already wrote a summary.\n const summary_path = volley_path(config.workspace, 'summary.json');\n const prior = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : run_result_from_state(config, initial_state(), status, null);\n write_run_summary(config, {\n ...prior,\n status,\n completed_at: new Date().toISOString(),\n });\n } catch {\n // Never mask the original failure with a bookkeeping error.\n }\n}\n","/**\n * The ONLY module that calls fascicle's `create_engine`. Every\n * other module receives an `Engine`-shaped value, which keeps the engine\n * mockable in tests and confines provider knowledge to one seam.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { create_engine } from 'fascicle';\nimport type { Engine, ProviderConfigMap, PricingTable } from 'fascicle';\nimport { config_error } from './types.js';\nimport type { BuilderProvider, CriticProvider } from './types.js';\n\nexport type { Engine } from 'fascicle';\n\n/** LM Studio's OpenAI-compatible server and Ollama's server-root defaults.\n * The Ollama URL is the server root, NOT `…/api`: `ai-sdk-ollama` appends\n * `/api/...` itself, so a base URL ending in `/api` requests `/api/api/chat`\n * and 404s. */\nexport const DEFAULT_OLLAMA_URL = 'http://localhost:11434';\nexport const DEFAULT_LMSTUDIO_URL = 'http://localhost:1234/v1';\n\n/** Loopback authorities the container→host crossing rewrites. A base URL\n * pointing at one of these is local to wherever volley runs; contained, that is\n * *inside* the sandbox container, where the host LLM daemon is unreachable\n * except across the boundary at `VOLLEY_MODEL_HOST`. */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '0.0.0.0']);\n\n/** Cross a loopback base URL to the host LLM endpoint. When volley\n * runs inside its sandbox container the local model daemon is on the *host*, so\n * the example's `docker run` injects `VOLLEY_MODEL_HOST=host.docker.internal`\n * (the host-gateway allowlist target; see `sandbox_invocation` in\n * `src/sandbox.ts`). This normalizer *consumes that override* and swaps a\n * loopback host for the gateway, so an unchanged `http://localhost:11434` still\n * reaches the host from in-container. A non-loopback URL (a real remote daemon)\n * is left untouched, and an unset `VOLLEY_MODEL_HOST` (the host / unsandboxed\n * path) is a no-op — so the default and all-Claude paths are unaffected. */\nexport function cross_to_host_gateway(\n base_url: string,\n env: Record<string, string | undefined>,\n): string {\n const host = env['VOLLEY_MODEL_HOST'];\n if (host === undefined || host === '') return base_url;\n let parsed: URL;\n try {\n parsed = new URL(base_url);\n } catch {\n return base_url;\n }\n if (!LOOPBACK_HOSTS.has(parsed.hostname.toLowerCase())) return base_url;\n parsed.hostname = host;\n // `URL` re-serializes `http://host:port` with a trailing `/`; drop it so the\n // Ollama server-root shape (no path) is preserved, while a real path (LM\n // Studio's `/v1`) is left intact.\n return parsed.toString().replace(/\\/$/, '');\n}\n\n/** The Ollama base URL from the environment or the localhost default,\n * normalized to the server root. A trailing `/api` (the pre-v0.3.1 documented\n * default, and a natural mistake since Ollama's REST paths all start with it)\n * is stripped rather than left to 404 every request, then a loopback authority\n * is crossed to the host LLM endpoint when volley runs contained. */\nexport function resolve_ollama_base_url(env: Record<string, string | undefined>): string {\n const raw = env['VOLLEY_OLLAMA_URL'] ?? DEFAULT_OLLAMA_URL;\n const normalized = raw.replace(/\\/+$/, '').replace(/\\/api$/, '');\n return cross_to_host_gateway(normalized, env);\n}\n\nfunction load_pricing_overrides(path: string): PricingTable {\n if (!existsSync(path)) {\n throw config_error(`VOLLEY_PRICING_PATH not found: ${path}`);\n }\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as PricingTable;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw config_error(`VOLLEY_PRICING_PATH is not valid JSON: ${detail}`);\n }\n}\n\nexport type EngineOptions = {\n workspace: string;\n /** When the builder runs on a local model, its provider is configured\n * alongside claude_cli so one engine drives both roles. */\n builder_provider?: BuilderProvider;\n /** When the critic runs on a local model, its provider is configured\n * alongside claude_cli so one engine drives both roles. */\n critic_provider?: CriticProvider;\n env?: Record<string, string | undefined>;\n};\n\n/** The local (non-CLI) providers a role can select. `claude_cli` needs no\n * ai-sdk wiring, so it never appears here. */\ntype LocalProvider = 'ollama' | 'lmstudio';\n\nfunction is_local_provider(\n provider: BuilderProvider | CriticProvider | undefined,\n): provider is LocalProvider {\n return provider === 'ollama' || provider === 'lmstudio';\n}\n\n/** Add a local provider (ollama/lmstudio) to the provider map, with a base URL\n * from the environment or a sensible localhost default. The ai-sdk peer\n * (`ai-sdk-ollama` / `@ai-sdk/openai-compatible`) is loaded lazily by fascicle\n * only when the provider actually runs.\n *\n * Native transport is the deferred future bridge, not adopted here: volley stays\n * on the ai_sdk transport, which fascicle 0.12.13 already selects by default\n * (`transport?: 'ai_sdk' | 'native'` defaults to `'ai_sdk'`), so no field is\n * needed today. Flipping later is a one-line change — add `transport: 'native'`\n * to the ollama/lmstudio config object returned below. No URL re-pointing is\n * required: `resolve_ollama_base_url` already yields the daemon-root URL the\n * native `/api/chat` transport wants (its adapter appends `/api/chat` itself),\n * which is exactly what the v0.3.1 base-URL fix produces. Kept as a\n * proven-once-then-reverted option so the transport stays a clean second variable\n * in the model-vs-transport comparison.\n *\n * Both providers' base URLs cross a loopback authority to `VOLLEY_MODEL_HOST` when\n * volley runs contained, so an in-container model client reaches the\n * host LLM endpoint at `host.docker.internal`; on the host / unsandboxed path the\n * override is unset and this is a no-op. */\nfunction local_provider_config(\n provider: LocalProvider,\n env: Record<string, string | undefined>,\n): ProviderConfigMap {\n if (provider === 'ollama') {\n return { ollama: { base_url: resolve_ollama_base_url(env) } };\n }\n const lmstudio_url = env['VOLLEY_LMSTUDIO_URL'] ?? DEFAULT_LMSTUDIO_URL;\n return { lmstudio: { base_url: cross_to_host_gateway(lmstudio_url, env) } };\n}\n\n/** Per-run engine. `claude_cli` is always configured with the workspace as its\n * session cwd; any local provider selected by the builder or critic role is\n * wired in alongside it so one engine drives both roles. Binary, auth mode,\n * provider URLs, and pricing come from the environment. */\nexport function create_volley_engine(options: EngineOptions): Engine {\n const env = options.env ?? process.env;\n\n const auth_mode = env['VOLLEY_AUTH_MODE'] ?? 'auto';\n if (auth_mode !== 'auto' && auth_mode !== 'oauth' && auth_mode !== 'api_key') {\n throw config_error(\n `VOLLEY_AUTH_MODE must be auto, oauth, or api_key; got: ${auth_mode}`,\n );\n }\n\n const binary = env['VOLLEY_CLAUDE_BIN'];\n const pricing_path = env['VOLLEY_PRICING_PATH'];\n\n // A run may select a local provider for the builder, the critic, or both\n // (even two different ones). Wire each distinct local provider once.\n const local_providers = new Set<LocalProvider>();\n if (is_local_provider(options.builder_provider)) local_providers.add(options.builder_provider);\n if (is_local_provider(options.critic_provider)) local_providers.add(options.critic_provider);\n\n const providers: ProviderConfigMap = {\n claude_cli: {\n default_cwd: options.workspace,\n setting_sources: ['project', 'local'],\n auth_mode,\n ...(binary !== undefined && binary.length > 0 ? { binary } : {}),\n ...(auth_mode === 'api_key' && env['ANTHROPIC_API_KEY'] !== undefined\n ? { api_key: env['ANTHROPIC_API_KEY'] }\n : {}),\n },\n };\n for (const provider of local_providers) {\n Object.assign(providers, local_provider_config(provider, env));\n }\n\n return create_engine({\n providers,\n ...(pricing_path !== undefined && pricing_path.length > 0\n ? { pricing: load_pricing_overrides(pricing_path) }\n : {}),\n });\n}\n","/**\n * The volley flow: the whole topology of one run, and nothing else. Step bodies\n * live in `./phases.ts`, the model boundaries in `./builder.ts` and\n * `./critic/run.ts`, the stopping rule in `./loop_state.ts`, and the shell\n * around the flow (workspace setup, the worktree lifecycle, `run`, the final\n * summary) in `./orchestrator.ts`.\n *\n * fascicle's `describe.diagram` draws the tree below from the flow itself, and\n * `test/unit/flow_diagram.test.ts` holds it to the code: change a row by changing\n * its step's `description`, then paste `pnpm diagram --prefix ' * '` over it.\n *\n * volley loop: one round per iteration, up to max_iterations\n * ├─ iteration sequence\n * │ ├─ build open the iteration, run the builder, measure the change\n * │ │ └─ builder model call: one agentic session in the build root\n * │ ├─ verify branch: did the build alone cross the cost cap?\n * │ │ ├─ then skip_verify record the check as skipped and call no critic\n * │ │ └─ else sequence\n * │ │ ├─ check the deterministic gate: checkride, a command, or none\n * │ │ └─ critique the read-only critic's verdict and feedback\n * │ │ └─ critic fallback: judge without tools if a local critic's stream keeps dying\n * │ │ ├─ retry one more try after a stream death, local providers only\n * │ │ │ └─ critic_tools model call with read-only workspace tools\n * │ │ └─ pipe mark the verdict degraded\n * │ │ └─ critic_toolless model call judging from the check output and a file list\n * │ └─ record archive the iteration and rewrite the run summary\n * └─ guard gate stop on approval over a green check, the cost cap, or a gate edit\n */\nimport { branch, fallback, loop, pipe, retry, sequence, step } from 'fascicle';\nimport type { Engine, Step } from 'fascicle';\nimport { make_builder_step } from './builder.js';\nimport type { BashExecutor } from './builder/tools.js';\nimport { cost_cap_hit } from './cost.js';\nimport {\n as_degraded,\n critic_retryable,\n make_critic_toolless_step,\n make_critic_tools_step,\n MAX_CRITIC_RETRIES,\n toolless_critic_prompt,\n with_fallback_cause,\n with_retries,\n} from './critic/run.js';\nimport type { CriticDeps, CriticStep } from './critic/run.js';\nimport { gate, initial_state, remaining_iterations } from './loop_state.js';\nimport {\n build_phase,\n check_phase,\n critique_phase,\n record_phase,\n skip_verify_phase,\n} from './phases.js';\nimport type { PhaseDeps } from './phases.js';\nimport type { LoopState, RunInput } from './types.js';\n\n/** What the flow is built from: the step bodies' dependencies, plus the engine\n * and `bash` executor its model boundaries are wired to. */\nexport type FlowDeps = PhaseDeps & {\n engine: Engine;\n /** The local builder's `bash` executor, or null for the host `spawnSync`\n * default (and for `claude_cli`, which supplies no volley tools). */\n bash_executor: BashExecutor | null;\n};\n\n/** What the flow resolves to: the final state, and whether the guard stopped the\n * loop (success, the cost cap, a gate edit) rather than the round budget. */\nexport type LoopOutcome = { value: LoopState; converged: boolean };\n\n/** The critic arm: the degradation ladder. A local critic whose tool-bearing\n * stream dies is retried at once (the death is stochastic parser failure, not\n * load, so waiting buys nothing), then judged once without tools; anything the\n * ladder does not retry propagates from either rung untouched. */\nexport function build_critic(deps: CriticDeps): CriticStep {\n const retryable = critic_retryable(deps.config);\n return fallback(\n retry(make_critic_tools_step(deps), {\n description: 'one more try after a stream death, local providers only',\n max_attempts: MAX_CRITIC_RETRIES + 1,\n backoff_ms: 0,\n when: retryable,\n project: with_retries,\n }),\n pipe(make_critic_toolless_step(deps), as_degraded, {\n description: 'mark the verdict degraded',\n }),\n {\n name: 'critic',\n description: \"judge without tools if a local critic's stream keeps dying\",\n when: retryable,\n handoff: (prompt) => toolless_critic_prompt(deps.config, prompt),\n project: with_fallback_cause,\n },\n );\n}\n\nexport function build_flow(\n deps: FlowDeps,\n resume_from: LoopState | null,\n): Step<RunInput, LoopOutcome> {\n const { config, renderer } = deps;\n\n const builder = make_builder_step({\n engine: deps.engine,\n config,\n on_chunk: renderer.builder_chunk,\n bash_executor: deps.bash_executor,\n });\n const critic = build_critic({ engine: deps.engine, config, on_chunk: renderer.critic_chunk });\n\n // `build` and `critique` hand their model boundary to `ctx.call` from inside\n // the body, because the prompt comes from the carried state and the result\n // folds back into it. Each declares that boundary as its `arm`, so it shows\n // up under the step in `describe` and the trajectory's flow structure.\n const build = step('build', (s: LoopState, ctx) => build_phase(deps, builder, s, ctx), {\n description: 'open the iteration, run the builder, measure the change',\n arm: builder,\n });\n const skip_verify = step('skip_verify', (s: LoopState) => skip_verify_phase(deps, s), {\n description: 'record the check as skipped and call no critic',\n });\n const check = step('check', (s: LoopState, ctx) => check_phase(deps, s, ctx), {\n description: 'the deterministic gate: checkride, a command, or none',\n });\n const critique = step(\n 'critique',\n (s: LoopState, ctx) => critique_phase(deps, critic, s, ctx),\n { description: \"the read-only critic's verdict and feedback\", arm: critic },\n );\n const record = step('record', (s: LoopState) => record_phase(deps, s), {\n description: 'archive the iteration and rewrite the run summary',\n });\n\n const verify: Step<LoopState, LoopState> = branch({\n name: 'verify',\n description: 'did the build alone cross the cost cap?',\n when: (s: LoopState) => cost_cap_hit(config, s),\n // fascicle names this arm `then`. It holds a Step object, never a function,\n // so nothing can mistake the config for a thenable.\n // oxlint-disable-next-line unicorn/no-thenable\n then: skip_verify,\n otherwise: sequence([check, critique]),\n });\n\n const iteration: Step<LoopState, LoopState> = sequence([build, verify, record], {\n name: 'iteration',\n });\n\n return loop<RunInput, LoopState, LoopOutcome>({\n name: 'volley',\n description: 'one round per iteration, up to max_iterations',\n init: (input) => input.resume_from ?? initial_state(),\n body: iteration,\n guard: step('gate', (s: LoopState) => gate(config, s), {\n description: 'stop on approval over a green check, the cost cap, or a gate edit',\n }),\n finish: (s, { converged }) => ({ value: s, converged }),\n max_rounds: remaining_iterations(config, resume_from),\n });\n}\n","/**\n * Builder invocation: one call to the builder leaf per iteration is one\n * complete agentic session in the workspace — Claude Code under `claude_cli`,\n * or a local model driving volley's tools.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { model_call } from 'fascicle';\nimport type {\n Engine,\n GenerateOptions,\n GenerateResult,\n ModelCallInput,\n RunContext,\n Step,\n StreamChunk,\n} from 'fascicle';\nimport { warn_small_local_context } from './builder/context_check.js';\nimport { builder_tools, type BashExecutor } from './builder/tools.js';\nimport { accumulate } from './cost.js';\nimport { resolve_ollama_base_url } from './engine.js';\nimport { prewarm_ollama_model } from './prewarm.js';\nimport { config_error, phase_error } from './types.js';\nimport type { LoopState, ResolvedConfig } from './types.js';\nimport { build_root } from './worktree.js';\n\nexport const BUILDER_ALLOWED_TOOLS = [\n 'Read',\n 'Write',\n 'Edit',\n 'MultiEdit',\n 'Bash',\n 'Grep',\n 'Glob',\n 'WebFetch',\n] as const;\n\nexport function compose_builder_system(): string {\n return [\n 'You are the builder inside the volley harness: an autonomous agent',\n 'iterating on a workspace until it satisfies a task and its acceptance',\n 'criteria. Work directly in the current working directory. Plan',\n 'internally, make the changes, and verify your own work before finishing.',\n ].join('\\n');\n}\n\n/** Walk up from this module to the package root (works from src/ under tsx\n * and from dist/ in the published package, which ships src/builder/presets). */\nexport function presets_dir(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(dir, 'src', 'builder', 'presets');\n if (existsSync(candidate)) return candidate;\n dir = dirname(dir);\n }\n throw config_error('builder presets directory not found');\n}\n\n// The CLI system prompt assumes CLI semantics (built-in tools, implicit\n// cwd), so the local builder gets its own — the volley tool set, the\n// workspace-is-cwd convention, and the harness-enforced `finish` stop.\nexport function compose_builder_system_local(): string {\n const identity = [\n 'You are the builder inside the volley harness: an autonomous agent',\n 'iterating on a workspace until it satisfies a task and its acceptance',\n 'criteria.',\n ].join('\\n');\n const append = readFileSync(join(presets_dir(), 'harness_append_local.md'), 'utf8');\n return `${identity}\\n\\n${append.trimEnd()}`;\n}\n\n/** The builder system prompt for the active provider: the `claude_cli`\n * prompt (implicit built-in tools, \"the current working directory\") for the\n * CLI builder, or the local prompt (volley's tool set, workspace-is-cwd, and\n * the harness-enforced `finish` stop) for a local model. Mirrors the critic's\n * `resolve_critic_prompt`. */\nfunction resolve_builder_system(config: ResolvedConfig): string {\n return config.builder_provider === 'claude_cli'\n ? compose_builder_system()\n : compose_builder_system_local();\n}\n\n// Salvage budget for a tool call a local model emits as assistant text instead\n// of a structured tool_call (Hermes / json-fenced / Qwen3-Coder XML). Must be\n// > 0 to turn salvage on; the budget is shared across the whole\n// generate call and each salvage is observable on the result for the\n// salvage-rate health metric.\nconst BUILDER_TOOL_CALL_REPAIR_ATTEMPTS = 3;\n\n/** Per-provider tool wiring for the builder, mirroring `critic_tool_options`.\n * The `claude_cli` builder is confined at the CLI permission layer (allowlist +\n * permission mode) and brings its own built-in tools — this arm is unchanged\n * from v2. A local builder brings none, so volley supplies its whole\n * workspace tool surface plus the five per-call loop knobs and **no**\n * schema (it produces a workspace, not a verdict); per-call values win over\n * engine defaults. */\nfunction builder_tool_options(\n config: ResolvedConfig,\n bash_executor: BashExecutor | null,\n): Pick<\n GenerateOptions,\n | 'tools'\n | 'provider_options'\n | 'max_steps'\n | 'tool_error_policy'\n | 'tool_call_repair_attempts'\n | 'max_tool_calls_per_step'\n> {\n if (config.builder_provider === 'claude_cli') {\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...BUILDER_ALLOWED_TOOLS],\n extra_args: ['--permission-mode', config.builder_permission_mode],\n },\n },\n };\n }\n return {\n // Containment root re-points to the worktree under `--worktree`, so\n // the model's writes, edits, and `bash` cwd land there and leave the\n // workspace untouched. When the sandbox is active its `docker exec` executor\n // runs `bash` in the container against the bind-mounted worktree; the\n // host `spawnSync` default stands in otherwise.\n tools: builder_tools(\n build_root(config.workspace, config.worktree),\n bash_executor !== null ? { bash_executor } : {},\n ),\n max_steps: config.builder_max_steps,\n tool_error_policy: 'feed_back',\n tool_call_repair_attempts: BUILDER_TOOL_CALL_REPAIR_ATTEMPTS,\n max_tool_calls_per_step: 1,\n };\n}\n\nexport type BuilderPromptInput = {\n task: string;\n criteria: string;\n feedback: string | null;\n iteration: number;\n checkride: boolean;\n};\n\nexport function compose_builder_prompt(input: BuilderPromptInput): string {\n const parts = [\n 'TASK',\n '----',\n input.task,\n '',\n 'ACCEPTANCE CRITERIA',\n '-------------------',\n input.criteria,\n '',\n `ITERATION: ${input.iteration}`,\n ];\n if (input.iteration > 1 && input.feedback !== null) {\n parts.push(\n '',\n 'PREVIOUS CRITIC FEEDBACK',\n '------------------------',\n input.feedback,\n '',\n 'Address the feedback above. The workspace already contains your prior work;',\n 'read the current state, then make the necessary changes.',\n );\n }\n if (input.checkride) {\n parts.push(\n '',\n 'The definition of done for this workspace includes `pnpm check` (checkride)',\n 'exiting 0. Run it yourself before finishing; on failure, read',\n '.check/summary.json, then the failing slot\\'s raw output, fix, and re-run.',\n );\n }\n return parts.join('\\n');\n}\n\n// A `max_steps` cutoff is not an error. The local builder burned its whole\n// step budget without calling `finish`, so its partial workspace goes to check\n// + critic exactly like a `finish`-terminated iteration (the critic sees\n// incomplete work and requests changes, the loop continues). The renderer\n// surfaces this as a warning and `finish_reason: 'max_steps'` is recorded in\n// the iteration summary — non-convergence is data, not an exception.\nfunction builder_max_steps_warning(max_steps: number): string {\n return (\n `builder hit the ${String(max_steps)}-step limit without calling finish; ` +\n 'handing the partial workspace to check + critic (raise --builder-max-steps if this recurs)'\n );\n}\n\nexport type BuilderDeps = {\n engine: Engine;\n config: ResolvedConfig;\n on_chunk: (chunk: StreamChunk) => void;\n /** The `bash` executor for a sandboxed local builder (`docker exec` against\n * the run's container), or null to use the host `spawnSync` default (the\n * unsandboxed escape hatch, or `claude_cli` which supplies no volley tools). */\n bash_executor?: BashExecutor | null;\n};\n\n/** The builder's model boundary: one call is one complete agentic session in\n * the build root, and its output is the whole `GenerateResult`, because the\n * phase records usage, cost, timing, and tool calls from it. */\nexport type BuilderStep = Step<ModelCallInput, GenerateResult>;\n\n/** Build the builder leaf for this run. Everything but the prompt is fixed for\n * the whole run, so it is wired once here: the provider's system prompt, its\n * tool surface, and the live chunk stream to the renderer. */\nexport function make_builder_step(deps: BuilderDeps): BuilderStep {\n const { config } = deps;\n return model_call({\n engine: deps.engine,\n id: 'builder',\n description: 'model call: one agentic session in the build root',\n provider: config.builder_provider,\n model: config.builder_model,\n system: resolve_builder_system(config),\n on_chunk: deps.on_chunk,\n ...builder_tool_options(config, deps.bash_executor ?? null),\n });\n}\n\nexport type BuilderRunDeps = {\n builder: BuilderStep;\n config: ResolvedConfig;\n warn: (message: string) => void;\n};\n\nexport async function run_builder(\n deps: BuilderRunDeps,\n state: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config } = deps;\n try {\n // Warn at builder start where a too-small context window is detectable —\n // it silently truncates tool schemas (the #1 local tool-calling failure) —\n // then pre-load the model so a cold multi-GB load doesn't blow the real\n // call's first-byte timeout. Both best-effort and Ollama-only; neither\n // blocks the build.\n if (config.builder_provider === 'ollama') {\n const base_url = resolve_ollama_base_url(process.env);\n await warn_small_local_context(\n config.builder_provider,\n config.builder_model,\n base_url,\n deps.warn,\n ctx.abort,\n );\n await prewarm_ollama_model(base_url, config.builder_model, ctx.abort);\n }\n const result = await ctx.call(\n deps.builder,\n compose_builder_prompt({\n task: config.prompt,\n criteria: config.criteria,\n feedback: state.feedback,\n iteration: state.iteration,\n checkride: config.check_resolved === 'checkride',\n }),\n );\n // `max_steps` is a backstop, not a failure — surface it and carry on.\n if (result.finish_reason === 'max_steps') {\n deps.warn(builder_max_steps_warning(config.builder_max_steps));\n }\n return accumulate(state, 'builder', result, config.builder_model);\n } catch (err) {\n throw phase_error('builder', state.iteration, err);\n }\n}\n","/**\n * Best-effort local-context guard. A too-small context window\n * silently truncates the tool schemas volley sends — the #1 reported local\n * tool-calling failure (Ollama's 4k default). We warn at builder start *where\n * the value is detectable* and never block or fail on it: detection is a\n * courtesy, the setup requirement is the user's (README `## Local builder`).\n *\n * On the ai_sdk transport this probe reads the server-side `num_ctx` (a\n * Modelfile or server default). Under fascicle's native transport (the\n * deferred future bridge) `num_ctx`/`keep_alive` become per-call\n * `provider_options.ollama` options set at request time, so the value would be\n * volley's to pass rather than a server default to probe — the warning stays\n * useful either way.\n */\nimport type { BuilderProvider } from '../types.js';\n\n/** Below this, tool schemas start getting truncated for volley's tool set. */\nexport const MIN_RECOMMENDED_NUM_CTX = 16384;\n\n/** Probe timeout — a local `/api/show` answers in single-digit ms when up; a\n * hung server must not stall builder start. */\nconst PROBE_TIMEOUT_MS = 2000;\n\n/** The warning when a detected context window is too small, or null when the\n * window is adequate or unknown (`num_ctx === null` = not detectable). Pure so\n * the threshold decision is unit-testable without a server. */\nexport function context_warning(model: string, num_ctx: number | null): string | null {\n if (num_ctx === null || num_ctx >= MIN_RECOMMENDED_NUM_CTX) return null;\n return (\n `local builder model '${model}' is configured with num_ctx ${String(num_ctx)}, below the ` +\n `~${String(MIN_RECOMMENDED_NUM_CTX)} volley recommends: a small context window silently ` +\n 'truncates the tool schemas (the #1 local tool-calling failure). Raise it (e.g. a Modelfile ' +\n '`PARAMETER num_ctx 16384`) or expect the model to ignore its tools.'\n );\n}\n\n/** Pull `num_ctx` out of Ollama's newline-delimited `parameters` blob\n * (e.g. `\"num_ctx 4096\\nstop \\\"<|im_end|>\\\"\"`). Null when\n * the parameter is absent or unparseable — which is the common case for a\n * server relying on its own default, and precisely the \"not detectable\" edge. */\nexport function parse_num_ctx(parameters: string | null): number | null {\n if (parameters === null) return null;\n const match = /^\\s*num_ctx\\s+(\\d+)\\s*$/m.exec(parameters);\n if (match === null) return null;\n const value = Number(match[1]);\n return Number.isFinite(value) ? value : null;\n}\n\n/** Best-effort probe of an Ollama server for a model's configured `num_ctx`\n * via `/api/show` (`base_url` is the server root). Returns null on any\n * failure (server down, non-OK, field absent, parse/JSON error) — the\n * warning never gates the builder. */\nexport async function probe_ollama_num_ctx(\n base_url: string,\n model: string,\n abort?: AbortSignal,\n): Promise<number | null> {\n const signals = [AbortSignal.timeout(PROBE_TIMEOUT_MS)];\n if (abort !== undefined) signals.push(abort);\n try {\n const res = await fetch(`${base_url.replace(/\\/$/, '')}/api/show`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model }),\n signal: AbortSignal.any(signals),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as { parameters?: unknown };\n return parse_num_ctx(typeof body.parameters === 'string' ? body.parameters : null);\n } catch {\n return null;\n }\n}\n\n/** Emit a small-context warning via `warn` when an Ollama builder model's\n * `num_ctx` is detectably below the recommended floor. Ollama-only — LM Studio\n * exposes no reliable pre-flight context field, so it is documented, not\n * probed. Never throws (setup friction is data, not an error). */\nexport async function warn_small_local_context(\n provider: BuilderProvider,\n model: string,\n base_url: string,\n warn: (message: string) => void,\n abort?: AbortSignal,\n): Promise<void> {\n if (provider !== 'ollama') return;\n const warning = context_warning(model, await probe_ollama_num_ctx(base_url, model, abort));\n if (warning !== null) warn(warning);\n}\n","/**\n * Builder tool set for local (non-CLI) builders.\n *\n * A local model brings no built-in tools, so volley supplies the whole\n * agentic surface: the shared read-only trio (reused from\n * `src/workspace_tools.ts`) plus `write_file`, `edit_file`, `bash`,\n * `fetch`, and the terminal `finish`. File paths are confined to the\n * workspace via `contain()`.\n *\n * Error semantics: a wrong-but-recoverable input — `edit_file`\n * matching 0 or N places, a `bash` command exiting non-zero or timing out, a\n * `fetch` that is SSRF-blocked or fails — is *returned* as a tool result the\n * model reads and acts on. Tools throw only on a genuine harness fault\n * (containment violation, unreadable input, over-cap write).\n *\n * `fetch` is a native readability pipeline (`linkedom` + `@mozilla/\n * readability` + `turndown`) with SSRF protection at the undici connector, not\n * as a pre-flight URL check: a validating DNS `lookup` rejects hostnames that\n * resolve to a non-unicast address before the TCP connect, and the resolved\n * socket's peer address is re-checked after connect — which also catches\n * literal-IP URLs (Node skips `lookup` for those) and every redirect hop\n * (each re-dispatches through the same guarded connector). The byte cap is\n * enforced while reading the HTTP stream, so raw HTML is never returned and a\n * huge page cannot OOM the tool.\n *\n * Egress is defended in two independent layers: this tool's SSRF\n * deny-list (above) and the sandbox's container network posture (`--network none`\n * by default, or a host-collapsed allowlist bridge — see `SandboxNetwork` in\n * `src/sandbox.ts`). Under whole-process containment the whole volley\n * process — `fetch` included — runs inside the container, so both layers apply to\n * `fetch`'s egress: `--network none` leaves it no route and it returns a \"could\n * not fetch\" error result, and the loop continues.\n */\nimport { spawnSync } from 'node:child_process';\nimport { lookup as dns_lookup } from 'node:dns';\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { LookupFunction } from 'node:net';\nimport { dirname } from 'node:path';\nimport { Readability } from '@mozilla/readability';\nimport ipaddr from 'ipaddr.js';\nimport { parseHTML } from 'linkedom';\nimport TurndownService from 'turndown';\nimport { Agent, buildConnector, interceptors, request } from 'undici';\nimport { z } from 'zod';\nimport type { Tool, ToolExecContext } from 'fascicle';\nimport { contain, read_only_tools } from '../workspace_tools.js';\n\nexport const WRITE_FILE_MAX_BYTES = 1_000_000;\n\n// Sized to fit a workspace `pnpm check`: volley's own checkride timeout is\n// 600s, so a shorter budget would kill the builder's self-verify\n// mid-run. Overridable per call site via `BuilderToolOptions` (tests use a\n// short value so the timeout path is exercised without a 10-minute wait).\nexport const BASH_TIMEOUT_MS = 600_000;\n\n// Model-facing cap on each of stdout/stderr; oversize output is truncated\n// with a marker. Not a memory guard — `BASH_CAPTURE_MAX_BYTES`\n// below bounds what `spawnSync` buffers before we ever truncate.\nconst BASH_MAX_OUTPUT_BYTES = 100_000;\n\n// OOM backstop on `spawnSync`'s captured output, well above the display cap:\n// a command that floods gigabytes is bounded here, then truncated to the\n// display cap for the model.\nconst BASH_CAPTURE_MAX_BYTES = 10_000_000;\n\n// Hard cap on bytes read from the HTTP stream before conversion: a page\n// larger than this is truncated at the socket, so raw HTML never reaches the\n// model and a huge page cannot OOM the tool.\nconst FETCH_MAX_BYTES = 200_000;\n\n// Default page-size for the model-facing markdown slice; `start_index`\n// paginates through the rest (MCP fetch-server contract).\nconst FETCH_MAX_CHARS = 5000;\n\n// How many redirect hops to follow. Each hop re-dispatches through the same\n// SSRF-guarded connector, so a redirect into a private range is still refused.\nconst FETCH_MAX_REDIRECTS = 5;\n\n// Per-request timeout (headers and body idle), in ms.\nconst FETCH_TIMEOUT_MS = 30_000;\n\n// Below this, readability's extraction is treated as a miss (empty article /\n// JS-rendered SPA) and we fall back to converting the whole document body.\nconst FETCH_MIN_EXTRACT_CHARS = 200;\n\nconst FETCH_USER_AGENT = 'volley-local-builder';\n\n/** The raw outcome of running one bash command, before the model-facing\n * truncation + timeout marker the `bash` tool applies. `status` is the exit code\n * (null when the process was killed by a signal — e.g. the timeout SIGKILL);\n * `timed_out` marks the timeout path. */\nexport type BashOutcome = {\n status: number | null;\n stdout: string;\n stderr: string;\n timed_out: boolean;\n};\n\n/** How the `bash` tool runs a command: the local `host_bash_executor`\n * (`spawnSync`) — which under whole-process containment runs *inside*\n * volley's own hardened container, no `docker exec` hop. The executor runs one\n * command to completion and returns its raw outcome; the `bash` tool owns the\n * truncation + timeout marker. Kept as an injectable seam so tests can supply a\n * fake and a future shape could re-point it (the `docker exec` executor was\n * retired). */\nexport type BashExecutor = (\n command: string,\n options: { timeout_ms: number; max_capture_bytes: number },\n) => BashOutcome;\n\nexport type BuilderToolOptions = {\n /** Override `BASH_TIMEOUT_MS` (ms). */\n bash_timeout_ms?: number;\n /** Override `BASH_MAX_OUTPUT_BYTES` (bytes, per stream). */\n bash_max_output_bytes?: number;\n /**\n * Where `bash` runs a command. Defaults to `host_bash_executor` — the local\n * `spawnSync`, which under containment runs inside volley's own container against the\n * bind-mounted worktree. Injectable so tests can supply a fake (the\n * `docker exec` executor was retired).\n */\n bash_executor?: BashExecutor;\n /** Override `FETCH_MAX_BYTES` (bytes read from the HTTP stream before the cap). */\n fetch_max_bytes?: number;\n /**\n * Test seam: override the connection-time SSRF classifier. Production leaves\n * this unset and uses `is_forbidden_address`, which rejects every non-unicast\n * (private / loopback / link-local / CGNAT / …) address. Tests set it to reach\n * a loopback fixture server while still exercising the real rejection path.\n */\n fetch_is_address_forbidden?: (address: string) => boolean;\n /**\n * Test seam: override the DNS resolver the SSRF connector validates through.\n * Defaults to `node:dns` `lookup`. Lets a test point a hostname at a private\n * address to exercise the redirect-into-private-range rejection.\n */\n fetch_lookup?: LookupFunction;\n};\n\nconst write_file_input = z.object({\n path: z.string().describe('Workspace-relative path to write. Parent directories are created.'),\n content: z.string().describe('Full UTF-8 content of the file. Overwrites any existing content.'),\n});\n\nconst edit_file_input = z.object({\n path: z.string().describe('Workspace-relative path of the file to edit.'),\n old_str: z\n .string()\n .min(1)\n .describe('Exact text to replace. Must occur exactly once in the file.'),\n new_str: z.string().describe('Replacement text.'),\n});\n\nconst bash_input = z.object({\n command: z.string().describe('Shell command to run in the workspace directory.'),\n});\n\nconst finish_input = z.object({\n summary: z.string().describe('Short summary of what was accomplished.'),\n});\n\nconst fetch_input = z.object({\n url: z.string().describe('Absolute http(s) URL to fetch.'),\n max_chars: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(`Maximum characters of extracted markdown to return (default ${String(FETCH_MAX_CHARS)}).`),\n start_index: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Character offset into the extracted markdown to start from, for paging a long page. Default 0.'),\n});\n\nfunction count_occurrences(haystack: string, needle: string): number {\n return haystack.split(needle).length - 1;\n}\n\n/** Truncate `text` to at most `max` bytes, appending a marker when clipped.\n * Byte-based to honor the byte cap; a split multibyte char at the boundary\n * renders as the replacement char, which is acceptable for tool output. */\nfunction truncate_bytes(text: string, max: number): string {\n if (Buffer.byteLength(text, 'utf8') <= max) return text;\n const clipped = Buffer.from(text, 'utf8').subarray(0, max).toString('utf8');\n return `${clipped}\\n… [truncated at ${String(max)} bytes]`;\n}\n\n/**\n * Non-unicast → forbidden. Rejects loopback, private, link-local,\n * unspecified, broadcast, multicast, CGNAT, and the IPv6 equivalents; an\n * IPv4-mapped IPv6 address is folded to its v4 form first so `::ffff:127.0.0.1`\n * is caught as loopback (and `::ffff:<public>` is still allowed). An\n * unparseable address fails closed.\n */\nexport function is_forbidden_address(address: string): boolean {\n let parsed;\n try {\n parsed = ipaddr.parse(address);\n } catch {\n return true;\n }\n const canonical =\n 'isIPv4MappedAddress' in parsed && parsed.isIPv4MappedAddress() ? parsed.toIPv4Address() : parsed;\n return canonical.range() !== 'unicast';\n}\n\n// Default DNS resolver the SSRF connector validates through; the `fetch_lookup`\n// option swaps it in tests.\nconst default_resolver: LookupFunction = (hostname, options, callback) => {\n dns_lookup(hostname, options, callback);\n};\n\n// A `lookup` that resolves normally, then rejects the connection if any\n// resolved address is forbidden — closing the DNS-rebinding / redirect-hop gap\n// a pre-flight URL check leaves open. Runs before the TCP connect, so a\n// hostname pointing at a private range never opens a socket.\nfunction guarded_lookup(is_forbidden: (address: string) => boolean, resolve: LookupFunction): LookupFunction {\n return (hostname, options, callback) => {\n resolve(hostname, options, (err, address, family) => {\n if (err !== null) {\n callback(err, '', 0);\n return;\n }\n const resolved = Array.isArray(address) ? address.map((entry) => entry.address) : [address];\n const blocked = resolved.find((entry) => is_forbidden(entry));\n if (blocked !== undefined) {\n callback(ssrf_error(blocked, hostname), '', 0);\n return;\n }\n callback(null, address, family);\n });\n };\n}\n\nfunction ssrf_error(address: string, hostname: string): NodeJS.ErrnoException {\n const err: NodeJS.ErrnoException = new Error(\n `blocked non-unicast address ${address} for host \"${hostname}\"`,\n );\n err.code = 'ERR_SSRF_BLOCKED';\n return err;\n}\n\n// An undici Agent whose connector validates SSRF at two points: the `lookup`\n// above (hostnames, before connect) and the peer address of the established\n// socket (which also catches literal-IP URLs — Node skips `lookup` for those —\n// and every redirect hop, since each re-dispatches through this connector).\nfunction create_ssrf_agent(is_forbidden: (address: string) => boolean, resolve: LookupFunction): Agent {\n const base = buildConnector({ lookup: guarded_lookup(is_forbidden, resolve), timeout: FETCH_TIMEOUT_MS });\n const connector: typeof base = (options, callback) => {\n base(options, (err, socket) => {\n if (err !== null) {\n callback(err, null);\n return;\n }\n if (socket === null) {\n callback(new Error('connection produced no socket'), null);\n return;\n }\n const remote = socket.remoteAddress;\n if (remote !== undefined && is_forbidden(remote)) {\n socket.destroy();\n callback(ssrf_error(remote, options.hostname), null);\n return;\n }\n callback(null, socket);\n });\n };\n return new Agent({ connect: connector, headersTimeout: FETCH_TIMEOUT_MS, bodyTimeout: FETCH_TIMEOUT_MS });\n}\n\n// Read the response body, stopping at `max_bytes` so raw HTML never fully\n// buffers. Breaking the `for await` destroys the stream, ending the\n// download.\nasync function read_body_capped(body: AsyncIterable<Buffer>, max_bytes: number): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of body) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n const remaining = max_bytes - total;\n if (buf.length >= remaining) {\n chunks.push(buf.subarray(0, remaining));\n break;\n }\n chunks.push(buf);\n total += buf.length;\n }\n return Buffer.concat(chunks);\n}\n\nfunction header_value(value: string | string[] | undefined): string {\n if (Array.isArray(value)) return value[0] ?? '';\n return value ?? '';\n}\n\nfunction content_kind(content_type: string, body: string): 'html' | 'text' | 'binary' {\n const ct = content_type.toLowerCase();\n if (ct.includes('html') || ct.includes('xml')) return 'html';\n if (\n ct.startsWith('text/') ||\n ct.includes('json') ||\n ct.includes('javascript') ||\n ct.includes('csv')\n ) {\n return 'text';\n }\n if (ct === '') return body.trimStart().startsWith('<') ? 'html' : 'text';\n return 'binary';\n}\n\n// Extract the main content as markdown: readability over a linkedom DOM, then\n// turndown. Falls back to converting the whole document when readability finds\n// little (empty article / JS-rendered SPA). Never returns raw HTML.\nfunction extract_markdown(html: string): string {\n const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });\n turndown.remove(['script', 'style', 'noscript']);\n let body_markdown = '';\n let title = '';\n try {\n const { document } = parseHTML(html);\n const article = new Readability(document).parse();\n if (article !== null) {\n title = (article.title ?? '').trim();\n if (article.content) {\n body_markdown = turndown.turndown(article.content).trim();\n }\n }\n } catch {\n body_markdown = '';\n }\n if (body_markdown.length < FETCH_MIN_EXTRACT_CHARS) {\n let fallback = '';\n try {\n fallback = turndown.turndown(html).trim();\n } catch {\n fallback = '';\n }\n if (fallback.length > body_markdown.length) body_markdown = fallback;\n }\n const prefix = title.length > 0 && !body_markdown.startsWith(`# ${title}`) ? `# ${title}\\n\\n` : '';\n return `${prefix}${body_markdown}`.trim();\n}\n\n// MCP fetch-server pagination: return the `max_chars` slice at `start_index`,\n// and when more remains, a self-describing trailer naming the next start_index.\nfunction paginate(full: string, max_chars: number, start_index: number): string {\n if (start_index >= full.length) {\n return `(no more content: start_index ${String(start_index)} is at or past the end of the ${String(full.length)}-character document)`;\n }\n const slice = full.slice(start_index, start_index + max_chars);\n const next = start_index + slice.length;\n if (next >= full.length) return slice;\n const remaining = full.length - next;\n return `${slice}\\n\\n<truncated: ${String(remaining)} more characters. Call fetch again with start_index=${String(next)} to continue.>`;\n}\n\n// Flatten an error (and its `cause` chain) into a single line for the model.\nfunction error_detail(err: unknown): string {\n const parts: string[] = [];\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current !== undefined && current !== null && !seen.has(current)) {\n seen.add(current);\n if (current instanceof Error) {\n const code = (current as NodeJS.ErrnoException).code;\n parts.push(code !== undefined ? `${current.message} [${code}]` : current.message);\n current = (current as { cause?: unknown }).cause;\n } else {\n // Thrown values are Errors in practice; a non-Error is defensive only, so\n // keep a string as-is and never risk an \"[object Object]\" stringification.\n parts.push(typeof current === 'string' ? current : `non-error value (${typeof current})`);\n break;\n }\n }\n return parts.length > 0 ? parts.join(' <- ') : 'unknown error';\n}\n\ntype FetchConfig = {\n is_forbidden: (address: string) => boolean;\n resolve: LookupFunction;\n max_bytes: number;\n};\n\nasync function run_fetch(raw: unknown, ctx: ToolExecContext, config: FetchConfig): Promise<string> {\n const input = fetch_input.parse(raw);\n const max_chars = input.max_chars ?? FETCH_MAX_CHARS;\n const start_index = input.start_index ?? 0;\n\n let target: URL;\n try {\n target = new URL(input.url);\n } catch {\n return `error: not a valid absolute URL: ${input.url}`;\n }\n if (target.protocol !== 'http:' && target.protocol !== 'https:') {\n return `error: unsupported URL scheme \"${target.protocol}\" — only http and https are fetched`;\n }\n\n const agent = create_ssrf_agent(config.is_forbidden, config.resolve);\n const dispatcher = agent.compose(interceptors.redirect({ maxRedirections: FETCH_MAX_REDIRECTS }));\n try {\n const res = await request(target.href, {\n dispatcher,\n signal: ctx.abort,\n headersTimeout: FETCH_TIMEOUT_MS,\n bodyTimeout: FETCH_TIMEOUT_MS,\n headers: {\n 'user-agent': FETCH_USER_AGENT,\n accept: 'text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.8',\n // No compression: keep the pipeline simple and the byte cap honest.\n 'accept-encoding': 'identity',\n },\n });\n if (res.statusCode >= 400) {\n await res.body.dump();\n return `error: HTTP ${String(res.statusCode)} fetching ${target.href}`;\n }\n const bytes = await read_body_capped(res.body, config.max_bytes);\n const content_type = header_value(res.headers['content-type']);\n const text = bytes.toString('utf8');\n if (text.trim().length === 0) {\n return `error: empty response body from ${target.href}`;\n }\n const kind = content_kind(content_type, text);\n if (kind === 'binary') {\n return `error: cannot extract non-text content (content-type: ${content_type}) from ${target.href}`;\n }\n const markdown = kind === 'html' ? extract_markdown(text) : text.trim();\n if (markdown.length === 0) {\n return `error: no readable content extracted from ${target.href}`;\n }\n return paginate(markdown, max_chars, start_index);\n } catch (err) {\n return `error: could not fetch ${target.href}: ${error_detail(err)}`;\n } finally {\n await agent.close().catch(() => undefined);\n }\n}\n\n/**\n * The `bash` executor: run the command via `spawnSync` with a shell, bounded by\n * the timeout (SIGKILL on expiry) and the OOM capture cap. Under whole-process\n * containment this runs *inside* volley's hardened container against the\n * bind-mounted worktree — the container is the isolation boundary, no\n * `docker exec` hop — and it is likewise the executor on the\n * `--allow-unsandboxed-builder` host escape hatch. `status` is null\n * when a signal (the timeout SIGKILL) killed the process.\n */\nfunction host_bash_executor(cwd: string): BashExecutor {\n return (command, options) => {\n const result = spawnSync(command, {\n shell: true,\n cwd,\n encoding: 'utf8',\n timeout: options.timeout_ms,\n killSignal: 'SIGKILL',\n maxBuffer: options.max_capture_bytes,\n });\n return {\n status: result.status,\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n timed_out: (result.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT',\n };\n };\n}\n\n// Same wiring convention as the shared read tools: each tool is typed as\n// fascicle's `Tool` (input `unknown`) and re-parses the model's raw\n// arguments with its own schema inside `execute`.\nexport function builder_tools(workspace: string, options: BuilderToolOptions = {}): Tool[] {\n const bash_timeout_ms = options.bash_timeout_ms ?? BASH_TIMEOUT_MS;\n const bash_max_output_bytes = options.bash_max_output_bytes ?? BASH_MAX_OUTPUT_BYTES;\n const bash_executor = options.bash_executor ?? host_bash_executor(workspace);\n\n const write_file: Tool = {\n name: 'write_file',\n description:\n 'Write a UTF-8 text file in the workspace, creating parent directories ' +\n 'and overwriting any existing content. Rejects content over ' +\n `${String(WRITE_FILE_MAX_BYTES)} bytes.`,\n input_schema: write_file_input,\n execute: (raw) => {\n const input = write_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const bytes = Buffer.byteLength(input.content, 'utf8');\n if (bytes > WRITE_FILE_MAX_BYTES) {\n throw new Error(\n `content is ${String(bytes)} bytes, over the ${String(WRITE_FILE_MAX_BYTES)}-byte write cap`,\n );\n }\n mkdirSync(dirname(abs), { recursive: true });\n writeFileSync(abs, input.content, 'utf8');\n return `wrote ${String(bytes)} bytes to ${input.path}`;\n },\n };\n\n const edit_file: Tool = {\n name: 'edit_file',\n description:\n 'Replace one exact occurrence of old_str with new_str in a workspace ' +\n 'file. old_str must match the file content exactly once — on 0 or ' +\n 'multiple matches nothing is changed and an error is returned; read ' +\n 'the file and retry with a longer, unique old_str.',\n input_schema: edit_file_input,\n execute: (raw) => {\n const input = edit_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const content = readFileSync(abs, 'utf8');\n const matches = count_occurrences(content, input.old_str);\n if (matches === 0) {\n return (\n `error: old_str not found in ${input.path} (0 matches). ` +\n 'No change made. Read the file and retry with an exact excerpt of its current content.'\n );\n }\n if (matches > 1) {\n return (\n `error: old_str matches ${String(matches)} times in ${input.path}. ` +\n 'No change made. Include more surrounding context to make old_str unique.'\n );\n }\n writeFileSync(abs, content.replace(input.old_str, input.new_str), 'utf8');\n return `edit applied to ${input.path}`;\n },\n };\n\n const bash: Tool = {\n name: 'bash',\n description:\n 'Run a shell command in the workspace and return its exit code, stdout, ' +\n 'and stderr. Each call is independent — no shell state (working ' +\n 'directory, environment, variables) carries over between commands. A ' +\n 'non-zero exit is a normal result, not an error: read it and adjust. ' +\n `Each stream is truncated past ${String(bash_max_output_bytes)} bytes, ` +\n `and the command is killed if it runs longer than ${String(bash_timeout_ms)}ms.`,\n input_schema: bash_input,\n // Stateless per command (the executor is injectable without touching\n // this contract — under containment it is the local `spawnSync` running in-container),\n // and never throws on the command's own failure — a non-zero exit or a\n // timeout is *returned* as `{ exit_code, stdout, stderr }` for the model to\n // read. The executor buffers up to `BASH_CAPTURE_MAX_BYTES` (OOM guard)\n // before we truncate to the model-facing cap.\n execute: (raw) => {\n const input = bash_input.parse(raw);\n const outcome = bash_executor(input.command, {\n timeout_ms: bash_timeout_ms,\n max_capture_bytes: BASH_CAPTURE_MAX_BYTES,\n });\n let stderr = truncate_bytes(outcome.stderr, bash_max_output_bytes);\n if (outcome.timed_out) {\n const note = `[command timed out after ${String(bash_timeout_ms)}ms and was killed]`;\n stderr = stderr.length > 0 ? `${stderr}\\n${note}` : note;\n }\n // `status` is the numeric exit code, or null when the process was killed\n // by a signal (e.g. the timeout SIGKILL).\n return {\n exit_code: outcome.status,\n stdout: truncate_bytes(outcome.stdout, bash_max_output_bytes),\n stderr,\n };\n },\n };\n\n const fetch: Tool = {\n name: 'fetch',\n description:\n 'Fetch an http(s) URL and return its main content converted to Markdown. ' +\n `Returns at most max_chars characters (default ${String(FETCH_MAX_CHARS)}); ` +\n 'when the page is longer, a trailer names the start_index to pass to read ' +\n 'the next slice. Private, loopback, and link-local addresses are refused. ' +\n 'A blocked, non-HTML, or failed request returns an error string you can read and act on.',\n input_schema: fetch_input,\n // Native readability pipeline with connection-time SSRF protection; a\n // blocked / non-HTML / HTTP error is returned as a tool result, not\n // thrown. The classifier and resolver are overridable for tests only.\n execute: (raw, ctx) =>\n run_fetch(raw, ctx, {\n is_forbidden: options.fetch_is_address_forbidden ?? is_forbidden_address,\n resolve: options.fetch_lookup ?? default_resolver,\n max_bytes: options.fetch_max_bytes ?? FETCH_MAX_BYTES,\n }),\n };\n\n const finish: Tool = {\n name: 'finish',\n description:\n 'Declare the task complete. Calling this tool ends your turn — do not ' +\n 'call it until the work is done and verified.',\n input_schema: finish_input,\n // A successful `finish` ends the loop deterministically. The summary\n // is recorded in the trajectory like any tool call and otherwise ignored\n // — the workspace, not the self-report, is truth.\n ends_turn: true,\n execute: (raw) => {\n const input = finish_input.parse(raw);\n return `finished: ${input.summary}`;\n },\n };\n\n return [...read_only_tools(workspace), write_file, edit_file, bash, fetch, finish];\n}\n","/**\n * Shared workspace tools: `contain()` path confinement plus the read-only\n * tool set (`read_file`, `search_files`, `list_files`).\n *\n * The claude_cli builder/critic get file access from the CLI's own built-in\n * tools. API-style providers (ollama, lmstudio, …) have no built-ins, so\n * volley supplies its own. The critic uses the read-only set as-is via\n * `src/critic/tools.ts`; the builder set in\n * `src/builder/tools.ts` reuses `contain()` and the read tools and adds its\n * write/exec surface. Every path is resolved and confined to the\n * workspace root.\n */\nimport { readFileSync, readdirSync, statSync } from 'node:fs';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { z } from 'zod';\nimport type { Tool } from 'fascicle';\n\nexport const READ_FILE_MAX_BYTES = 200_000;\nexport const SEARCH_MAX_MATCHES = 200;\nconst LIST_MAX_ENTRIES = 2000;\n\n/** Directories never worth handing a critic; they bury signal and blow the\n * traversal budget. */\nconst IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.volley',\n '.check',\n 'dist',\n '.cache',\n]);\n\n/** Resolve `rel` inside `workspace`, rejecting absolute paths and any `..`\n * escape. Returns the absolute path; throws on containment violation. The\n * `workspace` root passed here is the build root, which is the per-run git\n * worktree under `--worktree` (`build_root`), not necessarily the\n * control-plane workspace that holds `.volley/`. */\nexport function contain(workspace: string, rel: string): string {\n const root = resolve(workspace);\n const candidate = isAbsolute(rel) ? resolve(rel) : resolve(root, rel);\n const within = candidate === root || candidate.startsWith(`${root}${sep}`);\n if (!within) {\n throw new Error(`path escapes the workspace: ${rel}`);\n }\n return candidate;\n}\n\ntype WalkEntry = { rel: string; abs: string };\n\nfunction walk(root: string, start: string, limit: number): WalkEntry[] {\n const out: WalkEntry[] = [];\n const stack = [start];\n while (stack.length > 0 && out.length < limit) {\n const dir = stack.pop() as string;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const name of entries) {\n const abs = join(dir, name);\n let is_dir: boolean;\n try {\n is_dir = statSync(abs).isDirectory();\n } catch {\n continue;\n }\n if (is_dir) {\n if (!IGNORED_DIRS.has(name)) stack.push(abs);\n continue;\n }\n out.push({ rel: relative(root, abs), abs });\n if (out.length >= limit) break;\n }\n }\n return out;\n}\n\nfunction build_regex(pattern: string, flags: string): RegExp {\n try {\n return new RegExp(pattern, flags);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`invalid regular expression: ${detail}`);\n }\n}\n\nconst read_file_input = z.object({\n path: z.string().describe('Workspace-relative path to the file to read.'),\n});\n\nconst search_files_input = z.object({\n pattern: z.string().describe('JavaScript regular expression to match against each line.'),\n path: z\n .string()\n .optional()\n .describe('Optional workspace-relative subdirectory to limit the search to.'),\n ignore_case: z.boolean().optional().describe('Case-insensitive match. Default false.'),\n});\n\nconst list_files_input = z.object({\n path: z\n .string()\n .optional()\n .describe('Optional workspace-relative subdirectory. Default: the workspace root.'),\n contains: z\n .string()\n .optional()\n .describe('Optional substring filter applied to each relative path.'),\n});\n\n// Each tool is typed as fascicle's `Tool` (input `unknown`) and re-parses the\n// model's raw arguments with its own schema. fascicle's `Tool` is invariant\n// on the input type, so typed-per-tool values will not widen into `Tool[]`;\n// parsing inside `execute` keeps the wiring cast-free and validates arguments\n// at the boundary. The declared `input_schema` still drives the JSON schema\n// the model sees.\nexport function read_only_tools(workspace: string): Tool[] {\n const read_file: Tool = {\n name: 'read_file',\n description:\n 'Read a UTF-8 text file from the workspace. Returns the file content ' +\n `(truncated at ${String(READ_FILE_MAX_BYTES)} bytes).`,\n input_schema: read_file_input,\n execute: (raw) => {\n const input = read_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const content = readFileSync(abs, 'utf8');\n return content.length > READ_FILE_MAX_BYTES\n ? `${content.slice(0, READ_FILE_MAX_BYTES)}\\n… [truncated at ${String(READ_FILE_MAX_BYTES)} bytes]`\n : content;\n },\n };\n\n const search_files: Tool = {\n name: 'search_files',\n description:\n 'Search workspace files for lines matching a regular expression. Returns ' +\n `up to ${String(SEARCH_MAX_MATCHES)} \"relative/path:line: text\" hits.`,\n input_schema: search_files_input,\n execute: (raw) => {\n const input = search_files_input.parse(raw);\n const start = input.path !== undefined ? contain(workspace, input.path) : resolve(workspace);\n const regex = build_regex(input.pattern, input.ignore_case === true ? 'i' : '');\n const files = walk(resolve(workspace), start, LIST_MAX_ENTRIES);\n const hits: string[] = [];\n for (const file of files) {\n if (hits.length >= SEARCH_MAX_MATCHES) break;\n let content: string;\n try {\n content = readFileSync(file.abs, 'utf8');\n } catch {\n continue;\n }\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length; i += 1) {\n if (hits.length >= SEARCH_MAX_MATCHES) break;\n const line = lines[i] as string;\n if (regex.test(line)) hits.push(`${file.rel}:${String(i + 1)}: ${line.trim()}`);\n }\n }\n if (hits.length === 0) return 'no matches';\n const capped =\n hits.length >= SEARCH_MAX_MATCHES ? `\\n… [capped at ${String(SEARCH_MAX_MATCHES)} matches]` : '';\n return `${hits.join('\\n')}${capped}`;\n },\n };\n\n const list_files: Tool = {\n name: 'list_files',\n description:\n 'List files under a workspace directory (recursively; skips node_modules, ' +\n '.git, and other build/output directories).',\n input_schema: list_files_input,\n execute: (raw) => {\n const input = list_files_input.parse(raw);\n const start = input.path !== undefined ? contain(workspace, input.path) : resolve(workspace);\n let files = walk(resolve(workspace), start, LIST_MAX_ENTRIES).map((f) => f.rel);\n if (input.contains !== undefined) {\n const needle = input.contains;\n files = files.filter((f) => f.includes(needle));\n }\n if (files.length === 0) return 'no files';\n const capped =\n files.length >= LIST_MAX_ENTRIES ? `\\n… [capped at ${String(LIST_MAX_ENTRIES)} entries]` : '';\n return `${files.join('\\n')}${capped}`;\n },\n };\n\n return [read_file, search_files, list_files];\n}\n\n/** A `paths + sizes` listing of the workspace tree, no file contents — the\n * grounding a tool-less critic gets when its provider's tool parser died and the\n * degradation ladder traded read access for survival. Reuses the same\n * `walk` + `IGNORED_DIRS` traversal as the read tools, so the inventory matches\n * what a working `list_files` would have surfaced; caps at `limit` entries. */\nexport function workspace_inventory(root: string, limit: number = LIST_MAX_ENTRIES): string {\n const base = resolve(root);\n const files = walk(base, base, limit);\n if (files.length === 0) return 'no files';\n const lines = files.map((file) => {\n let size: number;\n try {\n size = statSync(file.abs).size;\n } catch {\n size = 0;\n }\n return `${file.rel} (${String(size)} bytes)`;\n });\n const capped =\n files.length >= limit ? `\\n… [capped at ${String(limit)} entries]` : '';\n return `${lines.join('\\n')}${capped}`;\n}\n","/**\n * Cost and usage accumulation. All pricing knowledge lives in\n * fascicle; volley only folds `GenerateResult.usage` / `.cost` into loop\n * state and enforces the cap predicate in the guard.\n */\nimport { claude_cli_reported, throughput } from 'fascicle';\nimport type { GenerateResult, UsageTotals } from 'fascicle';\nimport type {\n CostSource,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n} from './types.js';\n\nexport const EMPTY_USAGE: UsageTotals = { input_tokens: 0, output_tokens: 0 };\n\nexport function add_usage(a: UsageTotals, b: UsageTotals): UsageTotals {\n const sum: UsageTotals = {\n input_tokens: a.input_tokens + b.input_tokens,\n output_tokens: a.output_tokens + b.output_tokens,\n };\n const optional = ['cached_input_tokens', 'cache_write_tokens', 'reasoning_tokens'] as const;\n for (const key of optional) {\n const total = (a[key] ?? 0) + (b[key] ?? 0);\n if (a[key] !== undefined || b[key] !== undefined) sum[key] = total;\n }\n return sum;\n}\n\nexport function cost_source_of(result: GenerateResult<unknown>): CostSource {\n if (result.cost === undefined) return 'unknown';\n return result.model_resolved.provider === 'claude_cli'\n ? 'provider_reported'\n : 'engine_derived';\n}\n\n/** One phase's record from its generate result. The duration is fascicle's\n * call-level wall clock (`GenerateResult.timing`: every turn and the tools\n * between them) unless the caller measured a wider span, as the critic does for\n * its whole degradation ladder. */\nexport function phase_record(\n result: GenerateResult<unknown>,\n model: string,\n duration_ms: number = result.timing?.duration_ms ?? 0,\n): PhaseRecord {\n const rate = throughput(result);\n return {\n provider: result.model_resolved.provider,\n model,\n session_id: claude_cli_reported(result)?.session_id ?? null,\n duration_ms,\n usage: result.usage,\n cost_usd: result.cost?.total_usd ?? null,\n cost_source: cost_source_of(result),\n finish_reason: result.finish_reason,\n tool_calls: result.tool_calls.length,\n salvaged_tool_calls: result.tool_calls.filter((call) => call.salvaged === true).length,\n ...(rate !== undefined ? { throughput: rate } : {}),\n };\n}\n\n/** Fold one phase's result into the loop state. Unknown cost records `null`\n * for the phase and warns once per run — a run never fails over pricing. */\nexport function accumulate(\n state: LoopState,\n role: 'builder' | 'critic',\n result: GenerateResult<unknown>,\n model: string,\n duration_ms?: number,\n): LoopState {\n const record = phase_record(result, model, duration_ms);\n const cost = record.cost_usd ?? 0;\n return {\n ...state,\n [role]: record,\n total_usage: add_usage(state.total_usage, result.usage),\n total_cost_usd: state.total_cost_usd + cost,\n iteration_cost_usd: state.iteration_cost_usd + cost,\n builder_cost_usd: state.builder_cost_usd + (role === 'builder' ? cost : 0),\n critic_cost_usd: state.critic_cost_usd + (role === 'critic' ? cost : 0),\n cost_warned: state.cost_warned || record.cost_usd === null,\n };\n}\n\nexport function cost_cap_hit(config: ResolvedConfig, state: LoopState): boolean {\n return config.max_cost_usd !== null && state.total_cost_usd >= config.max_cost_usd;\n}\n","/**\n * Best-effort Ollama model pre-load. A cold multi-GB model can spend minutes\n * in load + first prompt eval — longer than the provider path's in-request\n * header timeout — so the first real `generate` dies with an opaque\n * `stream interrupted: fetch failed`. Ollama's documented load call (a\n * `/api/generate` POST with a model and no prompt) returns as soon as the\n * model is resident, so absorbing the load here keeps the real call's\n * time-to-first-byte inside its budget.\n *\n * Best-effort like the context probe: any failure (server down, unknown\n * model, timeout) is swallowed — the real generate call surfaces the error\n * with retry and reporting behind it. Ollama-only; LM Studio has no\n * equivalent load-without-generating endpoint.\n */\n\n/** Generous ceiling on the load itself: a disk-cold 30B-class model takes\n * tens of seconds to minutes. Past this, give up and let the real call try. */\nconst PREWARM_TIMEOUT_MS = 300_000;\n\n/** Load `model` into the Ollama server's memory (`base_url` is the server\n * root). Resolves when the model is resident, on any failure, or at the\n * timeout — never throws, never gates the phase. An already-resident model\n * returns immediately, so warming the same model for both roles is free.\n *\n * Load-bearing only on the ai_sdk transport: the cold-load death this\n * absorbs is the ai-sdk/undici in-request header timeout, not an Ollama\n * limit. On fascicle's native transport — the deferred future bridge, see\n * `local_provider_config` in engine.ts — the per-turn call is a bare\n * `fetch(..., { signal })` with no default body timeout, so a cold model can\n * take as long as it needs and this pre-warm's necessity drops away (keep it\n * regardless: a resident model makes it a no-op). Native would also move the\n * `num_ctx`/`keep_alive` levers to per-call `provider_options.ollama`, rather\n * than the server-side Modelfile defaults volley probes today. */\nexport async function prewarm_ollama_model(\n base_url: string,\n model: string,\n abort?: AbortSignal,\n): Promise<void> {\n const signals = [AbortSignal.timeout(PREWARM_TIMEOUT_MS)];\n if (abort !== undefined) signals.push(abort);\n try {\n await fetch(`${base_url.replace(/\\/$/, '')}/api/generate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model }),\n signal: AbortSignal.any(signals),\n });\n } catch {\n // Best-effort: the real generate call owns error surfacing.\n }\n}\n","/**\n * Git-worktree orchestration: isolate a builder run's\n * *effects* on a per-run branch checked out into a sibling worktree, then tear\n * the whole thing down when the run ends. The worktree lifecycle wraps the\n * fascicle loop — it is not itself a loop — so these are straight-line git\n * subprocess calls and the flow's no-loops rule is unaffected.\n *\n * Teardown is not one behaviour but three, decided by `worktree_fate` and\n * predicted out loud by `report_worktree_fate` before any model spend: a\n * converged `--worktree --git` run *integrates* (the orchestrator squash-merges,\n * then the branch is discarded), a `--discard-worktree` run *discards*, and a\n * plain `--worktree` run *salvages* — its work was never integrated and lives\n * nowhere else, so teardown commits it onto the run branch and keeps the branch\n * instead of force-deleting the build. Everything that did not converge still\n * discards wholesale.\n */\nimport { existsSync, renameSync, rmSync, symlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { check_error, config_error } from './types.js';\nimport { backup_stamp } from './workspace.js';\n\n/** A live worktree: the checked-out path and the branch it holds. */\nexport type WorktreeHandle = {\n path: string;\n branch: string;\n};\n\n/** The sibling directory a run's worktree is checked out into — one per\n * workspace, alongside it so it never nests inside the repo's own tree. */\nexport function worktree_path(workspace: string): string {\n return `${resolve(workspace)}.worktree`;\n}\n\n/** The per-run branch name (one named branch per phase). Derived from the\n * run id so it is stable across a resume. */\nexport function worktree_branch(run_id: string): string {\n return `volley/${run_id}`;\n}\n\n/**\n * The directory the builder's *effects* land in: the run's worktree\n * when `--worktree` is on, else the workspace itself. This is the containment\n * root the builder/critic file tools resolve through `contain()` and the\n * `bash` tool's cwd — re-pointing it moves writes into the worktree without\n * disturbing the workspace. `.volley/` state, the resolved config, and the\n * deterministic check stay under the workspace (the control plane), so only the\n * model-driven effect surface moves.\n */\nexport function build_root(workspace: string, worktree: boolean): string {\n return worktree ? worktree_path(workspace) : workspace;\n}\n\n/** What becomes of a *successful* `--worktree` run's effects. Any other\n * outcome — cost cap, budget, interrupt, error — always discards: an abandoned\n * phase's branch is thrown away wholesale, as it always has been. */\nexport type WorktreeFate = 'none' | 'integrate' | 'salvage' | 'discard';\n\n/** The config fields the fate turns on, as a structural subset of\n * `ResolvedConfig` so the decision is testable without a whole config. */\nexport type WorktreeFateConfig = {\n worktree: boolean;\n git_checkpoints: boolean;\n discard_worktree: boolean;\n};\n\n/**\n * Which of the three outcomes a converged run gets:\n *\n * - `integrate` — `--worktree --git`: the phase branch's checkpoints squash-merge\n * onto the workspace branch (`integrate_worktree`), then teardown discards it.\n * - `discard` — `--discard-worktree`: the effects go away with the branch. What\n * `volley matrix` sweeps with: isolate the effects, keep only verdicts.\n * - `salvage` — `--worktree` alone: nothing integrates, and the worktree holds the\n * run's only copy of its work, so teardown commits that onto the run branch and\n * keeps it rather than force-deleting a green run's build.\n *\n * `--git` wins over `--discard-worktree`, so the documented `--worktree --git`\n * integrate path is untouched by asking for a throw-away run.\n */\nexport function worktree_fate(config: WorktreeFateConfig): WorktreeFate {\n if (!config.worktree) return 'none';\n if (config.git_checkpoints) return 'integrate';\n if (config.discard_worktree) return 'discard';\n return 'salvage';\n}\n\n/** The run branch as a *prediction* can name it: `--dry-run` resolves its own\n * run id, which is not the id the real run will get, so the notice names the\n * pattern and the post-run report names the branch. */\nconst RUN_BRANCH_PATTERN = 'volley/<run id>';\n\nexport type WorktreeNotice = { level: 'info' | 'warn'; message: string };\n\n/**\n * What this run will do with its effects, in one line, said before any model\n * spend — the same predict-at-dry-run/warn-at-run-start shape as the local-critic\n * seat canary and the `num_ctx` guard. `salvage` is a warning, not an\n * info line: `--worktree` without `--git` integrates nothing, and it is the one\n * fate an operator is likely to have configured by accident.\n */\nexport function worktree_notice(config: WorktreeFateConfig): WorktreeNotice | null {\n const fate = worktree_fate(config);\n if (fate === 'none') return null;\n if (fate === 'integrate') {\n return {\n level: 'info',\n message:\n 'worktree: --worktree --git — a successful run squash-merges its run branch onto the ' +\n 'workspace branch at teardown; any other outcome is discarded.',\n };\n }\n if (fate === 'discard') {\n return {\n level: 'info',\n message:\n 'worktree: --discard-worktree — the run builds in an isolated worktree whose effects are ' +\n 'thrown away at teardown, converged or not. Verdicts only; no branch is kept.',\n };\n }\n return {\n level: 'warn',\n message:\n 'worktree: --worktree without --git — a successful run will NOT be integrated into the ' +\n 'workspace branch, and the builder writes only inside the sibling worktree, so your working ' +\n `tree stays as it is. The run's work is committed onto its own branch (${RUN_BRANCH_PATTERN}) ` +\n 'at teardown and left there for `git switch` / `git cherry-pick`. Add --git to squash-merge ' +\n 'it onto the workspace branch instead, or --discard-worktree to throw it away deliberately.',\n };\n}\n\n/** The renderer channels a notice writes through — structurally satisfied by\n * `Renderer`, so this module stays independent of the render layer. */\nexport type NoticeSink = {\n info: (message: string) => void;\n warn: (message: string) => void;\n};\n\n/** Emit the run's worktree fate on the channel its severity deserves (nothing at\n * all when `--worktree` is off). Called from the `--dry-run` preflight and again\n * at run start, so the outcome is predicted whether or not the operator dry-ran. */\nexport function report_worktree_fate(config: WorktreeFateConfig, sink: NoticeSink): void {\n const notice = worktree_notice(config);\n if (notice === null) return;\n if (notice.level === 'warn') {\n sink.warn(notice.message);\n return;\n }\n sink.info(notice.message);\n}\n\ntype GitResult = { status: number; stdout: string; stderr: string };\n\n/** Run git in `cwd`. A missing git binary is a precondition failure (like the\n * missing-repo guard); a non-zero exit is left to the caller to interpret. */\nfunction git(cwd: string, args: string[]): GitResult {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' });\n if (result.error !== undefined) {\n throw config_error(`git is required for --worktree but could not run: ${String(result.error)}`);\n }\n return { status: result.status ?? -1, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };\n}\n\n/** Run git and throw on a non-zero exit, surfacing git's own diagnostics. */\nfunction git_ok(cwd: string, args: string[]): GitResult {\n const result = git(cwd, args);\n if (result.status !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw check_error(`git ${args.join(' ')} failed: ${detail}`);\n }\n return result;\n}\n\n/** Best-effort git for teardown: swallows both spawn and exit failures so the\n * idempotent trio never throws out of a run's `finally`. Still reports what it\n * can — a spawn failure reads as a non-zero exit with no output — so the salvage\n * path can interrogate the repo without reintroducing a throw. */\nfunction git_quiet(cwd: string, args: string[]): GitResult {\n try {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' });\n return { status: result.status ?? -1, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };\n } catch {\n // Teardown is cleanup; never mask the run's real outcome.\n return { status: -1, stdout: '', stderr: '' };\n }\n}\n\nfunction branch_exists(repo: string, branch: string): boolean {\n return git(repo, ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`]).status === 0;\n}\n\n/**\n * Check `branch` out into a fresh worktree at `worktree_path(workspace)`.\n *\n * Rotate-on-conflict: a leftover worktree directory or branch from a\n * crashed run is renamed aside under a `.bak.<stamp>` name — never destroyed —\n * before the fresh one is created, mirroring `.volley.bak.<stamp>`.\n */\nexport function create_worktree(options: {\n workspace: string;\n branch: string;\n base?: string;\n log?: (message: string) => void;\n}): WorktreeHandle {\n const repo = resolve(options.workspace);\n if (!existsSync(join(repo, '.git'))) {\n throw config_error(`--worktree requires the workspace to be a git repository: ${repo}`);\n }\n const path = worktree_path(repo);\n const base = options.base ?? 'HEAD';\n const log = options.log ?? (() => {});\n\n // Preserve a leftover directory (possibly dirty), then drop its now-dangling\n // registration so `worktree add` sees a clean slate.\n if (existsSync(path)) {\n const backup = `${path}.bak.${backup_stamp()}`;\n renameSync(path, backup);\n git(repo, ['worktree', 'prune']);\n log(`worktree: rotated existing ${path} aside to ${backup}`);\n }\n // Preserve a leftover branch's commits rather than clobbering with `-B`.\n if (branch_exists(repo, options.branch)) {\n const backup_branch = `${options.branch}.bak.${backup_stamp()}`;\n git_ok(repo, ['branch', '-m', options.branch, backup_branch]);\n log(`worktree: rotated existing branch ${options.branch} aside to ${backup_branch}`);\n }\n\n git_ok(repo, ['worktree', 'add', '-b', options.branch, path, base]);\n\n // The toolchain rides along: `node_modules` is untracked, so a fresh\n // checkout has none — link the workspace's install in so the deterministic\n // check (which runs at the build root) and the builder's `bash` can\n // run the project toolchain without a per-run re-install.\n const modules = join(repo, 'node_modules');\n if (existsSync(modules) && !existsSync(join(path, 'node_modules'))) {\n symlinkSync(modules, join(path, 'node_modules'), 'dir');\n log(`worktree: linked node_modules from ${repo}`);\n }\n\n return { path, branch: options.branch };\n}\n\n/** What a teardown left behind. Both fields are null on the discarding path —\n * branch and checkout are gone, which is the point. */\nexport type TeardownOutcome = {\n /** The run branch teardown kept, holding work that was never integrated, for a\n * `git switch` / `git cherry-pick`. Null when the branch was deleted (nothing\n * was salvaged, or the run committed nothing worth keeping). */\n salvaged_branch: string | null;\n /** The checkout teardown refused to delete because its work could not be\n * committed (no git identity, a stale index lock, a broken repo): the files are\n * still on disk, and the next run rotates them aside rather than destroying\n * them. Null whenever the checkout was removed. */\n kept_path: string | null;\n};\n\n/**\n * Tear the worktree down with the idempotent trio: remove the worktree,\n * delete its branch, prune the registration. Each step tolerates the target\n * already being gone, so a second teardown — or teardown of a worktree that\n * was never created — is a safe no-op.\n *\n * `salvage` flips the trio from *discard* to *keep* for the one case that has no\n * other copy of its work: a converged run whose effects were never integrated\n * (`--worktree` without `--git` — there are no checkpoint commits and no squash\n * merge, so `branch -D` plus a `--force` removal would eat the build). Teardown\n * then commits the checkout's state onto the run branch, skips the `branch -D`,\n * and removes only the checkout. Failed and integrated runs keep discarding:\n * nothing is left to save.\n */\nexport function teardown_worktree(options: {\n workspace: string;\n branch: string;\n salvage?: boolean;\n}): TeardownOutcome {\n const repo = resolve(options.workspace);\n const path = worktree_path(repo);\n const outcome: TeardownOutcome =\n options.salvage === true\n ? salvage_worktree(repo, path, options.branch)\n : { salvaged_branch: null, kept_path: null };\n // Salvage that could not commit: the work exists only in this directory, so\n // leave the whole worktree standing rather than removing what holds it.\n if (outcome.kept_path !== null) return outcome;\n\n git_quiet(repo, ['worktree', 'remove', '--force', path]);\n if (outcome.salvaged_branch === null) {\n git_quiet(repo, ['branch', '-D', options.branch]);\n }\n git_quiet(repo, ['worktree', 'prune']);\n // If git left the directory behind (already detached from the repo), clear it.\n if (existsSync(path)) {\n try {\n rmSync(path, { recursive: true, force: true });\n } catch {\n // Best effort; a lingering directory does not fail the run.\n }\n }\n return outcome;\n}\n\n/**\n * Commit whatever the run left in the worktree onto the run's own branch, so an\n * unintegrated success survives its teardown. Reports the branch when it ends up\n * carrying commits the workspace branch does not — a run that changed nothing\n * leaves no branch behind — or the checkout path when the commit did not land,\n * which is teardown's signal to keep its hands off the directory.\n */\nfunction salvage_worktree(repo: string, path: string, branch: string): TeardownOutcome {\n if (existsSync(path)) {\n git_quiet(path, ['add', '-A']);\n git_quiet(path, [\n 'commit',\n '-m',\n `volley: salvage unintegrated worktree (${branch})`,\n '--no-verify',\n ]);\n if (worktree_dirty(path)) return { salvaged_branch: null, kept_path: path };\n }\n return { salvaged_branch: branch_ahead(repo, branch) ? branch : null, kept_path: null };\n}\n\n/** Uncommitted or untracked changes still in the checkout — i.e. the salvage\n * commit did not land. A git call that fails outright reads as clean: teardown's\n * existing guards already cope with a checkout git cannot speak for. */\nfunction worktree_dirty(path: string): boolean {\n const status = git_quiet(path, ['status', '--porcelain']);\n return status.status === 0 && status.stdout.trim().length > 0;\n}\n\n/** Does `branch` carry commits the workspace's HEAD does not? The run branch is\n * cut from HEAD, so this asks \"did the run commit anything?\" — and answers false\n * for a branch that does not exist, which keeps teardown idempotent. */\nfunction branch_ahead(repo: string, branch: string): boolean {\n const ahead = git_quiet(repo, ['rev-list', '--count', `HEAD..${branch}`]);\n return ahead.status === 0 && Number(ahead.stdout.trim()) > 0;\n}\n\nexport type WorktreeOptions<T> = {\n enabled: boolean;\n workspace: string;\n branch: string;\n log?: (message: string) => void;\n /** Consulted with the body's value on a clean exit: `true` means this run's\n * work was never integrated, so teardown must salvage it onto the run branch\n * instead of discarding it. Never consulted when the body throws — a\n * failed run's branch is thrown away wholesale. */\n salvage?: (value: T) => boolean;\n};\n\n/** The body's value plus what teardown left behind. */\nexport type WorktreeOutcome<T> = TeardownOutcome & { value: T };\n\n/**\n * Run `body` with the run's worktree lifecycle around it: when enabled, create\n * the worktree first and guarantee teardown on every exit path; when disabled,\n * this is a transparent pass-through so the default path is byte-for-byte\n * unchanged.\n *\n * The discarding teardown stays in the `finally` — it is what a throw, an abort,\n * or a non-salvaging exit gets. A *salvaging* teardown has to run inside the\n * `try` instead, because its outcome (the surviving branch) is part of this\n * call's return value; `discard_on_exit` hands the responsibility over so the\n * two never both fire and `branch -D` the branch salvage just kept.\n */\nexport async function with_worktree<T>(\n options: WorktreeOptions<T>,\n body: () => Promise<T>,\n): Promise<WorktreeOutcome<T>> {\n if (!options.enabled) {\n return { value: await body(), salvaged_branch: null, kept_path: null };\n }\n create_worktree({\n workspace: options.workspace,\n branch: options.branch,\n ...(options.log !== undefined ? { log: options.log } : {}),\n });\n let discard_on_exit = true;\n try {\n const value = await body();\n if (options.salvage?.(value) !== true) {\n return { value, salvaged_branch: null, kept_path: null };\n }\n discard_on_exit = false;\n return {\n value,\n ...teardown_worktree({\n workspace: options.workspace,\n branch: options.branch,\n salvage: true,\n }),\n };\n } finally {\n if (discard_on_exit) {\n teardown_worktree({ workspace: options.workspace, branch: options.branch });\n }\n }\n}\n","/**\n * Workspace lifecycle: `.volley/` initialization, stale-run\n * backup rotation, path helpers, and optional git checkpoints.\n */\nimport { existsSync, mkdirSync, renameSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { check_error, config_error } from './types.js';\nimport type { ResolvedConfig } from './types.js';\n\nexport function volley_path(workspace: string, ...parts: string[]): string {\n return join(workspace, '.volley', ...parts);\n}\n\nexport function iteration_dir(workspace: string, iteration: number): string {\n return volley_path(workspace, 'iterations', String(iteration).padStart(3, '0'));\n}\n\n/** Filesystem-safe timestamp for `.bak.<stamp>` rotation names. Shared by the\n * `.volley/` rotation here and the worktree rotation so both preserve\n * prior state under the same never-destroy naming. */\nexport function backup_stamp(date: Date = new Date()): string {\n return date.toISOString().replace(/[:.]/g, '-');\n}\n\n/** Fresh-run initialization: rotate a stale `.volley/` aside, then create the\n * directory tree. Resume runs skip rotation (`preserve: true`). */\nexport function initialize_workspace(\n workspace: string,\n options: { preserve?: boolean } = {},\n): void {\n const dir = volley_path(workspace);\n if (existsSync(dir) && options.preserve !== true) {\n renameSync(dir, join(workspace, `.volley.bak.${backup_stamp()}`));\n }\n mkdirSync(volley_path(workspace, 'iterations'), { recursive: true });\n}\n\nexport function write_resolved_config(config: ResolvedConfig): void {\n const record = {\n version: config.version,\n run_id: config.run_id,\n started_at: config.started_at,\n prompt: config.prompt,\n criteria: config.criteria,\n check: config.check,\n check_resolved: config.check_resolved,\n builder_model: config.builder_model,\n builder_provider: config.builder_provider,\n builder_max_steps: config.builder_max_steps,\n critic_model: config.critic_model,\n critic_provider: config.critic_provider,\n builder_permission_mode: config.builder_permission_mode,\n critic_preset: config.critic_preset,\n critic_prompt_path: config.critic_prompt_path,\n max_iterations: config.max_iterations,\n max_cost_usd: config.max_cost_usd,\n git_checkpoints: config.git_checkpoints,\n worktree: config.worktree,\n discard_worktree: config.discard_worktree,\n gate_paths: config.gate_paths,\n fail_on_gate_edit: config.fail_on_gate_edit,\n sandbox_image: config.sandbox_image,\n workspace: config.workspace,\n };\n writeFileSync(\n volley_path(config.workspace, 'config.json'),\n `${JSON.stringify(record, null, 2)}\\n`,\n );\n}\n\n/**\n * `--git`: commit everything under `root` after a phase (`git -C <root>`, run\n * here via the spawn `cwd`). `root` is the build root (`build_root`): the\n * workspace on the default path, or the per-run worktree under `--worktree`, so\n * checkpoints land on the worktree branch rather than the workspace's.\n * A checkpoint with nothing to commit is fine; a missing git binary or repo is\n * not.\n */\nexport function git_checkpoint(root: string, message: string): void {\n if (!existsSync(join(root, '.git'))) {\n // `.git` is a directory in the workspace and a file in a linked worktree;\n // existsSync accepts both.\n throw config_error(`git checkpoints require a git repository: ${root}`);\n }\n const add = spawnSync('git', ['add', '-A'], { cwd: root });\n if (add.error !== undefined || add.status !== 0) {\n throw check_error(`git add failed: ${add.stderr?.toString() ?? String(add.error)}`);\n }\n const commit = spawnSync('git', ['commit', '-m', message, '--no-verify'], {\n cwd: root,\n });\n // Exit 1 with \"nothing to commit\" is a no-op iteration, not a failure.\n if (commit.error !== undefined) {\n throw check_error(`git commit failed to start: ${String(commit.error)}`);\n }\n const out = `${commit.stdout?.toString() ?? ''}${commit.stderr?.toString() ?? ''}`;\n if (commit.status !== 0 && !out.includes('nothing to commit')) {\n throw check_error(`git commit failed: ${out.trim()}`);\n }\n}\n\n/**\n * Integration — bring a successful `--worktree --git` run's effects onto the\n * workspace branch. The per-phase checkpoints on `branch` are the raw\n * audit/replay trail; here they collapse into a single squash commit\n * (`git merge --squash` then `commit`) on the workspace's current branch. The\n * shared object store makes this a local, fetch-free merge, and — because the\n * workspace branch never moved during the run (checkpoints went to the phase\n * branch) — it is conflict-free by construction. A run whose phase branch has no\n * new commits integrates to a no-op. Only successful runs integrate; an\n * abandoned run's branch is discarded wholesale by the teardown trio instead.\n */\nexport function integrate_worktree(workspace: string, branch: string, message: string): void {\n if (!existsSync(join(workspace, '.git'))) {\n throw config_error(`--worktree integration requires a git repository: ${workspace}`);\n }\n const squash = spawnSync('git', ['merge', '--squash', branch], {\n cwd: workspace,\n encoding: 'utf8',\n });\n if (squash.error !== undefined) {\n throw check_error(`git merge --squash failed to start: ${String(squash.error)}`);\n }\n if (squash.status !== 0) {\n throw check_error(\n `git merge --squash ${branch} failed: ${(squash.stderr || squash.stdout).trim()}`,\n );\n }\n const commit = spawnSync('git', ['commit', '-m', message, '--no-verify'], {\n cwd: workspace,\n encoding: 'utf8',\n });\n if (commit.error !== undefined) {\n throw check_error(`git commit failed to start: ${String(commit.error)}`);\n }\n // An empty phase branch stages nothing; \"nothing to commit\" is a no-op.\n const out = `${commit.stdout ?? ''}${commit.stderr ?? ''}`;\n if (commit.status !== 0 && !out.includes('nothing to commit')) {\n throw check_error(`git commit failed: ${out.trim()}`);\n }\n}\n","/**\n * Critic invocation: a read-only session (`claude_cli`, or a local model with\n * volley's read tools) returning a schema-validated structured verdict. The\n * harness — not the critic — writes `.volley/feedback.md` and `.volley/verdict`.\n */\nimport { z } from 'zod';\nimport { model_call } from 'fascicle';\nimport type {\n Engine,\n FallbackOutcome,\n GenerateOptions,\n GenerateResult,\n RetryOutcome,\n RunContext,\n Step,\n StreamChunk,\n} from 'fascicle';\nimport { accumulate } from '../cost.js';\nimport { resolve_ollama_base_url } from '../engine.js';\nimport { prewarm_ollama_model } from '../prewarm.js';\nimport { error_kind, phase_error } from '../types.js';\nimport type { CauseKind, LoopState, ResolvedConfig } from '../types.js';\nimport { build_root } from '../worktree.js';\nimport { compose_critic_prompt, resolve_critic_prompt } from './prompt.js';\nimport { read_only_tools, workspace_inventory } from './tools.js';\n\nconst CRITIC_ALLOWED_TOOLS = ['Read', 'Grep', 'Glob'] as const;\n\nconst CRITIC_DISALLOWED_TOOLS = 'Write,Edit,MultiEdit,NotebookEdit,Bash';\n\nexport const verdict_schema = z.object({\n verdict: z.enum(['approved', 'changes_requested']),\n feedback: z\n .string()\n .describe(\n 'Free-form markdown for the builder. Concrete and actionable. ' +\n 'Will be passed verbatim into the next iteration.',\n ),\n unmet_criteria: z\n .array(z.string())\n .describe(\n 'The specific acceptance criteria judged unmet, verbatim. Empty when approved.',\n ),\n});\n\nexport type VerdictOutput = z.infer<typeof verdict_schema>;\n\nexport type CriticDeps = {\n engine: Engine;\n config: ResolvedConfig;\n on_chunk: (chunk: StreamChunk) => void;\n};\n\n/** Read-only tool wiring per provider. The claude_cli critic is confined at\n * the CLI permission layer (allowlist + explicit disallow); a local-model\n * critic gets volley's own workspace-scoped read-only tools and no write\n * path at all.\n *\n * The two providers also enforce `verdict_schema` by two different paths, both\n * verified live. The claude_cli critic compiles the schema for\n * `claude --json-schema`; that only works because fascicle 0.12.13's\n * `compile_schema` strips the top-level `$schema`/`$id` that zod v4 stamps (the\n * CLI rejects them) — `live_smoke` asserts a structured verdict comes back, so a\n * future fascicle regression there fails loudly rather than silently. The local\n * (ollama/lmstudio) critic instead gets Ollama **constrained decode** —\n * fascicle's ai_sdk default whenever a `schema` is passed — so the verdict is\n * structurally guaranteed at decode time, with no prompt-parse-repair;\n * `live_local_builder` exercises that path. Unchanged in v3: on ai_sdk\n * constrained decode needs no wiring, and under the deferred native flip it\n * would move to `provider_options.ollama.format` (parked). */\nfunction critic_tool_options(\n config: ResolvedConfig,\n): Pick<GenerateOptions<VerdictOutput>, 'tools' | 'provider_options'> {\n if (config.critic_provider === 'claude_cli') {\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...CRITIC_ALLOWED_TOOLS],\n extra_args: ['--disallowedTools', CRITIC_DISALLOWED_TOOLS],\n },\n },\n };\n }\n // Read the builder's actual output: under `--worktree` that lives in\n // the worktree, so the local critic's read tools resolve through the same\n // re-pointed containment root as the builder's writes.\n return { tools: read_only_tools(build_root(config.workspace, config.worktree)) };\n}\n\n/** Degradation ladder rung 1: how many times a local critic's call\n * is retried on a provider stream death before the ladder moves on. Capped at\n * one — the qwen3.6/Ollama tool-XML parser death is stochastic, so a same-call\n * retry often passes; past one attempt the failure is not transient and the\n * tool-less fallback must take over. */\nexport const MAX_CRITIC_RETRIES = 1;\n\n/** Is this critic failure the transient local-provider stream death the ladder\n * retries? Local providers only (the `claude_cli` path is proven and its\n * retries cost real money), and fascicle's typed `provider_error` only (no\n * message string-matching). A user abort never gets here: `retry` and\n * `fallback` pass control-flow signals through untouched, and `retry` checks the\n * signal before every attempt, so an abort stays exit-130. */\nfunction is_retryable_critic_error(config: ResolvedConfig, err: unknown): boolean {\n if (config.critic_provider === 'claude_cli') return false;\n return error_kind(err) === 'provider_error';\n}\n\n/** fascicle's `provider_error.cause_kind` is `... | undefined`; fold the\n * missing case into `'unknown'` so a recorded retry always names a cause. */\nfunction retry_cause_kind_of(err: unknown): CauseKind {\n const cause = (err as { cause_kind?: unknown }).cause_kind;\n return cause === 'provider_5xx' || cause === 'network' ? cause : 'unknown';\n}\n\n/** Bookkeeping stamped onto a critic record by the degradation ladder: how many\n * tool-bearing retries preceded this verdict, the last retry's cause, and — on the\n * tool-less rung — the `critic_degraded` mark. */\ntype LadderMark = {\n retries: number;\n retry_cause_kind: CauseKind | undefined;\n critic_degraded?: boolean;\n};\n\n/** Fold a successful critic `generate` result into loop state, stamping the\n * ladder bookkeeping onto the critic record. Shared by the tool-bearing path and\n * the tool-less fallback so both shape the record identically (the fallback just\n * adds `critic_degraded: true`). */\nfunction finalize_critic(\n state: LoopState,\n result: GenerateResult<VerdictOutput>,\n model: string,\n mark: LadderMark,\n duration_ms: number,\n): LoopState {\n const next = accumulate(state, 'critic', result, model, duration_ms);\n return {\n ...next,\n critic:\n next.critic === null\n ? null\n : {\n ...next.critic,\n retries: mark.retries,\n ...(mark.retry_cause_kind !== undefined\n ? { retry_cause_kind: mark.retry_cause_kind }\n : {}),\n ...(mark.critic_degraded === true ? { critic_degraded: true } : {}),\n },\n verdict: result.content.verdict,\n feedback: result.content.feedback,\n unmet_criteria: result.content.unmet_criteria,\n };\n}\n\n/** The tool-less fallback's prompt: the normal critic prompt plus a notice that\n * read tools are gone this pass and a paths+sizes workspace inventory, so\n * the critic still judges from the criteria, the raw check artifacts already in\n * the prompt, and the file layout — grounded, just shallower. */\nexport function toolless_critic_prompt(config: ResolvedConfig, tool_prompt: string): string {\n return [\n tool_prompt,\n '',\n 'NOTE: file-read tools are unavailable for this review. Judge from the',\n 'acceptance criteria, the deterministic check output above, and the workspace',\n 'file inventory below (paths and sizes only — file contents are not shown).',\n '',\n 'WORKSPACE FILE INVENTORY',\n '------------------------',\n workspace_inventory(build_root(config.workspace, config.worktree)),\n ].join('\\n');\n}\n\n/** What the critic arm answers with: the call that produced the verdict, and\n * how the ladder reached it. */\nexport type CriticAnswer = {\n result: GenerateResult<VerdictOutput>;\n mark: LadderMark;\n};\n\n/** The critic's model boundary: the whole degradation ladder behind one step\n * (composed in `../flow.ts`). */\nexport type CriticStep = Step<string, CriticAnswer>;\n\n/** One critic call returning the validated verdict in its `GenerateResult`. */\nexport type CriticCall = Step<string, GenerateResult<VerdictOutput>>;\n\nfunction critic_call_config(deps: CriticDeps) {\n const { config } = deps;\n return {\n engine: deps.engine,\n provider: config.critic_provider,\n model: config.critic_model,\n system: resolve_critic_prompt(config),\n schema: verdict_schema,\n on_chunk: deps.on_chunk,\n };\n}\n\n/** Rung 1's leaf: the critic with its read tools (or the CLI's read-only\n * allowlist). */\nexport function make_critic_tools_step(deps: CriticDeps): CriticCall {\n return model_call({\n ...critic_call_config(deps),\n id: 'critic_tools',\n description: 'model call with read-only workspace tools',\n ...critic_tool_options(deps.config),\n });\n}\n\n/** Rung 2's leaf: the same critic with no tools at all, so nothing enters\n * Ollama's broken tool parser; constrained decode (`schema`) still guarantees\n * the verdict. */\nexport function make_critic_toolless_step(deps: CriticDeps): CriticCall {\n return model_call({\n ...critic_call_config(deps),\n id: 'critic_toolless',\n description: 'model call judging from the check output and a file list',\n });\n}\n\n/** The ladder's retry predicate for this run's critic provider. */\nexport function critic_retryable(config: ResolvedConfig): (err: unknown) => boolean {\n return (err) => is_retryable_critic_error(config, err);\n}\n\n/** Rung 1's projection: a verdict the tool-bearing critic produced, marked with\n * how many stream deaths it took and the last one's cause. */\nexport function with_retries(outcome: RetryOutcome<GenerateResult<VerdictOutput>>): CriticAnswer {\n const last = outcome.errors.at(-1);\n return {\n result: outcome.value,\n mark: {\n retries: outcome.attempts - 1,\n retry_cause_kind: last === undefined ? undefined : retry_cause_kind_of(last),\n },\n };\n}\n\n/** Rung 2's answer: every retry was spent, and the verdict is marked degraded\n * so it never passes silently as a full critique. */\nexport function as_degraded(result: GenerateResult<VerdictOutput>): CriticAnswer {\n return {\n result,\n mark: { retries: MAX_CRITIC_RETRIES, retry_cause_kind: undefined, critic_degraded: true },\n };\n}\n\n/** The ladder's projection: the tool-less backup cannot see why it ran, so the\n * cause comes from the last stream death the retry rung gave up on. */\nexport function with_fallback_cause(outcome: FallbackOutcome<CriticAnswer>): CriticAnswer {\n if (outcome.source === 'primary') return outcome.value;\n return {\n ...outcome.value,\n mark: { ...outcome.value.mark, retry_cause_kind: retry_cause_kind_of(outcome.primary_error) },\n };\n}\n\n/** What the `--dry-run` canary learned about the critic seat:\n * `ok` — the tool-bearing call came back; `degraded` — the tool-bearing\n * call died on a provider stream error but a tool-less pass survived, so a real\n * run will likely finish via the fallback ladder (`critic_degraded`);\n * `failed` — even the tool-less pass died, so the combo would fail a real run\n * degraded or not. */\nexport type CanaryOutcome =\n | { outcome: 'ok' }\n | { outcome: 'degraded'; detail: string }\n | { outcome: 'failed'; detail: string };\n\n/** The canary must *elicit a real tool call*: the qwen3.6 death happens at\n * tool-markup emission inside Ollama's server-side parser, so a call that never\n * invokes a tool could not fail and would prove nothing. The target path need\n * not exist — a tool error is fed back and the model answers anyway; entering\n * the parser is the test. No token cap: the budget is behavioral (one tool call,\n * then an immediate one-word verdict), because a hard `max_tokens` could\n * truncate a thinking model mid-verdict and report `failed` for a combo that\n * works. A model that skips the tool and just answers passes stochastically —\n * acceptable: the canary is early warning, the ladder is the guarantee. */\nconst CANARY_PROMPT = [\n 'CANARY CHECK — a tiny wiring probe, not a real review.',\n 'First, call the read_file tool on the path \"package.json\".',\n 'Whatever the tool returns (content or an error), immediately answer with',\n 'verdict \"approved\", feedback exactly \"canary\", and empty unmet_criteria.',\n].join('\\n');\n\n/** The canary's tool-less rung: same schema-constrained call, no tool ask. */\nconst CANARY_TOOLLESS_PROMPT = [\n 'CANARY CHECK — a tiny wiring probe, not a real review.',\n 'Answer with verdict \"approved\", feedback exactly \"canary\", and empty',\n 'unmet_criteria.',\n].join('\\n');\n\nfunction canary_detail(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * The `--dry-run` critic-seat canary: one tiny generate through the *real*\n * production tool wiring (`critic_tool_options`) and `verdict_schema`, $0 on a\n * local model. The caller (preflight) gates it to local critics only —\n * `claude_cli` is proven and its calls cost real money.\n *\n * A tool-bearing death is classified by the same discriminant as the run-time\n * ladder (typed `provider_error` only), then probed tool-less exactly as\n * rung 2 would run, so the canary *predicts the ladder* instead of guessing:\n * tool-less survives → `degraded` (warn — the combo completes a real run,\n * marked); tool-less dies too → `failed` (the endpoint-down / model-missing\n * class that earns exit 5 because not even degradation would save it).\n */\nexport async function critic_canary(\n engine: Engine,\n config: ResolvedConfig,\n env: Record<string, string | undefined> = process.env,\n): Promise<CanaryOutcome> {\n // Same cold-load guard as the real critic phase: without it a disk-cold model\n // would die on the first-byte timeout and the canary would cry wolf.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(resolve_ollama_base_url(env), config.critic_model);\n }\n const base: Omit<GenerateOptions<VerdictOutput>, 'prompt' | 'tools' | 'provider_options'> = {\n provider: config.critic_provider,\n model: config.critic_model,\n system: resolve_critic_prompt(config),\n schema: verdict_schema,\n };\n try {\n await engine.generate({\n ...base,\n prompt: CANARY_PROMPT,\n ...critic_tool_options(config),\n });\n return { outcome: 'ok' };\n } catch (err) {\n if (error_kind(err) !== 'provider_error') {\n return { outcome: 'failed', detail: canary_detail(err) };\n }\n const tool_death = canary_detail(err);\n try {\n await engine.generate({ ...base, prompt: CANARY_TOOLLESS_PROMPT });\n return { outcome: 'degraded', detail: tool_death };\n } catch (fallback_err) {\n return { outcome: 'failed', detail: canary_detail(fallback_err) };\n }\n }\n}\n\nexport type CriticRunDeps = {\n critic: CriticStep;\n config: ResolvedConfig;\n};\n\nexport async function run_critic(\n deps: CriticRunDeps,\n state: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config } = deps;\n if (state.check === null) {\n throw phase_error('critic', state.iteration, new Error('check phase did not run'));\n }\n const check = state.check;\n try {\n // Same cold-load guard as the builder: pre-load an Ollama critic model so\n // a cold multi-GB load doesn't blow the real call's first-byte timeout.\n // Best-effort; a model the builder already warmed returns immediately.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(\n resolve_ollama_base_url(process.env),\n config.critic_model,\n ctx.abort,\n );\n }\n const prompt = compose_critic_prompt({\n criteria: config.criteria,\n iteration: state.iteration,\n check,\n changes: state.changes,\n });\n // The phase's duration spans every rung that ran, not just the call that\n // answered: a retried or degraded verdict took that long to get, and no one\n // result's `timing` covers the attempts before it.\n const started = Date.now();\n const { result, mark } = await ctx.call(deps.critic, prompt);\n return finalize_critic(state, result, config.critic_model, mark, Date.now() - started);\n } catch (err) {\n throw phase_error('critic', state.iteration, err);\n }\n}\n","/**\n * Critic prompt resolution and composition. Presets live as\n * markdown files in ./presets/ — discoverable by listing the directory —\n * and every critic system prompt gets the harness append.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { config_error } from '../types.js';\nimport type {\n ChangeSet,\n ChangeStatus,\n ChangedFile,\n CheckResult,\n ResolvedConfig,\n} from '../types.js';\n\n/** Walk up from this module to the package root (works from src/ under tsx\n * and from dist/ in the published package, which ships src/critic/presets). */\nexport function presets_dir(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(dir, 'src', 'critic', 'presets');\n if (existsSync(candidate)) return candidate;\n const local = join(dir, 'presets');\n if (existsSync(local)) return local;\n dir = dirname(dir);\n }\n throw config_error('critic presets directory not found');\n}\n\nexport function resolve_critic_prompt(config: ResolvedConfig): string {\n const base =\n config.critic_prompt_path !== null\n ? readFileSync(config.critic_prompt_path, 'utf8')\n : readFileSync(join(presets_dir(), `${config.critic_preset}.md`), 'utf8');\n // The CLI critic reads via built-in Read/Grep/Glob; a local-model critic\n // reads via volley's supplied read_file/search_files/list_files tools, so\n // its harness instructions name a different tool set.\n const append_file =\n config.critic_provider === 'claude_cli' ? 'harness_append.md' : 'harness_append_local.md';\n const append = readFileSync(join(presets_dir(), append_file), 'utf8');\n return `${base.trimEnd()}\\n\\n${append.trimEnd()}`;\n}\n\nexport type CriticPromptInput = {\n criteria: string;\n iteration: number;\n check: CheckResult;\n /** What the builder changed since the run's baseline (`src/changes.ts`), or\n * null when the build root is not a git repository — then the section is\n * omitted rather than claiming the builder changed nothing. */\n changes: ChangeSet | null;\n};\n\n/** One-letter status column, so a hundred-path list stays readable. */\nconst STATUS_MARKS: Record<ChangeStatus, string> = {\n added: 'A',\n modified: 'M',\n deleted: 'D',\n renamed: 'R',\n unknown: '?',\n};\n\nfunction format_change(file: ChangedFile): string {\n return ` ${STATUS_MARKS[file.status]} ${file.path}`;\n}\n\n/**\n * What the builder actually touched, handed to the critic as evidence.\n *\n * Two things this fixes, both surfaced by the reckon run\n * (`research/reckon-local-run-finding.md`). A critic that sees only the finished\n * tree reviews *state* and re-reads code the check already blessed; a critic\n * that sees the change list reviews the *change*, and knows where to point its\n * read tools. And a builder that edited its own tests could previously pass both\n * gates in silence — the check because it was rewritten, the critic because\n * nothing told it that had happened.\n *\n * Paths only, never diff hunks: the list stays bounded for a 32k-context local\n * critic, which can read any file it wants once it knows which ones moved.\n */\nfunction format_changes_section(changes: ChangeSet | null): string | null {\n if (changes === null) return null;\n const scope = changes.baseline === null ? 'this run' : `baseline ${changes.baseline.slice(0, 8)}`;\n if (changes.total === 0) {\n return [\n `BUILDER CHANGES (since ${scope})`,\n '------------------------------',\n 'The builder changed no files. Unless the acceptance criteria were already',\n 'met before this run, that is itself grounds for changes_requested.',\n ].join('\\n');\n }\n const lines = [\n `BUILDER CHANGES (since ${scope})`,\n '------------------------------',\n 'Review the work as a change, not just as a finished tree. Read the files',\n 'below with your tools as needed.',\n '',\n ...changes.files.map(format_change),\n ];\n if (changes.truncated) {\n lines.push(\n ` … showing ${String(changes.files.length)} of ${String(changes.total)} changed paths`,\n );\n }\n if (changes.gate_edits.length > 0) {\n lines.push(\n '',\n `GATE EDITS (${String(changes.gate_edits.length)})`,\n '-----------',\n 'These changed paths are part of the gate — the tests, fixtures, and check',\n 'configuration that decide whether this work passes. A check the builder can',\n 'edit proves less than one it cannot.',\n '',\n ...changes.gate_edits.map((path) => ` ! ${path}`),\n '',\n 'Judge whether each of these edits was necessary and legitimate for the task',\n 'as specified. If any of them weakened the check, deleted a case, or moved a',\n 'target rather than meeting it, the work does not meet the criteria: return',\n 'changes_requested, name the file, and say what was weakened.',\n );\n }\n return lines.join('\\n');\n}\n\nfunction format_check_section(check: CheckResult): string {\n if (!check.ran) {\n return 'No deterministic check ran for this iteration. Base your verdict on workspace inspection alone.';\n }\n const lines = [\n `DETERMINISTIC CHECK (${check.runner})`,\n '------------------------------------',\n `result: ${check.ok ? 'PASSED' : 'FAILED'} (exit ${String(check.exit_code)})`,\n ];\n if (check.failing_slots.length > 0) {\n lines.push(`failing slots: ${check.failing_slots.join(', ')}`);\n }\n if (check.summary !== undefined) {\n lines.push('', 'summary.json:', '```json', JSON.stringify(check.summary, null, 2), '```');\n }\n for (const artifact of check.detail) {\n lines.push(\n '',\n `--- raw output for failing slot \"${artifact.slot}\"${artifact.truncated ? ` (truncated; full output archived at ${artifact.path ?? 'n/a'})` : ''} ---`,\n artifact.content,\n );\n }\n if (check.log !== undefined && check.log.length > 0) {\n lines.push('', 'check output:', '```', check.log, '```');\n }\n return lines.join('\\n');\n}\n\nexport function compose_critic_prompt(input: CriticPromptInput): string {\n const changes = format_changes_section(input.changes);\n return [\n 'ACCEPTANCE CRITERIA',\n '-------------------',\n input.criteria,\n '',\n `ITERATION: ${input.iteration}`,\n '',\n format_check_section(input.check),\n ...(changes === null ? [] : ['', changes]),\n '',\n 'Review the workspace against the acceptance criteria and return your',\n 'structured verdict.',\n ].join('\\n');\n}\n","/**\n * The loop's carry-state across its life: the fresh state a run starts from,\n * the stopping rule the loop guard applies after every iteration, and the run\n * status the final state resolves to. Pure functions over `LoopState`; the\n * flow (`./flow.ts`) plugs them in.\n */\nimport { cost_cap_hit, EMPTY_USAGE } from './cost.js';\nimport type { LoopState, ResolvedConfig, RunStatus } from './types.js';\n\nexport function initial_state(): LoopState {\n return {\n iteration: 0,\n iteration_started_at: new Date().toISOString(),\n feedback: null,\n verdict: null,\n unmet_criteria: [],\n check: null,\n changes: null,\n builder: null,\n critic: null,\n total_usage: EMPTY_USAGE,\n total_cost_usd: 0,\n builder_cost_usd: 0,\n critic_cost_usd: 0,\n check_duration_ms: 0,\n iteration_cost_usd: 0,\n halt: null,\n cost_warned: false,\n };\n}\n\n/** How many rounds the loop may still run: the whole budget on a fresh run, what\n * the resumed run's completed iterations left of it otherwise. */\nexport function remaining_iterations(\n config: ResolvedConfig,\n resume_from: LoopState | null,\n): number {\n return config.max_iterations - (resume_from?.iteration ?? 0);\n}\n\n/** Did this iteration's builder edit the gate that judges it, with the operator\n * having asked for that to stop the run? Reported either way (the critic prompt\n * and the summary always carry it); only `--fail-on-gate-edit` makes it fatal. */\nfunction gate_edit_halt(config: ResolvedConfig, state: LoopState): boolean {\n return config.fail_on_gate_edit && (state.changes?.gate_edits.length ?? 0) > 0;\n}\n\n/** All stopping conditions live here: acceptance, cost cap, the gate\n * edit refusal, and — implicitly via `max_rounds` — the iteration budget.\n * Success wins when it and the cap land on the same iteration.\n *\n * A gate edit is the one condition that *beats* success rather than losing to\n * it: the run passed a check the builder had rewritten, so the pass is exactly\n * what is in question. It stops the run instead of iterating, because a model\n * that just edited the gate is not a promising candidate to be asked again. */\nexport function gate(\n config: ResolvedConfig,\n state: LoopState,\n): { stop: boolean; state: LoopState } {\n const gate_edit = gate_edit_halt(config, state);\n const success = state.check?.ok === true && state.verdict === 'approved' && !gate_edit;\n const cap = cost_cap_hit(config, state);\n const halt = gate_edit ? 'gate_edit' : !success && cap ? 'cost_cap' : null;\n return {\n stop: success || cap || gate_edit,\n state: { ...state, halt },\n };\n}\n\nexport function status_of(value: LoopState, converged: boolean): RunStatus {\n if (value.halt === 'gate_edit') return 'gate_edit_blocked';\n if (value.halt === 'cost_cap') return 'cost_cap_reached';\n return converged ? 'success' : 'budget_exhausted';\n}\n","/**\n * checkride runner: spawn `pnpm exec checkride --json`, gate on the\n * `.check/summary.json` contract (`schema_version: 1`), and collect raw\n * failing-slot artifacts for the critic — the critic reads what the tool\n * actually said, not a normalized digest.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { aborted_error } from 'fascicle';\nimport { check_error } from '../types.js';\nimport type { CheckArtifact, CheckResult } from '../types.js';\n\nexport const CHECK_ARTIFACT_MAX_CHARS = 8000;\n\nconst CHECKRIDE_SCHEMA_VERSION = 1;\n\nexport type CheckrideSummaryCheck = {\n name: string;\n adapter: string | null;\n ok: boolean;\n skipped?: boolean;\n exit_code: number | null;\n duration_ms: number;\n output_file: string | null;\n};\n\nexport type CheckrideSummary = {\n schema_version: number;\n ok: boolean;\n total_duration_ms: number;\n checks: CheckrideSummaryCheck[];\n};\n\nexport type SpawnCaptureResult = {\n exit_code: number | null;\n stdout: string;\n stderr: string;\n};\n\nexport function spawn_capture(\n cmd: string,\n args: string[],\n options: { cwd: string; abort?: AbortSignal },\n): Promise<SpawnCaptureResult> {\n return new Promise((resolve_promise, reject) => {\n const proc = spawn(cmd, args, {\n cwd: options.cwd,\n ...(options.abort !== undefined ? { signal: options.abort } : {}),\n });\n let stdout = '';\n let stderr = '';\n proc.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n proc.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n proc.on('error', (err) => {\n if (err.name === 'AbortError') {\n reject(new aborted_error('check aborted'));\n return;\n }\n reject(check_error(`check command failed to start: ${err.message}`));\n });\n proc.on('close', (code) => {\n resolve_promise({ exit_code: code, stdout, stderr });\n });\n });\n}\n\nexport type ParsedSummary = {\n summary: CheckrideSummary;\n warning: string | null;\n};\n\n/** Best-effort parse of the summary contract. `pnpm exec` talks over the\n * command's stdout (pnpm 11's dep-verify prints an \"Already up to date\"\n * install line ahead of the JSON), so the object is extracted between the\n * first `{` and the last `}` rather than parsed from byte 0. An unexpected\n * schema_version warns and still parses; no JSON object at all is a harness\n * error (exit 4). */\nexport function parse_checkride_summary(stdout: string): ParsedSummary {\n const start = stdout.indexOf('{');\n const end = stdout.lastIndexOf('}');\n let raw: unknown;\n try {\n if (start === -1 || end < start) throw new Error('no JSON object in stdout');\n raw = JSON.parse(stdout.slice(start, end + 1));\n } catch {\n throw check_error('checkride --json produced unparseable stdout');\n }\n if (typeof raw !== 'object' || raw === null || !Array.isArray((raw as CheckrideSummary).checks)) {\n throw check_error('checkride summary missing checks array');\n }\n const summary = raw as CheckrideSummary;\n const warning =\n summary.schema_version === CHECKRIDE_SCHEMA_VERSION\n ? null\n : `checkride summary schema_version ${String(summary.schema_version)} != ${String(CHECKRIDE_SCHEMA_VERSION)}; parsing best-effort`;\n return { summary, warning };\n}\n\n/** Parse the summary from stdout, falling back to the on-disk contract:\n * `.check/summary.json` is what checkride documents; stdout is its mirror and\n * wrappers may talk over it beyond what the tolerant slice can recover. */\nexport function parse_summary_with_fallback(stdout: string, workspace: string): ParsedSummary {\n try {\n return parse_checkride_summary(stdout);\n } catch (err) {\n const file = join(workspace, '.check', 'summary.json');\n if (!existsSync(file)) throw err;\n return parse_checkride_summary(readFileSync(file, 'utf8'));\n }\n}\n\nexport function failing_checks(summary: CheckrideSummary): CheckrideSummaryCheck[] {\n return summary.checks.filter((c) => !c.ok && c.skipped !== true);\n}\n\n/** Per failing slot: the raw artifact (`.check/<output_file>` when present,\n * else `.check/<slot>.stdout.txt`), truncated with a pointer to the file. */\nexport function read_failing_artifacts(\n workspace: string,\n failing: CheckrideSummaryCheck[],\n): CheckArtifact[] {\n return failing.map((check) => {\n const file = check.output_file ?? `${check.name}.stdout.txt`;\n const path = join(workspace, '.check', file);\n if (!existsSync(path)) {\n return { slot: check.name, path: null, content: '(no artifact found)', truncated: false };\n }\n const raw = readFileSync(path, 'utf8');\n const truncated = raw.length > CHECK_ARTIFACT_MAX_CHARS;\n return {\n slot: check.name,\n path,\n content: truncated ? raw.slice(0, CHECK_ARTIFACT_MAX_CHARS) : raw,\n truncated,\n };\n });\n}\n\nexport type CheckrideOpts = {\n workspace: string;\n abort?: AbortSignal;\n};\n\nexport async function run_checkride(opts: CheckrideOpts): Promise<CheckResult> {\n const proc = await spawn_capture('pnpm', ['exec', 'checkride', '--json'], {\n cwd: opts.workspace,\n ...(opts.abort !== undefined ? { abort: opts.abort } : {}),\n });\n // checkride exit 2 is a harness/usage error — an operator problem, not\n // something to iterate on.\n if (proc.exit_code === 2) {\n throw check_error(`checkride harness error: ${proc.stderr.trim()}`);\n }\n const { summary } = parse_summary_with_fallback(proc.stdout, opts.workspace);\n const failing = failing_checks(summary);\n return {\n ran: true,\n runner: 'checkride',\n ok: summary.ok,\n exit_code: proc.exit_code,\n duration_ms: summary.total_duration_ms,\n failing_slots: failing.map((c) => c.name),\n detail: read_failing_artifacts(opts.workspace, failing),\n summary,\n };\n}\n","/**\n * Generic command runner: `sh -c <command>`, combined\n * output captured, exit-0 semantics. Command-not-found is an operator error\n * (exit 4), not an iterable failure.\n */\nimport { check_error } from '../types.js';\nimport type { CheckResult } from '../types.js';\nimport { spawn_capture } from './checkride.js';\n\nexport type CommandCheckOpts = {\n command: string;\n workspace: string;\n abort?: AbortSignal;\n};\n\nexport async function run_command_check(opts: CommandCheckOpts): Promise<CheckResult> {\n const started = Date.now();\n const proc = await spawn_capture('sh', ['-c', opts.command], {\n cwd: opts.workspace,\n ...(opts.abort !== undefined ? { abort: opts.abort } : {}),\n });\n // sh reports 127 for command-not-found and 126 for not-executable.\n if (proc.exit_code === 127 || proc.exit_code === 126) {\n throw check_error(\n `check command failed to start (exit ${String(proc.exit_code)}): ${opts.command}`,\n );\n }\n const log = `${proc.stdout}${proc.stderr}`;\n return {\n ran: true,\n runner: 'command',\n ok: proc.exit_code === 0,\n exit_code: proc.exit_code,\n duration_ms: Date.now() - started,\n failing_slots: [],\n detail: [],\n log,\n };\n}\n\nexport function skipped_check(reason: 'none' | 'cost_cap'): CheckResult {\n return {\n ran: false,\n runner: 'none',\n // With no check configured the loop is critic-gated only, so the gate is\n // open (`ok: true`). A cost-cap skip must not look like a passing gate.\n ok: reason === 'none',\n exit_code: null,\n duration_ms: 0,\n failing_slots: [],\n detail: [],\n };\n}\n","/**\n * Iteration archiving, run-level summary, and resume-state recovery.\n * `feedback.md` and `verdict` are harness-written projections\n * of the critic's validated structured output.\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join } from 'node:path';\nimport { EMPTY_USAGE } from './cost.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CriticProvider,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n RunResult,\n RunStatus,\n Verdict,\n VolleyConfig,\n} from './types.js';\nimport { iteration_dir, volley_path } from './workspace.js';\n\nfunction write_json(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction persist_verdict_files(\n workspace: string,\n feedback: string,\n verdict: Verdict,\n): void {\n writeFileSync(volley_path(workspace, 'feedback.md'), feedback.endsWith('\\n') ? feedback : `${feedback}\\n`);\n writeFileSync(volley_path(workspace, 'verdict'), `${verdict}\\n`);\n}\n\nfunction phase_summary(record: PhaseRecord | null): Record<string, unknown> | null {\n if (record === null) return null;\n return {\n provider: record.provider,\n model: record.model,\n session_id: record.session_id,\n duration_ms: record.duration_ms,\n usage: record.usage,\n cost_usd: record.cost_usd,\n cost_source: record.cost_source,\n finish_reason: record.finish_reason,\n tool_calls: record.tool_calls,\n salvaged_tool_calls: record.salvaged_tool_calls,\n // Salvage rate (a health metric): the share of tool calls recovered from\n // assistant text. A high rate on a local run means the model's native\n // tool-call encoding is drifting from its runtime's parser (pin them as one\n // unit). 0 when the phase made no tool calls (the CLI builder's own loop).\n salvage_rate: record.tool_calls === 0 ? 0 : record.salvaged_tool_calls / record.tool_calls,\n // Degradation-ladder bookkeeping, critic-only: the provider-error\n // retries that preceded this verdict, their cause, and whether it was rendered\n // by the tool-less fallback. Emitted only when set, so the builder record and\n // old summary consumers are untouched. `critic_degraded` is the on-disk\n // half of the contract — the comparison block reads it back from here.\n ...(record.retries !== undefined ? { retries: record.retries } : {}),\n ...(record.retry_cause_kind !== undefined\n ? { retry_cause_kind: record.retry_cause_kind }\n : {}),\n ...(record.critic_degraded === true ? { critic_degraded: true } : {}),\n // Model speed, where fascicle could time the turns (never `claude_cli`).\n // Emitted only when measured. Additive.\n ...(record.throughput !== undefined ? { throughput: record.throughput } : {}),\n };\n}\n\n/** Archive one completed iteration: verdict files, check artifacts, and the\n * per-iteration summary. */\nexport function archive_iteration(config: ResolvedConfig, state: LoopState): void {\n const dir = iteration_dir(config.workspace, state.iteration);\n mkdirSync(join(dir, 'check'), { recursive: true });\n\n if (state.verdict !== null && state.feedback !== null) {\n persist_verdict_files(config.workspace, state.feedback, state.verdict);\n writeFileSync(join(dir, 'feedback.md'), readFileSync(volley_path(config.workspace, 'feedback.md')));\n writeFileSync(join(dir, 'verdict'), `${state.verdict}\\n`);\n }\n\n const check = state.check;\n if (check !== null && check.ran) {\n if (check.runner === 'checkride') {\n if (check.summary !== undefined) {\n write_json(join(dir, 'check', 'summary.json'), check.summary);\n }\n for (const artifact of check.detail) {\n if (artifact.path !== null && existsSync(artifact.path)) {\n writeFileSync(join(dir, 'check', basename(artifact.path)), readFileSync(artifact.path));\n }\n }\n } else {\n writeFileSync(join(dir, 'check', 'check.log'), check.log ?? '');\n writeFileSync(join(dir, 'check', 'check.exit'), `${String(check.exit_code)}\\n`);\n }\n }\n\n const completed_at = new Date().toISOString();\n write_json(join(dir, 'summary.json'), {\n iteration: state.iteration,\n started_at: state.iteration_started_at,\n completed_at,\n duration_ms: Date.parse(completed_at) - Date.parse(state.iteration_started_at),\n builder: phase_summary(state.builder),\n check:\n check === null\n ? null\n : {\n ran: check.ran,\n runner: check.runner,\n ok: check.ok,\n exit_code: check.exit_code,\n duration_ms: check.duration_ms,\n failing_slots: check.failing_slots,\n },\n critic: phase_summary(state.critic),\n // What the builder reached for this iteration (`src/changes.ts`), archived\n // beside the check's verdict so the two can be read against each other after\n // the fact: green + a gate edit is a different result from green alone.\n // Null when the build root is not a git repository. Additive.\n changes: state.changes,\n verdict: state.verdict,\n // The criteria the critic judged unmet, verbatim. The run-level summary\n // reads the last iteration's list, so a non-converged run says what it was\n // still missing when it stopped instead of only that it stopped. Additive.\n unmet_criteria: state.unmet_criteria,\n iteration_cost_usd: state.iteration_cost_usd,\n iteration_total_cost_usd: state.total_cost_usd,\n });\n}\n\nexport function run_result_from_state(\n config: ResolvedConfig,\n state: LoopState,\n status: RunStatus,\n completed_at: string | null,\n): RunResult {\n return {\n run_id: config.run_id,\n status,\n started_at: config.started_at,\n completed_at,\n iterations_completed: state.iteration,\n total_usage: state.total_usage,\n total_cost_usd: state.total_cost_usd,\n builder_cost_usd: state.builder_cost_usd,\n critic_cost_usd: state.critic_cost_usd,\n check_duration_ms: state.check_duration_ms,\n final_verdict: state.verdict,\n // The loop itself never salvages: the orchestrator re-stamps this after\n // teardown when a converged `--worktree` run's work was kept on its branch,\n // which is the only moment the branch's survival is known.\n salvaged_branch: null,\n };\n}\n\nexport type ResumeState = {\n raw_config: VolleyConfig;\n run_id: string;\n started_at: string;\n state: LoopState;\n iterations_completed: number;\n};\n\n/** Recover a resumable run from `.volley/`: settings from\n * config.json, totals from summary.json, feedback from feedback.md. An\n * iteration directory without a summary.json was interrupted mid-phase and\n * is discarded. */\nexport function load_resume_state(workspace: string, run_id: string): ResumeState {\n const config_path = volley_path(workspace, 'config.json');\n if (!existsSync(config_path)) {\n throw config_error(`no resumable run found: ${config_path} missing`);\n }\n const recorded = JSON.parse(readFileSync(config_path, 'utf8')) as Record<string, unknown>;\n if (recorded['run_id'] !== run_id) {\n throw config_error(\n `run ${run_id} not found in ${workspace} (recorded run: ${String(recorded['run_id'])})`,\n );\n }\n\n const iterations_root = volley_path(workspace, 'iterations');\n const dirs = existsSync(iterations_root)\n ? readdirSync(iterations_root).filter((d) => /^\\d{3}$/.test(d)).toSorted()\n : [];\n let completed = 0;\n for (const dir of dirs) {\n const full = join(iterations_root, dir);\n if (existsSync(join(full, 'summary.json'))) {\n completed = Number(dir);\n } else {\n rmSync(full, { recursive: true, force: true });\n }\n }\n\n const summary_path = volley_path(workspace, 'summary.json');\n const summary = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : null;\n\n const feedback_path = volley_path(workspace, 'feedback.md');\n const feedback = existsSync(feedback_path) ? readFileSync(feedback_path, 'utf8') : null;\n\n const raw_config: VolleyConfig = {\n prompt: String(recorded['prompt']),\n workspace: String(recorded['workspace']),\n criteria: String(recorded['criteria']),\n check: String(recorded['check']),\n builder_model: String(recorded['builder_model']),\n builder_provider: (recorded['builder_provider'] ?? 'claude_cli') as BuilderProvider,\n ...(recorded['builder_max_steps'] === undefined\n ? {}\n : { builder_max_steps: Number(recorded['builder_max_steps']) }),\n critic_model: String(recorded['critic_model']),\n critic_provider: (recorded['critic_provider'] ?? 'claude_cli') as CriticProvider,\n builder_permission_mode: recorded['builder_permission_mode'] as BuilderPermissionMode,\n critic:\n recorded['critic_preset'] === 'custom'\n ? String(recorded['critic_prompt_path'])\n : String(recorded['critic_preset']),\n max_iterations: Number(recorded['max_iterations']),\n max_cost_usd: recorded['max_cost_usd'] as number | null,\n git_checkpoints: recorded['git_checkpoints'] === true,\n worktree: recorded['worktree'] === true,\n discard_worktree: recorded['discard_worktree'] === true,\n ...(Array.isArray(recorded['gate_paths'])\n ? { gate_paths: recorded['gate_paths'] as string[] }\n : {}),\n fail_on_gate_edit: recorded['fail_on_gate_edit'] === true,\n ...(recorded['sandbox_image'] === undefined\n ? {}\n : { sandbox_image: recorded['sandbox_image'] as string }),\n };\n\n const state: LoopState = {\n iteration: completed,\n iteration_started_at: new Date().toISOString(),\n feedback,\n verdict: null,\n unmet_criteria: [],\n check: null,\n // Re-measured by the resumed run's first `build` step, against a baseline\n // captured at resume — a resumed run reports what it changes from there.\n changes: null,\n builder: null,\n critic: null,\n total_usage: summary?.total_usage ?? EMPTY_USAGE,\n total_cost_usd: summary?.total_cost_usd ?? 0,\n builder_cost_usd: summary?.builder_cost_usd ?? 0,\n critic_cost_usd: summary?.critic_cost_usd ?? 0,\n check_duration_ms: summary?.check_duration_ms ?? 0,\n iteration_cost_usd: 0,\n halt: null,\n cost_warned: false,\n };\n\n return {\n raw_config,\n run_id,\n started_at: String(recorded['started_at']),\n state,\n iterations_completed: completed,\n };\n}\n","/**\n * Enriched run summary (`.volley/summary.json`): the `RunResult` projection plus\n * a `comparison` block that makes the two blessed examples' runs diff-able.\n * The block gathers the seven comparison metrics — transport,\n * iterations-to-converge, wall-clock, cost, verdict, the deterministic check\n * trajectory, and the local salvage rate — into one self-contained surface so\n * the model-vs-transport write-up (verification §4) reads them from a single\n * object rather than re-deriving them from the per-iteration archive.\n *\n * This is the only writer of `summary.json`; the flow's `record` step calls it\n * every iteration (status `running`, `completed_at` still null), the orchestrator\n * once more with the final status, and — when a `--worktree` run's work was\n * salvaged onto its branch rather than integrated — a third time, to stamp the\n * surviving branch on `salvaged_branch`, which teardown only names after the\n * final status is known.\n * Each write recomputes the comparison from what is currently archived under\n * `.volley/iterations/`, so the trajectory grows as the run does.\n */\nimport { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';\nimport type {\n BuilderProvider,\n CriticProvider,\n ResolvedConfig,\n RunResult,\n Verdict,\n} from './types.js';\nimport { volley_path } from './workspace.js';\n\n/** How a role reached the model. volley stays on the `ai_sdk` transport for the\n * local providers (fascicle 0.12.13 defaults `transport` to `'ai_sdk'`, so\n * volley sets no field); `claude_cli` drives Claude through its own CLI\n * subprocess, not an ai-sdk transport at all. Recording both keeps the transport\n * a clean second variable in the comparison (model vs transport). */\nexport type Transport = 'ai_sdk' | 'claude_cli';\n\nexport function transport_of(provider: BuilderProvider | CriticProvider): Transport {\n return provider === 'claude_cli' ? 'claude_cli' : 'ai_sdk';\n}\n\n/** One iteration's deterministic-gate outcome, in run order. */\nexport type CheckTrajectoryPoint = {\n iteration: number;\n ran: boolean;\n ok: boolean;\n failing_slots: string[];\n};\n\n/** Run-level salvage aggregate (a health metric): the share of builder tool\n * calls recovered from assistant text rather than returned structurally. A high\n * rate on a local run means the model's native tool-call encoding is drifting\n * from its runtime's parser. `rate` is 0 when the builder made no tool calls\n * (the `claude_cli` builder runs its own loop and reports none). */\nexport type SalvageStats = {\n tool_calls: number;\n salvaged_tool_calls: number;\n rate: number;\n};\n\n/** The self-contained comparison surface the two blessed examples are read\n * through. Cost and verdict echo the `RunResult` top level on\n * purpose — this block is the single object the write-up diffs, so it carries\n * every comparison metric rather than pointing back out for some of them. */\nexport type ComparisonSummary = {\n builder_transport: Transport;\n critic_transport: Transport;\n /** The iteration the run converged on (check green + critic approved); null\n * when it never converged (budget/cap/interrupt/error). */\n iterations_to_converge: number | null;\n /** Total wall-clock across the run; null until `completed_at` is stamped. */\n wall_clock_ms: number | null;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n final_verdict: Verdict | null;\n check_trajectory: CheckTrajectoryPoint[];\n local_salvage: SalvageStats;\n /** Every gate path any iteration's builder edited — the tests, fixtures, and\n * check configuration that decide whether its own work passes (`src/changes.ts`).\n * Empty on a run that only touched the implementation, which is the shape of\n * the by-hand verification `research/reckon-local-run-finding.md` recommends\n * making routine: a green check plus an empty list is worth more than a green\n * check alone. Sorted and de-duplicated across iterations. */\n gate_edits: string[];\n /** What the critic still judged unmet when the run stopped — the last\n * iteration's `unmet_criteria`, verbatim. Empty on a converged run. This is the\n * \"why not\" a non-success status alone cannot give: `budget_exhausted` says the\n * run ran out of iterations, not what it was still missing. */\n unmet_criteria: string[];\n /** Any iteration's critic verdict was rendered by the tool-less fallback:\n * the tool-bearing critique kept dying on the provider's stream, so\n * the critic judged without read access — real, but shallower. The run's\n * headline honesty flag, and the \"degraded\" column the matrix runner\n * reads straight from this block. */\n critic_degraded: boolean;\n};\n\n/** `RunResult` plus the comparison block; `.volley/summary.json` mirrors this. */\nexport type RunSummary = RunResult & { comparison: ComparisonSummary };\n\n/** The subset of an archived per-iteration summary (written by\n * `archive_iteration`) the comparison block reads. Every field is optional so a\n * half-written or older archive degrades to zeros/empties rather than throwing. */\ntype IterationArchive = {\n iteration?: number;\n builder?: { tool_calls?: number; salvaged_tool_calls?: number } | null;\n check?: { ran?: boolean; ok?: boolean; failing_slots?: string[] } | null;\n changes?: { gate_edits?: string[] } | null;\n critic?: { critic_degraded?: boolean } | null;\n unmet_criteria?: string[];\n};\n\n/** Read the archived per-iteration summaries in order. A missing archive root\n * (a run that failed before the first `record`) or an unreadable entry yields an\n * empty/short list — the run summary still writes, just without that trajectory\n * detail. */\nfunction read_iteration_archives(workspace: string): IterationArchive[] {\n const root = volley_path(workspace, 'iterations');\n if (!existsSync(root)) return [];\n const dirs = readdirSync(root)\n .filter((dir) => /^\\d{3}$/.test(dir))\n .toSorted();\n const archives: IterationArchive[] = [];\n for (const dir of dirs) {\n const path = volley_path(workspace, 'iterations', dir, 'summary.json');\n if (!existsSync(path)) continue;\n try {\n archives.push(JSON.parse(readFileSync(path, 'utf8')) as IterationArchive);\n } catch {\n // A torn/half-written archive is skipped, never fatal to the run summary.\n }\n }\n return archives;\n}\n\nfunction check_trajectory(archives: IterationArchive[]): CheckTrajectoryPoint[] {\n return archives.map((archive, index) => ({\n iteration: typeof archive.iteration === 'number' ? archive.iteration : index + 1,\n ran: archive.check?.ran === true,\n ok: archive.check?.ok === true,\n failing_slots: archive.check?.failing_slots ?? [],\n }));\n}\n\n/** The run degraded if any archived iteration's critic verdict came from the\n * tool-less fallback. Reads the same on-disk archives as the other\n * comparison metrics, so it grows with the run. */\nfunction any_critic_degraded(archives: IterationArchive[]): boolean {\n return archives.some((archive) => archive.critic?.critic_degraded === true);\n}\n\n/** Every gate path the run's builder touched, across all iterations: an edit in\n * iteration 1 that a later iteration reverted still happened, so the run-level\n * answer is the union rather than the last iteration's list. */\nfunction all_gate_edits(archives: IterationArchive[]): string[] {\n const edits = new Set<string>();\n for (const archive of archives) {\n for (const path of archive.changes?.gate_edits ?? []) edits.add(path);\n }\n return [...edits].toSorted();\n}\n\nfunction salvage_stats(archives: IterationArchive[]): SalvageStats {\n let tool_calls = 0;\n let salvaged_tool_calls = 0;\n for (const archive of archives) {\n tool_calls += archive.builder?.tool_calls ?? 0;\n salvaged_tool_calls += archive.builder?.salvaged_tool_calls ?? 0;\n }\n return {\n tool_calls,\n salvaged_tool_calls,\n rate: tool_calls === 0 ? 0 : salvaged_tool_calls / tool_calls,\n };\n}\n\n/** Fold the comparison block onto a `RunResult`, reading the per-iteration\n * archive for the check trajectory and salvage aggregate. Pure over its inputs\n * plus the on-disk archive; `write_run_summary` persists the result. */\nexport function build_run_summary(config: ResolvedConfig, result: RunResult): RunSummary {\n const archives = read_iteration_archives(config.workspace);\n const wall_clock_ms =\n result.completed_at === null\n ? null\n : Date.parse(result.completed_at) - Date.parse(result.started_at);\n return {\n ...result,\n comparison: {\n builder_transport: transport_of(config.builder_provider),\n critic_transport: transport_of(config.critic_provider),\n iterations_to_converge:\n result.status === 'success' ? result.iterations_completed : null,\n wall_clock_ms,\n total_cost_usd: result.total_cost_usd,\n builder_cost_usd: result.builder_cost_usd,\n critic_cost_usd: result.critic_cost_usd,\n final_verdict: result.final_verdict,\n check_trajectory: check_trajectory(archives),\n gate_edits: all_gate_edits(archives),\n unmet_criteria: archives.at(-1)?.unmet_criteria ?? [],\n local_salvage: salvage_stats(archives),\n critic_degraded: any_critic_degraded(archives),\n },\n };\n}\n\n/** Write the enriched summary to `.volley/summary.json` (the projection the\n * examples' comparison is read from). */\nexport function write_run_summary(config: ResolvedConfig, result: RunResult): void {\n writeFileSync(\n volley_path(config.workspace, 'summary.json'),\n `${JSON.stringify(build_run_summary(config, result), null, 2)}\\n`,\n );\n}\n","/**\n * The step bodies behind the nodes of `./flow.ts`, one function per node. Each\n * takes the loop's carry-state and returns the next one. The phase modules they\n * call (`./builder.ts`, `./check/`, `./critic/`) do the work; these bodies add\n * what surrounds it: the renderer lines an operator watches, change detection,\n * git checkpoints, and the per-iteration archive.\n */\nimport type { RunContext } from 'fascicle';\nimport { run_builder } from './builder.js';\nimport type { BuilderStep } from './builder.js';\nimport { collect_changes } from './changes.js';\nimport { run_checkride } from './check/checkride.js';\nimport { run_command_check, skipped_check } from './check/command.js';\nimport { run_critic } from './critic/run.js';\nimport type { CriticStep } from './critic/run.js';\nimport { archive_iteration, run_result_from_state } from './iteration.js';\nimport type { Renderer } from './render/renderer.js';\nimport { write_run_summary } from './summary.js';\nimport { error_kind, phase_error } from './types.js';\nimport type { ChangeSet, CheckResult, LoopState, ResolvedConfig } from './types.js';\nimport { git_checkpoint } from './workspace.js';\nimport { build_root } from './worktree.js';\n\n/** What every step body closes over, fixed for the whole run. */\nexport type PhaseDeps = {\n config: ResolvedConfig;\n renderer: Renderer;\n /** The commit every iteration's change set is measured against, read after\n * the worktree exists and before the builder writes anything. Null when the\n * build root is not a git repo — then the run reports no changes at all\n * rather than guessing at them. */\n baseline: string | null;\n};\n\n/** How many gate edits a warning names before it summarises the rest. */\nconst LISTED_GATE_EDITS = 5;\n\n/**\n * Say what the builder reached for, every iteration. The count is an info line;\n * a gate edit is a warning, because it is the fact that changes how much a green\n * check is worth — and the operator should hear it from the harness rather than\n * discover it in the diff afterwards (the by-hand check that\n * `research/reckon-local-run-finding.md` recommends making routine).\n */\nfunction report_changes(\n config: ResolvedConfig,\n renderer: Renderer,\n changes: ChangeSet | null,\n): void {\n if (changes === null) return;\n renderer.info(\n `changes: ${String(changes.total)} file(s) changed since the run baseline` +\n (changes.truncated ? ` (listing the first ${String(changes.files.length)})` : ''),\n );\n if (changes.gate_edits.length === 0) return;\n const hidden = changes.gate_edits.length - LISTED_GATE_EDITS;\n const listed = changes.gate_edits.slice(0, LISTED_GATE_EDITS).join(', ');\n renderer.warn(\n `gate edit: the builder changed ${String(changes.gate_edits.length)} file(s) that decide ` +\n `whether its work passes — ${listed}${hidden > 0 ? ` (+${String(hidden)} more)` : ''}. ` +\n 'A green check proves less when the builder can edit the gate; the critic is told about ' +\n 'this and the run summary records it.' +\n // The halt lands at the loop guard, after this iteration's check and\n // critic have had their say — so promise the outcome, not the timing.\n (config.fail_on_gate_edit\n ? ' This run will end without success (--fail-on-gate-edit, exit 8).'\n : ''),\n );\n}\n\nasync function execute_check(\n config: ResolvedConfig,\n abort: AbortSignal,\n): Promise<CheckResult> {\n // The check gates the tree the builder actually wrote: the worktree\n // under `--worktree`, else the workspace.\n const root = build_root(config.workspace, config.worktree);\n if (config.check_resolved === 'checkride') {\n return run_checkride({ workspace: root, abort });\n }\n if (config.check_resolved === 'command') {\n return run_command_check({ command: config.check, workspace: root, abort });\n }\n return skipped_check('none');\n}\n\n/** Open the next iteration: advance the counter and clear every per-iteration\n * field, so nothing from the last round leaks into this one. */\nfunction next_iteration(s: LoopState): LoopState {\n return {\n ...s,\n iteration: s.iteration + 1,\n iteration_started_at: new Date().toISOString(),\n iteration_cost_usd: 0,\n builder: null,\n critic: null,\n check: null,\n verdict: null,\n unmet_criteria: [],\n };\n}\n\n/** `build`: one builder session edits the build root, then volley measures what\n * it changed and, under `--git`, checkpoints it. */\nexport async function build_phase(\n deps: PhaseDeps,\n builder: BuilderStep,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n const next = next_iteration(s);\n renderer.phase_start(next.iteration, 'builder');\n const built = await run_builder({ builder, config, warn: renderer.warn }, next, ctx);\n renderer.phase_end(built.iteration, 'builder', true);\n renderer.cost_line(\n built.iteration,\n 'builder',\n built.builder?.cost_usd ?? null,\n built.total_cost_usd,\n );\n if (built.cost_warned && !s.cost_warned) {\n renderer.warn('cost unavailable for this phase; recording null (run totals sum what is known)');\n }\n // What the builder actually did, measured before the check runs — so the\n // check's verdict and the builder's reach are two independent facts about\n // the same iteration rather than one inferred from the other.\n const changes = collect_changes({\n root: build_root(config.workspace, config.worktree),\n baseline: deps.baseline,\n gate_patterns: config.gate_paths,\n });\n report_changes(config, renderer, changes);\n if (config.git_checkpoints) {\n git_checkpoint(\n build_root(config.workspace, config.worktree),\n `volley iter ${String(built.iteration)}: build`,\n );\n }\n return { ...built, changes };\n}\n\n/** `skip_verify`: the build alone crossed the cost cap, so the check is recorded\n * as skipped and no critic is called — a doomed iteration spends nothing more.\n * The loop guard then halts the run on the cap. */\nexport function skip_verify_phase(deps: PhaseDeps, s: LoopState): LoopState {\n deps.renderer.warn('cost cap crossed during build; skipping check and critic');\n return { ...s, check: skipped_check('cost_cap') };\n}\n\n/** `check`: the deterministic gate over the tree the builder wrote. */\nexport async function check_phase(\n deps: PhaseDeps,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n renderer.phase_start(s.iteration, 'check');\n try {\n const result = await execute_check(config, ctx.abort);\n if (result.ran) {\n renderer.phase_end(\n s.iteration,\n 'check',\n result.ok,\n result.failing_slots.length > 0\n ? `failing: ${result.failing_slots.join(', ')}`\n : undefined,\n );\n } else {\n renderer.info('no deterministic check configured; loop is critic-gated only');\n }\n return {\n ...s,\n check: result,\n check_duration_ms: s.check_duration_ms + result.duration_ms,\n };\n } catch (err) {\n if (error_kind(err) === 'check_error') throw err;\n throw phase_error('check', s.iteration, err);\n }\n}\n\n/** `critique`: the read-only critic's verdict, feedback, and unmet criteria. */\nexport async function critique_phase(\n deps: PhaseDeps,\n critic: CriticStep,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { renderer } = deps;\n renderer.phase_start(s.iteration, 'critic');\n const critiqued = await run_critic({ critic, config: deps.config }, s, ctx);\n renderer.phase_end(\n critiqued.iteration,\n 'critic',\n critiqued.verdict === 'approved',\n critiqued.verdict ?? undefined,\n );\n renderer.cost_line(\n critiqued.iteration,\n 'critic',\n critiqued.critic?.cost_usd ?? null,\n critiqued.total_cost_usd,\n );\n return critiqued;\n}\n\n/** `record`: archive the iteration and rewrite the run summary, so the on-disk\n * state is consistent after every round (resume reads it back). */\nexport function record_phase(deps: PhaseDeps, s: LoopState): LoopState {\n const { config } = deps;\n archive_iteration(config, s);\n write_run_summary(config, run_result_from_state(config, s, 'running', null));\n if (config.git_checkpoints) {\n git_checkpoint(\n build_root(config.workspace, config.worktree),\n `volley iter ${String(s.iteration)}: critique (${s.verdict ?? 'skipped'})`,\n );\n }\n return s;\n}\n","/**\n * Display formatting: glyph taxonomy, role colors, truncation.\n * All human output goes to stderr; these helpers only build strings.\n */\nimport pc from 'picocolors';\n\nexport const GLYPH_TOOL = '🔧';\nexport const GLYPH_OK = '✅';\nexport const GLYPH_ERR = '❌';\nexport const GLYPH_COST = '💰';\nexport const GLYPH_PHASE_START = '▶';\nexport const GLYPH_PHASE_OK = '✓';\nexport const GLYPH_PHASE_FAIL = '✗';\n\nexport const VERBOSE_TRUNCATE_CHARS = 4000;\n\nexport type Role = 'builder' | 'critic' | 'check';\n\nexport function colors_enabled(\n env: Record<string, string | undefined> = process.env,\n is_tty: boolean = process.stderr.isTTY === true,\n): boolean {\n if (env['NO_COLOR'] !== undefined || env['VOLLEY_NO_COLOR'] !== undefined) {\n return false;\n }\n return is_tty;\n}\n\nexport function paint(role: Role | 'cost' | 'error', text: string, color: boolean): string {\n if (!color) return text;\n switch (role) {\n case 'builder':\n return pc.cyan(text);\n case 'critic':\n return pc.yellow(text);\n case 'check':\n return pc.green(text);\n case 'cost':\n return pc.magenta(text);\n case 'error':\n return pc.bold(pc.red(text));\n }\n}\n\nexport function dim(text: string, color: boolean): string {\n return color ? pc.dim(text) : text;\n}\n\nexport function truncate(text: string, max: number, pointer: string): string {\n if (text.length <= max) return text;\n return `${text.slice(0, max)}\\n… [truncated at ${String(max)} chars; ${pointer}]`;\n}\n\nexport function format_usd(value: number | null): string {\n return value === null ? '$?' : `$${value.toFixed(3)}`;\n}\n\n/** One-line summary of a tool input for the default streaming mode. */\nexport function summarize_value(value: unknown, max = 120): string {\n let text: string;\n try {\n text = typeof value === 'string' ? value : JSON.stringify(value) ?? '';\n } catch {\n text = String(value);\n }\n const flat = text.replace(/\\s+/g, ' ');\n return flat.length > max ? `${flat.slice(0, max)}…` : flat;\n}\n","/**\n * Live output renderer: consumes `StreamChunk`s from each\n * `generate` call plus volley's own phase/cost lines, and writes human\n * progress to stderr. Streaming is a display concern only — the trajectory\n * jsonl is the durable record.\n */\nimport type { StreamChunk } from 'fascicle';\nimport type { RunResult } from '../types.js';\nimport {\n GLYPH_COST,\n GLYPH_ERR,\n GLYPH_OK,\n GLYPH_PHASE_FAIL,\n GLYPH_PHASE_OK,\n GLYPH_PHASE_START,\n GLYPH_TOOL,\n VERBOSE_TRUNCATE_CHARS,\n dim,\n format_usd,\n paint,\n summarize_value,\n truncate,\n} from './format.js';\nimport type { Role } from './format.js';\n\nexport type RenderMode = 'default' | 'verbose' | 'quiet' | 'json';\n\nexport type RendererOptions = {\n mode: RenderMode;\n show_thinking: boolean;\n color: boolean;\n max_cost_usd: number | null;\n write?: (text: string) => void;\n};\n\nexport type Renderer = {\n builder_chunk: (chunk: StreamChunk) => void;\n critic_chunk: (chunk: StreamChunk) => void;\n phase_start: (iteration: number, phase: Role) => void;\n phase_end: (iteration: number, phase: Role, ok: boolean, detail?: string) => void;\n cost_line: (iteration: number, phase: Role, phase_cost: number | null, run_total: number) => void;\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n final_summary: (result: RunResult) => void;\n};\n\nexport function create_renderer(options: RendererOptions): Renderer {\n const write = options.write ?? ((text: string) => process.stderr.write(text));\n const { mode, color } = options;\n const silent = mode === 'json';\n const streaming = mode === 'default' || mode === 'verbose';\n\n // Tracks whether streamed prose left the cursor mid-line, so glyph lines\n // start on their own line.\n let mid_line = false;\n\n const line = (text: string): void => {\n if (silent) return;\n write(`${mid_line ? '\\n' : ''}${text}\\n`);\n mid_line = false;\n };\n\n const chunk_renderer = (role: Role) => (chunk: StreamChunk): void => {\n if (!streaming) return;\n switch (chunk.kind) {\n case 'text': {\n write(paint(role, chunk.text, color));\n mid_line = !chunk.text.endsWith('\\n');\n return;\n }\n case 'reasoning': {\n if (!options.show_thinking) return;\n write(dim(chunk.text, color));\n mid_line = !chunk.text.endsWith('\\n');\n return;\n }\n case 'tool_call_end': {\n const summary =\n mode === 'verbose'\n ? truncate(\n JSON.stringify(chunk.input, null, 2) ?? '',\n VERBOSE_TRUNCATE_CHARS,\n 'see .volley/trajectory.jsonl',\n )\n : summarize_value(chunk.input);\n line(`${GLYPH_TOOL} ${paint(role, chunk.id, color)} ${summary}`);\n return;\n }\n case 'tool_result': {\n const ok = chunk.error === undefined;\n if (mode === 'verbose') {\n const body = ok ? summarize_output(chunk.output) : chunk.error?.message ?? '';\n line(`${ok ? GLYPH_OK : GLYPH_ERR} ${truncate(body, VERBOSE_TRUNCATE_CHARS, 'see .volley/trajectory.jsonl')}`);\n } else {\n line(`${ok ? GLYPH_OK : GLYPH_ERR} ${ok ? '' : summarize_value(chunk.error?.message)}`);\n }\n return;\n }\n case 'tool_call_start': {\n line(`${GLYPH_TOOL} ${paint(role, chunk.name, color)} …`);\n return;\n }\n default:\n return;\n }\n };\n\n return {\n builder_chunk: chunk_renderer('builder'),\n critic_chunk: chunk_renderer('critic'),\n phase_start: (iteration, phase) => {\n if (mode === 'json') return;\n line(paint(phase, `${GLYPH_PHASE_START} [iter ${String(iteration)}] ${phase}`, color));\n },\n phase_end: (iteration, phase, ok, detail) => {\n if (mode === 'json') return;\n const glyph = ok ? GLYPH_PHASE_OK : GLYPH_PHASE_FAIL;\n const suffix = detail !== undefined ? ` — ${detail}` : '';\n line(paint(phase, `${glyph} [iter ${String(iteration)}] ${phase}${suffix}`, color));\n },\n cost_line: (iteration, phase, phase_cost, run_total) => {\n if (mode === 'json') return;\n const cap = options.max_cost_usd !== null ? ` / ${format_usd(options.max_cost_usd)}` : '';\n line(\n paint(\n 'cost',\n `${GLYPH_COST} [iter ${String(iteration)}] [${phase}] phase: ${format_usd(phase_cost)} | run: ${format_usd(run_total)}${cap}`,\n color,\n ),\n );\n },\n info: (message) => {\n line(message);\n },\n warn: (message) => {\n line(paint('critic', `warning: ${message}`, color));\n },\n error: (message) => {\n if (silent) {\n // Errors still surface in json mode — stderr stays human, stdout machine.\n write(`error: ${message}\\n`);\n return;\n }\n line(paint('error', `error: ${message}`, color));\n },\n final_summary: (result) => {\n if (silent) return;\n line('');\n line(`run ${result.run_id}: ${result.status}`);\n line(\n `iterations: ${String(result.iterations_completed)} | verdict: ${result.final_verdict ?? 'n/a'}`,\n );\n line(\n paint(\n 'cost',\n `${GLYPH_COST} total: ${format_usd(result.total_cost_usd)} (builder ${format_usd(result.builder_cost_usd)}, critic ${format_usd(result.critic_cost_usd)})`,\n color,\n ),\n );\n line(\n `tokens: ${String(result.total_usage.input_tokens)} in / ${String(result.total_usage.output_tokens)} out`,\n );\n },\n };\n}\n\nfunction summarize_output(output: unknown): string {\n if (typeof output === 'string') return output;\n try {\n return JSON.stringify(output) ?? '';\n } catch {\n return String(output);\n }\n}\n","/**\n * Exit codes and the mapping from fascicle's error taxonomy plus\n * volley's own tagged errors onto them.\n */\nimport { error_kind } from './types.js';\nimport type { PhaseError, RunStatus } from './types.js';\n\nexport const EXIT_SUCCESS = 0;\nexport const EXIT_BUDGET_EXHAUSTED = 2;\nexport const EXIT_BUILDER_ERROR = 3;\nexport const EXIT_CHECK_ERROR = 4;\nexport const EXIT_CONFIG_ERROR = 5;\nexport const EXIT_CRITIC_ERROR = 6;\nexport const EXIT_COST_CAP = 7;\n/** The builder edited the gate that judges it and `--fail-on-gate-edit` was set:\n * distinct from a failed check (4) and from a budget exhaustion (2), because\n * nothing failed — the run refused to count a pass it could not trust. */\nexport const EXIT_GATE_EDIT = 8;\nexport const EXIT_INTERRUPTED = 130;\n\nexport function exit_code_for_status(status: RunStatus): number {\n switch (status) {\n case 'success':\n return EXIT_SUCCESS;\n case 'budget_exhausted':\n return EXIT_BUDGET_EXHAUSTED;\n case 'cost_cap_reached':\n return EXIT_COST_CAP;\n case 'gate_edit_blocked':\n return EXIT_GATE_EDIT;\n case 'interrupted':\n return EXIT_INTERRUPTED;\n default:\n return EXIT_BUILDER_ERROR;\n }\n}\n\n/** Error kinds fascicle raises for provider-level failures. */\nconst PROVIDER_ERROR_KINDS = new Set([\n 'provider_error',\n 'provider_auth_error',\n 'provider_not_configured_error',\n 'provider_capability_error',\n 'claude_cli_error',\n 'rate_limit_error',\n 'engine_disposed_error',\n 'timeout_error',\n]);\n\nexport function exit_code_for_error(err: unknown): number {\n const kind = error_kind(err);\n if (kind === 'aborted_error') return EXIT_INTERRUPTED;\n if (kind === 'config_error' || kind === 'engine_config_error') {\n return EXIT_CONFIG_ERROR;\n }\n if (kind === 'check_error') return EXIT_CHECK_ERROR;\n if (kind === 'schema_validation_error') return EXIT_CRITIC_ERROR;\n if (kind === 'phase_error') {\n const phase = (err as PhaseError).phase;\n const cause_kind = error_kind((err as PhaseError).cause);\n if (cause_kind === 'aborted_error') return EXIT_INTERRUPTED;\n if (phase === 'critic') return EXIT_CRITIC_ERROR;\n if (phase === 'check') return EXIT_CHECK_ERROR;\n return EXIT_BUILDER_ERROR;\n }\n if (kind !== null && PROVIDER_ERROR_KINDS.has(kind)) {\n return EXIT_BUILDER_ERROR;\n }\n return EXIT_BUILDER_ERROR;\n}\n"],"mappings":"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","names":["existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","dirname","join","spawnSync","readFileSync","z","readFileSync","statSync","isAbsolute","resolve","z","resolve","fallback","spawnSync","readFileSync","fetch","existsSync","renameSync","join","resolve","spawnSync","existsSync","mkdirSync","writeFileSync","join","spawnSync","join","existsSync","mkdirSync","writeFileSync","spawnSync","branch","resolve","git","spawnSync","branch","existsSync","join","renameSync","dirname","join","existsSync","readFileSync","z","model_call","existsSync","readFileSync","dirname","join","fileURLToPath","presets_dir","dirname","fileURLToPath","join","existsSync","readFileSync","z","model_call","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","writeFileSync","join","writeFileSync","mkdirSync","join","readFileSync","existsSync","existsSync","readFileSync","readdirSync","writeFileSync","existsSync","readdirSync","readFileSync","writeFileSync","branch","existsSync","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/changes.ts","../src/check/detect.ts","../src/types.ts","../src/orchestrator.ts","../src/engine.ts","../src/flow.ts","../src/builder.ts","../src/builder/context_check.ts","../src/builder/tools.ts","../src/workspace_tools.ts","../src/cost.ts","../src/prewarm.ts","../src/worktree.ts","../src/workspace.ts","../src/critic/run.ts","../src/critic/prompt.ts","../src/loop_state.ts","../src/check/checkride.ts","../src/check/command.ts","../src/iteration.ts","../src/summary.ts","../src/phases.ts","../src/render/format.ts","../src/render/renderer.ts","../src/sandbox.ts","../src/exit_codes.ts"],"sourcesContent":["/**\n * Config resolution: merge CLI flags over an optional config file\n * over defaults, expand `@file` references, validate, and produce the\n * immutable `ResolvedConfig` that `.volley/config.json` records.\n */\nimport { accessSync, constants, existsSync, readFileSync, statSync } from 'node:fs';\nimport { isAbsolute, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { randomUUID } from 'node:crypto';\nimport { DEFAULT_GATE_PATTERNS } from './changes.js';\nimport { resolve_check_runner } from './check/detect.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CriticPreset,\n CriticProvider,\n ResolvedConfig,\n VolleyConfig,\n} from './types.js';\n\nexport const DEFAULT_BUILDER_MODEL = 'opus';\nconst DEFAULT_CRITIC_MODEL = 'opus';\nexport const DEFAULT_MAX_ITERATIONS = 10;\nexport const DEFAULT_BUILDER_MAX_STEPS = 50;\nexport const DEFAULT_CHECK = 'auto';\nconst DEFAULT_CRITIC = 'reviewer';\nconst DEFAULT_BUILDER_PROVIDER: BuilderProvider = 'claude_cli';\nconst DEFAULT_CRITIC_PROVIDER: CriticProvider = 'claude_cli';\nconst DEFAULT_PERMISSION_MODE: BuilderPermissionMode = 'acceptEdits';\n/** The image volley's own `Dockerfile` builds; the local-builder sandbox runs\n * it unless `--sandbox-image` / `VOLLEY_SANDBOX_IMAGE` overrides it. */\nexport const DEFAULT_SANDBOX_IMAGE = 'volley-sandbox:latest';\n\nconst BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n];\n\n/** Builder providers that run a local model through volley's own tool loop —\n * a real `bash` (write + exec). Refused unless volley is running\n * inside a container (the correct blast-radius default) or the operator\n * explicitly opts out; `claude_cli` has its own permission model and is\n * exempt. */\nconst LOCAL_BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'ollama',\n 'lmstudio',\n];\n\nconst CRITIC_PROVIDERS: ReadonlyArray<CriticProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n];\n\nconst CRITIC_PRESETS: ReadonlyArray<CriticPreset> = [\n 'reviewer',\n 'optimizer',\n 'researcher',\n];\n\nconst PERMISSION_MODES: ReadonlyArray<BuilderPermissionMode> = [\n 'acceptEdits',\n 'bypassPermissions',\n];\n\n/** `@path/to/file` reads the file; any other string passes through. */\nexport function expand_at_file(value: string, cwd: string): string {\n if (!value.startsWith('@')) return value;\n const path = resolve(cwd, value.slice(1));\n if (!existsSync(path)) {\n throw config_error(`file not found: ${path} (from ${value})`);\n }\n return readFileSync(path, 'utf8');\n}\n\nfunction is_critic_preset(value: string): value is CriticPreset {\n return (CRITIC_PRESETS as ReadonlyArray<string>).includes(value);\n}\n\n/** Load a `volley.config.ts` / `.js` file's default export. */\nexport async function load_config_file(path: string): Promise<VolleyConfig> {\n const abs = resolve(path);\n if (!existsSync(abs)) {\n throw config_error(`config file not found: ${abs}`);\n }\n let loaded: unknown;\n try {\n const mod = (await import(pathToFileURL(abs).href)) as {\n default?: unknown;\n };\n loaded = mod.default;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw config_error(`failed to load config file ${abs}: ${detail}`);\n }\n if (typeof loaded !== 'object' || loaded === null) {\n throw config_error(`config file ${abs} must default-export a VolleyConfig object`);\n }\n return loaded as VolleyConfig;\n}\n\nfunction validate_workspace(workspace: string): string {\n const abs = isAbsolute(workspace) ? workspace : resolve(workspace);\n if (!existsSync(abs)) {\n throw config_error(`workspace not found: ${abs}`);\n }\n if (!statSync(abs).isDirectory()) {\n throw config_error(`workspace is not a directory: ${abs}`);\n }\n try {\n accessSync(abs, constants.W_OK);\n } catch {\n throw config_error(`workspace not writable: ${abs}`);\n }\n return abs;\n}\n\nfunction resolve_critic(\n critic: string,\n cwd: string,\n): { critic_preset: CriticPreset | 'custom'; critic_prompt_path: string | null } {\n if (is_critic_preset(critic)) {\n return { critic_preset: critic, critic_prompt_path: null };\n }\n const path = resolve(cwd, critic);\n if (!existsSync(path)) {\n throw config_error(\n `--critic must be one of ${CRITIC_PRESETS.join(', ')} or a path to a prompt file; got: ${critic}`,\n );\n }\n return { critic_preset: 'custom', critic_prompt_path: path };\n}\n\nexport type ResolveOptions = {\n cwd?: string;\n run_id?: string;\n started_at?: string;\n env?: Record<string, string | undefined>;\n};\n\n/** `--builder-max-steps` (a merged flag/config value) wins over the\n * `VOLLEY_BUILDER_MAX_STEPS` env var, which wins over the default. Local\n * builder only; ignored by the `claude_cli` arm. */\nfunction resolve_builder_max_steps(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): number {\n if (raw.builder_max_steps !== undefined) {\n return validate_builder_max_steps(raw.builder_max_steps, raw.builder_max_steps);\n }\n const env_value = env['VOLLEY_BUILDER_MAX_STEPS'];\n if (env_value !== undefined && env_value !== '') {\n return validate_builder_max_steps(Number(env_value), env_value);\n }\n return DEFAULT_BUILDER_MAX_STEPS;\n}\n\nfunction validate_builder_max_steps(value: number, original: unknown): number {\n if (!Number.isInteger(value) || value < 1) {\n throw config_error(\n `--builder-max-steps / VOLLEY_BUILDER_MAX_STEPS must be a positive integer; got: ${String(original)}`,\n );\n }\n return value;\n}\n\n/** `--sandbox-image` (a merged flag/config value) wins over the\n * `VOLLEY_SANDBOX_IMAGE` env var, which wins over the default image. Used only\n * on the local-builder Docker sandbox path; the `claude_cli` path never\n * runs Docker. */\nfunction resolve_sandbox_image(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): string {\n if (raw.sandbox_image !== undefined && raw.sandbox_image !== '') {\n return raw.sandbox_image;\n }\n const env_value = env['VOLLEY_SANDBOX_IMAGE'];\n if (env_value !== undefined && env_value !== '') {\n return env_value;\n }\n return DEFAULT_SANDBOX_IMAGE;\n}\n\n/** The `--allow-unsandboxed-builder` flag/config value wins; otherwise\n * `VOLLEY_ALLOW_UNSANDBOXED_BUILDER=1` (or `=true`) opts out. Any other value\n * (incl. `0`/`false`/unset) leaves the local builder refused unless contained. */\nfunction resolve_allow_unsandboxed_builder(\n raw: VolleyConfig,\n env: Record<string, string | undefined>,\n): boolean {\n if (raw.allow_unsandboxed_builder === true) return true;\n const env_value = env['VOLLEY_ALLOW_UNSANDBOXED_BUILDER'];\n return env_value === '1' || env_value === 'true';\n}\n\n/** volley *detects* it is running inside its sandbox container rather than\n * starting the container itself. The signal is the `VOLLEY_CONTAINED=1` marker\n * volley's own image bakes in (`Dockerfile` `ENV`), so a `docker run <hardened\n * flags> <image> volley run …` is recognized as contained out of the box. Kept\n * env-only — no ambient `/.dockerenv` probe — so the safety gate is deterministic\n * and testable, and so a CI job that itself runs in an unrelated container does\n * not silently satisfy the gate; a hand-rolled sandbox must set the marker (or\n * the operator uses `--allow-unsandboxed-builder`). */\nexport function detect_containment(env: Record<string, string | undefined>): boolean {\n const value = env['VOLLEY_CONTAINED'];\n return value === '1' || value === 'true';\n}\n\n/** A caller's run id names the run's `volley/<run id>` branch, so it is held to\n * what a branch name accepts without quoting: letters, digits, `-`, and `_`,\n * starting with a letter or digit so it never reads as an option. */\nconst RUN_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;\n\nfunction resolve_run_id(run_id: string | undefined): string {\n if (run_id === undefined) return randomUUID();\n if (!RUN_ID_PATTERN.test(run_id)) {\n throw config_error(\n `--run-id must be letters, digits, '-', and '_', starting with a letter or digit; got: ${run_id}`,\n );\n }\n return run_id;\n}\n\n/** Merge, expand, and validate a raw `VolleyConfig` into a `ResolvedConfig`.\n * `check_resolved` comes from check detection against the workspace, so the\n * SDK and the CLI resolve `auto` and a command check the same way. */\nexport function resolve_config(\n raw: VolleyConfig,\n options: ResolveOptions = {},\n): ResolvedConfig {\n const cwd = options.cwd ?? process.cwd();\n const env = options.env ?? process.env;\n\n if (typeof raw.prompt !== 'string' || raw.prompt.length === 0) {\n throw config_error('missing required option: --prompt');\n }\n if (typeof raw.workspace !== 'string' || raw.workspace.length === 0) {\n throw config_error('missing required option: --workspace');\n }\n if (typeof raw.criteria !== 'string' || raw.criteria.length === 0) {\n throw config_error('missing required option: --criteria');\n }\n\n const workspace = validate_workspace(resolve(cwd, raw.workspace));\n const prompt = expand_at_file(raw.prompt, cwd);\n const criteria = expand_at_file(raw.criteria, cwd);\n\n const max_iterations = raw.max_iterations ?? DEFAULT_MAX_ITERATIONS;\n if (!Number.isInteger(max_iterations) || max_iterations < 1) {\n throw config_error(`--max-iterations must be a positive integer; got: ${String(raw.max_iterations)}`);\n }\n\n const max_cost_usd = raw.max_cost_usd ?? null;\n if (max_cost_usd !== null && !(typeof max_cost_usd === 'number' && max_cost_usd > 0)) {\n throw config_error(`--max-cost-usd must be a positive number; got: ${String(raw.max_cost_usd)}`);\n }\n\n const builder_permission_mode = raw.builder_permission_mode ?? DEFAULT_PERMISSION_MODE;\n if (!PERMISSION_MODES.includes(builder_permission_mode)) {\n throw config_error(\n `--builder-permission-mode must be one of ${PERMISSION_MODES.join(', ')}; got: ${String(raw.builder_permission_mode)}`,\n );\n }\n\n const { critic_preset, critic_prompt_path } = resolve_critic(\n raw.critic ?? DEFAULT_CRITIC,\n cwd,\n );\n\n const builder_provider = raw.builder_provider ?? DEFAULT_BUILDER_PROVIDER;\n if (!BUILDER_PROVIDERS.includes(builder_provider)) {\n throw config_error(\n `--builder-provider must be one of ${BUILDER_PROVIDERS.join(', ')}; got: ${String(raw.builder_provider)}`,\n );\n }\n\n // Safety gate: a local builder gets a real `bash` (write + exec),\n // so refuse it — before any model spend — unless volley is running *inside* a\n // container (the correct blast-radius default) or the operator explicitly\n // opts out to run uncontained on the host.\n const allow_unsandboxed_builder = resolve_allow_unsandboxed_builder(raw, env);\n const contained = detect_containment(env);\n if (\n LOCAL_BUILDER_PROVIDERS.includes(builder_provider) &&\n !contained &&\n !allow_unsandboxed_builder\n ) {\n throw config_error(\n `builder-provider '${builder_provider}' runs a local model with a real bash ` +\n `(write + exec) — refused unless contained. Launch volley inside its sandbox container ` +\n `(docker run <hardened flags> <image> volley run …, which sets VOLLEY_CONTAINED=1), or pass ` +\n `--allow-unsandboxed-builder (VOLLEY_ALLOW_UNSANDBOXED_BUILDER=1) to run uncontained on the host.`,\n );\n }\n\n const builder_max_steps = resolve_builder_max_steps(raw, env);\n\n const critic_provider = raw.critic_provider ?? DEFAULT_CRITIC_PROVIDER;\n if (!CRITIC_PROVIDERS.includes(critic_provider)) {\n throw config_error(\n `--critic-provider must be one of ${CRITIC_PROVIDERS.join(', ')}; got: ${String(raw.critic_provider)}`,\n );\n }\n\n // Containment auth gate: `claude_cli`'s subscription/OAuth credentials\n // do not survive containerization — the token is mangled inside the container —\n // so a contained run may drive Claude only by API key (a plain env var that\n // travels the boundary). Refuse a contained `claude_cli` role (builder and/or\n // critic) that is not explicitly in `api_key` mode; the all-Claude path stays\n // on the host and Docker-free by design, where subscription auth works.\n if (contained) {\n const claude_roles = [\n builder_provider === 'claude_cli' ? 'builder' : null,\n critic_provider === 'claude_cli' ? 'critic' : null,\n ].filter((role): role is string => role !== null);\n const auth_mode = env['VOLLEY_AUTH_MODE'] ?? 'auto';\n if (claude_roles.length > 0 && auth_mode !== 'api_key') {\n throw config_error(\n `claude_cli (${claude_roles.join(', ')}) cannot use its subscription/OAuth token inside a ` +\n `container — it is mangled there. Set VOLLEY_AUTH_MODE=api_key (with ANTHROPIC_API_KEY) to ` +\n `drive Claude contained, or run claude_cli on the host uncontained.`,\n );\n }\n }\n\n if (raw.git_checkpoints === true && !existsSync(resolve(workspace, '.git'))) {\n throw config_error(`--git requires the workspace to be a git repository: ${workspace}`);\n }\n\n // A worktree is checked out from the workspace's git history, so refuse the\n // flag before any model spend when the workspace is not a repository.\n const worktree = raw.worktree ?? false;\n if (worktree && !existsSync(resolve(workspace, '.git'))) {\n throw config_error(`--worktree requires the workspace to be a git repository: ${workspace}`);\n }\n\n // `--discard-worktree`: opt in to the throw-away mode — a converged run's\n // effects go away with its branch instead of being kept on it. Only meaningful\n // under `--worktree`, so a lone flag is refused rather than silently ignored:\n // it would otherwise read as isolation the run does not have.\n const discard_worktree = raw.discard_worktree ?? false;\n if (discard_worktree && !worktree) {\n throw config_error(\n '--discard-worktree applies only to a --worktree run: there is no worktree to discard',\n );\n }\n\n // What counts as the gate is the task's call, so a config's own list replaces\n // the defaults outright rather than extending them: a test-writing task owns\n // its tests, and an empty list turns the report off entirely.\n const gate_paths = raw.gate_paths ?? DEFAULT_GATE_PATTERNS;\n if (!Array.isArray(gate_paths) || gate_paths.some((glob) => typeof glob !== 'string')) {\n throw config_error('gate_paths must be an array of glob strings');\n }\n\n const sandbox_image = resolve_sandbox_image(raw, env);\n const run_id = resolve_run_id(options.run_id);\n const check = raw.check ?? DEFAULT_CHECK;\n\n return {\n version: 2,\n run_id,\n started_at: options.started_at ?? new Date().toISOString(),\n prompt,\n criteria,\n check,\n check_resolved: resolve_check_runner(check, workspace),\n builder_model: raw.builder_model ?? DEFAULT_BUILDER_MODEL,\n builder_provider,\n builder_max_steps,\n allow_unsandboxed_builder,\n critic_model: raw.critic_model ?? DEFAULT_CRITIC_MODEL,\n critic_provider,\n builder_permission_mode,\n critic_preset,\n critic_prompt_path,\n max_iterations,\n max_cost_usd,\n git_checkpoints: raw.git_checkpoints ?? false,\n worktree,\n discard_worktree,\n gate_paths: [...gate_paths],\n fail_on_gate_edit: raw.fail_on_gate_edit ?? false,\n sandbox_image,\n workspace,\n verbose: raw.verbose ?? false,\n quiet: raw.quiet ?? false,\n json: raw.json ?? false,\n show_thinking: raw.show_thinking ?? true,\n };\n}\n","/**\n * What the builder changed, and whether it touched the gate.\n *\n * Until now the harness's only view of a builder's work was \"the check exited\n * 0\" — which is exactly the thing a builder can arrange by editing the check.\n * The reckon run (`research/reckon-local-run-finding.md`) closed that hole by\n * hand: after a green all-local run, the salvage commit was inspected to confirm\n * it touched only the four source modules and no test, fixture, or manifest.\n * This module is that inspection, mechanized — diff the build root against a\n * baseline captured before the first iteration, classify every changed path\n * against the gate patterns, and hand the result to the critic prompt, the run\n * summary, and (opt-in) the loop's stopping condition.\n *\n * Everything here is best-effort and non-throwing. A build root that is not a\n * git repository simply has no change set (`null`) and the loop behaves exactly\n * as it did before: change detection is evidence, never a precondition.\n *\n * Deliberately *not* collected: diff hunks. The changed-path list is bounded and\n * cheap, while inlined content would blow a local critic's context (32k on the\n * reckon seats) for the one part of the picture its read tools can already\n * fetch — the critic learns *where* to look, then looks.\n */\nimport { spawnSync } from 'node:child_process';\nimport type { ChangeSet, ChangeStatus, ChangedFile } from './types.js';\n\n/**\n * The default gate: paths whose edits change *what passing means* rather than\n * whether the work passes. Tests and fixtures are the executable half of the\n * spec; the check configuration and manifest decide which tests run at all.\n *\n * Deliberately broad and language-general — a false positive costs one line in\n * the critic's prompt, while a miss is the failure mode this exists to prevent.\n * A config's own `gate_paths` replaces the list outright (spec-writing tasks\n * legitimately own their tests).\n */\nexport const DEFAULT_GATE_PATTERNS: string[] = [\n '**/*.test.*',\n '**/*.spec.*',\n '**/*_test.*',\n '**/test/**',\n '**/tests/**',\n '**/__tests__/**',\n '**/spec/**',\n '**/fixtures/**',\n '**/checkride.config.*',\n '**/vitest.config.*',\n '**/jest.config.*',\n '**/playwright.config.*',\n '**/package.json',\n '.github/workflows/**',\n];\n\n/** Harness state, toolchain, and VCS internals: never the builder's work, even\n * when they sit in the build root and show up dirty. `.volley/` is the control\n * plane, `.check/` is the check's own artifacts, `node_modules/` rides in on the\n * worktree symlink. */\nconst EXCLUDED_PREFIXES = ['.volley/', '.volley.bak.', '.check/', '.git/', 'node_modules/'];\n\n/** How many changed paths the set carries. The cap bounds the critic prompt and\n * the archived summary on a sweeping refactor; `gate_edits` and `total` are\n * always computed over the full list, so nothing load-bearing is truncated. */\nconst DEFAULT_LIMIT = 200;\n\ntype GitResult = { status: number; stdout: string };\n\n/** Run git in `root`, best-effort: a missing binary, a broken repo, or a\n * non-zero exit all read as \"no output\". Change detection reports what it can\n * and never fails a run over what it cannot (unlike `worktree.ts`, where git is\n * a precondition the operator asked for). */\nfunction git(root: string, args: string[]): GitResult {\n try {\n const result = spawnSync('git', args, {\n cwd: root,\n encoding: 'utf8',\n maxBuffer: 32 * 1024 * 1024,\n });\n return { status: result.status ?? -1, stdout: result.stdout ?? '' };\n } catch {\n return { status: -1, stdout: '' };\n }\n}\n\n/** Is this directory inside a git repository? Asked of git rather than by\n * looking for `.git`, so a workspace nested under a repo root — and a linked\n * worktree, whose `.git` is a file — both answer correctly. */\nfunction in_git_repo(root: string): boolean {\n return git(root, ['rev-parse', '--git-dir']).status === 0;\n}\n\n/**\n * The commit a run's changes are measured against: the build root's HEAD, read\n * once before the first iteration. Null when the root is not a repository or has\n * no commits yet — in the latter case `collect_changes` still reports untracked\n * files, which is the whole of a from-scratch build.\n */\nexport function capture_baseline(root: string): string | null {\n const head = git(root, ['rev-parse', 'HEAD']);\n if (head.status !== 0) return null;\n const sha = head.stdout.trim();\n return sha.length > 0 ? sha : null;\n}\n\n/** git's status letters, folded onto the four cases worth naming. Rename and\n * copy both record the destination path — where the content lives now. */\nfunction change_status(code: string): ChangeStatus {\n const letter = code.charAt(0);\n if (letter === 'A') return 'added';\n if (letter === 'M' || letter === 'T') return 'modified';\n if (letter === 'D') return 'deleted';\n if (letter === 'R' || letter === 'C') return 'renamed';\n return 'unknown';\n}\n\ntype RawChange = { path: string; status: ChangeStatus };\n\n/**\n * Parse `git diff --name-status -z`: a flat NUL-separated stream of\n * `status, path` pairs, except renames and copies, which carry `status, source,\n * destination`. NUL separation (rather than lines) is what makes paths with\n * spaces or newlines in them safe to read.\n */\nfunction parse_name_status(stdout: string): RawChange[] {\n const tokens = stdout.split('\\0').filter((token) => token.length > 0);\n const changes: RawChange[] = [];\n let index = 0;\n while (index < tokens.length) {\n const code = tokens[index] ?? '';\n const paired = code.startsWith('R') || code.startsWith('C');\n const path = tokens[index + (paired ? 2 : 1)];\n if (path !== undefined) changes.push({ path, status: change_status(code) });\n index += paired ? 3 : 2;\n }\n return changes;\n}\n\n/** Parse a NUL-separated path list (`git ls-files -z`). */\nfunction parse_paths(stdout: string): string[] {\n return stdout.split('\\0').filter((path) => path.length > 0);\n}\n\nfunction excluded(path: string): boolean {\n return EXCLUDED_PREFIXES.some((prefix) => path.startsWith(prefix));\n}\n\n/**\n * Compile one glob to an anchored regular expression. Supports the three forms\n * the gate patterns need — `**` across separators, `*` within a segment, `?` for\n * one character — in a single pass, because sequential string replacement would\n * re-process the regex syntax its own earlier passes emit.\n *\n * A leading globstar-plus-separator collapses to \"any number of leading\n * segments, including none\", so one `test` pattern matches `test/a.mjs` and\n * `src/test/a.mjs` alike instead of needing a rule per depth.\n */\nfunction glob_to_regexp(pattern: string): RegExp {\n let source = '';\n let index = 0;\n while (index < pattern.length) {\n const char = pattern.charAt(index);\n if (char === '*' && pattern.charAt(index + 1) === '*') {\n const slashed = pattern.charAt(index + 2) === '/';\n source += slashed ? '(?:.*/)?' : '.*';\n index += slashed ? 3 : 2;\n continue;\n }\n if (char === '*') {\n source += '[^/]*';\n index += 1;\n continue;\n }\n if (char === '?') {\n source += '[^/]';\n index += 1;\n continue;\n }\n source += /[.+^${}()|[\\]\\\\]/.test(char) ? `\\\\${char}` : char;\n index += 1;\n }\n return new RegExp(`^${source}$`);\n}\n\n/** Does this path match any of these glob patterns? Exported for the gate-path\n * unit tests, which pin the matcher's semantics independently of git. */\nexport function matches_any(path: string, patterns: string[]): boolean {\n return patterns.some((pattern) => glob_to_regexp(pattern).test(path));\n}\n\nexport type CollectChangesOptions = {\n /** Where the builder's effects land — the worktree under `--worktree`, else\n * the workspace (`build_root`). */\n root: string;\n /** The run's baseline commit, from `capture_baseline`. */\n baseline: string | null;\n gate_patterns: string[];\n limit?: number;\n};\n\nfunction by_path(left: ChangedFile, right: ChangedFile): number {\n if (left.path < right.path) return -1;\n return left.path > right.path ? 1 : 0;\n}\n\n/**\n * Everything the builder changed in `root` since `baseline`, classified against\n * the gate patterns. Tracked edits come from the diff, brand-new files from the\n * untracked list — together they cover both checkpoint styles, since `--git`\n * commits the builder's work as it goes while a plain run leaves it dirty.\n *\n * Returns null when `root` is not a git repository: the one honest answer, and\n * the signal every consumer uses to omit the section rather than claim the\n * builder changed nothing.\n */\nexport function collect_changes(options: CollectChangesOptions): ChangeSet | null {\n const { root, baseline } = options;\n if (!in_git_repo(root)) return null;\n const limit = options.limit ?? DEFAULT_LIMIT;\n\n // `--relative` + `-- .` keep both halves scoped to the build root and its own\n // path vocabulary, for the case where the workspace sits under a repo root.\n const tracked =\n baseline === null\n ? []\n : parse_name_status(\n git(root, ['diff', '--name-status', '--relative', '-z', baseline, '--', '.']).stdout,\n );\n const untracked: RawChange[] = parse_paths(\n git(root, ['ls-files', '--others', '--exclude-standard', '-z']).stdout,\n ).map((path) => ({ path, status: 'added' }));\n\n const seen = new Set<string>();\n const files: ChangedFile[] = [];\n for (const change of [...tracked, ...untracked]) {\n if (excluded(change.path) || seen.has(change.path)) continue;\n seen.add(change.path);\n files.push({ ...change, gate: matches_any(change.path, options.gate_patterns) });\n }\n const sorted = files.toSorted(by_path);\n\n return {\n baseline,\n // Over the full list, before the cap: truncation must never hide a gate edit.\n gate_edits: sorted.filter((file) => file.gate).map((file) => file.path),\n total: sorted.length,\n files: sorted.slice(0, limit),\n truncated: sorted.length > limit,\n };\n}\n","/**\n * `--check` resolution: `auto` detects checkride in the workspace;\n * `none` disables the gate; anything else is a shell command — unless it is\n * recognizably checkride itself, which gets the structured runner.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { CheckMode, CheckRunnerKind } from '../types.js';\n\nfunction package_check_script_is_checkride(workspace: string): boolean {\n const path = join(workspace, 'package.json');\n if (!existsSync(path)) return false;\n try {\n const pkg = JSON.parse(readFileSync(path, 'utf8')) as {\n scripts?: Record<string, string>;\n };\n const script = pkg.scripts?.['check'];\n return typeof script === 'string' && /(^|\\s)checkride(\\s|$)/.test(script);\n } catch {\n return false;\n }\n}\n\nexport function checkride_detected(workspace: string): boolean {\n return (\n existsSync(join(workspace, 'checkride.config.json')) ||\n package_check_script_is_checkride(workspace) ||\n existsSync(join(workspace, 'node_modules', '.bin', 'checkride'))\n );\n}\n\nexport function resolve_check_runner(\n check: CheckMode,\n workspace: string,\n): CheckRunnerKind {\n if (check === 'none') return 'none';\n if (check === 'auto') {\n return checkride_detected(workspace) ? 'checkride' : 'none';\n }\n return /(^|\\s)checkride(\\s|$)/.test(check.trim()) ? 'checkride' : 'command';\n}\n","/**\n * Shared value and type contracts for volley.\n *\n * Type aliases are PascalCase; value-level identifiers are snake_case.\n * Fascicle's usage/cost types are used verbatim so summaries carry the\n * substrate's shapes, not a re-derivation.\n */\nimport type { FinishReason, Throughput, UsageTotals } from 'fascicle';\n\nexport type Verdict = 'approved' | 'changes_requested';\n\nexport type CriticPreset = 'reviewer' | 'optimizer' | 'researcher';\n\n/** Transport for the critic role. The critic is read-only + schema-constrained,\n * so it has always been able to run on a local model. */\nexport type CriticProvider = 'claude_cli' | 'ollama' | 'lmstudio';\n\n/** Transport for the builder role. `claude_cli` is a full agentic Claude Code\n * session; the local providers run the builder as a volley-driven tool loop\n * (write/exec tools supplied by the harness). The execution path for the local\n * providers lands with the builder tool/termination work; this type and its\n * plumbing exist so that work has somewhere to attach (spec v3). */\nexport type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio';\n\nexport type BuilderPermissionMode = 'acceptEdits' | 'bypassPermissions';\n\n/** `auto`, `none`, or any shell command (the `string & {}` keeps the literal\n * hints in editor completions without collapsing the union). */\nexport type CheckMode = 'auto' | 'none' | (string & {});\n\nexport type CheckRunnerKind = 'checkride' | 'command' | 'none';\n\nexport type CostSource = 'provider_reported' | 'engine_derived' | 'unknown';\n\n/** Fascicle's `provider_error.cause_kind` discriminant — why a provider call\n * died. Recorded alongside a critic retry so a degraded run says\n * *what* failed, not just that it retried. */\nexport type CauseKind = 'provider_5xx' | 'network' | 'unknown';\n\nexport type RunStatus =\n | 'running'\n | 'success'\n | 'budget_exhausted'\n | 'cost_cap_reached'\n /** The builder edited the gate that judges it, under `--fail-on-gate-edit`:\n * the run halts on the spot rather than iterating, because a check the builder\n * can rewrite is not evidence the work is done. */\n | 'gate_edit_blocked'\n | 'interrupted'\n | 'error';\n\n/** User-facing configuration, before resolution (config file / flags). */\nexport type VolleyConfig = {\n prompt: string;\n workspace: string;\n criteria: string;\n check?: CheckMode;\n builder_model?: string;\n builder_provider?: BuilderProvider;\n builder_max_steps?: number;\n allow_unsandboxed_builder?: boolean;\n critic_model?: string;\n critic_provider?: CriticProvider;\n builder_permission_mode?: BuilderPermissionMode;\n critic?: CriticPreset | (string & {});\n max_iterations?: number;\n max_cost_usd?: number | null;\n git_checkpoints?: boolean;\n worktree?: boolean;\n discard_worktree?: boolean;\n gate_paths?: string[];\n fail_on_gate_edit?: boolean;\n sandbox_image?: string;\n verbose?: boolean;\n quiet?: boolean;\n json?: boolean;\n show_thinking?: boolean;\n dry_run?: boolean;\n};\n\n/** Fully resolved run configuration; `.volley/config.json` mirrors this. */\nexport type ResolvedConfig = {\n version: 2;\n run_id: string;\n started_at: string;\n prompt: string;\n criteria: string;\n check: CheckMode;\n check_resolved: CheckRunnerKind;\n builder_model: string;\n builder_provider: BuilderProvider;\n builder_max_steps: number;\n /** Operator opt-out permitting a local (non-`claude_cli`) builder to run\n * without a sandbox — it gets a real host bash. Refused by default. */\n allow_unsandboxed_builder: boolean;\n critic_model: string;\n critic_provider: CriticProvider;\n builder_permission_mode: BuilderPermissionMode;\n critic_preset: CriticPreset | 'custom';\n critic_prompt_path: string | null;\n max_iterations: number;\n max_cost_usd: number | null;\n git_checkpoints: boolean;\n /** Isolate the builder run's effects in a per-run git worktree: the\n * builder/critic file tools' containment root moves to the worktree, while\n * `.volley/` state stays under `workspace` (the control plane). Off by\n * default; requires the workspace to be a git repository. */\n worktree: boolean;\n /** Throw a `--worktree` run's effects away at teardown even when it converged:\n * the run branch is force-deleted rather than kept, because only the\n * verdicts are wanted. This is what `volley matrix` sweeps with — one config,\n * many builder×critic seats, no per-seat commits or branches left anywhere.\n * Refused without `--worktree`; `--git` still wins, so a `--worktree --git`\n * run integrates exactly as it always has. */\n discard_worktree: boolean;\n /** Glob patterns naming the *gate*: the tests, fixtures, and check\n * configuration that decide whether the builder's work passes. An edit to one\n * is reported to the critic and recorded in the summary — and refused outright\n * under `fail_on_gate_edit`. Defaults to `DEFAULT_GATE_PATTERNS`; a config's\n * own list replaces it, because what counts as the gate is the task's call\n * (a test-writing task edits tests by design). */\n gate_paths: string[];\n /** Halt the run when the builder edits a `gate_paths` match, instead of\n * reporting it and continuing. Off by default: a gate edit is legitimate often\n * enough that refusing it by default would break honest tasks, and the mark on\n * the summary already makes it impossible to miss. */\n fail_on_gate_edit: boolean;\n /** Container image the local-builder Docker sandbox runs. Defaults to\n * volley's own `Dockerfile`-built image; `--sandbox-image <tag>` /\n * `VOLLEY_SANDBOX_IMAGE` override it. Meaningful only for a local builder —\n * the `claude_cli` path never uses Docker. */\n sandbox_image: string;\n workspace: string;\n verbose: boolean;\n quiet: boolean;\n json: boolean;\n show_thinking: boolean;\n};\n\n/** One failing check slot's raw artifact, for the critic prompt. */\nexport type CheckArtifact = {\n slot: string;\n path: string | null;\n content: string;\n truncated: boolean;\n};\n\nexport type CheckResult = {\n ran: boolean;\n runner: CheckRunnerKind;\n ok: boolean;\n exit_code: number | null;\n duration_ms: number;\n failing_slots: string[];\n detail: CheckArtifact[];\n /** Raw checkride summary JSON (when the runner is checkride). */\n summary?: unknown;\n /** Captured combined output (when the runner is a shell command). */\n log?: string;\n};\n\n/** How one path changed between the run's baseline and the builder's output.\n * `renamed` covers git's rename/copy detection (the destination path is the one\n * recorded); `unknown` is any status git reports that none of these name. */\nexport type ChangeStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'unknown';\n\n/** One path the builder changed, and whether that path is part of the *gate* —\n * the tests, fixtures, and check configuration that decide whether the work\n * passes. A gate edit is not misconduct by itself (some tasks are *about* the\n * tests); it is the fact that makes a green check prove less. */\nexport type ChangedFile = {\n path: string;\n status: ChangeStatus;\n gate: boolean;\n};\n\n/** What the builder changed since the run's baseline, as the harness sees it\n * (`src/changes.ts`). Null in `LoopState` when the build root is not a git\n * repository — change detection is evidence, never a precondition. */\nexport type ChangeSet = {\n /** The commit the changes are measured against — the build root's HEAD before\n * the first iteration. Null in a repository with no commits yet, where only\n * untracked files can be reported. */\n baseline: string | null;\n /** The changed paths, sorted, capped at the collection limit. */\n files: ChangedFile[];\n /** Every gate-matching path — computed over the *full* list before the cap,\n * so truncation can never hide a gate edit. */\n gate_edits: string[];\n /** How many paths changed in total, before the cap. */\n total: number;\n truncated: boolean;\n};\n\n/** Per-phase record for iteration summaries. */\nexport type PhaseRecord = {\n provider: string;\n model: string;\n session_id: string | null;\n /** Wall-clock of the phase's model work, the same measure for every provider\n * so an all-local run and an all-Claude run compare directly. The builder's is\n * fascicle's `GenerateResult.timing`: the whole call, every turn and the tools\n * between them. The critic's spans its whole degradation ladder, failed\n * attempts included, since no one result's timing covers the attempts before\n * it. Neither counts the Ollama prewarm. */\n duration_ms: number;\n usage: UsageTotals;\n cost_usd: number | null;\n cost_source: CostSource;\n /** How the phase's generate call ended. For a local builder,\n * `'max_steps'` is a budget cutoff surfaced as a warning, not an error. */\n finish_reason: FinishReason;\n /** Tool calls fascicle executed in this phase, and how many were recovered\n * from assistant text rather than returned structurally — the raw\n * counts behind the salvage-rate health metric. */\n tool_calls: number;\n salvaged_tool_calls: number;\n /** Provider-error retries that preceded this phase's successful call\n * — the local-critic degradation ladder's first rung: a stochastic\n * Ollama stream death is retried once before falling back. Set on the critic\n * record (0 when the first call succeeded); absent on the builder, which is\n * not retried this build. Additive — old summary consumers ignore it. */\n retries?: number;\n /** The `cause_kind` of the retried provider error, recorded with `retries`.\n * Absent when no retry happened. */\n retry_cause_kind?: CauseKind;\n /** This local-critic verdict was rendered by the tool-less fallback rung:\n * the tool-bearing critique kept dying on the provider's stream\n * even after the bounded retry, so the critic judged with no read access —\n * grounded only by the criteria, the raw check artifacts, and a workspace file\n * inventory. Set (true) on a degraded critic record; absent on a full\n * critique and on the builder. Additive, and a degraded verdict is *always*\n * marked so it never passes silently as a full one. */\n critic_degraded?: boolean;\n /** Output tokens per second over the model's own turns (tool execution and\n * retry backoff excluded), from fascicle's per-step timing. `basis` is\n * `decode` when every turn streamed, `blended` when any round trip counted\n * prefill and network too — always the case for `claude_cli`, whose rate\n * fascicle derives from the CLI's reported API time. Absent when no turn\n * carried timing. Additive. */\n throughput?: Throughput;\n};\n\nexport type HaltReason = 'cost_cap' | 'gate_edit' | null;\n\n/** Carry-state threaded through the fascicle loop. */\nexport type LoopState = {\n iteration: number;\n iteration_started_at: string;\n feedback: string | null;\n verdict: Verdict | null;\n unmet_criteria: string[];\n check: CheckResult | null;\n /** What the builder changed this iteration, measured against the run's\n * baseline (`src/changes.ts`). Null when the build root is not a git\n * repository, and before the first `build` step of a run. */\n changes: ChangeSet | null;\n builder: PhaseRecord | null;\n critic: PhaseRecord | null;\n total_usage: UsageTotals;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n check_duration_ms: number;\n iteration_cost_usd: number;\n halt: HaltReason;\n cost_warned: boolean;\n};\n\nexport type RunInput = {\n resume_from: LoopState | null;\n};\n\n/** Projection of final loop state; `.volley/summary.json` mirrors this. */\nexport type RunResult = {\n run_id: string;\n status: RunStatus;\n started_at: string;\n completed_at: string | null;\n iterations_completed: number;\n total_usage: UsageTotals;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n check_duration_ms: number;\n final_verdict: Verdict | null;\n /** The run branch teardown left behind because this run's work was never\n * integrated: under `--worktree` without `--git` a converged run has no\n * other copy of its effects, so teardown commits them onto `volley/<run id>`\n * and keeps the branch instead of force-deleting it. Null whenever nothing\n * survived — every non-worktree run, every integrated run, every discarded\n * one. `--json` consumers read it here; `.volley/summary.json` mirrors it. */\n salvaged_branch: string | null;\n};\n\nexport type VolleyPhase = 'builder' | 'critic' | 'check';\n\n/** Recoverable domain failures surface as `kind`-tagged Error values (the\n * same discrimination style as fascicle's error taxonomy) so the top-level\n * handler maps them to exit codes without string matching or instanceof. */\nexport type ConfigError = Error & { kind: 'config_error' };\n\nexport type CheckError = Error & { kind: 'check_error' };\n\nexport type PhaseError = Error & {\n kind: 'phase_error';\n phase: VolleyPhase;\n iteration: number;\n cause: unknown;\n};\n\nexport function config_error(message: string): ConfigError {\n return Object.assign(new Error(message), { kind: 'config_error' as const });\n}\n\nexport function check_error(message: string): CheckError {\n return Object.assign(new Error(message), { kind: 'check_error' as const });\n}\n\n/** Wraps a provider/schema failure with the phase and iteration it hit. */\nexport function phase_error(\n phase: VolleyPhase,\n iteration: number,\n cause: unknown,\n): PhaseError {\n const detail = cause instanceof Error ? cause.message : String(cause);\n return Object.assign(\n new Error(`${phase} failed on iteration ${iteration}: ${detail}`),\n { kind: 'phase_error' as const, phase, iteration, cause },\n );\n}\n\nexport function error_kind(err: unknown): string | null {\n if (typeof err === 'object' && err !== null && 'kind' in err) {\n const kind = (err as { kind: unknown }).kind;\n return typeof kind === 'string' ? kind : null;\n }\n return null;\n}\n","/**\n * The shell around the volley flow (`./flow.ts`): set up the workspace, wrap\n * the run in the worktree lifecycle, execute the flow with a single `run` call,\n * and turn its outcome into the run summary. No hand-rolled runner — rounds,\n * abort threading, signal handlers, and cleanup order all belong to the\n * substrate.\n *\n * run_volley\n * ├─ initialize the workspace (or preserve it, on resume)\n * ├─ with_worktree off unless --worktree\n * │ ├─ capture the change baseline\n * │ ├─ run_loop run(build_flow(...)), then the final summary\n * │ └─ integrate a successful --worktree --git run only\n * └─ report a kept checkout, or a salvaged branch (re-stamping the summary)\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { run } from 'fascicle';\nimport { filesystem_logger } from 'fascicle/adapters';\nimport type { Engine } from 'fascicle';\nimport type { BashExecutor } from './builder/tools.js';\nimport { capture_baseline } from './changes.js';\nimport { create_volley_engine } from './engine.js';\nimport { build_flow } from './flow.js';\nimport { run_result_from_state } from './iteration.js';\nimport { initial_state, status_of } from './loop_state.js';\nimport { write_run_summary } from './summary.js';\nimport type { Renderer } from './render/renderer.js';\nimport { error_kind } from './types.js';\nimport type { LoopState, ResolvedConfig, RunResult, RunStatus } from './types.js';\nimport {\n initialize_workspace,\n integrate_worktree,\n volley_path,\n write_resolved_config,\n} from './workspace.js';\nimport {\n build_root,\n report_worktree_fate,\n with_worktree,\n worktree_branch,\n worktree_fate,\n} from './worktree.js';\n\nexport type OrchestratorDeps = {\n renderer: Renderer;\n engine?: Engine;\n abort?: AbortSignal;\n install_signal_handlers?: boolean;\n};\n\nexport async function run_volley(\n config: ResolvedConfig,\n deps: OrchestratorDeps,\n resume_from: LoopState | null = null,\n): Promise<RunResult> {\n const { renderer } = deps;\n\n if (resume_from === null) {\n initialize_workspace(config.workspace);\n write_resolved_config(config);\n } else {\n initialize_workspace(config.workspace, { preserve: true });\n }\n\n // Say what this run will do with its effects before it spends anything — the\n // same notice `--dry-run` prints, repeated here so a run started without a dry\n // run still hears it (the same predict-then-warn shape).\n report_worktree_fate(config, renderer);\n\n // The worktree lifecycle wraps the whole builder loop: created before the\n // first iteration, torn down after the last. Off unless `--worktree` is set\n // (config.worktree), so the default path never touches git here.\n const branch = worktree_branch(config.run_id);\n const fate = worktree_fate(config);\n const outcome = await with_worktree<RunResult>(\n {\n enabled: config.worktree,\n workspace: config.workspace,\n branch,\n log: (message) => renderer.info(message),\n // The one case teardown must keep rather than force-delete: a converged run\n // that integrated nothing, whose only copy of its work is the worktree.\n salvage: (result) => fate === 'salvage' && result.status === 'success',\n },\n async () => {\n // Whole-process containment: volley runs *inside* its hardened\n // container already — the operator/example's `docker run … <volley args>`\n // launched it — so there is no container lifecycle to orchestrate here. `bash`\n // is the local `host_bash_executor` running in-container (null executor,\n // the host `spawnSync` default) and the file tools write straight to the\n // bind-mounted worktree; the retired `docker exec` path is gone. The\n // hardened `docker run` invocation spec the example uses lives in\n // `src/sandbox.ts`.\n // The commit every iteration's change set is measured against, read after\n // the worktree exists and before the builder writes anything. Null when the\n // build root is not a git repo — then the run reports no changes at all\n // rather than guessing at them.\n const baseline = capture_baseline(build_root(config.workspace, config.worktree));\n const result = await run_loop(config, deps, resume_from, null, baseline);\n // Integration: a *successful* `--worktree --git` run squash-merges the\n // phase branch's checkpoints onto the workspace branch before teardown\n // discards it. Any non-success outcome (cost cap, budget, interrupt,\n // error) is abandoned — teardown discards the branch wholesale, nothing\n // integrated. Gated on `--git` too (`fate === 'integrate'`), so volley only\n // commits to the workspace branch when the operator opted into checkpoints;\n // without it the same work is salvaged onto its own branch instead.\n if (fate === 'integrate' && result.status === 'success') {\n integrate_worktree(config.workspace, branch, `volley run ${config.run_id}: integrate worktree (squash)`);\n renderer.info(`worktree: squash-merged ${branch} onto the workspace branch`);\n }\n return result;\n },\n );\n\n if (outcome.kept_path !== null) {\n renderer.warn(\n `worktree: could not commit this run's work onto ${branch}, so the checkout at ` +\n `${outcome.kept_path} was left standing rather than deleted — its files are intact, and ` +\n 'the next --worktree run rotates the directory aside instead of destroying it.',\n );\n }\n if (outcome.salvaged_branch === null) return outcome.value;\n renderer.info(\n `worktree: this run was not integrated; its work is preserved on branch ` +\n `${outcome.salvaged_branch} (git switch ${outcome.salvaged_branch}, or cherry-pick it).`,\n );\n // Teardown salvaged the branch *after* `run_loop` wrote the final summary, so\n // re-stamp it: `.volley/summary.json` and `--json` both name the survivor.\n const salvaged: RunResult = { ...outcome.value, salvaged_branch: outcome.salvaged_branch };\n write_run_summary(config, salvaged);\n return salvaged;\n}\n\nasync function run_loop(\n config: ResolvedConfig,\n deps: OrchestratorDeps,\n resume_from: LoopState | null,\n bash_executor: BashExecutor | null,\n baseline: string | null,\n): Promise<RunResult> {\n const { renderer } = deps;\n\n // The Claude session runs in the build root (the worktree under `--worktree`),\n // because that is where the check, the change report, the checkpoints, and the\n // critic all look. `.volley/` state stays under the workspace either way.\n const engine =\n deps.engine ??\n create_volley_engine({\n workspace: build_root(config.workspace, config.worktree),\n builder_provider: config.builder_provider,\n critic_provider: config.critic_provider,\n });\n\n const flow = build_flow({ engine, config, renderer, bash_executor, baseline }, resume_from);\n\n try {\n const { value, converged } = await run(\n flow,\n { resume_from },\n {\n trajectory: filesystem_logger({\n output_path: volley_path(config.workspace, 'trajectory.jsonl'),\n }),\n ...(deps.abort !== undefined ? { abort: deps.abort } : {}),\n ...(deps.install_signal_handlers !== undefined\n ? { install_signal_handlers: deps.install_signal_handlers }\n : {}),\n },\n );\n const status = status_of(value, converged);\n const result = run_result_from_state(config, value, status, new Date().toISOString());\n write_run_summary(config, result);\n return result;\n } catch (err) {\n finalize_failed_run(config, err);\n throw err;\n } finally {\n await engine.dispose();\n }\n}\n\n/** Best-effort status stamp on the run summary when the loop threw; the\n * on-disk iteration state is already consistent (record runs per round). */\nfunction finalize_failed_run(config: ResolvedConfig, err: unknown): void {\n const kind = error_kind(err);\n const cause = kind === 'phase_error' ? error_kind((err as { cause?: unknown }).cause) : null;\n const status: RunStatus =\n kind === 'aborted_error' || cause === 'aborted_error' ? 'interrupted' : 'error';\n try {\n // Preserve accumulated totals when `record` already wrote a summary.\n const summary_path = volley_path(config.workspace, 'summary.json');\n const prior = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : run_result_from_state(config, initial_state(), status, null);\n write_run_summary(config, {\n ...prior,\n status,\n completed_at: new Date().toISOString(),\n });\n } catch {\n // Never mask the original failure with a bookkeeping error.\n }\n}\n","/**\n * The ONLY module that calls fascicle's `create_engine`. Every\n * other module receives an `Engine`-shaped value, which keeps the engine\n * mockable in tests and confines provider knowledge to one seam.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { create_engine } from 'fascicle';\nimport type { Engine, ProviderConfigMap, PricingTable } from 'fascicle';\nimport { config_error } from './types.js';\nimport type { BuilderProvider, CriticProvider } from './types.js';\n\nexport type { Engine } from 'fascicle';\n\n/** LM Studio's OpenAI-compatible server and Ollama's server-root defaults.\n * The Ollama URL is the server root, NOT `…/api`: `ai-sdk-ollama` appends\n * `/api/...` itself, so a base URL ending in `/api` requests `/api/api/chat`\n * and 404s. */\nexport const DEFAULT_OLLAMA_URL = 'http://localhost:11434';\nexport const DEFAULT_LMSTUDIO_URL = 'http://localhost:1234/v1';\n\n/** Loopback authorities the container→host crossing rewrites. A base URL\n * pointing at one of these is local to wherever volley runs; contained, that is\n * *inside* the sandbox container, where the host LLM daemon is unreachable\n * except across the boundary at `VOLLEY_MODEL_HOST`. */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '0.0.0.0']);\n\n/** Cross a loopback base URL to the host LLM endpoint. When volley\n * runs inside its sandbox container the local model daemon is on the *host*, so\n * the example's `docker run` injects `VOLLEY_MODEL_HOST=host.docker.internal`\n * (the host-gateway allowlist target; see `sandbox_invocation` in\n * `src/sandbox.ts`). This normalizer *consumes that override* and swaps a\n * loopback host for the gateway, so an unchanged `http://localhost:11434` still\n * reaches the host from in-container. A non-loopback URL (a real remote daemon)\n * is left untouched, and an unset `VOLLEY_MODEL_HOST` (the host / unsandboxed\n * path) is a no-op — so the default and all-Claude paths are unaffected. */\nexport function cross_to_host_gateway(\n base_url: string,\n env: Record<string, string | undefined>,\n): string {\n const host = env['VOLLEY_MODEL_HOST'];\n if (host === undefined || host === '') return base_url;\n let parsed: URL;\n try {\n parsed = new URL(base_url);\n } catch {\n return base_url;\n }\n if (!LOOPBACK_HOSTS.has(parsed.hostname.toLowerCase())) return base_url;\n parsed.hostname = host;\n // `URL` re-serializes `http://host:port` with a trailing `/`; drop it so the\n // Ollama server-root shape (no path) is preserved, while a real path (LM\n // Studio's `/v1`) is left intact.\n return parsed.toString().replace(/\\/$/, '');\n}\n\n/** The Ollama base URL from the environment or the localhost default,\n * normalized to the server root. A trailing `/api` (the pre-v0.3.1 documented\n * default, and a natural mistake since Ollama's REST paths all start with it)\n * is stripped rather than left to 404 every request, then a loopback authority\n * is crossed to the host LLM endpoint when volley runs contained. */\nexport function resolve_ollama_base_url(env: Record<string, string | undefined>): string {\n const raw = env['VOLLEY_OLLAMA_URL'] ?? DEFAULT_OLLAMA_URL;\n const normalized = raw.replace(/\\/+$/, '').replace(/\\/api$/, '');\n return cross_to_host_gateway(normalized, env);\n}\n\nfunction load_pricing_overrides(path: string): PricingTable {\n if (!existsSync(path)) {\n throw config_error(`VOLLEY_PRICING_PATH not found: ${path}`);\n }\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as PricingTable;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw config_error(`VOLLEY_PRICING_PATH is not valid JSON: ${detail}`);\n }\n}\n\nexport type EngineOptions = {\n /** The Claude session's working directory. A run passes its build root, which\n * is the worktree under `--worktree`, so the builder writes where the check\n * and the critic look. */\n workspace: string;\n /** When the builder runs on a local model, its provider is configured\n * alongside claude_cli so one engine drives both roles. */\n builder_provider?: BuilderProvider;\n /** When the critic runs on a local model, its provider is configured\n * alongside claude_cli so one engine drives both roles. */\n critic_provider?: CriticProvider;\n env?: Record<string, string | undefined>;\n};\n\n/** The local (non-CLI) providers a role can select. `claude_cli` needs no\n * ai-sdk wiring, so it never appears here. */\ntype LocalProvider = 'ollama' | 'lmstudio';\n\nfunction is_local_provider(\n provider: BuilderProvider | CriticProvider | undefined,\n): provider is LocalProvider {\n return provider === 'ollama' || provider === 'lmstudio';\n}\n\n/** Add a local provider (ollama/lmstudio) to the provider map, with a base URL\n * from the environment or a sensible localhost default. The ai-sdk peer\n * (`ai-sdk-ollama` / `@ai-sdk/openai-compatible`) is loaded lazily by fascicle\n * only when the provider actually runs.\n *\n * Native transport is the deferred future bridge, not adopted here: volley stays\n * on the ai_sdk transport, which fascicle 0.12.13 already selects by default\n * (`transport?: 'ai_sdk' | 'native'` defaults to `'ai_sdk'`), so no field is\n * needed today. Flipping later is a one-line change — add `transport: 'native'`\n * to the ollama/lmstudio config object returned below. No URL re-pointing is\n * required: `resolve_ollama_base_url` already yields the daemon-root URL the\n * native `/api/chat` transport wants (its adapter appends `/api/chat` itself),\n * which is exactly what the v0.3.1 base-URL fix produces. Kept as a\n * proven-once-then-reverted option so the transport stays a clean second variable\n * in the model-vs-transport comparison.\n *\n * Both providers' base URLs cross a loopback authority to `VOLLEY_MODEL_HOST` when\n * volley runs contained, so an in-container model client reaches the\n * host LLM endpoint at `host.docker.internal`; on the host / unsandboxed path the\n * override is unset and this is a no-op. */\nfunction local_provider_config(\n provider: LocalProvider,\n env: Record<string, string | undefined>,\n): ProviderConfigMap {\n if (provider === 'ollama') {\n return { ollama: { base_url: resolve_ollama_base_url(env) } };\n }\n const lmstudio_url = env['VOLLEY_LMSTUDIO_URL'] ?? DEFAULT_LMSTUDIO_URL;\n return { lmstudio: { base_url: cross_to_host_gateway(lmstudio_url, env) } };\n}\n\n/** Per-run engine. `claude_cli` is always configured with `options.workspace`\n * (the run's build root) as its session cwd; any local provider selected by the\n * builder or critic role is wired in alongside it so one engine drives both\n * roles. Binary, auth mode, provider URLs, and pricing come from the\n * environment. */\nexport function create_volley_engine(options: EngineOptions): Engine {\n const env = options.env ?? process.env;\n\n const auth_mode = env['VOLLEY_AUTH_MODE'] ?? 'auto';\n if (auth_mode !== 'auto' && auth_mode !== 'oauth' && auth_mode !== 'api_key') {\n throw config_error(\n `VOLLEY_AUTH_MODE must be auto, oauth, or api_key; got: ${auth_mode}`,\n );\n }\n\n const binary = env['VOLLEY_CLAUDE_BIN'];\n const pricing_path = env['VOLLEY_PRICING_PATH'];\n\n // A run may select a local provider for the builder, the critic, or both\n // (even two different ones). Wire each distinct local provider once.\n const local_providers = new Set<LocalProvider>();\n if (is_local_provider(options.builder_provider)) local_providers.add(options.builder_provider);\n if (is_local_provider(options.critic_provider)) local_providers.add(options.critic_provider);\n\n const providers: ProviderConfigMap = {\n claude_cli: {\n default_cwd: options.workspace,\n setting_sources: ['project', 'local'],\n auth_mode,\n ...(binary !== undefined && binary.length > 0 ? { binary } : {}),\n ...(auth_mode === 'api_key' && env['ANTHROPIC_API_KEY'] !== undefined\n ? { api_key: env['ANTHROPIC_API_KEY'] }\n : {}),\n },\n };\n for (const provider of local_providers) {\n Object.assign(providers, local_provider_config(provider, env));\n }\n\n return create_engine({\n providers,\n ...(pricing_path !== undefined && pricing_path.length > 0\n ? { pricing: load_pricing_overrides(pricing_path) }\n : {}),\n });\n}\n","/**\n * The volley flow: the whole topology of one run, and nothing else. Step bodies\n * live in `./phases.ts`, the model boundaries in `./builder.ts` and\n * `./critic/run.ts`, the stopping rule in `./loop_state.ts`, and the shell\n * around the flow (workspace setup, the worktree lifecycle, `run`, the final\n * summary) in `./orchestrator.ts`.\n *\n * fascicle's `describe.diagram` draws the tree below from the flow itself, and\n * `test/unit/flow_diagram.test.ts` holds it to the code: change a row by changing\n * its step's `description`, then paste `pnpm diagram --prefix ' * '` over it.\n *\n * volley loop: one round per iteration, up to max_iterations\n * ├─ iteration sequence\n * │ ├─ build open the iteration, run the builder, measure the change\n * │ │ └─ builder model call: one agentic session in the build root\n * │ ├─ verify branch: did the build alone cross the cost cap?\n * │ │ ├─ then skip_verify record the check as skipped and call no critic\n * │ │ └─ else sequence\n * │ │ ├─ check the deterministic gate: checkride, a command, or none\n * │ │ └─ critique the read-only critic's verdict and feedback\n * │ │ └─ critic fallback: judge without tools if a local critic's stream keeps dying\n * │ │ ├─ retry one more try after a stream death, local providers only\n * │ │ │ └─ critic_tools model call with read-only workspace tools\n * │ │ └─ pipe mark the verdict degraded\n * │ │ └─ critic_toolless model call judging from the check output and a file list\n * │ └─ record archive the iteration and rewrite the run summary\n * └─ guard gate stop on approval over a green check, the cost cap, or a gate edit\n */\nimport { branch, fallback, loop, pipe, retry, sequence, step } from 'fascicle';\nimport type { Engine, Step } from 'fascicle';\nimport { make_builder_step } from './builder.js';\nimport type { BashExecutor } from './builder/tools.js';\nimport { cost_cap_hit } from './cost.js';\nimport {\n as_degraded,\n critic_retryable,\n make_critic_toolless_step,\n make_critic_tools_step,\n MAX_CRITIC_RETRIES,\n toolless_critic_prompt,\n with_fallback_cause,\n with_retries,\n} from './critic/run.js';\nimport type { CriticDeps, CriticStep } from './critic/run.js';\nimport { gate, initial_state, remaining_iterations } from './loop_state.js';\nimport {\n build_phase,\n check_phase,\n critique_phase,\n record_phase,\n skip_verify_phase,\n} from './phases.js';\nimport type { PhaseDeps } from './phases.js';\nimport type { LoopState, RunInput } from './types.js';\n\n/** What the flow is built from: the step bodies' dependencies, plus the engine\n * and `bash` executor its model boundaries are wired to. */\nexport type FlowDeps = PhaseDeps & {\n engine: Engine;\n /** The local builder's `bash` executor, or null for the host `spawnSync`\n * default (and for `claude_cli`, which supplies no volley tools). */\n bash_executor: BashExecutor | null;\n};\n\n/** What the flow resolves to: the final state, and whether the guard stopped the\n * loop (success, the cost cap, a gate edit) rather than the round budget. */\nexport type LoopOutcome = { value: LoopState; converged: boolean };\n\n/** The critic arm: the degradation ladder. A local critic whose tool-bearing\n * stream dies is retried at once (the death is stochastic parser failure, not\n * load, so waiting buys nothing), then judged once without tools; anything the\n * ladder does not retry propagates from either rung untouched. */\nexport function build_critic(deps: CriticDeps): CriticStep {\n const retryable = critic_retryable(deps.config);\n return fallback(\n retry(make_critic_tools_step(deps), {\n description: 'one more try after a stream death, local providers only',\n max_attempts: MAX_CRITIC_RETRIES + 1,\n backoff_ms: 0,\n when: retryable,\n project: with_retries,\n }),\n pipe(make_critic_toolless_step(deps), as_degraded, {\n description: 'mark the verdict degraded',\n }),\n {\n name: 'critic',\n description: \"judge without tools if a local critic's stream keeps dying\",\n when: retryable,\n handoff: (prompt) => toolless_critic_prompt(deps.config, prompt),\n project: with_fallback_cause,\n },\n );\n}\n\nexport function build_flow(\n deps: FlowDeps,\n resume_from: LoopState | null,\n): Step<RunInput, LoopOutcome> {\n const { config, renderer } = deps;\n\n const builder = make_builder_step({\n engine: deps.engine,\n config,\n on_chunk: renderer.builder_chunk,\n bash_executor: deps.bash_executor,\n });\n const critic = build_critic({ engine: deps.engine, config, on_chunk: renderer.critic_chunk });\n\n // `build` and `critique` hand their model boundary to `ctx.call` from inside\n // the body, because the prompt comes from the carried state and the result\n // folds back into it. Each declares that boundary as its `arm`, so it shows\n // up under the step in `describe` and the trajectory's flow structure.\n const build = step('build', (s: LoopState, ctx) => build_phase(deps, builder, s, ctx), {\n description: 'open the iteration, run the builder, measure the change',\n arm: builder,\n });\n const skip_verify = step('skip_verify', (s: LoopState) => skip_verify_phase(deps, s), {\n description: 'record the check as skipped and call no critic',\n });\n const check = step('check', (s: LoopState, ctx) => check_phase(deps, s, ctx), {\n description: 'the deterministic gate: checkride, a command, or none',\n });\n const critique = step(\n 'critique',\n (s: LoopState, ctx) => critique_phase(deps, critic, s, ctx),\n { description: \"the read-only critic's verdict and feedback\", arm: critic },\n );\n const record = step('record', (s: LoopState) => record_phase(deps, s), {\n description: 'archive the iteration and rewrite the run summary',\n });\n\n const verify: Step<LoopState, LoopState> = branch({\n name: 'verify',\n description: 'did the build alone cross the cost cap?',\n when: (s: LoopState) => cost_cap_hit(config, s),\n // fascicle names this arm `then`. It holds a Step object, never a function,\n // so nothing can mistake the config for a thenable.\n // oxlint-disable-next-line unicorn/no-thenable\n then: skip_verify,\n otherwise: sequence([check, critique]),\n });\n\n const iteration: Step<LoopState, LoopState> = sequence([build, verify, record], {\n name: 'iteration',\n });\n\n return loop<RunInput, LoopState, LoopOutcome>({\n name: 'volley',\n description: 'one round per iteration, up to max_iterations',\n init: (input) => input.resume_from ?? initial_state(),\n body: iteration,\n guard: step('gate', (s: LoopState) => gate(config, s), {\n description: 'stop on approval over a green check, the cost cap, or a gate edit',\n }),\n finish: (s, { converged }) => ({ value: s, converged }),\n max_rounds: remaining_iterations(config, resume_from),\n });\n}\n","/**\n * Builder invocation: one call to the builder leaf per iteration is one\n * complete agentic session in the workspace — Claude Code under `claude_cli`,\n * or a local model driving volley's tools.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { model_call } from 'fascicle';\nimport type {\n Engine,\n GenerateOptions,\n GenerateResult,\n ModelCallInput,\n RunContext,\n Step,\n StreamChunk,\n} from 'fascicle';\nimport { warn_small_local_context } from './builder/context_check.js';\nimport { builder_tools, type BashExecutor } from './builder/tools.js';\nimport { accumulate } from './cost.js';\nimport { resolve_ollama_base_url } from './engine.js';\nimport { prewarm_ollama_model } from './prewarm.js';\nimport { config_error, phase_error } from './types.js';\nimport type { LoopState, ResolvedConfig } from './types.js';\nimport { build_root } from './worktree.js';\n\nexport const BUILDER_ALLOWED_TOOLS = [\n 'Read',\n 'Write',\n 'Edit',\n 'MultiEdit',\n 'Bash',\n 'Grep',\n 'Glob',\n 'WebFetch',\n] as const;\n\nexport function compose_builder_system(): string {\n return [\n 'You are the builder inside the volley harness: an autonomous agent',\n 'iterating on a workspace until it satisfies a task and its acceptance',\n 'criteria. Work directly in the current working directory. Plan',\n 'internally, make the changes, and verify your own work before finishing.',\n ].join('\\n');\n}\n\n/** Walk up from this module to the package root (works from src/ under tsx\n * and from dist/ in the published package, which ships src/builder/presets). */\nexport function presets_dir(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(dir, 'src', 'builder', 'presets');\n if (existsSync(candidate)) return candidate;\n dir = dirname(dir);\n }\n throw config_error('builder presets directory not found');\n}\n\n// The CLI system prompt assumes CLI semantics (built-in tools, implicit\n// cwd), so the local builder gets its own — the volley tool set, the\n// workspace-is-cwd convention, and the harness-enforced `finish` stop.\nexport function compose_builder_system_local(): string {\n const identity = [\n 'You are the builder inside the volley harness: an autonomous agent',\n 'iterating on a workspace until it satisfies a task and its acceptance',\n 'criteria.',\n ].join('\\n');\n const append = readFileSync(join(presets_dir(), 'harness_append_local.md'), 'utf8');\n return `${identity}\\n\\n${append.trimEnd()}`;\n}\n\n/** The builder system prompt for the active provider: the `claude_cli`\n * prompt (implicit built-in tools, \"the current working directory\") for the\n * CLI builder, or the local prompt (volley's tool set, workspace-is-cwd, and\n * the harness-enforced `finish` stop) for a local model. Mirrors the critic's\n * `resolve_critic_prompt`. */\nfunction resolve_builder_system(config: ResolvedConfig): string {\n return config.builder_provider === 'claude_cli'\n ? compose_builder_system()\n : compose_builder_system_local();\n}\n\n// Salvage budget for a tool call a local model emits as assistant text instead\n// of a structured tool_call (Hermes / json-fenced / Qwen3-Coder XML). Must be\n// > 0 to turn salvage on; the budget is shared across the whole\n// generate call and each salvage is observable on the result for the\n// salvage-rate health metric.\nconst BUILDER_TOOL_CALL_REPAIR_ATTEMPTS = 3;\n\n/** Per-provider tool wiring for the builder, mirroring `critic_tool_options`.\n * The `claude_cli` builder is confined at the CLI permission layer (allowlist +\n * permission mode) and brings its own built-in tools — this arm is unchanged\n * from v2. A local builder brings none, so volley supplies its whole\n * workspace tool surface plus the five per-call loop knobs and **no**\n * schema (it produces a workspace, not a verdict); per-call values win over\n * engine defaults. */\nfunction builder_tool_options(\n config: ResolvedConfig,\n bash_executor: BashExecutor | null,\n): Pick<\n GenerateOptions,\n | 'tools'\n | 'provider_options'\n | 'max_steps'\n | 'tool_error_policy'\n | 'tool_call_repair_attempts'\n | 'max_tool_calls_per_step'\n> {\n if (config.builder_provider === 'claude_cli') {\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...BUILDER_ALLOWED_TOOLS],\n extra_args: ['--permission-mode', config.builder_permission_mode],\n },\n },\n };\n }\n return {\n // Containment root re-points to the worktree under `--worktree`, so\n // the model's writes, edits, and `bash` cwd land there and leave the\n // workspace untouched. When the sandbox is active its `docker exec` executor\n // runs `bash` in the container against the bind-mounted worktree; the\n // host `spawnSync` default stands in otherwise.\n tools: builder_tools(\n build_root(config.workspace, config.worktree),\n bash_executor !== null ? { bash_executor } : {},\n ),\n max_steps: config.builder_max_steps,\n tool_error_policy: 'feed_back',\n tool_call_repair_attempts: BUILDER_TOOL_CALL_REPAIR_ATTEMPTS,\n max_tool_calls_per_step: 1,\n };\n}\n\nexport type BuilderPromptInput = {\n task: string;\n criteria: string;\n feedback: string | null;\n iteration: number;\n checkride: boolean;\n};\n\nexport function compose_builder_prompt(input: BuilderPromptInput): string {\n const parts = [\n 'TASK',\n '----',\n input.task,\n '',\n 'ACCEPTANCE CRITERIA',\n '-------------------',\n input.criteria,\n '',\n `ITERATION: ${input.iteration}`,\n ];\n if (input.iteration > 1 && input.feedback !== null) {\n parts.push(\n '',\n 'PREVIOUS CRITIC FEEDBACK',\n '------------------------',\n input.feedback,\n '',\n 'Address the feedback above. The workspace already contains your prior work;',\n 'read the current state, then make the necessary changes.',\n );\n }\n if (input.checkride) {\n parts.push(\n '',\n 'The definition of done for this workspace includes `pnpm check` (checkride)',\n 'exiting 0. Run it yourself before finishing; on failure, read',\n '.check/summary.json, then the failing slot\\'s raw output, fix, and re-run.',\n );\n }\n return parts.join('\\n');\n}\n\n// A `max_steps` cutoff is not an error. The local builder burned its whole\n// step budget without calling `finish`, so its partial workspace goes to check\n// + critic exactly like a `finish`-terminated iteration (the critic sees\n// incomplete work and requests changes, the loop continues). The renderer\n// surfaces this as a warning and `finish_reason: 'max_steps'` is recorded in\n// the iteration summary — non-convergence is data, not an exception.\nfunction builder_max_steps_warning(max_steps: number): string {\n return (\n `builder hit the ${String(max_steps)}-step limit without calling finish; ` +\n 'handing the partial workspace to check + critic (raise --builder-max-steps if this recurs)'\n );\n}\n\nexport type BuilderDeps = {\n engine: Engine;\n config: ResolvedConfig;\n on_chunk: (chunk: StreamChunk) => void;\n /** The `bash` executor for a sandboxed local builder (`docker exec` against\n * the run's container), or null to use the host `spawnSync` default (the\n * unsandboxed escape hatch, or `claude_cli` which supplies no volley tools). */\n bash_executor?: BashExecutor | null;\n};\n\n/** The builder's model boundary: one call is one complete agentic session in\n * the build root, and its output is the whole `GenerateResult`, because the\n * phase records usage, cost, timing, and tool calls from it. */\nexport type BuilderStep = Step<ModelCallInput, GenerateResult>;\n\n/** Build the builder leaf for this run. Everything but the prompt is fixed for\n * the whole run, so it is wired once here: the provider's system prompt, its\n * tool surface, and the live chunk stream to the renderer. */\nexport function make_builder_step(deps: BuilderDeps): BuilderStep {\n const { config } = deps;\n return model_call({\n engine: deps.engine,\n id: 'builder',\n description: 'model call: one agentic session in the build root',\n provider: config.builder_provider,\n model: config.builder_model,\n system: resolve_builder_system(config),\n on_chunk: deps.on_chunk,\n ...builder_tool_options(config, deps.bash_executor ?? null),\n });\n}\n\nexport type BuilderRunDeps = {\n builder: BuilderStep;\n config: ResolvedConfig;\n warn: (message: string) => void;\n};\n\nexport async function run_builder(\n deps: BuilderRunDeps,\n state: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config } = deps;\n try {\n // Warn at builder start where a too-small context window is detectable —\n // it silently truncates tool schemas (the #1 local tool-calling failure) —\n // then pre-load the model so a cold multi-GB load doesn't blow the real\n // call's first-byte timeout. Both best-effort and Ollama-only; neither\n // blocks the build.\n if (config.builder_provider === 'ollama') {\n const base_url = resolve_ollama_base_url(process.env);\n await warn_small_local_context(\n config.builder_provider,\n config.builder_model,\n base_url,\n deps.warn,\n ctx.abort,\n );\n await prewarm_ollama_model(base_url, config.builder_model, ctx.abort);\n }\n const result = await ctx.call(\n deps.builder,\n compose_builder_prompt({\n task: config.prompt,\n criteria: config.criteria,\n feedback: state.feedback,\n iteration: state.iteration,\n checkride: config.check_resolved === 'checkride',\n }),\n );\n // `max_steps` is a backstop, not a failure — surface it and carry on.\n if (result.finish_reason === 'max_steps') {\n deps.warn(builder_max_steps_warning(config.builder_max_steps));\n }\n return accumulate(state, 'builder', result, config.builder_model);\n } catch (err) {\n throw phase_error('builder', state.iteration, err);\n }\n}\n","/**\n * Best-effort local-context guard. A too-small context window\n * silently truncates the tool schemas volley sends — the #1 reported local\n * tool-calling failure (Ollama's 4k default). We warn at builder start *where\n * the value is detectable* and never block or fail on it: detection is a\n * courtesy, the setup requirement is the user's (README `## Local builder`).\n *\n * On the ai_sdk transport this probe reads the server-side `num_ctx` (a\n * Modelfile or server default). Under fascicle's native transport (the\n * deferred future bridge) `num_ctx`/`keep_alive` become per-call\n * `provider_options.ollama` options set at request time, so the value would be\n * volley's to pass rather than a server default to probe — the warning stays\n * useful either way.\n */\nimport type { BuilderProvider } from '../types.js';\n\n/** Below this, tool schemas start getting truncated for volley's tool set. */\nexport const MIN_RECOMMENDED_NUM_CTX = 16384;\n\n/** Probe timeout — a local `/api/show` answers in single-digit ms when up; a\n * hung server must not stall builder start. */\nconst PROBE_TIMEOUT_MS = 2000;\n\n/** The warning when a detected context window is too small, or null when the\n * window is adequate or unknown (`num_ctx === null` = not detectable). Pure so\n * the threshold decision is unit-testable without a server. */\nexport function context_warning(model: string, num_ctx: number | null): string | null {\n if (num_ctx === null || num_ctx >= MIN_RECOMMENDED_NUM_CTX) return null;\n return (\n `local builder model '${model}' is configured with num_ctx ${String(num_ctx)}, below the ` +\n `~${String(MIN_RECOMMENDED_NUM_CTX)} volley recommends: a small context window silently ` +\n 'truncates the tool schemas (the #1 local tool-calling failure). Raise it (e.g. a Modelfile ' +\n '`PARAMETER num_ctx 16384`) or expect the model to ignore its tools.'\n );\n}\n\n/** Pull `num_ctx` out of Ollama's newline-delimited `parameters` blob\n * (e.g. `\"num_ctx 4096\\nstop \\\"<|im_end|>\\\"\"`). Null when\n * the parameter is absent or unparseable — which is the common case for a\n * server relying on its own default, and precisely the \"not detectable\" edge. */\nexport function parse_num_ctx(parameters: string | null): number | null {\n if (parameters === null) return null;\n const match = /^\\s*num_ctx\\s+(\\d+)\\s*$/m.exec(parameters);\n if (match === null) return null;\n const value = Number(match[1]);\n return Number.isFinite(value) ? value : null;\n}\n\n/** Best-effort probe of an Ollama server for a model's configured `num_ctx`\n * via `/api/show` (`base_url` is the server root). Returns null on any\n * failure (server down, non-OK, field absent, parse/JSON error) — the\n * warning never gates the builder. */\nexport async function probe_ollama_num_ctx(\n base_url: string,\n model: string,\n abort?: AbortSignal,\n): Promise<number | null> {\n const signals = [AbortSignal.timeout(PROBE_TIMEOUT_MS)];\n if (abort !== undefined) signals.push(abort);\n try {\n const res = await fetch(`${base_url.replace(/\\/$/, '')}/api/show`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model }),\n signal: AbortSignal.any(signals),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as { parameters?: unknown };\n return parse_num_ctx(typeof body.parameters === 'string' ? body.parameters : null);\n } catch {\n return null;\n }\n}\n\n/** Emit a small-context warning via `warn` when an Ollama builder model's\n * `num_ctx` is detectably below the recommended floor. Ollama-only — LM Studio\n * exposes no reliable pre-flight context field, so it is documented, not\n * probed. Never throws (setup friction is data, not an error). */\nexport async function warn_small_local_context(\n provider: BuilderProvider,\n model: string,\n base_url: string,\n warn: (message: string) => void,\n abort?: AbortSignal,\n): Promise<void> {\n if (provider !== 'ollama') return;\n const warning = context_warning(model, await probe_ollama_num_ctx(base_url, model, abort));\n if (warning !== null) warn(warning);\n}\n","/**\n * Builder tool set for local (non-CLI) builders.\n *\n * A local model brings no built-in tools, so volley supplies the whole\n * agentic surface: the shared read-only trio (reused from\n * `src/workspace_tools.ts`) plus `write_file`, `edit_file`, `bash`,\n * `fetch`, and the terminal `finish`. File paths are confined to the\n * workspace via `contain()`.\n *\n * Error semantics: a wrong-but-recoverable input — `edit_file`\n * matching 0 or N places, a `bash` command exiting non-zero or timing out, a\n * `fetch` that is SSRF-blocked or fails — is *returned* as a tool result the\n * model reads and acts on. Tools throw only on a genuine harness fault\n * (containment violation, unreadable input, over-cap write).\n *\n * `fetch` is a native readability pipeline (`linkedom` + `@mozilla/\n * readability` + `turndown`) with SSRF protection at the undici connector, not\n * as a pre-flight URL check: a validating DNS `lookup` rejects hostnames that\n * resolve to a non-unicast address before the TCP connect, and the resolved\n * socket's peer address is re-checked after connect — which also catches\n * literal-IP URLs (Node skips `lookup` for those) and every redirect hop\n * (each re-dispatches through the same guarded connector). The byte cap is\n * enforced while reading the HTTP stream, so raw HTML is never returned and a\n * huge page cannot OOM the tool.\n *\n * Egress is defended in two independent layers: this tool's SSRF\n * deny-list (above) and the sandbox's container network posture (`--network none`\n * by default, or a host-collapsed allowlist bridge — see `SandboxNetwork` in\n * `src/sandbox.ts`). Under whole-process containment the whole volley\n * process — `fetch` included — runs inside the container, so both layers apply to\n * `fetch`'s egress: `--network none` leaves it no route and it returns a \"could\n * not fetch\" error result, and the loop continues.\n */\nimport { spawnSync } from 'node:child_process';\nimport { lookup as dns_lookup } from 'node:dns';\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { LookupFunction } from 'node:net';\nimport { dirname } from 'node:path';\nimport { Readability } from '@mozilla/readability';\nimport ipaddr from 'ipaddr.js';\nimport { parseHTML } from 'linkedom';\nimport TurndownService from 'turndown';\nimport { Agent, buildConnector, interceptors, request } from 'undici';\nimport { z } from 'zod';\nimport type { Tool, ToolExecContext } from 'fascicle';\nimport { contain, read_only_tools } from '../workspace_tools.js';\n\nexport const WRITE_FILE_MAX_BYTES = 1_000_000;\n\n// Sized to fit a workspace `pnpm check`: volley's own checkride timeout is\n// 600s, so a shorter budget would kill the builder's self-verify\n// mid-run. Overridable per call site via `BuilderToolOptions` (tests use a\n// short value so the timeout path is exercised without a 10-minute wait).\nexport const BASH_TIMEOUT_MS = 600_000;\n\n// Model-facing cap on each of stdout/stderr; oversize output is truncated\n// with a marker. Not a memory guard — `BASH_CAPTURE_MAX_BYTES`\n// below bounds what `spawnSync` buffers before we ever truncate.\nconst BASH_MAX_OUTPUT_BYTES = 100_000;\n\n// OOM backstop on `spawnSync`'s captured output, well above the display cap:\n// a command that floods gigabytes is bounded here, then truncated to the\n// display cap for the model.\nconst BASH_CAPTURE_MAX_BYTES = 10_000_000;\n\n// Hard cap on bytes read from the HTTP stream before conversion: a page\n// larger than this is truncated at the socket, so raw HTML never reaches the\n// model and a huge page cannot OOM the tool.\nconst FETCH_MAX_BYTES = 200_000;\n\n// Default page-size for the model-facing markdown slice; `start_index`\n// paginates through the rest (MCP fetch-server contract).\nconst FETCH_MAX_CHARS = 5000;\n\n// How many redirect hops to follow. Each hop re-dispatches through the same\n// SSRF-guarded connector, so a redirect into a private range is still refused.\nconst FETCH_MAX_REDIRECTS = 5;\n\n// Per-request timeout (headers and body idle), in ms.\nconst FETCH_TIMEOUT_MS = 30_000;\n\n// Below this, readability's extraction is treated as a miss (empty article /\n// JS-rendered SPA) and we fall back to converting the whole document body.\nconst FETCH_MIN_EXTRACT_CHARS = 200;\n\nconst FETCH_USER_AGENT = 'volley-local-builder';\n\n/** The raw outcome of running one bash command, before the model-facing\n * truncation + timeout marker the `bash` tool applies. `status` is the exit code\n * (null when the process was killed by a signal — e.g. the timeout SIGKILL);\n * `timed_out` marks the timeout path. */\nexport type BashOutcome = {\n status: number | null;\n stdout: string;\n stderr: string;\n timed_out: boolean;\n};\n\n/** How the `bash` tool runs a command: the local `host_bash_executor`\n * (`spawnSync`) — which under whole-process containment runs *inside*\n * volley's own hardened container, no `docker exec` hop. The executor runs one\n * command to completion and returns its raw outcome; the `bash` tool owns the\n * truncation + timeout marker. Kept as an injectable seam so tests can supply a\n * fake and a future shape could re-point it (the `docker exec` executor was\n * retired). */\nexport type BashExecutor = (\n command: string,\n options: { timeout_ms: number; max_capture_bytes: number },\n) => BashOutcome;\n\nexport type BuilderToolOptions = {\n /** Override `BASH_TIMEOUT_MS` (ms). */\n bash_timeout_ms?: number;\n /** Override `BASH_MAX_OUTPUT_BYTES` (bytes, per stream). */\n bash_max_output_bytes?: number;\n /**\n * Where `bash` runs a command. Defaults to `host_bash_executor` — the local\n * `spawnSync`, which under containment runs inside volley's own container against the\n * bind-mounted worktree. Injectable so tests can supply a fake (the\n * `docker exec` executor was retired).\n */\n bash_executor?: BashExecutor;\n /** Override `FETCH_MAX_BYTES` (bytes read from the HTTP stream before the cap). */\n fetch_max_bytes?: number;\n /**\n * Test seam: override the connection-time SSRF classifier. Production leaves\n * this unset and uses `is_forbidden_address`, which rejects every non-unicast\n * (private / loopback / link-local / CGNAT / …) address. Tests set it to reach\n * a loopback fixture server while still exercising the real rejection path.\n */\n fetch_is_address_forbidden?: (address: string) => boolean;\n /**\n * Test seam: override the DNS resolver the SSRF connector validates through.\n * Defaults to `node:dns` `lookup`. Lets a test point a hostname at a private\n * address to exercise the redirect-into-private-range rejection.\n */\n fetch_lookup?: LookupFunction;\n};\n\nconst write_file_input = z.object({\n path: z.string().describe('Workspace-relative path to write. Parent directories are created.'),\n content: z.string().describe('Full UTF-8 content of the file. Overwrites any existing content.'),\n});\n\nconst edit_file_input = z.object({\n path: z.string().describe('Workspace-relative path of the file to edit.'),\n old_str: z\n .string()\n .min(1)\n .describe('Exact text to replace. Must occur exactly once in the file.'),\n new_str: z.string().describe('Replacement text.'),\n});\n\nconst bash_input = z.object({\n command: z.string().describe('Shell command to run in the workspace directory.'),\n});\n\nconst finish_input = z.object({\n summary: z.string().describe('Short summary of what was accomplished.'),\n});\n\nconst fetch_input = z.object({\n url: z.string().describe('Absolute http(s) URL to fetch.'),\n max_chars: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(`Maximum characters of extracted markdown to return (default ${String(FETCH_MAX_CHARS)}).`),\n start_index: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Character offset into the extracted markdown to start from, for paging a long page. Default 0.'),\n});\n\nfunction count_occurrences(haystack: string, needle: string): number {\n return haystack.split(needle).length - 1;\n}\n\n/** Truncate `text` to at most `max` bytes, appending a marker when clipped.\n * Byte-based to honor the byte cap; a split multibyte char at the boundary\n * renders as the replacement char, which is acceptable for tool output. */\nfunction truncate_bytes(text: string, max: number): string {\n if (Buffer.byteLength(text, 'utf8') <= max) return text;\n const clipped = Buffer.from(text, 'utf8').subarray(0, max).toString('utf8');\n return `${clipped}\\n… [truncated at ${String(max)} bytes]`;\n}\n\n/**\n * Non-unicast → forbidden. Rejects loopback, private, link-local,\n * unspecified, broadcast, multicast, CGNAT, and the IPv6 equivalents; an\n * IPv4-mapped IPv6 address is folded to its v4 form first so `::ffff:127.0.0.1`\n * is caught as loopback (and `::ffff:<public>` is still allowed). An\n * unparseable address fails closed.\n */\nexport function is_forbidden_address(address: string): boolean {\n let parsed;\n try {\n parsed = ipaddr.parse(address);\n } catch {\n return true;\n }\n const canonical =\n 'isIPv4MappedAddress' in parsed && parsed.isIPv4MappedAddress() ? parsed.toIPv4Address() : parsed;\n return canonical.range() !== 'unicast';\n}\n\n// Default DNS resolver the SSRF connector validates through; the `fetch_lookup`\n// option swaps it in tests.\nconst default_resolver: LookupFunction = (hostname, options, callback) => {\n dns_lookup(hostname, options, callback);\n};\n\n// A `lookup` that resolves normally, then rejects the connection if any\n// resolved address is forbidden — closing the DNS-rebinding / redirect-hop gap\n// a pre-flight URL check leaves open. Runs before the TCP connect, so a\n// hostname pointing at a private range never opens a socket.\nfunction guarded_lookup(is_forbidden: (address: string) => boolean, resolve: LookupFunction): LookupFunction {\n return (hostname, options, callback) => {\n resolve(hostname, options, (err, address, family) => {\n if (err !== null) {\n callback(err, '', 0);\n return;\n }\n const resolved = Array.isArray(address) ? address.map((entry) => entry.address) : [address];\n const blocked = resolved.find((entry) => is_forbidden(entry));\n if (blocked !== undefined) {\n callback(ssrf_error(blocked, hostname), '', 0);\n return;\n }\n callback(null, address, family);\n });\n };\n}\n\nfunction ssrf_error(address: string, hostname: string): NodeJS.ErrnoException {\n const err: NodeJS.ErrnoException = new Error(\n `blocked non-unicast address ${address} for host \"${hostname}\"`,\n );\n err.code = 'ERR_SSRF_BLOCKED';\n return err;\n}\n\n// An undici Agent whose connector validates SSRF at two points: the `lookup`\n// above (hostnames, before connect) and the peer address of the established\n// socket (which also catches literal-IP URLs — Node skips `lookup` for those —\n// and every redirect hop, since each re-dispatches through this connector).\nfunction create_ssrf_agent(is_forbidden: (address: string) => boolean, resolve: LookupFunction): Agent {\n const base = buildConnector({ lookup: guarded_lookup(is_forbidden, resolve), timeout: FETCH_TIMEOUT_MS });\n const connector: typeof base = (options, callback) => {\n base(options, (err, socket) => {\n if (err !== null) {\n callback(err, null);\n return;\n }\n if (socket === null) {\n callback(new Error('connection produced no socket'), null);\n return;\n }\n const remote = socket.remoteAddress;\n if (remote !== undefined && is_forbidden(remote)) {\n socket.destroy();\n callback(ssrf_error(remote, options.hostname), null);\n return;\n }\n callback(null, socket);\n });\n };\n return new Agent({ connect: connector, headersTimeout: FETCH_TIMEOUT_MS, bodyTimeout: FETCH_TIMEOUT_MS });\n}\n\n// Read the response body, stopping at `max_bytes` so raw HTML never fully\n// buffers. Breaking the `for await` destroys the stream, ending the\n// download.\nasync function read_body_capped(body: AsyncIterable<Buffer>, max_bytes: number): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of body) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n const remaining = max_bytes - total;\n if (buf.length >= remaining) {\n chunks.push(buf.subarray(0, remaining));\n break;\n }\n chunks.push(buf);\n total += buf.length;\n }\n return Buffer.concat(chunks);\n}\n\nfunction header_value(value: string | string[] | undefined): string {\n if (Array.isArray(value)) return value[0] ?? '';\n return value ?? '';\n}\n\nfunction content_kind(content_type: string, body: string): 'html' | 'text' | 'binary' {\n const ct = content_type.toLowerCase();\n if (ct.includes('html') || ct.includes('xml')) return 'html';\n if (\n ct.startsWith('text/') ||\n ct.includes('json') ||\n ct.includes('javascript') ||\n ct.includes('csv')\n ) {\n return 'text';\n }\n if (ct === '') return body.trimStart().startsWith('<') ? 'html' : 'text';\n return 'binary';\n}\n\n// Extract the main content as markdown: readability over a linkedom DOM, then\n// turndown. Falls back to converting the whole document when readability finds\n// little (empty article / JS-rendered SPA). Never returns raw HTML.\nfunction extract_markdown(html: string): string {\n const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });\n turndown.remove(['script', 'style', 'noscript']);\n let body_markdown = '';\n let title = '';\n try {\n const { document } = parseHTML(html);\n const article = new Readability(document).parse();\n if (article !== null) {\n title = (article.title ?? '').trim();\n if (article.content) {\n body_markdown = turndown.turndown(article.content).trim();\n }\n }\n } catch {\n body_markdown = '';\n }\n if (body_markdown.length < FETCH_MIN_EXTRACT_CHARS) {\n let fallback = '';\n try {\n fallback = turndown.turndown(html).trim();\n } catch {\n fallback = '';\n }\n if (fallback.length > body_markdown.length) body_markdown = fallback;\n }\n const prefix = title.length > 0 && !body_markdown.startsWith(`# ${title}`) ? `# ${title}\\n\\n` : '';\n return `${prefix}${body_markdown}`.trim();\n}\n\n// MCP fetch-server pagination: return the `max_chars` slice at `start_index`,\n// and when more remains, a self-describing trailer naming the next start_index.\nfunction paginate(full: string, max_chars: number, start_index: number): string {\n if (start_index >= full.length) {\n return `(no more content: start_index ${String(start_index)} is at or past the end of the ${String(full.length)}-character document)`;\n }\n const slice = full.slice(start_index, start_index + max_chars);\n const next = start_index + slice.length;\n if (next >= full.length) return slice;\n const remaining = full.length - next;\n return `${slice}\\n\\n<truncated: ${String(remaining)} more characters. Call fetch again with start_index=${String(next)} to continue.>`;\n}\n\n// Flatten an error (and its `cause` chain) into a single line for the model.\nfunction error_detail(err: unknown): string {\n const parts: string[] = [];\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current !== undefined && current !== null && !seen.has(current)) {\n seen.add(current);\n if (current instanceof Error) {\n const code = (current as NodeJS.ErrnoException).code;\n parts.push(code !== undefined ? `${current.message} [${code}]` : current.message);\n current = (current as { cause?: unknown }).cause;\n } else {\n // Thrown values are Errors in practice; a non-Error is defensive only, so\n // keep a string as-is and never risk an \"[object Object]\" stringification.\n parts.push(typeof current === 'string' ? current : `non-error value (${typeof current})`);\n break;\n }\n }\n return parts.length > 0 ? parts.join(' <- ') : 'unknown error';\n}\n\ntype FetchConfig = {\n is_forbidden: (address: string) => boolean;\n resolve: LookupFunction;\n max_bytes: number;\n};\n\nasync function run_fetch(raw: unknown, ctx: ToolExecContext, config: FetchConfig): Promise<string> {\n const input = fetch_input.parse(raw);\n const max_chars = input.max_chars ?? FETCH_MAX_CHARS;\n const start_index = input.start_index ?? 0;\n\n let target: URL;\n try {\n target = new URL(input.url);\n } catch {\n return `error: not a valid absolute URL: ${input.url}`;\n }\n if (target.protocol !== 'http:' && target.protocol !== 'https:') {\n return `error: unsupported URL scheme \"${target.protocol}\" — only http and https are fetched`;\n }\n\n const agent = create_ssrf_agent(config.is_forbidden, config.resolve);\n const dispatcher = agent.compose(interceptors.redirect({ maxRedirections: FETCH_MAX_REDIRECTS }));\n try {\n const res = await request(target.href, {\n dispatcher,\n signal: ctx.abort,\n headersTimeout: FETCH_TIMEOUT_MS,\n bodyTimeout: FETCH_TIMEOUT_MS,\n headers: {\n 'user-agent': FETCH_USER_AGENT,\n accept: 'text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.8',\n // No compression: keep the pipeline simple and the byte cap honest.\n 'accept-encoding': 'identity',\n },\n });\n if (res.statusCode >= 400) {\n await res.body.dump();\n return `error: HTTP ${String(res.statusCode)} fetching ${target.href}`;\n }\n const bytes = await read_body_capped(res.body, config.max_bytes);\n const content_type = header_value(res.headers['content-type']);\n const text = bytes.toString('utf8');\n if (text.trim().length === 0) {\n return `error: empty response body from ${target.href}`;\n }\n const kind = content_kind(content_type, text);\n if (kind === 'binary') {\n return `error: cannot extract non-text content (content-type: ${content_type}) from ${target.href}`;\n }\n const markdown = kind === 'html' ? extract_markdown(text) : text.trim();\n if (markdown.length === 0) {\n return `error: no readable content extracted from ${target.href}`;\n }\n return paginate(markdown, max_chars, start_index);\n } catch (err) {\n return `error: could not fetch ${target.href}: ${error_detail(err)}`;\n } finally {\n await agent.close().catch(() => undefined);\n }\n}\n\n/**\n * The `bash` executor: run the command via `spawnSync` with a shell, bounded by\n * the timeout (SIGKILL on expiry) and the OOM capture cap. Under whole-process\n * containment this runs *inside* volley's hardened container against the\n * bind-mounted worktree — the container is the isolation boundary, no\n * `docker exec` hop — and it is likewise the executor on the\n * `--allow-unsandboxed-builder` host escape hatch. `status` is null\n * when a signal (the timeout SIGKILL) killed the process.\n */\nfunction host_bash_executor(cwd: string): BashExecutor {\n return (command, options) => {\n const result = spawnSync(command, {\n shell: true,\n cwd,\n encoding: 'utf8',\n timeout: options.timeout_ms,\n killSignal: 'SIGKILL',\n maxBuffer: options.max_capture_bytes,\n });\n return {\n status: result.status,\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n timed_out: (result.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT',\n };\n };\n}\n\n// Same wiring convention as the shared read tools: each tool is typed as\n// fascicle's `Tool` (input `unknown`) and re-parses the model's raw\n// arguments with its own schema inside `execute`.\nexport function builder_tools(workspace: string, options: BuilderToolOptions = {}): Tool[] {\n const bash_timeout_ms = options.bash_timeout_ms ?? BASH_TIMEOUT_MS;\n const bash_max_output_bytes = options.bash_max_output_bytes ?? BASH_MAX_OUTPUT_BYTES;\n const bash_executor = options.bash_executor ?? host_bash_executor(workspace);\n\n const write_file: Tool = {\n name: 'write_file',\n description:\n 'Write a UTF-8 text file in the workspace, creating parent directories ' +\n 'and overwriting any existing content. Rejects content over ' +\n `${String(WRITE_FILE_MAX_BYTES)} bytes.`,\n input_schema: write_file_input,\n execute: (raw) => {\n const input = write_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const bytes = Buffer.byteLength(input.content, 'utf8');\n if (bytes > WRITE_FILE_MAX_BYTES) {\n throw new Error(\n `content is ${String(bytes)} bytes, over the ${String(WRITE_FILE_MAX_BYTES)}-byte write cap`,\n );\n }\n mkdirSync(dirname(abs), { recursive: true });\n writeFileSync(abs, input.content, 'utf8');\n return `wrote ${String(bytes)} bytes to ${input.path}`;\n },\n };\n\n const edit_file: Tool = {\n name: 'edit_file',\n description:\n 'Replace one exact occurrence of old_str with new_str in a workspace ' +\n 'file. old_str must match the file content exactly once — on 0 or ' +\n 'multiple matches nothing is changed and an error is returned; read ' +\n 'the file and retry with a longer, unique old_str.',\n input_schema: edit_file_input,\n execute: (raw) => {\n const input = edit_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const content = readFileSync(abs, 'utf8');\n const matches = count_occurrences(content, input.old_str);\n if (matches === 0) {\n return (\n `error: old_str not found in ${input.path} (0 matches). ` +\n 'No change made. Read the file and retry with an exact excerpt of its current content.'\n );\n }\n if (matches > 1) {\n return (\n `error: old_str matches ${String(matches)} times in ${input.path}. ` +\n 'No change made. Include more surrounding context to make old_str unique.'\n );\n }\n writeFileSync(abs, content.replace(input.old_str, input.new_str), 'utf8');\n return `edit applied to ${input.path}`;\n },\n };\n\n const bash: Tool = {\n name: 'bash',\n description:\n 'Run a shell command in the workspace and return its exit code, stdout, ' +\n 'and stderr. Each call is independent — no shell state (working ' +\n 'directory, environment, variables) carries over between commands. A ' +\n 'non-zero exit is a normal result, not an error: read it and adjust. ' +\n `Each stream is truncated past ${String(bash_max_output_bytes)} bytes, ` +\n `and the command is killed if it runs longer than ${String(bash_timeout_ms)}ms.`,\n input_schema: bash_input,\n // Stateless per command (the executor is injectable without touching\n // this contract — under containment it is the local `spawnSync` running in-container),\n // and never throws on the command's own failure — a non-zero exit or a\n // timeout is *returned* as `{ exit_code, stdout, stderr }` for the model to\n // read. The executor buffers up to `BASH_CAPTURE_MAX_BYTES` (OOM guard)\n // before we truncate to the model-facing cap.\n execute: (raw) => {\n const input = bash_input.parse(raw);\n const outcome = bash_executor(input.command, {\n timeout_ms: bash_timeout_ms,\n max_capture_bytes: BASH_CAPTURE_MAX_BYTES,\n });\n let stderr = truncate_bytes(outcome.stderr, bash_max_output_bytes);\n if (outcome.timed_out) {\n const note = `[command timed out after ${String(bash_timeout_ms)}ms and was killed]`;\n stderr = stderr.length > 0 ? `${stderr}\\n${note}` : note;\n }\n // `status` is the numeric exit code, or null when the process was killed\n // by a signal (e.g. the timeout SIGKILL).\n return {\n exit_code: outcome.status,\n stdout: truncate_bytes(outcome.stdout, bash_max_output_bytes),\n stderr,\n };\n },\n };\n\n const fetch: Tool = {\n name: 'fetch',\n description:\n 'Fetch an http(s) URL and return its main content converted to Markdown. ' +\n `Returns at most max_chars characters (default ${String(FETCH_MAX_CHARS)}); ` +\n 'when the page is longer, a trailer names the start_index to pass to read ' +\n 'the next slice. Private, loopback, and link-local addresses are refused. ' +\n 'A blocked, non-HTML, or failed request returns an error string you can read and act on.',\n input_schema: fetch_input,\n // Native readability pipeline with connection-time SSRF protection; a\n // blocked / non-HTML / HTTP error is returned as a tool result, not\n // thrown. The classifier and resolver are overridable for tests only.\n execute: (raw, ctx) =>\n run_fetch(raw, ctx, {\n is_forbidden: options.fetch_is_address_forbidden ?? is_forbidden_address,\n resolve: options.fetch_lookup ?? default_resolver,\n max_bytes: options.fetch_max_bytes ?? FETCH_MAX_BYTES,\n }),\n };\n\n const finish: Tool = {\n name: 'finish',\n description:\n 'Declare the task complete. Calling this tool ends your turn — do not ' +\n 'call it until the work is done and verified.',\n input_schema: finish_input,\n // A successful `finish` ends the loop deterministically. The summary\n // is recorded in the trajectory like any tool call and otherwise ignored\n // — the workspace, not the self-report, is truth.\n ends_turn: true,\n execute: (raw) => {\n const input = finish_input.parse(raw);\n return `finished: ${input.summary}`;\n },\n };\n\n return [...read_only_tools(workspace), write_file, edit_file, bash, fetch, finish];\n}\n","/**\n * Shared workspace tools: `contain()` path confinement plus the read-only\n * tool set (`read_file`, `search_files`, `list_files`).\n *\n * The claude_cli builder/critic get file access from the CLI's own built-in\n * tools. API-style providers (ollama, lmstudio, …) have no built-ins, so\n * volley supplies its own. The critic uses the read-only set as-is via\n * `src/critic/tools.ts`; the builder set in\n * `src/builder/tools.ts` reuses `contain()` and the read tools and adds its\n * write/exec surface. Every path is resolved and confined to the\n * workspace root.\n */\nimport { readFileSync, readdirSync, statSync } from 'node:fs';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { z } from 'zod';\nimport type { Tool } from 'fascicle';\n\nexport const READ_FILE_MAX_BYTES = 200_000;\nexport const SEARCH_MAX_MATCHES = 200;\nconst LIST_MAX_ENTRIES = 2000;\n\n/** Directories never worth handing a critic; they bury signal and blow the\n * traversal budget. */\nconst IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.volley',\n '.check',\n 'dist',\n '.cache',\n]);\n\n/** Resolve `rel` inside `workspace`, rejecting absolute paths and any `..`\n * escape. Returns the absolute path; throws on containment violation. The\n * `workspace` root passed here is the build root, which is the per-run git\n * worktree under `--worktree` (`build_root`), not necessarily the\n * control-plane workspace that holds `.volley/`. */\nexport function contain(workspace: string, rel: string): string {\n const root = resolve(workspace);\n const candidate = isAbsolute(rel) ? resolve(rel) : resolve(root, rel);\n const within = candidate === root || candidate.startsWith(`${root}${sep}`);\n if (!within) {\n throw new Error(`path escapes the workspace: ${rel}`);\n }\n return candidate;\n}\n\ntype WalkEntry = { rel: string; abs: string };\n\nfunction walk(root: string, start: string, limit: number): WalkEntry[] {\n const out: WalkEntry[] = [];\n const stack = [start];\n while (stack.length > 0 && out.length < limit) {\n const dir = stack.pop() as string;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const name of entries) {\n const abs = join(dir, name);\n let is_dir: boolean;\n try {\n is_dir = statSync(abs).isDirectory();\n } catch {\n continue;\n }\n if (is_dir) {\n if (!IGNORED_DIRS.has(name)) stack.push(abs);\n continue;\n }\n out.push({ rel: relative(root, abs), abs });\n if (out.length >= limit) break;\n }\n }\n return out;\n}\n\nfunction build_regex(pattern: string, flags: string): RegExp {\n try {\n return new RegExp(pattern, flags);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(`invalid regular expression: ${detail}`);\n }\n}\n\nconst read_file_input = z.object({\n path: z.string().describe('Workspace-relative path to the file to read.'),\n});\n\nconst search_files_input = z.object({\n pattern: z.string().describe('JavaScript regular expression to match against each line.'),\n path: z\n .string()\n .optional()\n .describe('Optional workspace-relative subdirectory to limit the search to.'),\n ignore_case: z.boolean().optional().describe('Case-insensitive match. Default false.'),\n});\n\nconst list_files_input = z.object({\n path: z\n .string()\n .optional()\n .describe('Optional workspace-relative subdirectory. Default: the workspace root.'),\n contains: z\n .string()\n .optional()\n .describe('Optional substring filter applied to each relative path.'),\n});\n\n// Each tool is typed as fascicle's `Tool` (input `unknown`) and re-parses the\n// model's raw arguments with its own schema. fascicle's `Tool` is invariant\n// on the input type, so typed-per-tool values will not widen into `Tool[]`;\n// parsing inside `execute` keeps the wiring cast-free and validates arguments\n// at the boundary. The declared `input_schema` still drives the JSON schema\n// the model sees.\nexport function read_only_tools(workspace: string): Tool[] {\n const read_file: Tool = {\n name: 'read_file',\n description:\n 'Read a UTF-8 text file from the workspace. Returns the file content ' +\n `(truncated at ${String(READ_FILE_MAX_BYTES)} bytes).`,\n input_schema: read_file_input,\n execute: (raw) => {\n const input = read_file_input.parse(raw);\n const abs = contain(workspace, input.path);\n const content = readFileSync(abs, 'utf8');\n return content.length > READ_FILE_MAX_BYTES\n ? `${content.slice(0, READ_FILE_MAX_BYTES)}\\n… [truncated at ${String(READ_FILE_MAX_BYTES)} bytes]`\n : content;\n },\n };\n\n const search_files: Tool = {\n name: 'search_files',\n description:\n 'Search workspace files for lines matching a regular expression. Returns ' +\n `up to ${String(SEARCH_MAX_MATCHES)} \"relative/path:line: text\" hits.`,\n input_schema: search_files_input,\n execute: (raw) => {\n const input = search_files_input.parse(raw);\n const start = input.path !== undefined ? contain(workspace, input.path) : resolve(workspace);\n const regex = build_regex(input.pattern, input.ignore_case === true ? 'i' : '');\n const files = walk(resolve(workspace), start, LIST_MAX_ENTRIES);\n const hits: string[] = [];\n for (const file of files) {\n if (hits.length >= SEARCH_MAX_MATCHES) break;\n let content: string;\n try {\n content = readFileSync(file.abs, 'utf8');\n } catch {\n continue;\n }\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length; i += 1) {\n if (hits.length >= SEARCH_MAX_MATCHES) break;\n const line = lines[i] as string;\n if (regex.test(line)) hits.push(`${file.rel}:${String(i + 1)}: ${line.trim()}`);\n }\n }\n if (hits.length === 0) return 'no matches';\n const capped =\n hits.length >= SEARCH_MAX_MATCHES ? `\\n… [capped at ${String(SEARCH_MAX_MATCHES)} matches]` : '';\n return `${hits.join('\\n')}${capped}`;\n },\n };\n\n const list_files: Tool = {\n name: 'list_files',\n description:\n 'List files under a workspace directory (recursively; skips node_modules, ' +\n '.git, and other build/output directories).',\n input_schema: list_files_input,\n execute: (raw) => {\n const input = list_files_input.parse(raw);\n const start = input.path !== undefined ? contain(workspace, input.path) : resolve(workspace);\n let files = walk(resolve(workspace), start, LIST_MAX_ENTRIES).map((f) => f.rel);\n if (input.contains !== undefined) {\n const needle = input.contains;\n files = files.filter((f) => f.includes(needle));\n }\n if (files.length === 0) return 'no files';\n const capped =\n files.length >= LIST_MAX_ENTRIES ? `\\n… [capped at ${String(LIST_MAX_ENTRIES)} entries]` : '';\n return `${files.join('\\n')}${capped}`;\n },\n };\n\n return [read_file, search_files, list_files];\n}\n\n/** A `paths + sizes` listing of the workspace tree, no file contents — the\n * grounding a tool-less critic gets when its provider's tool parser died and the\n * degradation ladder traded read access for survival. Reuses the same\n * `walk` + `IGNORED_DIRS` traversal as the read tools, so the inventory matches\n * what a working `list_files` would have surfaced; caps at `limit` entries. */\nexport function workspace_inventory(root: string, limit: number = LIST_MAX_ENTRIES): string {\n const base = resolve(root);\n const files = walk(base, base, limit);\n if (files.length === 0) return 'no files';\n const lines = files.map((file) => {\n let size: number;\n try {\n size = statSync(file.abs).size;\n } catch {\n size = 0;\n }\n return `${file.rel} (${String(size)} bytes)`;\n });\n const capped =\n files.length >= limit ? `\\n… [capped at ${String(limit)} entries]` : '';\n return `${lines.join('\\n')}${capped}`;\n}\n","/**\n * Cost and usage accumulation. All pricing knowledge lives in\n * fascicle; volley only folds `GenerateResult.usage` / `.cost` into loop\n * state and enforces the cap predicate in the guard.\n */\nimport { claude_cli_reported, throughput } from 'fascicle';\nimport type { GenerateResult, UsageTotals } from 'fascicle';\nimport type {\n CostSource,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n} from './types.js';\n\nexport const EMPTY_USAGE: UsageTotals = { input_tokens: 0, output_tokens: 0 };\n\nexport function add_usage(a: UsageTotals, b: UsageTotals): UsageTotals {\n const sum: UsageTotals = {\n input_tokens: a.input_tokens + b.input_tokens,\n output_tokens: a.output_tokens + b.output_tokens,\n };\n const optional = ['cached_input_tokens', 'cache_write_tokens', 'reasoning_tokens'] as const;\n for (const key of optional) {\n const total = (a[key] ?? 0) + (b[key] ?? 0);\n if (a[key] !== undefined || b[key] !== undefined) sum[key] = total;\n }\n return sum;\n}\n\nexport function cost_source_of(result: GenerateResult<unknown>): CostSource {\n if (result.cost === undefined) return 'unknown';\n return result.model_resolved.provider === 'claude_cli'\n ? 'provider_reported'\n : 'engine_derived';\n}\n\n/** One phase's record from its generate result. The duration is fascicle's\n * call-level wall clock (`GenerateResult.timing`: every turn and the tools\n * between them) unless the caller measured a wider span, as the critic does for\n * its whole degradation ladder. */\nexport function phase_record(\n result: GenerateResult<unknown>,\n model: string,\n duration_ms: number = result.timing?.duration_ms ?? 0,\n): PhaseRecord {\n const rate = throughput(result);\n return {\n provider: result.model_resolved.provider,\n model,\n session_id: claude_cli_reported(result)?.session_id ?? null,\n duration_ms,\n usage: result.usage,\n cost_usd: result.cost?.total_usd ?? null,\n cost_source: cost_source_of(result),\n finish_reason: result.finish_reason,\n tool_calls: result.tool_calls.length,\n salvaged_tool_calls: result.tool_calls.filter((call) => call.salvaged === true).length,\n ...(rate !== undefined ? { throughput: rate } : {}),\n };\n}\n\n/** Fold one phase's result into the loop state. Unknown cost records `null`\n * for the phase and warns once per run — a run never fails over pricing. */\nexport function accumulate(\n state: LoopState,\n role: 'builder' | 'critic',\n result: GenerateResult<unknown>,\n model: string,\n duration_ms?: number,\n): LoopState {\n const record = phase_record(result, model, duration_ms);\n const cost = record.cost_usd ?? 0;\n return {\n ...state,\n [role]: record,\n total_usage: add_usage(state.total_usage, result.usage),\n total_cost_usd: state.total_cost_usd + cost,\n iteration_cost_usd: state.iteration_cost_usd + cost,\n builder_cost_usd: state.builder_cost_usd + (role === 'builder' ? cost : 0),\n critic_cost_usd: state.critic_cost_usd + (role === 'critic' ? cost : 0),\n cost_warned: state.cost_warned || record.cost_usd === null,\n };\n}\n\nexport function cost_cap_hit(config: ResolvedConfig, state: LoopState): boolean {\n return config.max_cost_usd !== null && state.total_cost_usd >= config.max_cost_usd;\n}\n","/**\n * Best-effort Ollama model pre-load. A cold multi-GB model can spend minutes\n * in load + first prompt eval — longer than the provider path's in-request\n * header timeout — so the first real `generate` dies with an opaque\n * `stream interrupted: fetch failed`. Ollama's documented load call (a\n * `/api/generate` POST with a model and no prompt) returns as soon as the\n * model is resident, so absorbing the load here keeps the real call's\n * time-to-first-byte inside its budget.\n *\n * Best-effort like the context probe: any failure (server down, unknown\n * model, timeout) is swallowed — the real generate call surfaces the error\n * with retry and reporting behind it. Ollama-only; LM Studio has no\n * equivalent load-without-generating endpoint.\n */\n\n/** Generous ceiling on the load itself: a disk-cold 30B-class model takes\n * tens of seconds to minutes. Past this, give up and let the real call try. */\nconst PREWARM_TIMEOUT_MS = 300_000;\n\n/** Load `model` into the Ollama server's memory (`base_url` is the server\n * root). Resolves when the model is resident, on any failure, or at the\n * timeout — never throws, never gates the phase. An already-resident model\n * returns immediately, so warming the same model for both roles is free.\n *\n * Load-bearing only on the ai_sdk transport: the cold-load death this\n * absorbs is the ai-sdk/undici in-request header timeout, not an Ollama\n * limit. On fascicle's native transport — the deferred future bridge, see\n * `local_provider_config` in engine.ts — the per-turn call is a bare\n * `fetch(..., { signal })` with no default body timeout, so a cold model can\n * take as long as it needs and this pre-warm's necessity drops away (keep it\n * regardless: a resident model makes it a no-op). Native would also move the\n * `num_ctx`/`keep_alive` levers to per-call `provider_options.ollama`, rather\n * than the server-side Modelfile defaults volley probes today. */\nexport async function prewarm_ollama_model(\n base_url: string,\n model: string,\n abort?: AbortSignal,\n): Promise<void> {\n const signals = [AbortSignal.timeout(PREWARM_TIMEOUT_MS)];\n if (abort !== undefined) signals.push(abort);\n try {\n await fetch(`${base_url.replace(/\\/$/, '')}/api/generate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model }),\n signal: AbortSignal.any(signals),\n });\n } catch {\n // Best-effort: the real generate call owns error surfacing.\n }\n}\n","/**\n * Git-worktree orchestration: isolate a builder run's\n * *effects* on a per-run branch checked out into a sibling worktree, then tear\n * the whole thing down when the run ends. The worktree lifecycle wraps the\n * fascicle loop — it is not itself a loop — so these are straight-line git\n * subprocess calls and the flow's no-loops rule is unaffected.\n *\n * Teardown is not one behaviour but three, decided by `worktree_fate` and\n * predicted out loud by `report_worktree_fate` before any model spend: a\n * converged `--worktree --git` run *integrates* (the orchestrator squash-merges,\n * then the branch is discarded), a `--discard-worktree` run *discards*, and a\n * plain `--worktree` run *salvages* — its work was never integrated and lives\n * nowhere else, so teardown commits it onto the run branch and keeps the branch\n * instead of force-deleting the build. Everything that did not converge still\n * discards wholesale.\n */\nimport { existsSync, renameSync, rmSync, symlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { check_error, config_error } from './types.js';\nimport { backup_stamp } from './workspace.js';\n\n/** A live worktree: the checked-out path and the branch it holds. */\nexport type WorktreeHandle = {\n path: string;\n branch: string;\n};\n\n/** The sibling directory a run's worktree is checked out into — one per\n * workspace, alongside it so it never nests inside the repo's own tree. */\nexport function worktree_path(workspace: string): string {\n return `${resolve(workspace)}.worktree`;\n}\n\n/** The per-run branch name (one named branch per phase). Derived from the\n * run id so it is stable across a resume. */\nexport function worktree_branch(run_id: string): string {\n return `volley/${run_id}`;\n}\n\n/**\n * The directory the builder's *effects* land in: the run's worktree\n * when `--worktree` is on, else the workspace itself. This is the containment\n * root the builder/critic file tools resolve through `contain()` and the\n * `bash` tool's cwd — re-pointing it moves writes into the worktree without\n * disturbing the workspace. `.volley/` state, the resolved config, and the\n * deterministic check stay under the workspace (the control plane), so only the\n * model-driven effect surface moves.\n */\nexport function build_root(workspace: string, worktree: boolean): string {\n return worktree ? worktree_path(workspace) : workspace;\n}\n\n/** What becomes of a *successful* `--worktree` run's effects. Any other\n * outcome — cost cap, budget, interrupt, error — always discards: an abandoned\n * phase's branch is thrown away wholesale, as it always has been. */\nexport type WorktreeFate = 'none' | 'integrate' | 'salvage' | 'discard';\n\n/** The config fields the fate turns on, as a structural subset of\n * `ResolvedConfig` so the decision is testable without a whole config. */\nexport type WorktreeFateConfig = {\n worktree: boolean;\n git_checkpoints: boolean;\n discard_worktree: boolean;\n};\n\n/**\n * Which of the three outcomes a converged run gets:\n *\n * - `integrate` — `--worktree --git`: the phase branch's checkpoints squash-merge\n * onto the workspace branch (`integrate_worktree`), then teardown discards it.\n * - `discard` — `--discard-worktree`: the effects go away with the branch. What\n * `volley matrix` sweeps with: isolate the effects, keep only verdicts.\n * - `salvage` — `--worktree` alone: nothing integrates, and the worktree holds the\n * run's only copy of its work, so teardown commits that onto the run branch and\n * keeps it rather than force-deleting a green run's build.\n *\n * `--git` wins over `--discard-worktree`, so the documented `--worktree --git`\n * integrate path is untouched by asking for a throw-away run.\n */\nexport function worktree_fate(config: WorktreeFateConfig): WorktreeFate {\n if (!config.worktree) return 'none';\n if (config.git_checkpoints) return 'integrate';\n if (config.discard_worktree) return 'discard';\n return 'salvage';\n}\n\n/** The run branch as a *prediction* can name it: `--dry-run` resolves its own\n * run id, which is not the id the real run will get, so the notice names the\n * pattern and the post-run report names the branch. */\nconst RUN_BRANCH_PATTERN = 'volley/<run id>';\n\nexport type WorktreeNotice = { level: 'info' | 'warn'; message: string };\n\n/**\n * What this run will do with its effects, in one line, said before any model\n * spend — the same predict-at-dry-run/warn-at-run-start shape as the local-critic\n * seat canary and the `num_ctx` guard. `salvage` is a warning, not an\n * info line: `--worktree` without `--git` integrates nothing, and it is the one\n * fate an operator is likely to have configured by accident.\n */\nexport function worktree_notice(config: WorktreeFateConfig): WorktreeNotice | null {\n const fate = worktree_fate(config);\n if (fate === 'none') return null;\n if (fate === 'integrate') {\n return {\n level: 'info',\n message:\n 'worktree: --worktree --git — a successful run squash-merges its run branch onto the ' +\n 'workspace branch at teardown; any other outcome is discarded.',\n };\n }\n if (fate === 'discard') {\n return {\n level: 'info',\n message:\n 'worktree: --discard-worktree — the run builds in an isolated worktree whose effects are ' +\n 'thrown away at teardown, converged or not. Verdicts only; no branch is kept.',\n };\n }\n return {\n level: 'warn',\n message:\n 'worktree: --worktree without --git — a successful run will NOT be integrated into the ' +\n 'workspace branch, and the builder writes only inside the sibling worktree, so your working ' +\n `tree stays as it is. The run's work is committed onto its own branch (${RUN_BRANCH_PATTERN}) ` +\n 'at teardown and left there for `git switch` / `git cherry-pick`. Add --git to squash-merge ' +\n 'it onto the workspace branch instead, or --discard-worktree to throw it away deliberately.',\n };\n}\n\n/** The renderer channels a notice writes through — structurally satisfied by\n * `Renderer`, so this module stays independent of the render layer. */\nexport type NoticeSink = {\n info: (message: string) => void;\n warn: (message: string) => void;\n};\n\n/** Emit the run's worktree fate on the channel its severity deserves (nothing at\n * all when `--worktree` is off). Called from the `--dry-run` preflight and again\n * at run start, so the outcome is predicted whether or not the operator dry-ran. */\nexport function report_worktree_fate(config: WorktreeFateConfig, sink: NoticeSink): void {\n const notice = worktree_notice(config);\n if (notice === null) return;\n if (notice.level === 'warn') {\n sink.warn(notice.message);\n return;\n }\n sink.info(notice.message);\n}\n\ntype GitResult = { status: number; stdout: string; stderr: string };\n\n/** Run git in `cwd`. A missing git binary is a precondition failure (like the\n * missing-repo guard); a non-zero exit is left to the caller to interpret. */\nfunction git(cwd: string, args: string[]): GitResult {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' });\n if (result.error !== undefined) {\n throw config_error(`git is required for --worktree but could not run: ${String(result.error)}`);\n }\n return { status: result.status ?? -1, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };\n}\n\n/** Run git and throw on a non-zero exit, surfacing git's own diagnostics. */\nfunction git_ok(cwd: string, args: string[]): GitResult {\n const result = git(cwd, args);\n if (result.status !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw check_error(`git ${args.join(' ')} failed: ${detail}`);\n }\n return result;\n}\n\n/** Best-effort git for teardown: swallows both spawn and exit failures so the\n * idempotent trio never throws out of a run's `finally`. Still reports what it\n * can — a spawn failure reads as a non-zero exit with no output — so the salvage\n * path can interrogate the repo without reintroducing a throw. */\nfunction git_quiet(cwd: string, args: string[]): GitResult {\n try {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' });\n return { status: result.status ?? -1, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };\n } catch {\n // Teardown is cleanup; never mask the run's real outcome.\n return { status: -1, stdout: '', stderr: '' };\n }\n}\n\nfunction branch_exists(repo: string, branch: string): boolean {\n return git(repo, ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`]).status === 0;\n}\n\n/**\n * Check `branch` out into a fresh worktree at `worktree_path(workspace)`.\n *\n * Rotate-on-conflict: a leftover worktree directory or branch from a\n * crashed run is renamed aside under a `.bak.<stamp>` name — never destroyed —\n * before the fresh one is created, mirroring `.volley.bak.<stamp>`.\n */\nexport function create_worktree(options: {\n workspace: string;\n branch: string;\n base?: string;\n log?: (message: string) => void;\n}): WorktreeHandle {\n const repo = resolve(options.workspace);\n if (!existsSync(join(repo, '.git'))) {\n throw config_error(`--worktree requires the workspace to be a git repository: ${repo}`);\n }\n const path = worktree_path(repo);\n const base = options.base ?? 'HEAD';\n const log = options.log ?? (() => {});\n\n // Preserve a leftover directory (possibly dirty), then drop its now-dangling\n // registration so `worktree add` sees a clean slate.\n if (existsSync(path)) {\n const backup = `${path}.bak.${backup_stamp()}`;\n renameSync(path, backup);\n git(repo, ['worktree', 'prune']);\n log(`worktree: rotated existing ${path} aside to ${backup}`);\n }\n // Preserve a leftover branch's commits rather than clobbering with `-B`.\n if (branch_exists(repo, options.branch)) {\n const backup_branch = `${options.branch}.bak.${backup_stamp()}`;\n git_ok(repo, ['branch', '-m', options.branch, backup_branch]);\n log(`worktree: rotated existing branch ${options.branch} aside to ${backup_branch}`);\n }\n\n git_ok(repo, ['worktree', 'add', '-b', options.branch, path, base]);\n\n // The toolchain rides along: `node_modules` is untracked, so a fresh\n // checkout has none — link the workspace's install in so the deterministic\n // check (which runs at the build root) and the builder's `bash` can\n // run the project toolchain without a per-run re-install.\n const modules = join(repo, 'node_modules');\n if (existsSync(modules) && !existsSync(join(path, 'node_modules'))) {\n symlinkSync(modules, join(path, 'node_modules'), 'dir');\n log(`worktree: linked node_modules from ${repo}`);\n }\n\n return { path, branch: options.branch };\n}\n\n/** What a teardown left behind. Both fields are null on the discarding path —\n * branch and checkout are gone, which is the point. */\nexport type TeardownOutcome = {\n /** The run branch teardown kept, holding work that was never integrated, for a\n * `git switch` / `git cherry-pick`. Null when the branch was deleted (nothing\n * was salvaged, or the run committed nothing worth keeping). */\n salvaged_branch: string | null;\n /** The checkout teardown refused to delete because its work could not be\n * committed (no git identity, a stale index lock, a broken repo): the files are\n * still on disk, and the next run rotates them aside rather than destroying\n * them. Null whenever the checkout was removed. */\n kept_path: string | null;\n};\n\n/**\n * Tear the worktree down with the idempotent trio: remove the worktree,\n * delete its branch, prune the registration. Each step tolerates the target\n * already being gone, so a second teardown — or teardown of a worktree that\n * was never created — is a safe no-op.\n *\n * `salvage` flips the trio from *discard* to *keep* for the one case that has no\n * other copy of its work: a converged run whose effects were never integrated\n * (`--worktree` without `--git` — there are no checkpoint commits and no squash\n * merge, so `branch -D` plus a `--force` removal would eat the build). Teardown\n * then commits the checkout's state onto the run branch, skips the `branch -D`,\n * and removes only the checkout. Failed and integrated runs keep discarding:\n * nothing is left to save.\n */\nexport function teardown_worktree(options: {\n workspace: string;\n branch: string;\n salvage?: boolean;\n}): TeardownOutcome {\n const repo = resolve(options.workspace);\n const path = worktree_path(repo);\n const outcome: TeardownOutcome =\n options.salvage === true\n ? salvage_worktree(repo, path, options.branch)\n : { salvaged_branch: null, kept_path: null };\n // Salvage that could not commit: the work exists only in this directory, so\n // leave the whole worktree standing rather than removing what holds it.\n if (outcome.kept_path !== null) return outcome;\n\n git_quiet(repo, ['worktree', 'remove', '--force', path]);\n if (outcome.salvaged_branch === null) {\n git_quiet(repo, ['branch', '-D', options.branch]);\n }\n git_quiet(repo, ['worktree', 'prune']);\n // If git left the directory behind (already detached from the repo), clear it.\n if (existsSync(path)) {\n try {\n rmSync(path, { recursive: true, force: true });\n } catch {\n // Best effort; a lingering directory does not fail the run.\n }\n }\n return outcome;\n}\n\n/**\n * Commit whatever the run left in the worktree onto the run's own branch, so an\n * unintegrated success survives its teardown. Reports the branch when it ends up\n * carrying commits the workspace branch does not — a run that changed nothing\n * leaves no branch behind — or the checkout path when the commit did not land,\n * which is teardown's signal to keep its hands off the directory.\n */\nfunction salvage_worktree(repo: string, path: string, branch: string): TeardownOutcome {\n if (existsSync(path)) {\n git_quiet(path, ['add', '-A']);\n git_quiet(path, [\n 'commit',\n '-m',\n `volley: salvage unintegrated worktree (${branch})`,\n '--no-verify',\n ]);\n if (worktree_dirty(path)) return { salvaged_branch: null, kept_path: path };\n }\n return { salvaged_branch: branch_ahead(repo, branch) ? branch : null, kept_path: null };\n}\n\n/** Uncommitted or untracked changes still in the checkout — i.e. the salvage\n * commit did not land. A git call that fails outright reads as clean: teardown's\n * existing guards already cope with a checkout git cannot speak for. */\nfunction worktree_dirty(path: string): boolean {\n const status = git_quiet(path, ['status', '--porcelain']);\n return status.status === 0 && status.stdout.trim().length > 0;\n}\n\n/** Does `branch` carry commits the workspace's HEAD does not? The run branch is\n * cut from HEAD, so this asks \"did the run commit anything?\" — and answers false\n * for a branch that does not exist, which keeps teardown idempotent. */\nfunction branch_ahead(repo: string, branch: string): boolean {\n const ahead = git_quiet(repo, ['rev-list', '--count', `HEAD..${branch}`]);\n return ahead.status === 0 && Number(ahead.stdout.trim()) > 0;\n}\n\nexport type WorktreeOptions<T> = {\n enabled: boolean;\n workspace: string;\n branch: string;\n log?: (message: string) => void;\n /** Consulted with the body's value on a clean exit: `true` means this run's\n * work was never integrated, so teardown must salvage it onto the run branch\n * instead of discarding it. Never consulted when the body throws — a\n * failed run's branch is thrown away wholesale. */\n salvage?: (value: T) => boolean;\n};\n\n/** The body's value plus what teardown left behind. */\nexport type WorktreeOutcome<T> = TeardownOutcome & { value: T };\n\n/**\n * Run `body` with the run's worktree lifecycle around it: when enabled, create\n * the worktree first and guarantee teardown on every exit path; when disabled,\n * this is a transparent pass-through so the default path is byte-for-byte\n * unchanged.\n *\n * The discarding teardown stays in the `finally` — it is what a throw, an abort,\n * or a non-salvaging exit gets. A *salvaging* teardown has to run inside the\n * `try` instead, because its outcome (the surviving branch) is part of this\n * call's return value; `discard_on_exit` hands the responsibility over so the\n * two never both fire and `branch -D` the branch salvage just kept.\n */\nexport async function with_worktree<T>(\n options: WorktreeOptions<T>,\n body: () => Promise<T>,\n): Promise<WorktreeOutcome<T>> {\n if (!options.enabled) {\n return { value: await body(), salvaged_branch: null, kept_path: null };\n }\n create_worktree({\n workspace: options.workspace,\n branch: options.branch,\n ...(options.log !== undefined ? { log: options.log } : {}),\n });\n let discard_on_exit = true;\n try {\n const value = await body();\n if (options.salvage?.(value) !== true) {\n return { value, salvaged_branch: null, kept_path: null };\n }\n discard_on_exit = false;\n return {\n value,\n ...teardown_worktree({\n workspace: options.workspace,\n branch: options.branch,\n salvage: true,\n }),\n };\n } finally {\n if (discard_on_exit) {\n teardown_worktree({ workspace: options.workspace, branch: options.branch });\n }\n }\n}\n","/**\n * Workspace lifecycle: `.volley/` initialization, stale-run\n * backup rotation, path helpers, and optional git checkpoints.\n */\nimport { existsSync, mkdirSync, renameSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { check_error, config_error } from './types.js';\nimport type { ResolvedConfig } from './types.js';\n\nexport function volley_path(workspace: string, ...parts: string[]): string {\n return join(workspace, '.volley', ...parts);\n}\n\nexport function iteration_dir(workspace: string, iteration: number): string {\n return volley_path(workspace, 'iterations', String(iteration).padStart(3, '0'));\n}\n\n/** Filesystem-safe timestamp for `.bak.<stamp>` rotation names. Shared by the\n * `.volley/` rotation here and the worktree rotation so both preserve\n * prior state under the same never-destroy naming. */\nexport function backup_stamp(date: Date = new Date()): string {\n return date.toISOString().replace(/[:.]/g, '-');\n}\n\n/** Fresh-run initialization: rotate a stale `.volley/` aside, then create the\n * directory tree. Resume runs skip rotation (`preserve: true`). */\nexport function initialize_workspace(\n workspace: string,\n options: { preserve?: boolean } = {},\n): void {\n const dir = volley_path(workspace);\n if (existsSync(dir) && options.preserve !== true) {\n renameSync(dir, join(workspace, `.volley.bak.${backup_stamp()}`));\n }\n mkdirSync(volley_path(workspace, 'iterations'), { recursive: true });\n}\n\nexport function write_resolved_config(config: ResolvedConfig): void {\n const record = {\n version: config.version,\n run_id: config.run_id,\n started_at: config.started_at,\n prompt: config.prompt,\n criteria: config.criteria,\n check: config.check,\n check_resolved: config.check_resolved,\n builder_model: config.builder_model,\n builder_provider: config.builder_provider,\n builder_max_steps: config.builder_max_steps,\n critic_model: config.critic_model,\n critic_provider: config.critic_provider,\n builder_permission_mode: config.builder_permission_mode,\n critic_preset: config.critic_preset,\n critic_prompt_path: config.critic_prompt_path,\n max_iterations: config.max_iterations,\n max_cost_usd: config.max_cost_usd,\n git_checkpoints: config.git_checkpoints,\n worktree: config.worktree,\n discard_worktree: config.discard_worktree,\n gate_paths: config.gate_paths,\n fail_on_gate_edit: config.fail_on_gate_edit,\n sandbox_image: config.sandbox_image,\n workspace: config.workspace,\n };\n writeFileSync(\n volley_path(config.workspace, 'config.json'),\n `${JSON.stringify(record, null, 2)}\\n`,\n );\n}\n\n/**\n * `--git`: commit everything under `root` after a phase (`git -C <root>`, run\n * here via the spawn `cwd`). `root` is the build root (`build_root`): the\n * workspace on the default path, or the per-run worktree under `--worktree`, so\n * checkpoints land on the worktree branch rather than the workspace's.\n * A checkpoint with nothing to commit is fine; a missing git binary or repo is\n * not.\n */\nexport function git_checkpoint(root: string, message: string): void {\n if (!existsSync(join(root, '.git'))) {\n // `.git` is a directory in the workspace and a file in a linked worktree;\n // existsSync accepts both.\n throw config_error(`git checkpoints require a git repository: ${root}`);\n }\n const add = spawnSync('git', ['add', '-A'], { cwd: root });\n if (add.error !== undefined || add.status !== 0) {\n throw check_error(`git add failed: ${add.stderr?.toString() ?? String(add.error)}`);\n }\n const commit = spawnSync('git', ['commit', '-m', message, '--no-verify'], {\n cwd: root,\n });\n // Exit 1 with \"nothing to commit\" is a no-op iteration, not a failure.\n if (commit.error !== undefined) {\n throw check_error(`git commit failed to start: ${String(commit.error)}`);\n }\n const out = `${commit.stdout?.toString() ?? ''}${commit.stderr?.toString() ?? ''}`;\n if (commit.status !== 0 && !out.includes('nothing to commit')) {\n throw check_error(`git commit failed: ${out.trim()}`);\n }\n}\n\n/**\n * Integration — bring a successful `--worktree --git` run's effects onto the\n * workspace branch. The per-phase checkpoints on `branch` are the raw\n * audit/replay trail; here they collapse into a single squash commit\n * (`git merge --squash` then `commit`) on the workspace's current branch. The\n * shared object store makes this a local, fetch-free merge, and — because the\n * workspace branch never moved during the run (checkpoints went to the phase\n * branch) — it is conflict-free by construction. A run whose phase branch has no\n * new commits integrates to a no-op. Only successful runs integrate; an\n * abandoned run's branch is discarded wholesale by the teardown trio instead.\n */\nexport function integrate_worktree(workspace: string, branch: string, message: string): void {\n if (!existsSync(join(workspace, '.git'))) {\n throw config_error(`--worktree integration requires a git repository: ${workspace}`);\n }\n const squash = spawnSync('git', ['merge', '--squash', branch], {\n cwd: workspace,\n encoding: 'utf8',\n });\n if (squash.error !== undefined) {\n throw check_error(`git merge --squash failed to start: ${String(squash.error)}`);\n }\n if (squash.status !== 0) {\n throw check_error(\n `git merge --squash ${branch} failed: ${(squash.stderr || squash.stdout).trim()}`,\n );\n }\n const commit = spawnSync('git', ['commit', '-m', message, '--no-verify'], {\n cwd: workspace,\n encoding: 'utf8',\n });\n if (commit.error !== undefined) {\n throw check_error(`git commit failed to start: ${String(commit.error)}`);\n }\n // An empty phase branch stages nothing; \"nothing to commit\" is a no-op.\n const out = `${commit.stdout ?? ''}${commit.stderr ?? ''}`;\n if (commit.status !== 0 && !out.includes('nothing to commit')) {\n throw check_error(`git commit failed: ${out.trim()}`);\n }\n}\n","/**\n * Critic invocation: a read-only session (`claude_cli`, or a local model with\n * volley's read tools) returning a schema-validated structured verdict. The\n * harness — not the critic — writes `.volley/feedback.md` and `.volley/verdict`.\n */\nimport { z } from 'zod';\nimport { model_call } from 'fascicle';\nimport type {\n Engine,\n FallbackOutcome,\n GenerateOptions,\n GenerateResult,\n RetryOutcome,\n RunContext,\n Step,\n StreamChunk,\n} from 'fascicle';\nimport { accumulate } from '../cost.js';\nimport { resolve_ollama_base_url } from '../engine.js';\nimport { prewarm_ollama_model } from '../prewarm.js';\nimport { error_kind, phase_error } from '../types.js';\nimport type { CauseKind, LoopState, ResolvedConfig } from '../types.js';\nimport { build_root } from '../worktree.js';\nimport { compose_critic_prompt, resolve_critic_prompt } from './prompt.js';\nimport { read_only_tools, workspace_inventory } from './tools.js';\n\nconst CRITIC_ALLOWED_TOOLS = ['Read', 'Grep', 'Glob'] as const;\n\nconst CRITIC_DISALLOWED_TOOLS = 'Write,Edit,MultiEdit,NotebookEdit,Bash';\n\nexport const verdict_schema = z.object({\n verdict: z.enum(['approved', 'changes_requested']),\n feedback: z\n .string()\n .describe(\n 'Free-form markdown for the builder. Concrete and actionable. ' +\n 'Will be passed verbatim into the next iteration.',\n ),\n unmet_criteria: z\n .array(z.string())\n .describe(\n 'The specific acceptance criteria judged unmet, verbatim. Empty when approved.',\n ),\n});\n\nexport type VerdictOutput = z.infer<typeof verdict_schema>;\n\nexport type CriticDeps = {\n engine: Engine;\n config: ResolvedConfig;\n on_chunk: (chunk: StreamChunk) => void;\n};\n\n/** Read-only tool wiring per provider. The claude_cli critic is confined at\n * the CLI permission layer (allowlist + explicit disallow); a local-model\n * critic gets volley's own workspace-scoped read-only tools and no write\n * path at all.\n *\n * The two providers also enforce `verdict_schema` by two different paths, both\n * verified live. The claude_cli critic compiles the schema for\n * `claude --json-schema`; that only works because fascicle 0.12.13's\n * `compile_schema` strips the top-level `$schema`/`$id` that zod v4 stamps (the\n * CLI rejects them) — `live_smoke` asserts a structured verdict comes back, so a\n * future fascicle regression there fails loudly rather than silently. The local\n * (ollama/lmstudio) critic instead gets Ollama **constrained decode** —\n * fascicle's ai_sdk default whenever a `schema` is passed — so the verdict is\n * structurally guaranteed at decode time, with no prompt-parse-repair;\n * `live_local_builder` exercises that path. Unchanged in v3: on ai_sdk\n * constrained decode needs no wiring, and under the deferred native flip it\n * would move to `provider_options.ollama.format` (parked). */\nfunction critic_tool_options(\n config: ResolvedConfig,\n): Pick<GenerateOptions<VerdictOutput>, 'tools' | 'provider_options'> {\n if (config.critic_provider === 'claude_cli') {\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...CRITIC_ALLOWED_TOOLS],\n extra_args: ['--disallowedTools', CRITIC_DISALLOWED_TOOLS],\n },\n },\n };\n }\n // Read the builder's actual output: under `--worktree` that lives in\n // the worktree, so the local critic's read tools resolve through the same\n // re-pointed containment root as the builder's writes.\n return { tools: read_only_tools(build_root(config.workspace, config.worktree)) };\n}\n\n/** Degradation ladder rung 1: how many times a local critic's call\n * is retried on a provider stream death before the ladder moves on. Capped at\n * one — the qwen3.6/Ollama tool-XML parser death is stochastic, so a same-call\n * retry often passes; past one attempt the failure is not transient and the\n * tool-less fallback must take over. */\nexport const MAX_CRITIC_RETRIES = 1;\n\n/** Is this critic failure the transient local-provider stream death the ladder\n * retries? Local providers only (the `claude_cli` path is proven and its\n * retries cost real money), and fascicle's typed `provider_error` only (no\n * message string-matching). A user abort never gets here: `retry` and\n * `fallback` pass control-flow signals through untouched, and `retry` checks the\n * signal before every attempt, so an abort stays exit-130. */\nfunction is_retryable_critic_error(config: ResolvedConfig, err: unknown): boolean {\n if (config.critic_provider === 'claude_cli') return false;\n return error_kind(err) === 'provider_error';\n}\n\n/** fascicle's `provider_error.cause_kind` is `... | undefined`; fold the\n * missing case into `'unknown'` so a recorded retry always names a cause. */\nfunction retry_cause_kind_of(err: unknown): CauseKind {\n const cause = (err as { cause_kind?: unknown }).cause_kind;\n return cause === 'provider_5xx' || cause === 'network' ? cause : 'unknown';\n}\n\n/** Bookkeeping stamped onto a critic record by the degradation ladder: how many\n * tool-bearing retries preceded this verdict, the last retry's cause, and — on the\n * tool-less rung — the `critic_degraded` mark. */\ntype LadderMark = {\n retries: number;\n retry_cause_kind: CauseKind | undefined;\n critic_degraded?: boolean;\n};\n\n/** Fold a successful critic `generate` result into loop state, stamping the\n * ladder bookkeeping onto the critic record. Shared by the tool-bearing path and\n * the tool-less fallback so both shape the record identically (the fallback just\n * adds `critic_degraded: true`). */\nfunction finalize_critic(\n state: LoopState,\n result: GenerateResult<VerdictOutput>,\n model: string,\n mark: LadderMark,\n duration_ms: number,\n): LoopState {\n const next = accumulate(state, 'critic', result, model, duration_ms);\n return {\n ...next,\n critic:\n next.critic === null\n ? null\n : {\n ...next.critic,\n retries: mark.retries,\n ...(mark.retry_cause_kind !== undefined\n ? { retry_cause_kind: mark.retry_cause_kind }\n : {}),\n ...(mark.critic_degraded === true ? { critic_degraded: true } : {}),\n },\n verdict: result.content.verdict,\n feedback: result.content.feedback,\n unmet_criteria: result.content.unmet_criteria,\n };\n}\n\n/** The tool-less fallback's prompt: the normal critic prompt plus a notice that\n * read tools are gone this pass and a paths+sizes workspace inventory, so\n * the critic still judges from the criteria, the raw check artifacts already in\n * the prompt, and the file layout — grounded, just shallower. */\nexport function toolless_critic_prompt(config: ResolvedConfig, tool_prompt: string): string {\n return [\n tool_prompt,\n '',\n 'NOTE: file-read tools are unavailable for this review. Judge from the',\n 'acceptance criteria, the deterministic check output above, and the workspace',\n 'file inventory below (paths and sizes only — file contents are not shown).',\n '',\n 'WORKSPACE FILE INVENTORY',\n '------------------------',\n workspace_inventory(build_root(config.workspace, config.worktree)),\n ].join('\\n');\n}\n\n/** What the critic arm answers with: the call that produced the verdict, and\n * how the ladder reached it. */\nexport type CriticAnswer = {\n result: GenerateResult<VerdictOutput>;\n mark: LadderMark;\n};\n\n/** The critic's model boundary: the whole degradation ladder behind one step\n * (composed in `../flow.ts`). */\nexport type CriticStep = Step<string, CriticAnswer>;\n\n/** One critic call returning the validated verdict in its `GenerateResult`. */\nexport type CriticCall = Step<string, GenerateResult<VerdictOutput>>;\n\nfunction critic_call_config(deps: CriticDeps) {\n const { config } = deps;\n return {\n engine: deps.engine,\n provider: config.critic_provider,\n model: config.critic_model,\n system: resolve_critic_prompt(config),\n schema: verdict_schema,\n on_chunk: deps.on_chunk,\n };\n}\n\n/** Rung 1's leaf: the critic with its read tools (or the CLI's read-only\n * allowlist). */\nexport function make_critic_tools_step(deps: CriticDeps): CriticCall {\n return model_call({\n ...critic_call_config(deps),\n id: 'critic_tools',\n description: 'model call with read-only workspace tools',\n ...critic_tool_options(deps.config),\n });\n}\n\n/** Rung 2's leaf: the same critic with no tools at all, so nothing enters\n * Ollama's broken tool parser; constrained decode (`schema`) still guarantees\n * the verdict. */\nexport function make_critic_toolless_step(deps: CriticDeps): CriticCall {\n return model_call({\n ...critic_call_config(deps),\n id: 'critic_toolless',\n description: 'model call judging from the check output and a file list',\n });\n}\n\n/** The ladder's retry predicate for this run's critic provider. */\nexport function critic_retryable(config: ResolvedConfig): (err: unknown) => boolean {\n return (err) => is_retryable_critic_error(config, err);\n}\n\n/** Rung 1's projection: a verdict the tool-bearing critic produced, marked with\n * how many stream deaths it took and the last one's cause. */\nexport function with_retries(outcome: RetryOutcome<GenerateResult<VerdictOutput>>): CriticAnswer {\n const last = outcome.errors.at(-1);\n return {\n result: outcome.value,\n mark: {\n retries: outcome.attempts - 1,\n retry_cause_kind: last === undefined ? undefined : retry_cause_kind_of(last),\n },\n };\n}\n\n/** Rung 2's answer: every retry was spent, and the verdict is marked degraded\n * so it never passes silently as a full critique. */\nexport function as_degraded(result: GenerateResult<VerdictOutput>): CriticAnswer {\n return {\n result,\n mark: { retries: MAX_CRITIC_RETRIES, retry_cause_kind: undefined, critic_degraded: true },\n };\n}\n\n/** The ladder's projection: the tool-less backup cannot see why it ran, so the\n * cause comes from the last stream death the retry rung gave up on. */\nexport function with_fallback_cause(outcome: FallbackOutcome<CriticAnswer>): CriticAnswer {\n if (outcome.source === 'primary') return outcome.value;\n return {\n ...outcome.value,\n mark: { ...outcome.value.mark, retry_cause_kind: retry_cause_kind_of(outcome.primary_error) },\n };\n}\n\n/** What the `--dry-run` canary learned about the critic seat:\n * `ok` — the tool-bearing call came back; `degraded` — the tool-bearing\n * call died on a provider stream error but a tool-less pass survived, so a real\n * run will likely finish via the fallback ladder (`critic_degraded`);\n * `failed` — even the tool-less pass died, so the combo would fail a real run\n * degraded or not. */\nexport type CanaryOutcome =\n | { outcome: 'ok' }\n | { outcome: 'degraded'; detail: string }\n | { outcome: 'failed'; detail: string };\n\n/** The canary must *elicit a real tool call*: the qwen3.6 death happens at\n * tool-markup emission inside Ollama's server-side parser, so a call that never\n * invokes a tool could not fail and would prove nothing. The target path need\n * not exist — a tool error is fed back and the model answers anyway; entering\n * the parser is the test. No token cap: the budget is behavioral (one tool call,\n * then an immediate one-word verdict), because a hard `max_tokens` could\n * truncate a thinking model mid-verdict and report `failed` for a combo that\n * works. A model that skips the tool and just answers passes stochastically —\n * acceptable: the canary is early warning, the ladder is the guarantee. */\nconst CANARY_PROMPT = [\n 'CANARY CHECK — a tiny wiring probe, not a real review.',\n 'First, call the read_file tool on the path \"package.json\".',\n 'Whatever the tool returns (content or an error), immediately answer with',\n 'verdict \"approved\", feedback exactly \"canary\", and empty unmet_criteria.',\n].join('\\n');\n\n/** The canary's tool-less rung: same schema-constrained call, no tool ask. */\nconst CANARY_TOOLLESS_PROMPT = [\n 'CANARY CHECK — a tiny wiring probe, not a real review.',\n 'Answer with verdict \"approved\", feedback exactly \"canary\", and empty',\n 'unmet_criteria.',\n].join('\\n');\n\nfunction canary_detail(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * The `--dry-run` critic-seat canary: one tiny generate through the *real*\n * production tool wiring (`critic_tool_options`) and `verdict_schema`, $0 on a\n * local model. The caller (preflight) gates it to local critics only —\n * `claude_cli` is proven and its calls cost real money.\n *\n * A tool-bearing death is classified by the same discriminant as the run-time\n * ladder (typed `provider_error` only), then probed tool-less exactly as\n * rung 2 would run, so the canary *predicts the ladder* instead of guessing:\n * tool-less survives → `degraded` (warn — the combo completes a real run,\n * marked); tool-less dies too → `failed` (the endpoint-down / model-missing\n * class that earns exit 5 because not even degradation would save it).\n */\nexport async function critic_canary(\n engine: Engine,\n config: ResolvedConfig,\n env: Record<string, string | undefined> = process.env,\n): Promise<CanaryOutcome> {\n // Same cold-load guard as the real critic phase: without it a disk-cold model\n // would die on the first-byte timeout and the canary would cry wolf.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(resolve_ollama_base_url(env), config.critic_model);\n }\n const base: Omit<GenerateOptions<VerdictOutput>, 'prompt' | 'tools' | 'provider_options'> = {\n provider: config.critic_provider,\n model: config.critic_model,\n system: resolve_critic_prompt(config),\n schema: verdict_schema,\n };\n try {\n await engine.generate({\n ...base,\n prompt: CANARY_PROMPT,\n ...critic_tool_options(config),\n });\n return { outcome: 'ok' };\n } catch (err) {\n if (error_kind(err) !== 'provider_error') {\n return { outcome: 'failed', detail: canary_detail(err) };\n }\n const tool_death = canary_detail(err);\n try {\n await engine.generate({ ...base, prompt: CANARY_TOOLLESS_PROMPT });\n return { outcome: 'degraded', detail: tool_death };\n } catch (fallback_err) {\n return { outcome: 'failed', detail: canary_detail(fallback_err) };\n }\n }\n}\n\nexport type CriticRunDeps = {\n critic: CriticStep;\n config: ResolvedConfig;\n};\n\nexport async function run_critic(\n deps: CriticRunDeps,\n state: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config } = deps;\n if (state.check === null) {\n throw phase_error('critic', state.iteration, new Error('check phase did not run'));\n }\n const check = state.check;\n try {\n // Same cold-load guard as the builder: pre-load an Ollama critic model so\n // a cold multi-GB load doesn't blow the real call's first-byte timeout.\n // Best-effort; a model the builder already warmed returns immediately.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(\n resolve_ollama_base_url(process.env),\n config.critic_model,\n ctx.abort,\n );\n }\n const prompt = compose_critic_prompt({\n criteria: config.criteria,\n iteration: state.iteration,\n check,\n changes: state.changes,\n });\n // The phase's duration spans every rung that ran, not just the call that\n // answered: a retried or degraded verdict took that long to get, and no one\n // result's `timing` covers the attempts before it.\n const started = Date.now();\n const { result, mark } = await ctx.call(deps.critic, prompt);\n return finalize_critic(state, result, config.critic_model, mark, Date.now() - started);\n } catch (err) {\n throw phase_error('critic', state.iteration, err);\n }\n}\n","/**\n * Critic prompt resolution and composition. Presets live as\n * markdown files in ./presets/ — discoverable by listing the directory —\n * and every critic system prompt gets the harness append.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { config_error } from '../types.js';\nimport type {\n ChangeSet,\n ChangeStatus,\n ChangedFile,\n CheckResult,\n ResolvedConfig,\n} from '../types.js';\n\n/** Walk up from this module to the package root (works from src/ under tsx\n * and from dist/ in the published package, which ships src/critic/presets). */\nexport function presets_dir(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(dir, 'src', 'critic', 'presets');\n if (existsSync(candidate)) return candidate;\n const local = join(dir, 'presets');\n if (existsSync(local)) return local;\n dir = dirname(dir);\n }\n throw config_error('critic presets directory not found');\n}\n\nexport function resolve_critic_prompt(config: ResolvedConfig): string {\n const base =\n config.critic_prompt_path !== null\n ? readFileSync(config.critic_prompt_path, 'utf8')\n : readFileSync(join(presets_dir(), `${config.critic_preset}.md`), 'utf8');\n // The CLI critic reads via built-in Read/Grep/Glob; a local-model critic\n // reads via volley's supplied read_file/search_files/list_files tools, so\n // its harness instructions name a different tool set.\n const append_file =\n config.critic_provider === 'claude_cli' ? 'harness_append.md' : 'harness_append_local.md';\n const append = readFileSync(join(presets_dir(), append_file), 'utf8');\n return `${base.trimEnd()}\\n\\n${append.trimEnd()}`;\n}\n\nexport type CriticPromptInput = {\n criteria: string;\n iteration: number;\n check: CheckResult;\n /** What the builder changed since the run's baseline (`src/changes.ts`), or\n * null when the build root is not a git repository — then the section is\n * omitted rather than claiming the builder changed nothing. */\n changes: ChangeSet | null;\n};\n\n/** One-letter status column, so a hundred-path list stays readable. */\nconst STATUS_MARKS: Record<ChangeStatus, string> = {\n added: 'A',\n modified: 'M',\n deleted: 'D',\n renamed: 'R',\n unknown: '?',\n};\n\nfunction format_change(file: ChangedFile): string {\n return ` ${STATUS_MARKS[file.status]} ${file.path}`;\n}\n\n/**\n * What the builder actually touched, handed to the critic as evidence.\n *\n * Two things this fixes, both surfaced by the reckon run\n * (`research/reckon-local-run-finding.md`). A critic that sees only the finished\n * tree reviews *state* and re-reads code the check already blessed; a critic\n * that sees the change list reviews the *change*, and knows where to point its\n * read tools. And a builder that edited its own tests could previously pass both\n * gates in silence — the check because it was rewritten, the critic because\n * nothing told it that had happened.\n *\n * Paths only, never diff hunks: the list stays bounded for a 32k-context local\n * critic, which can read any file it wants once it knows which ones moved.\n */\nfunction format_changes_section(changes: ChangeSet | null): string | null {\n if (changes === null) return null;\n const scope = changes.baseline === null ? 'this run' : `baseline ${changes.baseline.slice(0, 8)}`;\n if (changes.total === 0) {\n return [\n `BUILDER CHANGES (since ${scope})`,\n '------------------------------',\n 'The builder changed no files. Unless the acceptance criteria were already',\n 'met before this run, that is itself grounds for changes_requested.',\n ].join('\\n');\n }\n const lines = [\n `BUILDER CHANGES (since ${scope})`,\n '------------------------------',\n 'Review the work as a change, not just as a finished tree. Read the files',\n 'below with your tools as needed.',\n '',\n ...changes.files.map(format_change),\n ];\n if (changes.truncated) {\n lines.push(\n ` … showing ${String(changes.files.length)} of ${String(changes.total)} changed paths`,\n );\n }\n if (changes.gate_edits.length > 0) {\n lines.push(\n '',\n `GATE EDITS (${String(changes.gate_edits.length)})`,\n '-----------',\n 'These changed paths are part of the gate — the tests, fixtures, and check',\n 'configuration that decide whether this work passes. A check the builder can',\n 'edit proves less than one it cannot.',\n '',\n ...changes.gate_edits.map((path) => ` ! ${path}`),\n '',\n 'Judge whether each of these edits was necessary and legitimate for the task',\n 'as specified. If any of them weakened the check, deleted a case, or moved a',\n 'target rather than meeting it, the work does not meet the criteria: return',\n 'changes_requested, name the file, and say what was weakened.',\n );\n }\n return lines.join('\\n');\n}\n\nfunction format_check_section(check: CheckResult): string {\n if (!check.ran) {\n return 'No deterministic check ran for this iteration. Base your verdict on workspace inspection alone.';\n }\n const lines = [\n `DETERMINISTIC CHECK (${check.runner})`,\n '------------------------------------',\n `result: ${check.ok ? 'PASSED' : 'FAILED'} (exit ${String(check.exit_code)})`,\n ];\n if (check.failing_slots.length > 0) {\n lines.push(`failing slots: ${check.failing_slots.join(', ')}`);\n }\n if (check.summary !== undefined) {\n lines.push('', 'summary.json:', '```json', JSON.stringify(check.summary, null, 2), '```');\n }\n for (const artifact of check.detail) {\n lines.push(\n '',\n `--- raw output for failing slot \"${artifact.slot}\"${artifact.truncated ? ` (truncated; full output archived at ${artifact.path ?? 'n/a'})` : ''} ---`,\n artifact.content,\n );\n }\n if (check.log !== undefined && check.log.length > 0) {\n lines.push('', 'check output:', '```', check.log, '```');\n }\n return lines.join('\\n');\n}\n\nexport function compose_critic_prompt(input: CriticPromptInput): string {\n const changes = format_changes_section(input.changes);\n return [\n 'ACCEPTANCE CRITERIA',\n '-------------------',\n input.criteria,\n '',\n `ITERATION: ${input.iteration}`,\n '',\n format_check_section(input.check),\n ...(changes === null ? [] : ['', changes]),\n '',\n 'Review the workspace against the acceptance criteria and return your',\n 'structured verdict.',\n ].join('\\n');\n}\n","/**\n * The loop's carry-state across its life: the fresh state a run starts from,\n * the stopping rule the loop guard applies after every iteration, and the run\n * status the final state resolves to. Pure functions over `LoopState`; the\n * flow (`./flow.ts`) plugs them in.\n */\nimport { cost_cap_hit, EMPTY_USAGE } from './cost.js';\nimport type { LoopState, ResolvedConfig, RunStatus } from './types.js';\n\nexport function initial_state(): LoopState {\n return {\n iteration: 0,\n iteration_started_at: new Date().toISOString(),\n feedback: null,\n verdict: null,\n unmet_criteria: [],\n check: null,\n changes: null,\n builder: null,\n critic: null,\n total_usage: EMPTY_USAGE,\n total_cost_usd: 0,\n builder_cost_usd: 0,\n critic_cost_usd: 0,\n check_duration_ms: 0,\n iteration_cost_usd: 0,\n halt: null,\n cost_warned: false,\n };\n}\n\n/** How many rounds the loop may still run: the whole budget on a fresh run, what\n * the resumed run's completed iterations left of it otherwise. */\nexport function remaining_iterations(\n config: ResolvedConfig,\n resume_from: LoopState | null,\n): number {\n return config.max_iterations - (resume_from?.iteration ?? 0);\n}\n\n/** Did this iteration's builder edit the gate that judges it, with the operator\n * having asked for that to stop the run? Reported either way (the critic prompt\n * and the summary always carry it); only `--fail-on-gate-edit` makes it fatal. */\nfunction gate_edit_halt(config: ResolvedConfig, state: LoopState): boolean {\n return config.fail_on_gate_edit && (state.changes?.gate_edits.length ?? 0) > 0;\n}\n\n/** All stopping conditions live here: acceptance, cost cap, the gate\n * edit refusal, and — implicitly via `max_rounds` — the iteration budget.\n * Success wins when it and the cap land on the same iteration.\n *\n * A gate edit is the one condition that *beats* success rather than losing to\n * it: the run passed a check the builder had rewritten, so the pass is exactly\n * what is in question. It stops the run instead of iterating, because a model\n * that just edited the gate is not a promising candidate to be asked again. */\nexport function gate(\n config: ResolvedConfig,\n state: LoopState,\n): { stop: boolean; state: LoopState } {\n const gate_edit = gate_edit_halt(config, state);\n const success = state.check?.ok === true && state.verdict === 'approved' && !gate_edit;\n const cap = cost_cap_hit(config, state);\n const halt = gate_edit ? 'gate_edit' : !success && cap ? 'cost_cap' : null;\n return {\n stop: success || cap || gate_edit,\n state: { ...state, halt },\n };\n}\n\nexport function status_of(value: LoopState, converged: boolean): RunStatus {\n if (value.halt === 'gate_edit') return 'gate_edit_blocked';\n if (value.halt === 'cost_cap') return 'cost_cap_reached';\n return converged ? 'success' : 'budget_exhausted';\n}\n","/**\n * checkride runner: spawn `pnpm exec checkride --json`, gate on the\n * `.check/summary.json` contract (`schema_version: 1`), and collect raw\n * failing-slot artifacts for the critic — the critic reads what the tool\n * actually said, not a normalized digest.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { aborted_error } from 'fascicle';\nimport { check_error } from '../types.js';\nimport type { CheckArtifact, CheckResult } from '../types.js';\n\nexport const CHECK_ARTIFACT_MAX_CHARS = 8000;\n\nconst CHECKRIDE_SCHEMA_VERSION = 1;\n\nexport type CheckrideSummaryCheck = {\n name: string;\n adapter: string | null;\n ok: boolean;\n skipped?: boolean;\n exit_code: number | null;\n duration_ms: number;\n output_file: string | null;\n};\n\nexport type CheckrideSummary = {\n schema_version: number;\n ok: boolean;\n total_duration_ms: number;\n checks: CheckrideSummaryCheck[];\n};\n\nexport type SpawnCaptureResult = {\n exit_code: number | null;\n stdout: string;\n stderr: string;\n};\n\nexport function spawn_capture(\n cmd: string,\n args: string[],\n options: { cwd: string; abort?: AbortSignal },\n): Promise<SpawnCaptureResult> {\n return new Promise((resolve_promise, reject) => {\n const proc = spawn(cmd, args, {\n cwd: options.cwd,\n ...(options.abort !== undefined ? { signal: options.abort } : {}),\n });\n let stdout = '';\n let stderr = '';\n proc.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n proc.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n proc.on('error', (err) => {\n if (err.name === 'AbortError') {\n reject(new aborted_error('check aborted'));\n return;\n }\n reject(check_error(`check command failed to start: ${err.message}`));\n });\n proc.on('close', (code) => {\n resolve_promise({ exit_code: code, stdout, stderr });\n });\n });\n}\n\nexport type ParsedSummary = {\n summary: CheckrideSummary;\n warning: string | null;\n};\n\n/** Best-effort parse of the summary contract. `pnpm exec` talks over the\n * command's stdout (pnpm 11's dep-verify prints an \"Already up to date\"\n * install line ahead of the JSON), so the object is extracted between the\n * first `{` and the last `}` rather than parsed from byte 0. An unexpected\n * schema_version warns and still parses; no JSON object at all is a harness\n * error (exit 4). */\nexport function parse_checkride_summary(stdout: string): ParsedSummary {\n const start = stdout.indexOf('{');\n const end = stdout.lastIndexOf('}');\n let raw: unknown;\n try {\n if (start === -1 || end < start) throw new Error('no JSON object in stdout');\n raw = JSON.parse(stdout.slice(start, end + 1));\n } catch {\n throw check_error('checkride --json produced unparseable stdout');\n }\n if (typeof raw !== 'object' || raw === null || !Array.isArray((raw as CheckrideSummary).checks)) {\n throw check_error('checkride summary missing checks array');\n }\n const summary = raw as CheckrideSummary;\n const warning =\n summary.schema_version === CHECKRIDE_SCHEMA_VERSION\n ? null\n : `checkride summary schema_version ${String(summary.schema_version)} != ${String(CHECKRIDE_SCHEMA_VERSION)}; parsing best-effort`;\n return { summary, warning };\n}\n\n/** Parse the summary from stdout, falling back to the on-disk contract:\n * `.check/summary.json` is what checkride documents; stdout is its mirror and\n * wrappers may talk over it beyond what the tolerant slice can recover. */\nexport function parse_summary_with_fallback(stdout: string, workspace: string): ParsedSummary {\n try {\n return parse_checkride_summary(stdout);\n } catch (err) {\n const file = join(workspace, '.check', 'summary.json');\n if (!existsSync(file)) throw err;\n return parse_checkride_summary(readFileSync(file, 'utf8'));\n }\n}\n\nexport function failing_checks(summary: CheckrideSummary): CheckrideSummaryCheck[] {\n return summary.checks.filter((c) => !c.ok && c.skipped !== true);\n}\n\n/** Per failing slot: the raw artifact (`.check/<output_file>` when present,\n * else `.check/<slot>.stdout.txt`), truncated with a pointer to the file. */\nexport function read_failing_artifacts(\n workspace: string,\n failing: CheckrideSummaryCheck[],\n): CheckArtifact[] {\n return failing.map((check) => {\n const file = check.output_file ?? `${check.name}.stdout.txt`;\n const path = join(workspace, '.check', file);\n if (!existsSync(path)) {\n return { slot: check.name, path: null, content: '(no artifact found)', truncated: false };\n }\n const raw = readFileSync(path, 'utf8');\n const truncated = raw.length > CHECK_ARTIFACT_MAX_CHARS;\n return {\n slot: check.name,\n path,\n content: truncated ? raw.slice(0, CHECK_ARTIFACT_MAX_CHARS) : raw,\n truncated,\n };\n });\n}\n\nexport type CheckrideOpts = {\n workspace: string;\n abort?: AbortSignal;\n};\n\nexport async function run_checkride(opts: CheckrideOpts): Promise<CheckResult> {\n const proc = await spawn_capture('pnpm', ['exec', 'checkride', '--json'], {\n cwd: opts.workspace,\n ...(opts.abort !== undefined ? { abort: opts.abort } : {}),\n });\n // checkride exit 2 is a harness/usage error — an operator problem, not\n // something to iterate on.\n if (proc.exit_code === 2) {\n throw check_error(`checkride harness error: ${proc.stderr.trim()}`);\n }\n const { summary } = parse_summary_with_fallback(proc.stdout, opts.workspace);\n const failing = failing_checks(summary);\n return {\n ran: true,\n runner: 'checkride',\n ok: summary.ok,\n exit_code: proc.exit_code,\n duration_ms: summary.total_duration_ms,\n failing_slots: failing.map((c) => c.name),\n detail: read_failing_artifacts(opts.workspace, failing),\n summary,\n };\n}\n","/**\n * Generic command runner: `sh -c <command>`, combined\n * output captured, exit-0 semantics. Command-not-found is an operator error\n * (exit 4), not an iterable failure.\n */\nimport { check_error } from '../types.js';\nimport type { CheckResult } from '../types.js';\nimport { spawn_capture } from './checkride.js';\n\nexport type CommandCheckOpts = {\n command: string;\n workspace: string;\n abort?: AbortSignal;\n};\n\nexport async function run_command_check(opts: CommandCheckOpts): Promise<CheckResult> {\n const started = Date.now();\n const proc = await spawn_capture('sh', ['-c', opts.command], {\n cwd: opts.workspace,\n ...(opts.abort !== undefined ? { abort: opts.abort } : {}),\n });\n // sh reports 127 for command-not-found and 126 for not-executable.\n if (proc.exit_code === 127 || proc.exit_code === 126) {\n throw check_error(\n `check command failed to start (exit ${String(proc.exit_code)}): ${opts.command}`,\n );\n }\n const log = `${proc.stdout}${proc.stderr}`;\n return {\n ran: true,\n runner: 'command',\n ok: proc.exit_code === 0,\n exit_code: proc.exit_code,\n duration_ms: Date.now() - started,\n failing_slots: [],\n detail: [],\n log,\n };\n}\n\nexport function skipped_check(reason: 'none' | 'cost_cap'): CheckResult {\n return {\n ran: false,\n runner: 'none',\n // With no check configured the loop is critic-gated only, so the gate is\n // open (`ok: true`). A cost-cap skip must not look like a passing gate.\n ok: reason === 'none',\n exit_code: null,\n duration_ms: 0,\n failing_slots: [],\n detail: [],\n };\n}\n","/**\n * Iteration archiving, run-level summary, and resume-state recovery.\n * `feedback.md` and `verdict` are harness-written projections\n * of the critic's validated structured output.\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join } from 'node:path';\nimport { EMPTY_USAGE } from './cost.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CriticProvider,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n RunResult,\n RunStatus,\n Verdict,\n VolleyConfig,\n} from './types.js';\nimport { iteration_dir, volley_path } from './workspace.js';\n\nfunction write_json(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction persist_verdict_files(\n workspace: string,\n feedback: string,\n verdict: Verdict,\n): void {\n writeFileSync(volley_path(workspace, 'feedback.md'), feedback.endsWith('\\n') ? feedback : `${feedback}\\n`);\n writeFileSync(volley_path(workspace, 'verdict'), `${verdict}\\n`);\n}\n\nfunction phase_summary(record: PhaseRecord | null): Record<string, unknown> | null {\n if (record === null) return null;\n return {\n provider: record.provider,\n model: record.model,\n session_id: record.session_id,\n duration_ms: record.duration_ms,\n usage: record.usage,\n cost_usd: record.cost_usd,\n cost_source: record.cost_source,\n finish_reason: record.finish_reason,\n tool_calls: record.tool_calls,\n salvaged_tool_calls: record.salvaged_tool_calls,\n // Salvage rate (a health metric): the share of tool calls recovered from\n // assistant text. A high rate on a local run means the model's native\n // tool-call encoding is drifting from its runtime's parser (pin them as one\n // unit). 0 when the phase made no tool calls (the CLI builder's own loop).\n salvage_rate: record.tool_calls === 0 ? 0 : record.salvaged_tool_calls / record.tool_calls,\n // Degradation-ladder bookkeeping, critic-only: the provider-error\n // retries that preceded this verdict, their cause, and whether it was rendered\n // by the tool-less fallback. Emitted only when set, so the builder record and\n // old summary consumers are untouched. `critic_degraded` is the on-disk\n // half of the contract — the comparison block reads it back from here.\n ...(record.retries !== undefined ? { retries: record.retries } : {}),\n ...(record.retry_cause_kind !== undefined\n ? { retry_cause_kind: record.retry_cause_kind }\n : {}),\n ...(record.critic_degraded === true ? { critic_degraded: true } : {}),\n // Model speed, where fascicle could time the turns (never `claude_cli`).\n // Emitted only when measured. Additive.\n ...(record.throughput !== undefined ? { throughput: record.throughput } : {}),\n };\n}\n\n/** Archive one completed iteration: verdict files, check artifacts, and the\n * per-iteration summary. */\nexport function archive_iteration(config: ResolvedConfig, state: LoopState): void {\n const dir = iteration_dir(config.workspace, state.iteration);\n mkdirSync(join(dir, 'check'), { recursive: true });\n\n if (state.verdict !== null && state.feedback !== null) {\n persist_verdict_files(config.workspace, state.feedback, state.verdict);\n writeFileSync(join(dir, 'feedback.md'), readFileSync(volley_path(config.workspace, 'feedback.md')));\n writeFileSync(join(dir, 'verdict'), `${state.verdict}\\n`);\n }\n\n const check = state.check;\n if (check !== null && check.ran) {\n if (check.runner === 'checkride') {\n if (check.summary !== undefined) {\n write_json(join(dir, 'check', 'summary.json'), check.summary);\n }\n for (const artifact of check.detail) {\n if (artifact.path !== null && existsSync(artifact.path)) {\n writeFileSync(join(dir, 'check', basename(artifact.path)), readFileSync(artifact.path));\n }\n }\n } else {\n writeFileSync(join(dir, 'check', 'check.log'), check.log ?? '');\n writeFileSync(join(dir, 'check', 'check.exit'), `${String(check.exit_code)}\\n`);\n }\n }\n\n const completed_at = new Date().toISOString();\n write_json(join(dir, 'summary.json'), {\n iteration: state.iteration,\n started_at: state.iteration_started_at,\n completed_at,\n duration_ms: Date.parse(completed_at) - Date.parse(state.iteration_started_at),\n builder: phase_summary(state.builder),\n check:\n check === null\n ? null\n : {\n ran: check.ran,\n runner: check.runner,\n ok: check.ok,\n exit_code: check.exit_code,\n duration_ms: check.duration_ms,\n failing_slots: check.failing_slots,\n },\n critic: phase_summary(state.critic),\n // What the builder reached for this iteration (`src/changes.ts`), archived\n // beside the check's verdict so the two can be read against each other after\n // the fact: green + a gate edit is a different result from green alone.\n // Null when the build root is not a git repository. Additive.\n changes: state.changes,\n verdict: state.verdict,\n // The criteria the critic judged unmet, verbatim. The run-level summary\n // reads the last iteration's list, so a non-converged run says what it was\n // still missing when it stopped instead of only that it stopped. Additive.\n unmet_criteria: state.unmet_criteria,\n iteration_cost_usd: state.iteration_cost_usd,\n iteration_total_cost_usd: state.total_cost_usd,\n });\n}\n\nexport function run_result_from_state(\n config: ResolvedConfig,\n state: LoopState,\n status: RunStatus,\n completed_at: string | null,\n): RunResult {\n return {\n run_id: config.run_id,\n status,\n started_at: config.started_at,\n completed_at,\n iterations_completed: state.iteration,\n total_usage: state.total_usage,\n total_cost_usd: state.total_cost_usd,\n builder_cost_usd: state.builder_cost_usd,\n critic_cost_usd: state.critic_cost_usd,\n check_duration_ms: state.check_duration_ms,\n final_verdict: state.verdict,\n // The loop itself never salvages: the orchestrator re-stamps this after\n // teardown when a converged `--worktree` run's work was kept on its branch,\n // which is the only moment the branch's survival is known.\n salvaged_branch: null,\n };\n}\n\nexport type ResumeState = {\n raw_config: VolleyConfig;\n run_id: string;\n started_at: string;\n state: LoopState;\n iterations_completed: number;\n};\n\n/** Recover a resumable run from `.volley/`: settings from\n * config.json, totals from summary.json, feedback from feedback.md. An\n * iteration directory without a summary.json was interrupted mid-phase and\n * is discarded. */\nexport function load_resume_state(workspace: string, run_id: string): ResumeState {\n const config_path = volley_path(workspace, 'config.json');\n if (!existsSync(config_path)) {\n throw config_error(`no resumable run found: ${config_path} missing`);\n }\n const recorded = JSON.parse(readFileSync(config_path, 'utf8')) as Record<string, unknown>;\n if (recorded['run_id'] !== run_id) {\n throw config_error(\n `run ${run_id} not found in ${workspace} (recorded run: ${String(recorded['run_id'])})`,\n );\n }\n\n const iterations_root = volley_path(workspace, 'iterations');\n const dirs = existsSync(iterations_root)\n ? readdirSync(iterations_root).filter((d) => /^\\d{3}$/.test(d)).toSorted()\n : [];\n let completed = 0;\n for (const dir of dirs) {\n const full = join(iterations_root, dir);\n if (existsSync(join(full, 'summary.json'))) {\n completed = Number(dir);\n } else {\n rmSync(full, { recursive: true, force: true });\n }\n }\n\n const summary_path = volley_path(workspace, 'summary.json');\n const summary = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : null;\n\n const feedback_path = volley_path(workspace, 'feedback.md');\n const feedback = existsSync(feedback_path) ? readFileSync(feedback_path, 'utf8') : null;\n\n const raw_config: VolleyConfig = {\n prompt: String(recorded['prompt']),\n workspace: String(recorded['workspace']),\n criteria: String(recorded['criteria']),\n check: String(recorded['check']),\n builder_model: String(recorded['builder_model']),\n builder_provider: (recorded['builder_provider'] ?? 'claude_cli') as BuilderProvider,\n ...(recorded['builder_max_steps'] === undefined\n ? {}\n : { builder_max_steps: Number(recorded['builder_max_steps']) }),\n critic_model: String(recorded['critic_model']),\n critic_provider: (recorded['critic_provider'] ?? 'claude_cli') as CriticProvider,\n builder_permission_mode: recorded['builder_permission_mode'] as BuilderPermissionMode,\n critic:\n recorded['critic_preset'] === 'custom'\n ? String(recorded['critic_prompt_path'])\n : String(recorded['critic_preset']),\n max_iterations: Number(recorded['max_iterations']),\n max_cost_usd: recorded['max_cost_usd'] as number | null,\n git_checkpoints: recorded['git_checkpoints'] === true,\n worktree: recorded['worktree'] === true,\n discard_worktree: recorded['discard_worktree'] === true,\n ...(Array.isArray(recorded['gate_paths'])\n ? { gate_paths: recorded['gate_paths'] as string[] }\n : {}),\n fail_on_gate_edit: recorded['fail_on_gate_edit'] === true,\n ...(recorded['sandbox_image'] === undefined\n ? {}\n : { sandbox_image: recorded['sandbox_image'] as string }),\n };\n\n const state: LoopState = {\n iteration: completed,\n iteration_started_at: new Date().toISOString(),\n feedback,\n verdict: null,\n unmet_criteria: [],\n check: null,\n // Re-measured by the resumed run's first `build` step, against a baseline\n // captured at resume — a resumed run reports what it changes from there.\n changes: null,\n builder: null,\n critic: null,\n total_usage: summary?.total_usage ?? EMPTY_USAGE,\n total_cost_usd: summary?.total_cost_usd ?? 0,\n builder_cost_usd: summary?.builder_cost_usd ?? 0,\n critic_cost_usd: summary?.critic_cost_usd ?? 0,\n check_duration_ms: summary?.check_duration_ms ?? 0,\n iteration_cost_usd: 0,\n halt: null,\n cost_warned: false,\n };\n\n return {\n raw_config,\n run_id,\n started_at: String(recorded['started_at']),\n state,\n iterations_completed: completed,\n };\n}\n","/**\n * Enriched run summary (`.volley/summary.json`): the `RunResult` projection plus\n * a `comparison` block that makes the two blessed examples' runs diff-able.\n * The block gathers the seven comparison metrics — transport,\n * iterations-to-converge, wall-clock, cost, verdict, the deterministic check\n * trajectory, and the local salvage rate — into one self-contained surface so\n * the model-vs-transport write-up (verification §4) reads them from a single\n * object rather than re-deriving them from the per-iteration archive.\n *\n * This is the only writer of `summary.json`; the flow's `record` step calls it\n * every iteration (status `running`, `completed_at` still null), the orchestrator\n * once more with the final status, and — when a `--worktree` run's work was\n * salvaged onto its branch rather than integrated — a third time, to stamp the\n * surviving branch on `salvaged_branch`, which teardown only names after the\n * final status is known.\n * Each write recomputes the comparison from what is currently archived under\n * `.volley/iterations/`, so the trajectory grows as the run does.\n */\nimport { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';\nimport type {\n BuilderProvider,\n CriticProvider,\n ResolvedConfig,\n RunResult,\n Verdict,\n} from './types.js';\nimport { volley_path } from './workspace.js';\n\n/** How a role reached the model. volley stays on the `ai_sdk` transport for the\n * local providers (fascicle 0.12.13 defaults `transport` to `'ai_sdk'`, so\n * volley sets no field); `claude_cli` drives Claude through its own CLI\n * subprocess, not an ai-sdk transport at all. Recording both keeps the transport\n * a clean second variable in the comparison (model vs transport). */\nexport type Transport = 'ai_sdk' | 'claude_cli';\n\nexport function transport_of(provider: BuilderProvider | CriticProvider): Transport {\n return provider === 'claude_cli' ? 'claude_cli' : 'ai_sdk';\n}\n\n/** One iteration's deterministic-gate outcome, in run order. */\nexport type CheckTrajectoryPoint = {\n iteration: number;\n ran: boolean;\n ok: boolean;\n failing_slots: string[];\n};\n\n/** Run-level salvage aggregate (a health metric): the share of builder tool\n * calls recovered from assistant text rather than returned structurally. A high\n * rate on a local run means the model's native tool-call encoding is drifting\n * from its runtime's parser. `rate` is 0 when the builder made no tool calls\n * (the `claude_cli` builder runs its own loop and reports none). */\nexport type SalvageStats = {\n tool_calls: number;\n salvaged_tool_calls: number;\n rate: number;\n};\n\n/** The self-contained comparison surface the two blessed examples are read\n * through. Cost and verdict echo the `RunResult` top level on\n * purpose — this block is the single object the write-up diffs, so it carries\n * every comparison metric rather than pointing back out for some of them. */\nexport type ComparisonSummary = {\n builder_transport: Transport;\n critic_transport: Transport;\n /** The iteration the run converged on (check green + critic approved); null\n * when it never converged (budget/cap/interrupt/error). */\n iterations_to_converge: number | null;\n /** Total wall-clock across the run; null until `completed_at` is stamped. */\n wall_clock_ms: number | null;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n final_verdict: Verdict | null;\n check_trajectory: CheckTrajectoryPoint[];\n local_salvage: SalvageStats;\n /** Every gate path any iteration's builder edited — the tests, fixtures, and\n * check configuration that decide whether its own work passes (`src/changes.ts`).\n * Empty on a run that only touched the implementation, which is the shape of\n * the by-hand verification `research/reckon-local-run-finding.md` recommends\n * making routine: a green check plus an empty list is worth more than a green\n * check alone. Sorted and de-duplicated across iterations. */\n gate_edits: string[];\n /** What the critic still judged unmet when the run stopped — the last\n * iteration's `unmet_criteria`, verbatim. Empty on a converged run. This is the\n * \"why not\" a non-success status alone cannot give: `budget_exhausted` says the\n * run ran out of iterations, not what it was still missing. */\n unmet_criteria: string[];\n /** Any iteration's critic verdict was rendered by the tool-less fallback:\n * the tool-bearing critique kept dying on the provider's stream, so\n * the critic judged without read access — real, but shallower. The run's\n * headline honesty flag, and the \"degraded\" column the matrix runner\n * reads straight from this block. */\n critic_degraded: boolean;\n};\n\n/** `RunResult` plus the comparison block; `.volley/summary.json` mirrors this. */\nexport type RunSummary = RunResult & { comparison: ComparisonSummary };\n\n/** The subset of an archived per-iteration summary (written by\n * `archive_iteration`) the comparison block reads. Every field is optional so a\n * half-written or older archive degrades to zeros/empties rather than throwing. */\ntype IterationArchive = {\n iteration?: number;\n builder?: { tool_calls?: number; salvaged_tool_calls?: number } | null;\n check?: { ran?: boolean; ok?: boolean; failing_slots?: string[] } | null;\n changes?: { gate_edits?: string[] } | null;\n critic?: { critic_degraded?: boolean } | null;\n unmet_criteria?: string[];\n};\n\n/** Read the archived per-iteration summaries in order. A missing archive root\n * (a run that failed before the first `record`) or an unreadable entry yields an\n * empty/short list — the run summary still writes, just without that trajectory\n * detail. */\nfunction read_iteration_archives(workspace: string): IterationArchive[] {\n const root = volley_path(workspace, 'iterations');\n if (!existsSync(root)) return [];\n const dirs = readdirSync(root)\n .filter((dir) => /^\\d{3}$/.test(dir))\n .toSorted();\n const archives: IterationArchive[] = [];\n for (const dir of dirs) {\n const path = volley_path(workspace, 'iterations', dir, 'summary.json');\n if (!existsSync(path)) continue;\n try {\n archives.push(JSON.parse(readFileSync(path, 'utf8')) as IterationArchive);\n } catch {\n // A torn/half-written archive is skipped, never fatal to the run summary.\n }\n }\n return archives;\n}\n\nfunction check_trajectory(archives: IterationArchive[]): CheckTrajectoryPoint[] {\n return archives.map((archive, index) => ({\n iteration: typeof archive.iteration === 'number' ? archive.iteration : index + 1,\n ran: archive.check?.ran === true,\n ok: archive.check?.ok === true,\n failing_slots: archive.check?.failing_slots ?? [],\n }));\n}\n\n/** The run degraded if any archived iteration's critic verdict came from the\n * tool-less fallback. Reads the same on-disk archives as the other\n * comparison metrics, so it grows with the run. */\nfunction any_critic_degraded(archives: IterationArchive[]): boolean {\n return archives.some((archive) => archive.critic?.critic_degraded === true);\n}\n\n/** Every gate path the run's builder touched, across all iterations: an edit in\n * iteration 1 that a later iteration reverted still happened, so the run-level\n * answer is the union rather than the last iteration's list. */\nfunction all_gate_edits(archives: IterationArchive[]): string[] {\n const edits = new Set<string>();\n for (const archive of archives) {\n for (const path of archive.changes?.gate_edits ?? []) edits.add(path);\n }\n return [...edits].toSorted();\n}\n\nfunction salvage_stats(archives: IterationArchive[]): SalvageStats {\n let tool_calls = 0;\n let salvaged_tool_calls = 0;\n for (const archive of archives) {\n tool_calls += archive.builder?.tool_calls ?? 0;\n salvaged_tool_calls += archive.builder?.salvaged_tool_calls ?? 0;\n }\n return {\n tool_calls,\n salvaged_tool_calls,\n rate: tool_calls === 0 ? 0 : salvaged_tool_calls / tool_calls,\n };\n}\n\n/** Fold the comparison block onto a `RunResult`, reading the per-iteration\n * archive for the check trajectory and salvage aggregate. Pure over its inputs\n * plus the on-disk archive; `write_run_summary` persists the result. */\nexport function build_run_summary(config: ResolvedConfig, result: RunResult): RunSummary {\n const archives = read_iteration_archives(config.workspace);\n const wall_clock_ms =\n result.completed_at === null\n ? null\n : Date.parse(result.completed_at) - Date.parse(result.started_at);\n return {\n ...result,\n comparison: {\n builder_transport: transport_of(config.builder_provider),\n critic_transport: transport_of(config.critic_provider),\n iterations_to_converge:\n result.status === 'success' ? result.iterations_completed : null,\n wall_clock_ms,\n total_cost_usd: result.total_cost_usd,\n builder_cost_usd: result.builder_cost_usd,\n critic_cost_usd: result.critic_cost_usd,\n final_verdict: result.final_verdict,\n check_trajectory: check_trajectory(archives),\n gate_edits: all_gate_edits(archives),\n unmet_criteria: archives.at(-1)?.unmet_criteria ?? [],\n local_salvage: salvage_stats(archives),\n critic_degraded: any_critic_degraded(archives),\n },\n };\n}\n\n/** Write the enriched summary to `.volley/summary.json` (the projection the\n * examples' comparison is read from). */\nexport function write_run_summary(config: ResolvedConfig, result: RunResult): void {\n writeFileSync(\n volley_path(config.workspace, 'summary.json'),\n `${JSON.stringify(build_run_summary(config, result), null, 2)}\\n`,\n );\n}\n","/**\n * The step bodies behind the nodes of `./flow.ts`, one function per node. Each\n * takes the loop's carry-state and returns the next one. The phase modules they\n * call (`./builder.ts`, `./check/`, `./critic/`) do the work; these bodies add\n * what surrounds it: the renderer lines an operator watches, change detection,\n * git checkpoints, and the per-iteration archive.\n */\nimport type { RunContext } from 'fascicle';\nimport { run_builder } from './builder.js';\nimport type { BuilderStep } from './builder.js';\nimport { collect_changes } from './changes.js';\nimport { run_checkride } from './check/checkride.js';\nimport { run_command_check, skipped_check } from './check/command.js';\nimport { run_critic } from './critic/run.js';\nimport type { CriticStep } from './critic/run.js';\nimport { archive_iteration, run_result_from_state } from './iteration.js';\nimport type { Renderer } from './render/renderer.js';\nimport { write_run_summary } from './summary.js';\nimport { error_kind, phase_error } from './types.js';\nimport type { ChangeSet, CheckResult, LoopState, ResolvedConfig } from './types.js';\nimport { git_checkpoint } from './workspace.js';\nimport { build_root } from './worktree.js';\n\n/** What every step body closes over, fixed for the whole run. */\nexport type PhaseDeps = {\n config: ResolvedConfig;\n renderer: Renderer;\n /** The commit every iteration's change set is measured against, read after\n * the worktree exists and before the builder writes anything. Null when the\n * build root is not a git repo — then the run reports no changes at all\n * rather than guessing at them. */\n baseline: string | null;\n};\n\n/** How many gate edits a warning names before it summarises the rest. */\nconst LISTED_GATE_EDITS = 5;\n\n/**\n * Say what the builder reached for, every iteration. The count is an info line;\n * a gate edit is a warning, because it is the fact that changes how much a green\n * check is worth — and the operator should hear it from the harness rather than\n * discover it in the diff afterwards (the by-hand check that\n * `research/reckon-local-run-finding.md` recommends making routine).\n */\nfunction report_changes(\n config: ResolvedConfig,\n renderer: Renderer,\n changes: ChangeSet | null,\n): void {\n if (changes === null) return;\n renderer.info(\n `changes: ${String(changes.total)} file(s) changed since the run baseline` +\n (changes.truncated ? ` (listing the first ${String(changes.files.length)})` : ''),\n );\n if (changes.gate_edits.length === 0) return;\n const hidden = changes.gate_edits.length - LISTED_GATE_EDITS;\n const listed = changes.gate_edits.slice(0, LISTED_GATE_EDITS).join(', ');\n renderer.warn(\n `gate edit: the builder changed ${String(changes.gate_edits.length)} file(s) that decide ` +\n `whether its work passes — ${listed}${hidden > 0 ? ` (+${String(hidden)} more)` : ''}. ` +\n 'A green check proves less when the builder can edit the gate; the critic is told about ' +\n 'this and the run summary records it.' +\n // The halt lands at the loop guard, after this iteration's check and\n // critic have had their say — so promise the outcome, not the timing.\n (config.fail_on_gate_edit\n ? ' This run will end without success (--fail-on-gate-edit, exit 8).'\n : ''),\n );\n}\n\nasync function execute_check(\n config: ResolvedConfig,\n abort: AbortSignal,\n): Promise<CheckResult> {\n // The check gates the tree the builder actually wrote: the worktree\n // under `--worktree`, else the workspace.\n const root = build_root(config.workspace, config.worktree);\n if (config.check_resolved === 'checkride') {\n return run_checkride({ workspace: root, abort });\n }\n if (config.check_resolved === 'command') {\n return run_command_check({ command: config.check, workspace: root, abort });\n }\n return skipped_check('none');\n}\n\n/** Open the next iteration: advance the counter and clear every per-iteration\n * field, so nothing from the last round leaks into this one. */\nfunction next_iteration(s: LoopState): LoopState {\n return {\n ...s,\n iteration: s.iteration + 1,\n iteration_started_at: new Date().toISOString(),\n iteration_cost_usd: 0,\n builder: null,\n critic: null,\n check: null,\n verdict: null,\n unmet_criteria: [],\n };\n}\n\n/** `build`: one builder session edits the build root, then volley measures what\n * it changed and, under `--git`, checkpoints it. */\nexport async function build_phase(\n deps: PhaseDeps,\n builder: BuilderStep,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n const next = next_iteration(s);\n renderer.phase_start(next.iteration, 'builder');\n const built = await run_builder({ builder, config, warn: renderer.warn }, next, ctx);\n renderer.phase_end(built.iteration, 'builder', true);\n renderer.cost_line(\n built.iteration,\n 'builder',\n built.builder?.cost_usd ?? null,\n built.total_cost_usd,\n );\n if (built.cost_warned && !s.cost_warned) {\n renderer.warn('cost unavailable for this phase; recording null (run totals sum what is known)');\n }\n // What the builder actually did, measured before the check runs — so the\n // check's verdict and the builder's reach are two independent facts about\n // the same iteration rather than one inferred from the other.\n const changes = collect_changes({\n root: build_root(config.workspace, config.worktree),\n baseline: deps.baseline,\n gate_patterns: config.gate_paths,\n });\n report_changes(config, renderer, changes);\n if (config.git_checkpoints) {\n git_checkpoint(\n build_root(config.workspace, config.worktree),\n `volley iter ${String(built.iteration)}: build`,\n );\n }\n return { ...built, changes };\n}\n\n/** `skip_verify`: the build alone crossed the cost cap, so the check is recorded\n * as skipped and no critic is called — a doomed iteration spends nothing more.\n * The loop guard then halts the run on the cap. */\nexport function skip_verify_phase(deps: PhaseDeps, s: LoopState): LoopState {\n deps.renderer.warn('cost cap crossed during build; skipping check and critic');\n return { ...s, check: skipped_check('cost_cap') };\n}\n\n/** `check`: the deterministic gate over the tree the builder wrote. */\nexport async function check_phase(\n deps: PhaseDeps,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n renderer.phase_start(s.iteration, 'check');\n try {\n const result = await execute_check(config, ctx.abort);\n if (result.ran) {\n renderer.phase_end(\n s.iteration,\n 'check',\n result.ok,\n result.failing_slots.length > 0\n ? `failing: ${result.failing_slots.join(', ')}`\n : undefined,\n );\n } else {\n renderer.info('no deterministic check configured; loop is critic-gated only');\n }\n return {\n ...s,\n check: result,\n check_duration_ms: s.check_duration_ms + result.duration_ms,\n };\n } catch (err) {\n if (error_kind(err) === 'check_error') throw err;\n throw phase_error('check', s.iteration, err);\n }\n}\n\n/** `critique`: the read-only critic's verdict, feedback, and unmet criteria. */\nexport async function critique_phase(\n deps: PhaseDeps,\n critic: CriticStep,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { renderer } = deps;\n renderer.phase_start(s.iteration, 'critic');\n const critiqued = await run_critic({ critic, config: deps.config }, s, ctx);\n renderer.phase_end(\n critiqued.iteration,\n 'critic',\n critiqued.verdict === 'approved',\n critiqued.verdict ?? undefined,\n );\n renderer.cost_line(\n critiqued.iteration,\n 'critic',\n critiqued.critic?.cost_usd ?? null,\n critiqued.total_cost_usd,\n );\n return critiqued;\n}\n\n/** `record`: archive the iteration and rewrite the run summary, so the on-disk\n * state is consistent after every round (resume reads it back). */\nexport function record_phase(deps: PhaseDeps, s: LoopState): LoopState {\n const { config } = deps;\n archive_iteration(config, s);\n write_run_summary(config, run_result_from_state(config, s, 'running', null));\n if (config.git_checkpoints) {\n git_checkpoint(\n build_root(config.workspace, config.worktree),\n `volley iter ${String(s.iteration)}: critique (${s.verdict ?? 'skipped'})`,\n );\n }\n return s;\n}\n","/**\n * Display formatting: glyph taxonomy, role colors, truncation.\n * All human output goes to stderr; these helpers only build strings.\n */\nimport pc from 'picocolors';\n\nexport const GLYPH_TOOL = '🔧';\nexport const GLYPH_OK = '✅';\nexport const GLYPH_ERR = '❌';\nexport const GLYPH_COST = '💰';\nexport const GLYPH_PHASE_START = '▶';\nexport const GLYPH_PHASE_OK = '✓';\nexport const GLYPH_PHASE_FAIL = '✗';\n\nexport const VERBOSE_TRUNCATE_CHARS = 4000;\n\nexport type Role = 'builder' | 'critic' | 'check';\n\nexport function colors_enabled(\n env: Record<string, string | undefined> = process.env,\n is_tty: boolean = process.stderr.isTTY === true,\n): boolean {\n if (env['NO_COLOR'] !== undefined || env['VOLLEY_NO_COLOR'] !== undefined) {\n return false;\n }\n return is_tty;\n}\n\nexport function paint(role: Role | 'cost' | 'error', text: string, color: boolean): string {\n if (!color) return text;\n switch (role) {\n case 'builder':\n return pc.cyan(text);\n case 'critic':\n return pc.yellow(text);\n case 'check':\n return pc.green(text);\n case 'cost':\n return pc.magenta(text);\n case 'error':\n return pc.bold(pc.red(text));\n }\n}\n\nexport function dim(text: string, color: boolean): string {\n return color ? pc.dim(text) : text;\n}\n\nexport function truncate(text: string, max: number, pointer: string): string {\n if (text.length <= max) return text;\n return `${text.slice(0, max)}\\n… [truncated at ${String(max)} chars; ${pointer}]`;\n}\n\nexport function format_usd(value: number | null): string {\n return value === null ? '$?' : `$${value.toFixed(3)}`;\n}\n\n/** One-line summary of a tool input for the default streaming mode. */\nexport function summarize_value(value: unknown, max = 120): string {\n let text: string;\n try {\n text = typeof value === 'string' ? value : JSON.stringify(value) ?? '';\n } catch {\n text = String(value);\n }\n const flat = text.replace(/\\s+/g, ' ');\n return flat.length > max ? `${flat.slice(0, max)}…` : flat;\n}\n","/**\n * Live output renderer: consumes `StreamChunk`s from each\n * `generate` call plus volley's own phase/cost lines, and writes human\n * progress to stderr. Streaming is a display concern only — the trajectory\n * jsonl is the durable record.\n */\nimport type { StreamChunk } from 'fascicle';\nimport type { RunResult } from '../types.js';\nimport {\n GLYPH_COST,\n GLYPH_ERR,\n GLYPH_OK,\n GLYPH_PHASE_FAIL,\n GLYPH_PHASE_OK,\n GLYPH_PHASE_START,\n GLYPH_TOOL,\n VERBOSE_TRUNCATE_CHARS,\n dim,\n format_usd,\n paint,\n summarize_value,\n truncate,\n} from './format.js';\nimport type { Role } from './format.js';\n\nexport type RenderMode = 'default' | 'verbose' | 'quiet' | 'json';\n\nexport type RendererOptions = {\n mode: RenderMode;\n show_thinking: boolean;\n color: boolean;\n max_cost_usd: number | null;\n write?: (text: string) => void;\n};\n\nexport type Renderer = {\n builder_chunk: (chunk: StreamChunk) => void;\n critic_chunk: (chunk: StreamChunk) => void;\n phase_start: (iteration: number, phase: Role) => void;\n phase_end: (iteration: number, phase: Role, ok: boolean, detail?: string) => void;\n cost_line: (iteration: number, phase: Role, phase_cost: number | null, run_total: number) => void;\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n final_summary: (result: RunResult) => void;\n};\n\nexport function create_renderer(options: RendererOptions): Renderer {\n const write = options.write ?? ((text: string) => process.stderr.write(text));\n const { mode, color } = options;\n const silent = mode === 'json';\n const streaming = mode === 'default' || mode === 'verbose';\n\n // Tracks whether streamed prose left the cursor mid-line, so glyph lines\n // start on their own line.\n let mid_line = false;\n\n const line = (text: string): void => {\n if (silent) return;\n write(`${mid_line ? '\\n' : ''}${text}\\n`);\n mid_line = false;\n };\n\n const chunk_renderer = (role: Role) => (chunk: StreamChunk): void => {\n if (!streaming) return;\n switch (chunk.kind) {\n case 'text': {\n write(paint(role, chunk.text, color));\n mid_line = !chunk.text.endsWith('\\n');\n return;\n }\n case 'reasoning': {\n if (!options.show_thinking) return;\n write(dim(chunk.text, color));\n mid_line = !chunk.text.endsWith('\\n');\n return;\n }\n case 'tool_call_end': {\n const summary =\n mode === 'verbose'\n ? truncate(\n JSON.stringify(chunk.input, null, 2) ?? '',\n VERBOSE_TRUNCATE_CHARS,\n 'see .volley/trajectory.jsonl',\n )\n : summarize_value(chunk.input);\n line(`${GLYPH_TOOL} ${paint(role, chunk.id, color)} ${summary}`);\n return;\n }\n case 'tool_result': {\n const ok = chunk.error === undefined;\n if (mode === 'verbose') {\n const body = ok ? summarize_output(chunk.output) : chunk.error?.message ?? '';\n line(`${ok ? GLYPH_OK : GLYPH_ERR} ${truncate(body, VERBOSE_TRUNCATE_CHARS, 'see .volley/trajectory.jsonl')}`);\n } else {\n line(`${ok ? GLYPH_OK : GLYPH_ERR} ${ok ? '' : summarize_value(chunk.error?.message)}`);\n }\n return;\n }\n case 'tool_call_start': {\n line(`${GLYPH_TOOL} ${paint(role, chunk.name, color)} …`);\n return;\n }\n default:\n return;\n }\n };\n\n return {\n builder_chunk: chunk_renderer('builder'),\n critic_chunk: chunk_renderer('critic'),\n phase_start: (iteration, phase) => {\n if (mode === 'json') return;\n line(paint(phase, `${GLYPH_PHASE_START} [iter ${String(iteration)}] ${phase}`, color));\n },\n phase_end: (iteration, phase, ok, detail) => {\n if (mode === 'json') return;\n const glyph = ok ? GLYPH_PHASE_OK : GLYPH_PHASE_FAIL;\n const suffix = detail !== undefined ? ` — ${detail}` : '';\n line(paint(phase, `${glyph} [iter ${String(iteration)}] ${phase}${suffix}`, color));\n },\n cost_line: (iteration, phase, phase_cost, run_total) => {\n if (mode === 'json') return;\n const cap = options.max_cost_usd !== null ? ` / ${format_usd(options.max_cost_usd)}` : '';\n line(\n paint(\n 'cost',\n `${GLYPH_COST} [iter ${String(iteration)}] [${phase}] phase: ${format_usd(phase_cost)} | run: ${format_usd(run_total)}${cap}`,\n color,\n ),\n );\n },\n info: (message) => {\n line(message);\n },\n warn: (message) => {\n line(paint('critic', `warning: ${message}`, color));\n },\n error: (message) => {\n if (silent) {\n // Errors still surface in json mode — stderr stays human, stdout machine.\n write(`error: ${message}\\n`);\n return;\n }\n line(paint('error', `error: ${message}`, color));\n },\n final_summary: (result) => {\n if (silent) return;\n line('');\n line(`run ${result.run_id}: ${result.status}`);\n line(\n `iterations: ${String(result.iterations_completed)} | verdict: ${result.final_verdict ?? 'n/a'}`,\n );\n line(\n paint(\n 'cost',\n `${GLYPH_COST} total: ${format_usd(result.total_cost_usd)} (builder ${format_usd(result.builder_cost_usd)}, critic ${format_usd(result.critic_cost_usd)})`,\n color,\n ),\n );\n line(\n `tokens: ${String(result.total_usage.input_tokens)} in / ${String(result.total_usage.output_tokens)} out`,\n );\n },\n };\n}\n\nfunction summarize_output(output: unknown): string {\n if (typeof output === 'string') return output;\n try {\n return JSON.stringify(output) ?? '';\n } catch {\n return String(output);\n }\n}\n","/**\n * Docker sandbox invocation spec: the hardened\n * `docker run` argv that launches the *whole* volley builder inside one\n * container. volley no longer orchestrates the container — instead\n * the operator/example runs `docker run <these flags> <image> <volley args>` and\n * volley detects it is already contained. The create/`exec`/reap/teardown\n * lifecycle and the `docker exec` bash executor were retired; what\n * remains here is the *spec* — pure, daemon-free flag-builders the blessed\n * examples and the `--dry-run` preflight render into the `docker run` line,\n * unit-testable without a daemon.\n *\n * Inside that container volley's `bash` is the local `host_bash_executor`\n * (`spawnSync`, now running in-container), its file tools write straight to the\n * bind-mounted worktree at `/workspace`, and its model client reaches the host\n * LLM endpoint across the boundary at `host.docker.internal` (the allowlist\n * target; see the `VOLLEY_MODEL_HOST` crossing in `src/engine.ts`).\n *\n * Hardening: non-root as the worktree owner, cap-drop-all,\n * no-new-privileges, default seccomp, tini as PID 1 (`--init`), memory/cpu/pids\n * caps, a read-only rootfs with tmpfs for the few writable paths, and, when the\n * caller names one, the pnpm store on a named volume. Never `--privileged`,\n * never `--user 0`. volley's Node process reaps its own bash children\n * in-container, so the old reap-between-`exec` rider falls away.\n */\nimport { resolve } from 'node:path';\nimport { config_error } from './types.js';\n\n/** The in-container mount point for the bind-mounted worktree; matches the\n * `Dockerfile`'s `WORKDIR`, so a workspace-relative path resolves against the\n * same tree volley's file tools write. */\nconst SANDBOX_WORKDIR = '/workspace';\n\n/** The container user's home; matches the `Dockerfile`'s `node` user. `HOME` is\n * pinned here (a numeric `--user` has no `/etc/passwd` entry, so `~` is\n * otherwise unset) and its `.cache` is a tmpfs so the read-only rootfs does not\n * brick tools that scribble there. */\nconst SANDBOX_HOME = '/home/node';\n\n/** Named volume for the pnpm store: survives the read-only rootfs and\n * persists the content-addressed store across runs. (Making a `--user`-mapped,\n * non-1000 uid writable to a fresh volume is a footgun handled where pnpm\n * actually runs — the blessed examples — not here.) `sandbox_invocation` mounts\n * it; a bare `sandbox_run_args` caller chooses whether to. */\nconst SANDBOX_STORE_VOLUME = 'volley-pnpm-store';\n\n/** The host spelling of the Docker gateway (Linux-portable; Docker Desktop\n * already provides it). It is both the `--add-host` target for the allowlist\n * bridge and the value the example injects as `VOLLEY_MODEL_HOST` so the\n * in-container model client crosses to the host LLM endpoint (see\n * `resolve_ollama_base_url` in `src/engine.ts`). */\nexport const HOST_GATEWAY_HOST = 'host.docker.internal';\n\n/** Canonical identity of the allowlist bridge the examples create (`docker\n * network create --subnet <SANDBOX_NETWORK_SUBNET> <SANDBOX_NETWORK_NAME>`) and\n * the host `DOCKER-USER` rules scope to. Exported so the blessed examples\n * share one spelling of the invocation spec. */\nexport const SANDBOX_NETWORK_NAME = 'volley-sandbox-net';\nexport const SANDBOX_NETWORK_SUBNET = '172.31.99.0/24';\n\n/**\n * The container's egress posture. Under whole-process containment\n * the model client and the `fetch` tool run inside the container, so its\n * legitimate egress is the package registry for `pnpm install` plus the host LLM\n * endpoint the model client reaches via host-gateway.\n *\n * - `'none'` — `--network none`: no interface at all, a complete L3 egress deny.\n * The default-deny default; it fits a genuinely offline run where the model and\n * deps are already in-container (a host-run model is unreachable under `none`).\n * With the whole process in-container, `fetch` has no route either, so it\n * degrades cleanly to a returned error result and the run continues.\n * - `'allowlist'` — the container sits on volley's dedicated user-defined bridge\n * with `host.docker.internal:host-gateway`, collapsing the allowlist targets\n * (the package registry, and the host LLM endpoint the in-container model\n * client now reaches) onto the host gateway. The L3/L4 default-DROP that\n * makes the bridge a true allowlist is the host-applied, subnet-scoped\n * `DOCKER-USER` rule the operator installs (volley never installs it — that\n * chain is root and host-global, and on Docker Desktop lives inside a VM). The\n * always-on tool-level SSRF deny-list is the second, in-process defense-in-depth\n * layer. Host hardening, run once as root on a Linux host, scoped to volley's\n * subnet so it never touches other containers (insert ahead of the chain's\n * terminating RETURN, in order):\n * iptables -I DOCKER-USER -s 172.31.99.0/24 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n * iptables -I DOCKER-USER -s 172.31.99.0/24 -d <host-gateway-ip> -j ACCEPT # collapsed allowlist\n * iptables -I DOCKER-USER -s 172.31.99.0/24 -p udp --dport 53 -j ACCEPT # DNS\n * iptables -I DOCKER-USER -s 172.31.99.0/24 -j DROP # default-deny the rest\n */\nexport type SandboxNetwork = 'none' | 'allowlist';\n\n/**\n * The network-related `docker run` args for a posture, pure and exported\n * so the policy is unit-testable without a daemon. `'none'` denies all egress\n * (`--network none`); `'allowlist'` attaches the dedicated user-defined bridge and\n * collapses the allowlist targets onto the host gateway (`host.docker.internal`,\n * the Linux-portable spelling — harmless where Docker Desktop already provides it).\n */\nexport function network_run_args(network: SandboxNetwork, network_name: string): string[] {\n if (network === 'none') return ['--network', 'none'];\n return ['--network', network_name, '--add-host', `${HOST_GATEWAY_HOST}:host-gateway`];\n}\n\n/**\n * The hardened `docker run` argv that launches volley inside its container.\n * Pure and exported so the flag set is unit-testable without a\n * daemon and the blessed examples / `--dry-run` preflight can render it.\n *\n * A one-shot, foreground `--rm` container — the whole run *is* this\n * container (an earlier design ran a detached `-d … sleep infinity` daemon volley\n * `exec`'d against), so `--rm` cleans it up when volley exits. `command`\n * appends the container command (the volley args); omit it to use the image's\n * `volley` entrypoint. `env` injects `-e KEY=VALUE` pairs (the `VOLLEY_MODEL_HOST`\n * crossing). `labels` adds `--label KEY=VALUE` pairs, so a caller that owns the\n * container's lifecycle can find and reap it by label. `entrypoint` overrides\n * the image entrypoint (the opt-in real-docker isolation test runs a raw `sh`\n * this way).\n *\n * `store_volume` mounts the named volume as the pnpm store; omit it and no store\n * is mounted. A store is shared by every run that mounts it, so a caller that\n * installs dependencies in a separate container first can keep the builder's\n * container off it, and no builder can leave files in a store a later install\n * trusts.\n *\n * Never emits `--privileged` and refuses `--user 0`: volley must not hand\n * the sandbox root or full capabilities. Everything writable under the\n * `--read-only` rootfs is an explicit tmpfs or volume; the bind-mounted worktree\n * is the one host-visible write path.\n */\nexport function sandbox_run_args(options: {\n image: string;\n build_root: string;\n uid: number | null;\n gid: number | null;\n store_volume?: string | null;\n network: SandboxNetwork;\n network_name: string;\n name?: string | null;\n env?: ReadonlyArray<readonly [string, string]>;\n labels?: ReadonlyArray<readonly [string, string]>;\n entrypoint?: string | null;\n command?: ReadonlyArray<string>;\n}): string[] {\n if (options.uid === 0) {\n throw config_error('refusing to start the builder sandbox as root (uid 0)');\n }\n const user =\n options.uid !== null && options.gid !== null\n ? ['--user', `${String(options.uid)}:${String(options.gid)}`]\n : [];\n const name =\n options.name !== undefined && options.name !== null ? ['--name', options.name] : [];\n const entrypoint =\n options.entrypoint !== undefined && options.entrypoint !== null\n ? ['--entrypoint', options.entrypoint]\n : [];\n const env = (options.env ?? []).flatMap(([key, value]) => ['-e', `${key}=${value}`]);\n const labels = (options.labels ?? []).flatMap(([key, value]) => ['--label', `${key}=${value}`]);\n const store =\n options.store_volume !== undefined && options.store_volume !== null\n ? ['-v', `${options.store_volume}:${SANDBOX_HOME}/.local/share/pnpm/store`]\n : [];\n return [\n 'run',\n // One-shot, foreground container: the whole run *is* this container, so\n // remove it when volley exits.\n '--rm',\n ...name,\n ...labels,\n ...user,\n // Network policy: default-deny egress. `'none'` gives the container\n // no interface; `'allowlist'` puts it on the user-defined bridge and collapses\n // the allowlist targets onto the host gateway.\n ...network_run_args(options.network, options.network_name),\n // Resource caps: contain a runaway / fork-bomb / OOM without starving\n // pnpm/tsc (pids 1024, not 100; nofile high enough for esbuild/watchers).\n '--memory=4g',\n '--memory-swap=4g',\n '--memory-swappiness=0',\n '--cpus=2',\n '--pids-limit=1024',\n '--ulimit',\n 'nofile=8192:16384',\n '--ulimit',\n 'core=0',\n // Privilege caps: drop every capability, forbid privilege\n // escalation, keep the default seccomp profile, and run tini (PID 1) to reap\n // zombies. Never `--privileged`.\n '--cap-drop=ALL',\n '--security-opt',\n 'no-new-privileges',\n '--init',\n // Read-only rootfs with tmpfs for the few writable paths the toolchain\n // needs; a pnpm store, when mounted, persists on a named volume.\n '--read-only',\n '--tmpfs',\n '/tmp',\n '--tmpfs',\n '/run',\n '--tmpfs',\n `${SANDBOX_HOME}/.cache`,\n '-e',\n `HOME=${SANDBOX_HOME}`,\n ...env,\n // The bind-mounted worktree (writable — a bind mount is exempt from\n // `--read-only`) and, when one is named, the persistent pnpm store.\n '-v',\n `${resolve(options.build_root)}:${SANDBOX_WORKDIR}`,\n ...store,\n '-w',\n SANDBOX_WORKDIR,\n ...entrypoint,\n options.image,\n ...(options.command ?? []),\n ];\n}\n\n/**\n * The small helper that surfaces the full invocation spec: compose the\n * hardened `docker run` argv with the canonical bridge + pnpm store and, when\n * crossing to a host-run model (the `'allowlist'` posture), the\n * `VOLLEY_MODEL_HOST` env the base-url normalizer consumes (engine.ts). The\n * operator/example runs this (`format_docker_run` renders it as a copy-paste\n * shell line); volley detects it is contained rather than running it itself.\n */\nexport function sandbox_invocation(options: {\n image: string;\n build_root: string;\n uid: number | null;\n gid: number | null;\n network: SandboxNetwork;\n command: ReadonlyArray<string>;\n name?: string | null;\n /** The host the in-container model client crosses to (e.g. `HOST_GATEWAY_HOST`)\n * — injected as `VOLLEY_MODEL_HOST`; omit for a fully-offline `'none'` run. */\n model_host?: string;\n}): string[] {\n const env: ReadonlyArray<readonly [string, string]> =\n options.model_host !== undefined && options.model_host !== ''\n ? [['VOLLEY_MODEL_HOST', options.model_host]]\n : [];\n return sandbox_run_args({\n image: options.image,\n build_root: options.build_root,\n name: options.name ?? null,\n uid: options.uid,\n gid: options.gid,\n store_volume: SANDBOX_STORE_VOLUME,\n network: options.network,\n network_name: SANDBOX_NETWORK_NAME,\n env,\n command: options.command,\n });\n}\n\n/** Render a docker argv as a copy-pasteable shell line for the examples /\n * `--dry-run` preflight. Minimal POSIX quoting: single-quote any token with\n * whitespace or shell-special characters. */\nexport function format_docker_run(run_args: ReadonlyArray<string>): string {\n return ['docker', ...run_args].map(quote_shell_token).join(' ');\n}\n\nfunction quote_shell_token(token: string): string {\n if (token.length > 0 && /^[A-Za-z0-9_./:=@-]+$/.test(token)) return token;\n return `'${token.replace(/'/g, `'\\\\''`)}'`;\n}\n","/**\n * Exit codes and the mapping from fascicle's error taxonomy plus\n * volley's own tagged errors onto them.\n */\nimport { error_kind } from './types.js';\nimport type { PhaseError, RunStatus } from './types.js';\n\nexport const EXIT_SUCCESS = 0;\nexport const EXIT_BUDGET_EXHAUSTED = 2;\nexport const EXIT_BUILDER_ERROR = 3;\nexport const EXIT_CHECK_ERROR = 4;\nexport const EXIT_CONFIG_ERROR = 5;\nexport const EXIT_CRITIC_ERROR = 6;\nexport const EXIT_COST_CAP = 7;\n/** The builder edited the gate that judges it and `--fail-on-gate-edit` was set:\n * distinct from a failed check (4) and from a budget exhaustion (2), because\n * nothing failed — the run refused to count a pass it could not trust. */\nexport const EXIT_GATE_EDIT = 8;\nexport const EXIT_INTERRUPTED = 130;\n\nexport function exit_code_for_status(status: RunStatus): number {\n switch (status) {\n case 'success':\n return EXIT_SUCCESS;\n case 'budget_exhausted':\n return EXIT_BUDGET_EXHAUSTED;\n case 'cost_cap_reached':\n return EXIT_COST_CAP;\n case 'gate_edit_blocked':\n return EXIT_GATE_EDIT;\n case 'interrupted':\n return EXIT_INTERRUPTED;\n default:\n return EXIT_BUILDER_ERROR;\n }\n}\n\n/** Error kinds fascicle raises for provider-level failures. */\nconst PROVIDER_ERROR_KINDS = new Set([\n 'provider_error',\n 'provider_auth_error',\n 'provider_not_configured_error',\n 'provider_capability_error',\n 'claude_cli_error',\n 'rate_limit_error',\n 'engine_disposed_error',\n 'timeout_error',\n]);\n\nexport function exit_code_for_error(err: unknown): number {\n const kind = error_kind(err);\n if (kind === 'aborted_error') return EXIT_INTERRUPTED;\n if (kind === 'config_error' || kind === 'engine_config_error') {\n return EXIT_CONFIG_ERROR;\n }\n if (kind === 'check_error') return EXIT_CHECK_ERROR;\n if (kind === 'schema_validation_error') return EXIT_CRITIC_ERROR;\n if (kind === 'phase_error') {\n const phase = (err as PhaseError).phase;\n const cause_kind = error_kind((err as PhaseError).cause);\n if (cause_kind === 'aborted_error') return EXIT_INTERRUPTED;\n if (phase === 'critic') return EXIT_CRITIC_ERROR;\n if (phase === 'check') return EXIT_CHECK_ERROR;\n return EXIT_BUILDER_ERROR;\n }\n if (kind !== null && PROVIDER_ERROR_KINDS.has(kind)) {\n return EXIT_BUILDER_ERROR;\n }\n return EXIT_BUILDER_ERROR;\n}\n"],"mappings":"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","names":["existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","existsSync","readFileSync","dirname","join","spawnSync","readFileSync","z","readFileSync","statSync","isAbsolute","join","resolve","z","resolve","fallback","spawnSync","readFileSync","fetch","existsSync","renameSync","join","resolve","spawnSync","existsSync","mkdirSync","writeFileSync","join","spawnSync","join","existsSync","mkdirSync","writeFileSync","spawnSync","branch","resolve","git","spawnSync","branch","existsSync","join","renameSync","dirname","join","existsSync","readFileSync","z","model_call","existsSync","readFileSync","dirname","join","fileURLToPath","presets_dir","dirname","fileURLToPath","join","existsSync","readFileSync","z","model_call","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","writeFileSync","join","writeFileSync","mkdirSync","join","readFileSync","existsSync","existsSync","readFileSync","readdirSync","writeFileSync","existsSync","readdirSync","readFileSync","writeFileSync","branch","existsSync","readFileSync","resolve","resolve"]}
|