@robmclarty/volley 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["git"],"sources":["../src/types.ts","../src/engine.ts","../src/changes.ts","../src/check/detect.ts","../src/containment.ts","../src/trust.ts","../src/workspace.ts","../src/config.ts","../src/builder/context_check.ts","../src/builder/countdown.ts","../src/builder/prepare_step.ts","../src/builder/trim.ts","../src/workspace_tools.ts","../src/builder/tools.ts","../src/check/checkride.ts","../src/check/command.ts","../src/claude_cli_permissions.ts","../src/cost.ts","../src/prewarm.ts","../src/worktree.ts","../src/builder.ts","../src/critic/prompt.ts","../src/critic/run.ts","../src/loop_state.ts","../src/render/format.ts","../src/iteration.ts","../src/summary.ts","../src/phases.ts","../src/flow.ts","../src/orchestrator.ts","../src/render/renderer.ts","../src/sandbox.ts","../src/exit_codes.ts"],"sourcesContent":["/**\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. `openrouter` reaches a\n * hosted model over one API key and takes the local critic's tools and\n * degradation ladder. */\nexport type CriticProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';\n\n/** Transport for the builder role. `claude_cli` is a full agentic Claude Code\n * session; every other provider runs the builder as a volley-driven tool loop\n * (write/exec tools supplied by the harness), whether its model is local\n * (`ollama`, `lmstudio`) or hosted (`openrouter`). */\nexport type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';\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\n/** Why a local critic's verdict came from the tool-less fallback:\n * `stream_error`, the tool-bearing call kept dying on the provider's stream\n * after the bounded retry; `step_exhaustion`, it spent its step budget (or\n * stopped on a tool call) without producing a verdict. */\nexport type DegradeCause = 'stream_error' | 'step_exhaustion';\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 /** A critique's other outcome: the critic requested changes, or the check\n * failed, on the one change it reviewed. A run never ends this way. */\n | 'rejected'\n | 'interrupted'\n | 'error';\n\n/** What a run does: the builder/critic loop (`run`), or one check and one\n * critique of a change already made, with no builder at all (`critique`). */\nexport type RunMode = 'run' | 'critique';\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_url?: string;\n builder_max_steps?: number;\n builder_max_tool_calls?: number;\n builder_max_output_tokens?: number;\n builder_trim_history?: number;\n allow_unsandboxed_builder?: boolean;\n critic_model?: string;\n critic_provider?: CriticProvider;\n critic_url?: string;\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 state_dir?: 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; the run's `config.json` mirrors this. */\nexport type ResolvedConfig = {\n version: 2;\n run_id: string;\n started_at: string;\n /** A run, or a critique (`volley critique`). A critique's builder fields\n * hold the defaults, untouched by flags and the environment, since no\n * builder is ever constructed, and its loop settings are one round with\n * nothing isolated or committed. */\n mode: RunMode;\n /** The task. A critique needs none, since a critic judges against the\n * criteria alone, so it's empty unless one was given to record. */\n prompt: string;\n criteria: string;\n check: CheckMode;\n check_resolved: CheckRunnerKind;\n builder_model: string;\n builder_provider: BuilderProvider;\n /** The builder seat's own model server base URL (`--builder-url`), as given.\n * It is normalized, and crossed to the host LLM endpoint when contained, only\n * where it is used, because the crossing depends on where the run executes.\n * Null falls back to the provider's env var (`VOLLEY_OLLAMA_URL` /\n * `VOLLEY_LMSTUDIO_URL` / `VOLLEY_OPENROUTER_URL`), then its default, never to\n * the critic's URL. Only a provider volley reaches at a base URL (ollama,\n * lmstudio, openrouter) takes one. */\n builder_url: string | null;\n builder_max_steps: number;\n /** How many tool calls a tool-loop builder may make in one turn, reads\n * aside (`read_file`, `search_files`, `list_files` are `read_only` and\n * don't count); fascicle runs a turn's calls in order up to the first one\n * past the cap, drops the rest, and tells the model which it dropped. 1 by\n * default, since some model and runtime pairs return parallel calls badly;\n * raise it for a pair that handles them. Ignored by the `claude_cli`\n * builder. */\n builder_max_tool_calls: number;\n /** The most output tokens a tool-loop builder may generate in one turn,\n * reasoning included, or null to leave each turn to the provider's own\n * limit. 16384 by default on a local builder (ollama, lmstudio), null on\n * openrouter. A turn cut off at it before it made a tool call costs that\n * one step, not the session: fascicle feeds back that it hit the limit and\n * the loop goes on. Ignored by the `claude_cli` builder. */\n builder_max_output_tokens: number | null;\n /** The estimated request size, in tokens, above which a tool-loop builder's\n * turns send older tool results as one-line stubs (#7), or null to send\n * every turn whole. Null by default, until a long local session is shown\n * to run faster with it on. Ignored by the `claude_cli` builder. */\n builder_trim_history: number | null;\n /** Operator opt-out permitting a non-`claude_cli` builder to run without a\n * sandbox — it gets a real host bash. Refused by default. */\n allow_unsandboxed_builder: boolean;\n critic_model: string;\n critic_provider: CriticProvider;\n /** The critic seat's own model server base URL (`--critic-url`), as given;\n * resolved like `builder_url`, and null never falls back to the builder's. */\n critic_url: string | null;\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 * the run's state stays where `state_dir` puts it (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 /** The root that holds each run's state at `<state_dir>/<run_id>/`, as an\n * absolute path: `--state-dir`, else the default root,\n * `$XDG_STATE_HOME/volley` or `~/.local/state/volley`. `resolve_config`\n * always sets one. Null is the layout older runs used, `<workspace>/.volley/`,\n * rotated aside by the next fresh run: a run an older volley started\n * resumes in it, and a hand-built config can still ask for it. */\n state_dir: string | null;\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 /** checkride's capped excerpt of the failing slots (`.check/digest.md`),\n * when the check failed and checkride wrote one. */\n digest?: string;\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 /** Turns the provider cut off at the output cap before they made a tool\n * call (`--builder-max-output-tokens`), each of which cost a step and went\n * on. Set on a builder record when any was; absent otherwise. Additive. */\n truncated_turns?: 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, or ran out of steps before its verdict, so the\n * critic judged with no read access — grounded only by the criteria, the raw\n * check artifacts, and a workspace file inventory. Set (true) on a degraded\n * critic record; absent on a full critique and on the builder. Additive, and a\n * degraded verdict is *always* marked so it never passes silently as a full\n * one. */\n critic_degraded?: boolean;\n /** Why the verdict degraded, set with `critic_degraded`. Additive. */\n degrade_cause?: DegradeCause;\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 *\n * On Ollama, `decode` holds only while a turn's first chunk arrives as its\n * first token is generated. Ollama sends a tool call whole, so a turn whose\n * only output is a tool call dispatches nothing until generation ends, and\n * its tokens are divided by the last few milliseconds: a non-thinking seat's\n * rate reads far too high until robmclarty/fascicle#12 times those turns\n * another way. A thinking seat needs ai-sdk-ollama 4.3.0 or later, which\n * streams the reasoning even though volley never sets `think`. */\n throughput?: Throughput;\n /** Each turn of a builder session, in order, so a long session's growth\n * and where its time went can be read off the archive (#7). Set on a builder\n * record whose provider reported steps (every tool-loop builder); absent on\n * the critic and on a session with none. Additive. */\n steps?: BuilderStepRecord[];\n};\n\n/** Where a builder turn's prefill and decode times came from.\n * `ollama_reported`: Ollama's own `prompt_eval_duration` and `eval_duration`\n * (native transport). `ollama_derived`: prefill as `total_duration` less\n * `load_duration` and `eval_duration`, the ai_sdk transport's metadata, which\n * leaves `prompt_eval_duration` out; slightly high, since the total includes\n * Ollama's own overhead. `first_chunk`: prefill as the time to the first\n * streamed chunk, decode as the rest of the round trip. `none`: no split. */\nexport type StepTimingBasis = 'ollama_reported' | 'ollama_derived' | 'first_chunk' | 'none';\n\n/** One turn of a builder session. */\nexport type BuilderStepRecord = {\n index: number;\n /** The whole request this turn sent, so the session's growth reads as the\n * sequence of these. */\n input_tokens: number;\n output_tokens: number;\n /** The turn's provider round trip, tool execution excluded. */\n duration_ms: number;\n prefill_ms?: number;\n decode_ms?: number;\n timing_basis: StepTimingBasis;\n finish_reason: FinishReason;\n truncated?: true;\n /** Each tool call the turn made, and how many characters its result put\n * into the transcript every later turn resends. */\n tool_calls: Array<{ name: string; output_chars: number }>;\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 /** How many of the run's builder sessions ended on the step limit\n * (`max_steps`) rather than calling finish. */\n builder_max_steps_hits: 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; the run's `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 /** How many of the run's builder sessions hit the step limit before they\n * called finish: work handed to the check and critic unverified. The\n * warning a run prints for each goes to stderr, which `--json` silences, so\n * a harness reads it here. Always 0 for a `claude_cli` builder, which has\n * no step limit, and for a critique. */\n builder_max_steps_hits: 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; the run's `summary.json` mirrors it. */\n salvaged_branch: string | null;\n /** A run, or a critique, which runs no builder. */\n mode: RunMode;\n /** Where this run keeps its config, summary, trajectory, feedback, verdict,\n * and iterations: `<state_dir>/<run_id>/` under a state root, else the\n * workspace's `.volley/`. Inside the sandbox container it is the container's\n * path, which a harness maps back to the directory it mounted. */\n run_state_dir: string;\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 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/** OpenRouter's API root, the one fascicle's openrouter adapter defaults to. */\nexport const DEFAULT_OPENROUTER_URL = 'https://openrouter.ai/api/v1';\n\n/** The variable an `openrouter` seat's API key is read from. */\nconst OPENROUTER_KEY_VAR = 'OPENROUTER_API_KEY';\n\n/** The variable a `claude_cli` seat's API key is read from, which the Claude\n * CLI also reads on its own. */\nconst ANTHROPIC_KEY_VAR = 'ANTHROPIC_API_KEY';\n\n/** Every variable a seat reads a credential from. Every process volley starts\n * runs without them (the check, the builder's commands, and volley's own git\n * and checkride calls, which run hooks and filters the builder can write), so\n * nothing the builder writes can read the keys its seats spend. */\nexport const SEAT_CREDENTIAL_VARS: ReadonlyArray<string> = [OPENROUTER_KEY_VAR, ANTHROPIC_KEY_VAR];\n\n/** The environment every process volley starts runs with: `env`, `PATH`\n * included, less every variable a seat reads a credential from. */\nexport function command_env(env: Readonly<Record<string, string | undefined>>): Record<string, string> {\n const stripped: ReadonlySet<string> = new Set(SEAT_CREDENTIAL_VARS);\n return Object.fromEntries(\n Object.entries(env).filter(\n (entry): entry is [string, string] => entry[1] !== undefined && !stripped.has(entry[0]),\n ),\n );\n}\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`. `URL.hostname` keeps an\n * IPv6 literal's brackets, so the IPv6 loopback is spelled `[::1]`. */\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 providers a seat reaches at a base URL volley configures. `claude_cli`\n * picks its own endpoint, so it never appears here. */\ntype UrlProvider = 'ollama' | 'lmstudio' | 'openrouter';\n\n/** Where a URL-taking provider's base URL comes from when a seat names none of\n * its own: the provider's env var, then its default. `normalize` canonicalizes\n * a URL from any source, so two spellings of one server compare equal. */\ntype SeatUrlSource = {\n env: string;\n default_url: string;\n normalize: (url: string) => string;\n};\n\nfunction strip_trailing_slashes(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\nconst SEAT_URL_SOURCES: Readonly<Record<UrlProvider, SeatUrlSource>> = {\n // A trailing `/api` (the pre-v0.3.1 documented default, and a natural mistake\n // since Ollama's REST paths all start with it) is stripped rather than left\n // to 404 every request.\n ollama: {\n env: 'VOLLEY_OLLAMA_URL',\n default_url: DEFAULT_OLLAMA_URL,\n normalize: (url) => strip_trailing_slashes(url).replace(/\\/api$/, ''),\n },\n // LM Studio's base URL keeps its `/v1`: the OpenAI-compatible client appends\n // `/chat/completions` to it.\n lmstudio: {\n env: 'VOLLEY_LMSTUDIO_URL',\n default_url: DEFAULT_LMSTUDIO_URL,\n normalize: strip_trailing_slashes,\n },\n // OpenRouter's base URL keeps its `/api/v1` the same way, so a seat URL can\n // name a proxy or another OpenAI-compatible gateway.\n openrouter: {\n env: 'VOLLEY_OPENROUTER_URL',\n default_url: DEFAULT_OPENROUTER_URL,\n normalize: strip_trailing_slashes,\n },\n};\n\n/** The providers that take a seat URL (`--builder-url` / `--critic-url`), and\n * so get their endpoint probed by `--dry-run`. */\nexport const SEAT_URL_PROVIDERS = Object.keys(SEAT_URL_SOURCES) as ReadonlyArray<UrlProvider>;\n\n/** Whether a seat on `provider` reaches its model at a base URL volley\n * configures, and so takes a URL of its own. */\nexport function takes_seat_url(\n provider: BuilderProvider | CriticProvider | undefined,\n): provider is UrlProvider {\n return (SEAT_URL_PROVIDERS as ReadonlyArray<string | undefined>).includes(provider);\n}\n\n/** An absent, empty, or all-whitespace value counts as unset. */\nfunction present(value: string | null | undefined): string | null {\n const trimmed = value?.trim() ?? '';\n return trimmed === '' ? null : trimmed;\n}\n\n/** The base URL a seat's model calls go to: the seat's own URL, else the\n * provider's env var (`VOLLEY_OLLAMA_URL` / `VOLLEY_LMSTUDIO_URL` /\n * `VOLLEY_OPENROUTER_URL`), else its default. A seat never falls back to the\n * other seat's URL. The result is normalized, then a loopback authority is\n * crossed to the host LLM endpoint when volley runs contained. Both seats can\n * be loopback URLs on different ports, and each crosses on its own port. */\nexport function seat_base_url(\n provider: UrlProvider,\n seat_url: string | null,\n env: Record<string, string | undefined>,\n): string {\n const source = SEAT_URL_SOURCES[provider];\n const raw = present(seat_url) ?? present(env[source.env]) ?? source.default_url;\n return cross_to_host_gateway(source.normalize(raw), env);\n}\n\n/** The API key an `openrouter` seat sends, from `OPENROUTER_API_KEY`. An unset\n * or blank key is a config error naming the variable, which `resolve_config`\n * raises before any work, because fascicle's own \"requires a non-empty\n * api_key\" doesn't say where the key comes from. */\nexport function openrouter_api_key(env: Record<string, string | undefined>): string {\n const key = present(env[OPENROUTER_KEY_VAR]);\n if (key === null) {\n throw config_error(\n `${OPENROUTER_KEY_VAR} is not set: an openrouter seat sends it as its API key`,\n );\n }\n return key;\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 URL-taking provider, that provider is\n * configured alongside claude_cli so one engine drives both roles. */\n builder_provider?: BuilderProvider;\n /** The builder seat's own base URL (`--builder-url`); null or absent falls\n * back to the provider's env var, then its default. */\n builder_url?: string | null;\n /** When the critic runs on a URL-taking provider, that provider is\n * configured alongside claude_cli so one engine drives both roles. */\n critic_provider?: CriticProvider;\n /** The critic seat's own base URL (`--critic-url`), resolved the same way. */\n critic_url?: string | null;\n env?: Record<string, string | undefined>;\n};\n\n/** A seat's provider entry, with the base URL resolved for that seat. The ai-sdk\n * peer (`ai-sdk-ollama` / `@ai-sdk/openai-compatible`) is loaded lazily by\n * fascicle only when the provider actually runs. The entry is complete, because\n * `Engine.with_providers` replaces a provider's whole entry: whatever this\n * returns is all a seat's derived engine knows about the provider, so an\n * `openrouter` entry carries its key and its transport along with its URL.\n *\n * `openrouter` runs on fascicle's native transport, its OpenAI-compatible core,\n * so no ai-sdk peer gets installed for it, and its `X-Title` attributes the\n * traffic to volley.\n *\n * For the local providers, native transport is the deferred future bridge, not\n * adopted here: they stay on the ai_sdk transport, which fascicle 0.14.0 already\n * selects by default (`transport?: 'ai_sdk' | 'native'` defaults to `'ai_sdk'`),\n * so no field is needed today. Flipping later is a one-line change — add\n * `transport: 'native'` to the ollama/lmstudio entry returned below, which both\n * seats' engines then share. No URL re-pointing is required: `seat_base_url`\n * already yields the daemon-root URL the native `/api/chat` transport wants\n * (its adapter appends `/api/chat` itself), which is exactly what the v0.3.1\n * base-URL fix produces.\n * Kept as a proven-once-then-reverted option so the transport stays a clean\n * second variable in the model-vs-transport comparison. Flipping it today would\n * also lose the reasoning: fascicle's native Ollama adapter drops\n * `message.thinking`, with `think` unset or true (robmclarty/fascicle#12), so a\n * thinking seat's reasoning would vanish from the terminal and the trajectory.\n *\n * Every provider's base URL crosses a loopback authority to `VOLLEY_MODEL_HOST`\n * when 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 seat_provider_config(\n provider: UrlProvider,\n seat_url: string | null,\n env: Record<string, string | undefined>,\n): ProviderConfigMap {\n const base_url = seat_base_url(provider, seat_url, env);\n switch (provider) {\n case 'ollama':\n return { ollama: { base_url } };\n case 'lmstudio':\n return { lmstudio: { base_url } };\n case 'openrouter':\n return {\n openrouter: {\n api_key: openrouter_api_key(env),\n base_url,\n transport: 'native',\n x_title: 'volley',\n },\n };\n }\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 URL-taking provider selected\n * by the builder or critic role is wired in alongside it, at that seat's URL,\n * so one engine drives both roles. An engine holds one URL per provider, so on\n * a provider both seats share it carries the builder's; `create_seat_engines`\n * gives the critic its own engine when its URL differs. Binary, auth mode,\n * fallback 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 const providers: ProviderConfigMap = {\n claude_cli: {\n default_cwd: options.workspace,\n setting_sources: ['project', 'local'],\n auth_mode,\n // Under `oauth` the CLI inherits the whole environment to reach its\n // login, and hands it on to every command it runs; this keeps the other\n // seat's key out. fascicle drops these before it applies the auth mode,\n // so a configured `api_key` still reaches the CLI.\n omit_env: SEAT_CREDENTIAL_VARS,\n ...(binary !== undefined && binary.length > 0 ? { binary } : {}),\n ...(auth_mode === 'api_key' && env[ANTHROPIC_KEY_VAR] !== undefined\n ? { api_key: env[ANTHROPIC_KEY_VAR] }\n : {}),\n },\n };\n // A run may select a URL-taking provider for the builder, the critic, or both\n // (even two different ones). The critic's goes in first, so a critic-only\n // engine (the dry-run canary's) gets the critic's URL, and on a provider both\n // seats share, the builder's URL wins.\n if (takes_seat_url(options.critic_provider)) {\n Object.assign(\n providers,\n seat_provider_config(options.critic_provider, options.critic_url ?? null, env),\n );\n }\n if (takes_seat_url(options.builder_provider)) {\n Object.assign(\n providers,\n seat_provider_config(options.builder_provider, options.builder_url ?? null, env),\n );\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 engine each seat's model calls go through. */\nexport type SeatEngines = { builder: Engine; critic: Engine };\n\n/** One engine per seat, shared unless it can't be. fascicle fixes one base URL\n * per provider when it builds an engine, so two seats on the same provider at\n * different URLs need two engines: the critic's is derived from the builder's\n * with `with_providers`, which keeps claude_cli, auth, and pricing and\n * overrides only the shared provider's entry. Every other pairing, including a\n * run that sets no seat URL at all, gets the one engine a run has always had. */\nexport async function create_seat_engines(options: EngineOptions): Promise<SeatEngines> {\n const env = options.env ?? process.env;\n const builder = create_volley_engine(options);\n const provider = options.critic_provider;\n if (\n provider !== options.builder_provider ||\n !takes_seat_url(provider) ||\n seat_base_url(provider, options.builder_url ?? null, env) ===\n seat_base_url(provider, options.critic_url ?? null, env)\n ) {\n return { builder, critic: builder };\n }\n try {\n const critic = builder.with_providers(\n seat_provider_config(provider, options.critic_url ?? null, env),\n );\n return { builder, critic };\n } catch (err) {\n // Nothing has run on the builder's engine yet; release it, not leak it.\n await builder.dispose();\n throw err;\n }\n}\n\n/** Dispose each distinct seat engine once. Both disposals start together, so\n * one that fails doesn't keep the other from running. */\nexport async function dispose_seat_engines(engines: SeatEngines): Promise<void> {\n const distinct =\n engines.critic === engines.builder ? [engines.builder] : [engines.builder, engines.critic];\n await Promise.all(distinct.map((engine) => engine.dispose()));\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 { command_env } from './engine.js';\nimport { config_error } from './types.js';\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 env: command_env(process.env),\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/**\n * The commit a critique's change is measured from: `rev` (`--baseline`)\n * resolved in `root`, so the change is everything that differs from it,\n * committed or not, untracked files included. With no revision named it's\n * HEAD, so the uncommitted and untracked edits are the change, and, as for a\n * run, null where there's no repository or no commit yet. A named revision\n * that isn't a commit there, or one named where there's no repository, is a\n * config error.\n */\nexport function resolve_baseline(root: string, rev: string | undefined): string | null {\n if (rev === undefined) return capture_baseline(root);\n if (!in_git_repo(root)) {\n throw config_error(`--baseline needs the workspace to be a git repository: ${root}`);\n }\n // `--end-of-options` keeps a revision that starts with `-` from reading as a flag.\n const resolved = git(root, ['rev-parse', '--verify', '--quiet', '--end-of-options', `${rev}^{commit}`]);\n const sha = resolved.stdout.trim();\n if (resolved.status !== 0 || sha.length === 0) {\n throw config_error(`--baseline names no commit in ${root}: ${rev}`);\n }\n return sha;\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, excluded_dir: string | null): boolean {\n if (excluded_dir !== null && path.startsWith(`${excluded_dir}/`)) return true;\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 /** A state root inside `root`, relative to it (`state_root_within`): the\n * harness's files, never the builder's. */\n excluded_dir?: string | null;\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 excluded_dir = options.excluded_dir ?? null;\n const seen = new Set<string>();\n const files: ChangedFile[] = [];\n for (const change of [...tracked, ...untracked]) {\n if (excluded(change.path, excluded_dir) || 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 * Whether volley is running inside its sandbox container. A leaf, so the\n * config resolution, the preflight, and the run-config signing can all ask\n * without importing one another.\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: Readonly<Record<string, string | undefined>>): boolean {\n const value = env['VOLLEY_CONTAINED'];\n return value === '1' || value === 'true';\n}\n","/**\n * Which run configs a host-side resume may trust. A resume runs what a run's\n * `config.json` says: its check, a shell command, and its seats, permission\n * mode and prompt included. Inside the sandbox the builder runs arbitrary\n * commands with write access to its own run's state, so a contained run's\n * config is the builder's to rewrite, and resuming it on the host would run\n * whatever the builder left there.\n *\n * So volley on the host signs each config it writes, an HMAC under a key of\n * this machine's that never enters the container, and a host-side resume\n * trusts only a config whose signature holds. Inside the sandbox nothing is\n * signed, since the key isn't there and one made there would be in the\n * builder's reach, so a contained run's config never carries a signature the\n * host accepts, and the builder can't forge one without the key.\n */\nimport { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport { detect_containment } from './containment.js';\n\ntype Env = Readonly<Record<string, string | undefined>>;\n\n/** Prefixed to what is signed, so a signature over a run config can't pass for\n * one over anything else under the same key. */\nconst DOMAIN = 'volley run config v1\\n';\n\n/** Where this machine's key lives: `$XDG_CONFIG_HOME/volley/run-key`, else\n * `~/.config/volley/run-key`, outside every state root, so a container a run\n * root is mounted into still can't read it. A relative `XDG_CONFIG_HOME` is\n * ignored, as the XDG spec says. */\nexport function trust_key_path(env: Env, home: string = homedir()): string {\n const xdg = env['XDG_CONFIG_HOME'];\n const base = xdg !== undefined && isAbsolute(xdg) ? xdg : join(home, '.config');\n return join(base, 'volley', 'run-key');\n}\n\nfunction error_code(err: unknown): unknown {\n return (err as { code?: unknown }).code;\n}\n\n/** The key as stored, or null when there is none or it isn't one. */\nfunction read_key(path: string): Buffer | null {\n try {\n const hex = readFileSync(path, 'utf8').trim();\n return /^[0-9a-f]{64}$/.test(hex) ? Buffer.from(hex, 'hex') : null;\n } catch {\n return null;\n }\n}\n\n/** The key, created on first use: 32 random bytes in a file only its user can\n * read, in a directory only its user can enter. Two runs that start together\n * race to create it; the loser reads the winner's. */\nfunction machine_key(env: Env): Buffer | null {\n const path = trust_key_path(env);\n const existing = read_key(path);\n if (existing !== null) return existing;\n try {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, `${randomBytes(32).toString('hex')}\\n`, { flag: 'wx', mode: 0o600 });\n } catch (err) {\n if (error_code(err) !== 'EEXIST') return null;\n }\n return read_key(path);\n}\n\nfunction hmac(key: Buffer, config_text: string): string {\n return createHmac('sha256', key).update(DOMAIN).update(config_text).digest('hex');\n}\n\n/** This machine's signature over a run's `config.json` text, or null where\n * there's none to give: inside the sandbox, or when the key can't be read or\n * created. */\nexport function sign_config(config_text: string, env: Env = process.env): string | null {\n if (detect_containment(env)) return null;\n const key = machine_key(env);\n return key === null ? null : hmac(key, config_text);\n}\n\n/** Does `signature` hold for `config_text` under this machine's key? Never\n * creates the key: with none there's nothing it could hold under. */\nexport function config_signed(\n config_text: string,\n signature: string | null,\n env: Env = process.env,\n): boolean {\n if (signature === null) return false;\n const key = read_key(trust_key_path(env));\n if (key === null) return false;\n const expected = Buffer.from(hmac(key, config_text), 'hex');\n const given = Buffer.from(signature.trim(), 'hex');\n return given.length === expected.length && timingSafeEqual(given, expected);\n}\n","/**\n * Workspace lifecycle: run-state initialization, stale-run\n * backup rotation, path helpers, and optional git checkpoints.\n */\nimport { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { command_env } from './engine.js';\nimport { sign_config } from './trust.js';\nimport { check_error, config_error } from './types.js';\nimport type { ResolvedConfig } from './types.js';\n\n/** A run id names the run's `volley/<run id>` branch and its state directory,\n * so it is held to what both take without quoting: letters, digits, `-`, and\n * `_`, starting with a letter or digit, so it never reads as an option and\n * never climbs out of the directory it names. */\nexport const RUN_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;\n\n/** The root each run's state sits under when `--state-dir` names none:\n * `$XDG_STATE_HOME/volley`, else `<home>/.local/state/volley`. A relative\n * `XDG_STATE_HOME` is ignored, as the XDG spec says. `home` is the host's by\n * default; the sandbox passes its container's to spell the same root inside. */\nexport function default_state_root(\n env: Readonly<Record<string, string | undefined>>,\n home: string = homedir(),\n): string {\n const xdg = env['XDG_STATE_HOME'];\n const base = xdg !== undefined && isAbsolute(xdg) ? xdg : join(home, '.local', 'state');\n return join(base, 'volley');\n}\n\n/** What locates a run's state, as a structural subset of `ResolvedConfig` so a\n * resume can find a run before it has a whole config. */\nexport type StateLocation = Pick<ResolvedConfig, 'workspace' | 'state_dir' | 'run_id'>;\n\n/** Where a run keeps its config, summary, trajectory, feedback, verdict, and\n * iterations: `<state_dir>/<run_id>/` under its state root, or, in the layout\n * older runs used (`state_dir` null), `<workspace>/.volley/`. */\nexport function run_state_dir(run: StateLocation): string {\n return run.state_dir === null ? join(run.workspace, '.volley') : join(run.state_dir, run.run_id);\n}\n\nexport function state_path(run: StateLocation, ...parts: string[]): string {\n return join(run_state_dir(run), ...parts);\n}\n\nexport function iteration_dir(run: StateLocation, iteration: number): string {\n return state_path(run, 'iterations', String(iteration).padStart(3, '0'));\n}\n\n/** A state root that sits inside `root` (the build root), as the path from\n * there in git's `/`-separated vocabulary, or null when it sits outside. A\n * root inside the tree would otherwise pass for the builder's work: listed in\n * the changes the critic reads, and committed by every `--git` checkpoint.\n * The legacy `.volley/` (`state_dir` null) is excluded by name already. */\nexport function state_root_within(root: string, state_dir: string | null): string | null {\n if (state_dir === null) return null;\n const path = relative(resolve(root), resolve(state_dir));\n if (path === '' || path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path)) return null;\n return path.split(sep).join('/');\n}\n\n/** Filesystem-safe timestamp for `.bak.<stamp>` rotation names. Shared by the\n * run-state 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 state directory aside (a prior\n * `.volley/` becomes `.volley.bak.<stamp>`), then create the directory tree.\n * Under a state root each run has a directory of its own, so only a reused\n * `--run-id` ever finds one to rotate. An empty one is used as it is: that is\n * what a contained run is handed when its run directory is the mount, which\n * can't be renamed. Resume runs skip rotation (`preserve: true`). */\nexport function initialize_run_state(\n run: StateLocation,\n options: { preserve?: boolean } = {},\n): void {\n const dir = run_state_dir(run);\n if (existsSync(dir) && options.preserve !== true && readdirSync(dir).length > 0) {\n renameSync(dir, `${dir}.bak.${backup_stamp()}`);\n }\n if (run.state_dir !== null && !existsSync(run.state_dir)) {\n // Trajectories hold prompts and tool output, so a root volley creates is\n // its user's alone, as the XDG spec asks of a state directory.\n mkdirSync(run.state_dir, { recursive: true, mode: 0o700 });\n }\n mkdirSync(join(dir, 'iterations'), { recursive: true });\n}\n\n/** Beside a run's `config.json`: this machine's signature over it\n * (`./trust.ts`), which a host-side resume checks before it trusts the\n * config. */\nexport const CONFIG_SIGNATURE = 'config.sig';\n\n/** Record the run's config, signed when volley runs on the host. Returns\n * whether it was signed: inside the sandbox it never is, and on the host only\n * when the machine's key can't be read or created. A signature a reused run\n * directory held from before is removed rather than left to vouch for this\n * config. */\nexport function write_resolved_config(\n config: ResolvedConfig,\n env: Readonly<Record<string, string | undefined>> = process.env,\n): boolean {\n const record = {\n version: config.version,\n run_id: config.run_id,\n started_at: config.started_at,\n mode: config.mode,\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_url: config.builder_url,\n builder_max_steps: config.builder_max_steps,\n builder_max_tool_calls: config.builder_max_tool_calls,\n builder_max_output_tokens: config.builder_max_output_tokens,\n builder_trim_history: config.builder_trim_history,\n critic_model: config.critic_model,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\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 state_dir: config.state_dir,\n workspace: config.workspace,\n };\n const text = `${JSON.stringify(record, null, 2)}\\n`;\n writeFileSync(state_path(config, 'config.json'), text);\n const signature = sign_config(text, env);\n if (signature === null) {\n rmSync(state_path(config, CONFIG_SIGNATURE), { force: true });\n return false;\n }\n writeFileSync(state_path(config, CONFIG_SIGNATURE), `${signature}\\n`);\n return true;\n}\n\n/** The identity volley's own commits fall back to. git won't commit without a\n * name and an email, and the sandbox image carries no git config, so inside\n * it a checkpoint or a worktree's salvage commit failed outright; a machine\n * never set up for git can be the same. `.invalid` is reserved, so the email\n * can't reach anyone. */\nconst FALLBACK_IDENTITY: ReadonlyArray<readonly [string, string]> = [\n ['user.name', 'volley'],\n ['user.email', 'volley@volley.invalid'],\n];\n\n/** The `-c` flags that give a commit in `cwd` the fallback identity for each\n * part git has no value for. One the repo or the user configured wins, and so\n * does a `GIT_AUTHOR_*` or `GIT_COMMITTER_*` variable, which git ranks above\n * any config. Put them ahead of the subcommand. */\nexport function commit_identity(cwd: string): string[] {\n return FALLBACK_IDENTITY.flatMap(([key, value]) => {\n const set = spawnSync('git', ['config', '--get', key], {\n cwd,\n env: command_env(process.env),\n encoding: 'utf8',\n });\n return set.status === 0 && set.stdout.trim() !== '' ? [] : ['-c', `${key}=${value}`];\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. `excluded_dir` (from `state_root_within`) keeps a state root inside the\n * tree out of the commit; `:/` keeps the rest of the staging repo-wide, as a\n * bare `git add -A` is, and `literal` reads the path as written, wildcards and\n * all.\n */\nexport function git_checkpoint(root: string, message: string, excluded_dir: string | null = null): 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 pathspec = excluded_dir === null ? [] : ['--', ':/', `:(exclude,literal)${excluded_dir}`];\n const add = spawnSync('git', ['add', '-A', ...pathspec], { cwd: root, env: command_env(process.env) });\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_identity(root), 'commit', '-m', message, '--no-verify'], {\n cwd: root,\n env: command_env(process.env),\n });\n // Exit 1 with \"nothing to commit\" is a no-op iteration, not a failure. So is\n // \"nothing added to commit\", which git says instead when the only untracked\n // files left are the state root `excluded_dir` kept out.\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 && !/nothing (?:added )?to commit/.test(out)) {\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 env: command_env(process.env),\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_identity(workspace), 'commit', '-m', message, '--no-verify'], {\n cwd: workspace,\n env: command_env(process.env),\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 * Config resolution: merge CLI flags over an optional config file\n * over defaults, expand `@file` references, validate, and produce the\n * immutable `ResolvedConfig` that the run's `config.json` records.\n */\nimport { accessSync, constants, existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, 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 { detect_containment } from './containment.js';\nimport { openrouter_api_key, SEAT_URL_PROVIDERS, takes_seat_url } from './engine.js';\nimport { config_error } from './types.js';\nimport { default_state_root, RUN_ID_PATTERN } from './workspace.js';\nimport type {\n RunMode,\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_BUILDER_MAX_TOOL_CALLS = 1;\nexport const DEFAULT_BUILDER_MAX_OUTPUT_TOKENS = 16384;\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 'openrouter',\n];\n\n/** Builder providers that drive their model through volley's own tool loop —\n * a real `bash` (write + exec), wherever the model runs. Refused unless volley\n * is running inside a container (the correct blast-radius default) or the\n * operator explicitly opts out; `claude_cli` has its own permission model and\n * is exempt. */\nconst TOOL_LOOP_BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'ollama',\n 'lmstudio',\n 'openrouter',\n];\n\nconst CRITIC_PROVIDERS: ReadonlyArray<CriticProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n 'openrouter',\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 /** What happens to a tool-loop builder with nothing between its commands\n * and the host (`unguarded_builder`): the CLI `refuse`s it, the default,\n * while under `volley acp` each of its commands `ask`s a person first, which\n * takes the container's place. */\n uncontained_builder?: 'refuse' | 'ask';\n /** Where the run's state goes, in place of what the config says: `volley\n * resume` passes the root it found the run under, or null for a run an older\n * volley kept in the workspace's `.volley/`, which resumes there. */\n state_dir?: string | null;\n /** A run (the default), or a critique, which has no builder or loop. */\n mode?: RunMode;\n};\n\n/** What only a builder, or the loop around it, uses, with the flag that sets\n * each: a critique has no use for any of them, so naming one is an error\n * rather than something quietly ignored. */\nconst CRITIQUE_REFUSED: ReadonlyArray<readonly [keyof VolleyConfig, string]> = [\n ['builder_model', '--builder-model'],\n ['builder_provider', '--builder-provider'],\n ['builder_url', '--builder-url'],\n ['builder_max_steps', '--builder-max-steps'],\n ['builder_max_tool_calls', '--builder-max-tool-calls'],\n ['builder_max_output_tokens', '--builder-max-output-tokens'],\n ['builder_trim_history', '--builder-trim-history'],\n ['builder_permission_mode', '--builder-permission-mode'],\n ['allow_unsandboxed_builder', '--allow-unsandboxed-builder'],\n ['sandbox_image', '--sandbox-image'],\n ['max_iterations', '--max-iterations'],\n ['max_cost_usd', '--max-cost-usd'],\n ['git_checkpoints', '--git'],\n ['worktree', '--worktree'],\n ['discard_worktree', '--discard-worktree'],\n ['fail_on_gate_edit', '--fail-on-gate-edit'],\n];\n\nfunction refuse_builder_settings(raw: VolleyConfig): void {\n for (const [field, flag] of CRITIQUE_REFUSED) {\n if (raw[field] !== undefined && raw[field] !== false) {\n throw config_error(\n `volley critique refuses ${flag} (${field}): a critique runs no builder and no loop`,\n );\n }\n }\n}\n\n/** A tool-loop builder's count: its step cap, its tool calls per turn, or\n * its output tokens per turn, with the value it takes when nothing sets it. */\ntype BuilderCount<fallback extends number | null = number> = {\n flag: string;\n env_var: string;\n fallback: fallback;\n};\n\nconst BUILDER_MAX_STEPS: BuilderCount = {\n flag: '--builder-max-steps',\n env_var: 'VOLLEY_BUILDER_MAX_STEPS',\n fallback: DEFAULT_BUILDER_MAX_STEPS,\n};\n\nconst BUILDER_MAX_TOOL_CALLS: BuilderCount = {\n flag: '--builder-max-tool-calls',\n env_var: 'VOLLEY_BUILDER_MAX_TOOL_CALLS',\n fallback: DEFAULT_BUILDER_MAX_TOOL_CALLS,\n};\n\n/** The builders whose turns are capped when nothing sets a cap: the local\n * ones, where nothing else bounds a turn. Ollama's MLX runner lets an unset\n * `num_predict` run to the model's trained context less the prompt, which is\n * how one qwen3.8 turn spent 30,847 tokens thinking. A hosted model on\n * OpenRouter has its own output limit, and a request for more than it allows\n * can be refused, so it's capped only when asked. */\nconst CAPPED_BY_DEFAULT: ReadonlyArray<BuilderProvider> = ['ollama', 'lmstudio'];\n\n/** The output cap's flag and env var, and its default for `provider`: 16k\n * tokens on a local builder, else the provider's own limit (null). */\nfunction builder_max_output_tokens_count(provider: BuilderProvider): BuilderCount<number | null> {\n return {\n flag: '--builder-max-output-tokens',\n env_var: 'VOLLEY_BUILDER_MAX_OUTPUT_TOKENS',\n fallback: CAPPED_BY_DEFAULT.includes(provider) ? DEFAULT_BUILDER_MAX_OUTPUT_TOKENS : null,\n };\n}\n\n/** The history trim's size: off unless something sets it. */\nconst BUILDER_TRIM_HISTORY: BuilderCount<null> = {\n flag: '--builder-trim-history',\n env_var: 'VOLLEY_BUILDER_TRIM_HISTORY',\n fallback: null,\n};\n\n/** A builder count's flag or config value wins over its env var, which wins\n * over the default, and either must be a positive integer. Local builder\n * only; ignored by the `claude_cli` arm. */\nfunction resolve_builder_count<fallback extends number | null>(\n value: number | undefined,\n env: Record<string, string | undefined>,\n count: BuilderCount<fallback>,\n): number | fallback {\n if (value !== undefined) return positive_count(value, value, count);\n const env_value = env[count.env_var];\n if (env_value !== undefined && env_value !== '') {\n return positive_count(Number(env_value), env_value, count);\n }\n return count.fallback;\n}\n\nfunction positive_count(\n value: number,\n original: unknown,\n count: Pick<BuilderCount, 'flag' | 'env_var'>,\n): number {\n if (!Number.isInteger(value) || value < 1) {\n throw config_error(\n `${count.flag} / ${count.env_var} 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 a tool-loop builder refused unless\n * contained. */\nfunction resolve_allow_unsandboxed_builder(\n raw: Pick<VolleyConfig, 'allow_unsandboxed_builder'>,\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/** A seat's own model server URL (`--builder-url` / `--critic-url`), trimmed,\n * or null when unset; an empty value counts as unset, as it does for the env\n * vars it overrides. Only a provider volley reaches at a base URL takes one: on\n * a `claude_cli` seat the setting would silently do nothing, so it is refused.\n * The URL must be plain http(s), with no credentials, query, or fragment:\n * volley appends API paths to it for prewarm and the context probe, which a\n * query or fragment would break, and it is persisted and printed, which\n * credentials must never be. */\nfunction resolve_seat_url(\n seat: 'builder' | 'critic',\n value: unknown,\n provider: BuilderProvider | CriticProvider,\n): string | null {\n const setting = `--${seat}-url (${seat}_url)`;\n if (value === undefined || value === null) return null;\n if (typeof value !== 'string') {\n throw config_error(`${setting} must be a URL string; got a ${typeof value}`);\n }\n const url = value.trim();\n if (url === '') return null;\n if (!takes_seat_url(provider)) {\n const url_providers = new Intl.ListFormat('en', { type: 'disjunction' }).format(\n SEAT_URL_PROVIDERS,\n );\n throw config_error(\n `${setting} applies only to a ${seat} on ${url_providers}; ` +\n `${seat}-provider is ${provider}`,\n );\n }\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw config_error(`${setting} must be an http(s) URL; got: ${url}`);\n }\n // Checked first, so no later message echoes the credentials back.\n if (parsed.username !== '' || parsed.password !== '') {\n throw config_error(`${setting} must not carry credentials`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw config_error(`${setting} must be an http(s) URL; got: ${url}`);\n }\n if (parsed.search !== '' || parsed.hash !== '') {\n throw config_error(`${setting} must not carry a query or fragment; got: ${url}`);\n }\n return url;\n}\n\n/** `--state-dir` (`state_dir`): the root each run's state sits under at\n * `<root>/<run_id>/`, resolved against `cwd` so a resumed run finds the same\n * place. Unset, or empty as a seat URL may be, it's the default root,\n * `$XDG_STATE_HOME/volley`, else `~/.local/state/volley`: outside the\n * workspace, where no check that reads every file can trip over the run's own\n * feedback. */\nfunction resolve_state_dir(\n value: unknown,\n cwd: string,\n env: Record<string, string | undefined>,\n): string {\n if (value === undefined || value === null) return default_state_root(env);\n if (typeof value !== 'string') {\n throw config_error(`--state-dir (state_dir) must be a path string; got a ${typeof value}`);\n }\n const path = value.trim();\n return path === '' ? default_state_root(env) : resolve(cwd, path);\n}\n\nfunction is_writable_dir(path: string): boolean {\n try {\n if (!statSync(path).isDirectory()) return false;\n accessSync(path, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** The run's state directory must be one volley can write: the directory\n * itself when it's there, as a contained run's mount is, else the nearest\n * directory above it, where volley creates it. Checked before any spend,\n * because otherwise the run dies as it starts on a raw EROFS or EACCES. Inside\n * the sandbox the root filesystem is read-only, so that is what an unmounted\n * run directory looks like, and the message says what to mount. */\nfunction validate_run_state_dir(dir: string, contained: boolean): void {\n let existing = dir;\n while (!existsSync(existing) && dirname(existing) !== existing) existing = dirname(existing);\n if (is_writable_dir(existing)) return;\n throw config_error(\n contained\n ? `run state directory not writable: ${dir}. Inside the sandbox, mount the run's own host ` +\n `directory there (sandbox_run_args run_state, or -v <root>/<run id>:${dir}), created on the ` +\n 'host first, and pass volley the same --run-id; or point --state-dir at a writable mount'\n : `run state directory not writable: ${dir}. Point --state-dir at a directory volley can write`,\n );\n}\n\n/** Whether a tool-loop builder's commands would reach the host with nothing in\n * between: volley isn't contained, and the operator hasn't opted out with\n * `--allow-unsandboxed-builder` or `VOLLEY_ALLOW_UNSANDBOXED_BUILDER`. */\nexport function unguarded_builder(\n raw: Pick<VolleyConfig, 'allow_unsandboxed_builder'>,\n env: Record<string, string | undefined>,\n): boolean {\n return !detect_containment(env) && !resolve_allow_unsandboxed_builder(raw, env);\n}\n\n/** A caller's run id, held to `RUN_ID_PATTERN`; none gets a fresh UUID. */\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 // A critique runs no builder, so it reads nothing a run reads for one: the\n // builder's settings are refused, its env vars go unread, and its seat keeps\n // the defaults.\n const critique = options.mode === 'critique';\n if (critique) refuse_builder_settings(raw);\n const builder_env = critique ? {} : env;\n\n const has_prompt = typeof raw.prompt === 'string' && raw.prompt.length > 0;\n if (!has_prompt && !critique) {\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 = has_prompt ? expand_at_file(raw.prompt, cwd) : '';\n const criteria = expand_at_file(raw.criteria, cwd);\n\n const max_iterations = raw.max_iterations ?? (critique ? 1 : 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 tool-loop builder gets a real `bash` (write + exec), local\n // model or hosted, so refuse it — before any model spend — unless volley is\n // running *inside* a container (the correct blast-radius default) or the\n // operator explicitly opts out to run uncontained on the host. Under acp,\n // a person approves each command instead, so nothing is refused here.\n const allow_unsandboxed_builder = resolve_allow_unsandboxed_builder(raw, builder_env);\n const contained = detect_containment(env);\n if (\n TOOL_LOOP_BUILDER_PROVIDERS.includes(builder_provider) &&\n options.uncontained_builder !== 'ask' &&\n unguarded_builder(raw, builder_env)\n ) {\n throw config_error(\n `builder-provider '${builder_provider}' runs volley's tool loop 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_count(raw.builder_max_steps, builder_env, BUILDER_MAX_STEPS);\n const builder_max_tool_calls = resolve_builder_count(\n raw.builder_max_tool_calls,\n builder_env,\n BUILDER_MAX_TOOL_CALLS,\n );\n const builder_max_output_tokens = resolve_builder_count(\n raw.builder_max_output_tokens,\n builder_env,\n builder_max_output_tokens_count(builder_provider),\n );\n const builder_trim_history = resolve_builder_count(\n raw.builder_trim_history,\n builder_env,\n BUILDER_TRIM_HISTORY,\n );\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 const builder_url = resolve_seat_url('builder', raw.builder_url, builder_provider);\n const critic_url = resolve_seat_url('critic', raw.critic_url, critic_provider);\n\n // An openrouter seat sends `OPENROUTER_API_KEY`, so an unset key is refused\n // here, naming the variable, before any work rather than at the first call.\n if (builder_provider === 'openrouter' || critic_provider === 'openrouter') {\n openrouter_api_key(env);\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' && !critique ? '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, builder_env);\n const state_dir =\n options.state_dir !== undefined ? options.state_dir : resolve_state_dir(raw.state_dir, cwd, env);\n // Each run's folder would land among the workspace's own files, where no\n // exclusion can tell earlier runs' state from the builder's work.\n if (state_dir === workspace) {\n throw config_error(`--state-dir (state_dir) can't be the workspace itself: ${workspace}`);\n }\n const run_id = resolve_run_id(options.run_id);\n // A legacy `.volley/` lives in the workspace, already checked writable.\n if (state_dir !== null) validate_run_state_dir(join(state_dir, run_id), contained);\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 mode: critique ? 'critique' : 'run',\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_url,\n builder_max_steps,\n builder_max_tool_calls,\n builder_max_output_tokens,\n builder_trim_history,\n allow_unsandboxed_builder,\n critic_model: raw.critic_model ?? DEFAULT_CRITIC_MODEL,\n critic_provider,\n critic_url,\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 state_dir,\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 * 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 * The tool-loop builder's step countdown. A model that explores first can\n * spend its whole budget before it verifies: in volley-41806476 the builder's\n * 50th step was a `bash` call fascicle refused, and the half-fixed tree went to\n * the check and critic. So for the last few steps of a session, each turn's\n * request ends with a note of how many are left and what to do with them.\n *\n * The note goes in through fascicle's `prepare_step`, which reshapes only what\n * one turn sends, so the transcript stays as the model wrote it, and the note\n * sits after everything a local runtime has cached, so its cached prefix holds.\n */\nimport type { PrepareStepHook } from 'fascicle';\n\n/** How many of a session's last steps carry the countdown: five, or a tenth\n * of a long budget, but never more than half of it, so a short session still\n * starts without one. */\nexport function countdown_window(max_steps: number): number {\n return Math.min(Math.max(5, Math.ceil(max_steps / 10)), Math.floor(max_steps / 2));\n}\n\n/** The note for a turn with `steps_left` steps left, this one included.\n * `check` names how to run the check. On the last step fascicle runs only a\n * call that ends the session, which for the builder is `finish`. */\nexport function countdown_note(steps_left: number, check: string): string {\n if (steps_left <= 1) {\n return (\n '[volley] This is the last step of this session, and only finish runs on it. ' +\n \"Call finish now, with a summary that says what's done and what isn't verified.\"\n );\n }\n return (\n `[volley] ${String(steps_left)} steps left in this session, this one included, ` +\n 'and on the last one only finish runs. ' +\n `If you haven't run ${check} since your last edit, run it now, ` +\n 'then fix what it reports or call finish.'\n );\n}\n\n/** The `prepare_step` hook that adds the countdown to a session of\n * `max_steps` steps. */\nexport function step_countdown(max_steps: number, check: string): PrepareStepHook {\n const window = countdown_window(max_steps);\n return ({ step_index, messages }) => {\n const steps_left = max_steps - step_index;\n if (steps_left > window) return undefined;\n return {\n messages: [...messages, { role: 'user', content: countdown_note(steps_left, check) }],\n };\n };\n}\n","/**\n * The tool-loop builder's one `prepare_step` slot, shared by the hooks that\n * reshape a turn's request: the history trim, then the step countdown, whose\n * note goes last so it sits after everything a local runtime has cached.\n */\nimport type { PrepareStepHook } from 'fascicle';\n\n/** One hook that runs `hooks` in order, each on the request the one before it\n * made, and reports no change when none of them made one. */\nexport function compose_prepare_steps(hooks: ReadonlyArray<PrepareStepHook>): PrepareStepHook {\n return async ({ step_index, messages }) => {\n let request = messages;\n let changed = false;\n for (const hook of hooks) {\n const prepared = await hook({ step_index, messages: request });\n if (prepared?.messages !== undefined) {\n request = prepared.messages;\n changed = true;\n }\n }\n return changed ? { messages: request } : undefined;\n };\n}\n","/**\n * Trimming a long tool-loop session's history (#7). Every turn resends the\n * whole session, every earlier `read_file` result included, even for files the\n * builder has rewritten since, so a long local session's requests grow\n * linearly and each turn's latency grows with them: volley-41806476's input\n * went from 2.6k to 57k tokens over 50 steps, and its turns from 3 s to as\n * much as 120 s.\n *\n * Above a size the operator sets (`--builder-trim-history`), each turn's\n * request replaces the older tool results with one-line stubs: a read of a\n * file a later call wrote, edited, or read whole says so, and any other result\n * names its call and size. The last `TRIM_KEEP_TURNS` turns, every assistant\n * and user message, every failed call's result, and anything short stay as\n * they are. It goes in through fascicle's `prepare_step`, which reshapes only\n * what one turn sends, so the transcript stays as the model wrote it.\n *\n * A local runtime reuses the KV cache for the prefix a request shares with\n * the last one, and rewriting an earlier message breaks that prefix, so the\n * window is prefilled again. So the trim moves in coarse steps: it stubs\n * everything before a turn boundary, boundaries fall every\n * `TRIM_STRIDE_TURNS` turns, and the boundary moves on only when the trimmed\n * request has grown past the size again. Between moves each request starts\n * with the same bytes as the last, since a stub depends only on what came\n * before its boundary and never on the step. The trim keeps no state:\n * `trim_cutoff` works the boundary out again from the transcript each turn.\n */\nimport { posix } from 'node:path';\nimport type { Message, PrepareStepHook } from 'fascicle';\n\n/** A rough token count per character: the hook sees no token counts, so a\n * request's size is estimated from its text. */\nconst CHARS_PER_TOKEN = 4;\n\n/** Turns at the end of a session whose tool results are never stubbed. */\nexport const TRIM_KEEP_TURNS = 6;\n\n/** How many turns apart the boundaries the trim may cut at fall. */\nexport const TRIM_STRIDE_TURNS = 8;\n\n/** Results this short are kept, since a stub would save next to nothing. */\nexport const STUB_MIN_CHARS = 200;\n\n/** What a message costs beyond its text: its role and framing. */\nconst MESSAGE_OVERHEAD_TOKENS = 8;\n\n/** The calls that change a file, whose success makes an earlier read of it\n * stale. Both volley's tools and fascicle's ACP tools use these names and a\n * `path` input. */\nconst FILE_WRITERS: ReadonlySet<string> = new Set(['write_file', 'edit_file']);\n\nconst COMMAND_TOOLS: ReadonlySet<string> = new Set(['bash', 'run_command']);\n\nfunction message_chars(message: Message): number {\n if (typeof message.content === 'string') return message.content.length;\n let chars = 0;\n for (const part of message.content) {\n if (part.type === 'text' || part.type === 'reasoning') chars += part.text.length;\n else if (part.type === 'tool_call') chars += part.name.length + (JSON.stringify(part.input) ?? '').length;\n }\n return chars;\n}\n\n/** A request's size in tokens, estimated from its characters. */\nexport function estimate_tokens(messages: ReadonlyArray<Message>): number {\n let tokens = 0;\n for (const message of messages) {\n tokens += Math.ceil(message_chars(message) / CHARS_PER_TOKEN) + MESSAGE_OVERHEAD_TOKENS;\n }\n return tokens;\n}\n\n/** What a tool call asked for, as far as the trim reads it. */\ntype CallInput = { path: string | null; whole: boolean };\n\nfunction call_input(input: unknown): CallInput {\n if (typeof input !== 'object' || input === null) return { path: null, whole: true };\n const fields = input as Record<string, unknown>;\n const path = typeof fields['path'] === 'string' ? posix.normalize(fields['path']) : null;\n // An ACP read names a range with `offset` or `limit`; volley's never does.\n return { path, whole: fields['offset'] === undefined && fields['limit'] === undefined };\n}\n\n/** Each tool call's input, by call id, from the assistant messages in\n * `messages`. */\nfunction call_inputs(messages: ReadonlyArray<Message>): Map<string, CallInput> {\n const inputs = new Map<string, CallInput>();\n for (const message of messages) {\n if (message.role !== 'assistant' || typeof message.content === 'string') continue;\n for (const part of message.content) {\n if (part.type === 'tool_call') inputs.set(part.id, call_input(part.input));\n }\n }\n return inputs;\n}\n\ntype ToolMessage = Extract<Message, { role: 'tool' }>;\n\n/** A later call on a path that makes an earlier read of it stale. */\ntype Supersession = { tool: string; changed: boolean };\n\n/** Whether this result is one whose call changed its file or read it whole. */\nfunction supersession_of(message: ToolMessage, input: CallInput | undefined): Supersession | null {\n if (input === undefined || input.path === null || message.is_error === true) return null;\n if (FILE_WRITERS.has(message.name)) {\n return message.content.startsWith('error:') ? null : { tool: message.name, changed: true };\n }\n if (message.name === 'read_file' && input.whole) return { tool: 'read_file', changed: false };\n return null;\n}\n\nfunction exit_code_of(content: string): number | null {\n try {\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed === 'object' && parsed !== null) {\n const code = (parsed as Record<string, unknown>)['exit_code'];\n if (typeof code === 'number') return code;\n }\n } catch {\n // Not JSON: a command result without an exit code to keep.\n }\n return null;\n}\n\nfunction stub(message: ToolMessage, input: CallInput | undefined, later: Supersession | undefined): string {\n const size = `${String(message.content.length)} chars`;\n if (later !== undefined && input !== undefined && input.path !== null) {\n return later.changed\n ? `[volley] read_file ${input.path} (${size}) elided: a later ${later.tool} changed this file. Read it again for its current content.`\n : `[volley] read_file ${input.path} (${size}) elided: it was read again later in this session.`;\n }\n const exit_code = COMMAND_TOOLS.has(message.name) ? exit_code_of(message.content) : null;\n const detail = exit_code === null ? size : `${size}, exit ${String(exit_code)}`;\n return `[volley] ${message.name} output (${detail}) elided from an earlier turn. Run it again if you need it.`;\n}\n\n/**\n * The request with every tool result before `cutoff` that is long enough to\n * matter and didn't fail replaced by a stub. Every message keeps its place,\n * role, id, and name. A stub reads only what comes before `cutoff`, so the\n * same transcript prefix always gives the same bytes.\n */\nexport function trim_view(messages: ReadonlyArray<Message>, cutoff: number): Message[] {\n const window = messages.slice(0, cutoff);\n const inputs = call_inputs(window);\n // Walk back from the boundary so each read meets the nearest later call on\n // its path.\n const next_on_path = new Map<string, Supersession>();\n const later_for = new Map<number, Supersession>();\n for (let i = window.length - 1; i >= 0; i -= 1) {\n const message = window[i];\n if (message?.role !== 'tool') continue;\n const input = inputs.get(message.tool_call_id);\n const path = input?.path ?? null;\n if (path === null) continue;\n if (message.name === 'read_file') {\n const later = next_on_path.get(path);\n if (later !== undefined) later_for.set(i, later);\n }\n const supersedes = supersession_of(message, input);\n if (supersedes !== null) next_on_path.set(path, supersedes);\n }\n return messages.map((message, i) => {\n if (i >= cutoff || message.role !== 'tool' || message.is_error === true) return message;\n if (message.content.length <= STUB_MIN_CHARS) return message;\n return { ...message, content: stub(message, inputs.get(message.tool_call_id), later_for.get(i)) };\n });\n}\n\n/**\n * Where to cut this turn's request, as a message index, or null to send it\n * whole. Boundaries are the starts of turns `TRIM_STRIDE_TURNS`,\n * `2 * TRIM_STRIDE_TURNS`, and so on, short of the last `TRIM_KEEP_TURNS`.\n * The cut moves to the next boundary only while the request, trimmed at the\n * last one, is still over `threshold`. A trimmed request only grows as the\n * session goes on, so a boundary once taken is kept.\n */\nexport function trim_cutoff(messages: ReadonlyArray<Message>, threshold: number): number | null {\n const turn_starts = messages.flatMap((message, i) => (message.role === 'assistant' ? [i] : []));\n let cutoff: number | null = null;\n for (let turn = TRIM_STRIDE_TURNS; turn <= turn_starts.length - TRIM_KEEP_TURNS; turn += TRIM_STRIDE_TURNS) {\n const view = cutoff === null ? messages : trim_view(messages, cutoff);\n if (estimate_tokens(view) <= threshold) break;\n cutoff = turn_starts[turn] ?? null;\n }\n return cutoff;\n}\n\n/** The `prepare_step` hook that trims a request estimated above `threshold`\n * tokens. */\nexport function step_trim(threshold: number): PrepareStepHook {\n return ({ messages }) => {\n const cutoff = trim_cutoff(messages, threshold);\n return cutoff === null ? undefined : { messages: trim_view(messages, cutoff) };\n };\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 seat; they bury signal and blow the\n * traversal budget. The acp seats' `list_files` and `search` skip the same\n * names (`./acp_tools.ts`), so a seat sees one tree under acp and on the CLI. */\nexport const IGNORED_DIRS: ReadonlySet<string> = new Set([\n 'node_modules',\n '.git',\n '.volley',\n '.check',\n 'dist',\n '.cache',\n]);\n\n/** Which tool set a seat holds, so its prompt names the tools it has: volley's\n * own (`'volley'`), or fascicle's workspace tools under `volley acp`\n * (`'acp'`). */\nexport type ToolSet = 'volley' | 'acp';\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 * workspace the run was started on. */\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\n/** The files a read tool's optional `path` covers: the whole tree, the tree\n * under a directory, or the one file it names. A path that doesn't exist\n * throws, so the seat reads why rather than an empty result that looks like\n * \"nothing matched\". */\nfunction scoped_files(workspace: string, path: string | undefined, limit: number): WalkEntry[] {\n const root = resolve(workspace);\n if (path === undefined) return walk(root, root, limit);\n const start = contain(workspace, path);\n let is_dir: boolean;\n try {\n is_dir = statSync(start).isDirectory();\n } catch (err) {\n throw new Error(`no such file or directory: ${path}`, { cause: err });\n }\n return is_dir ? walk(root, start, limit) : [{ rel: relative(root, start), abs: start }];\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 directory or file 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 directory or file. 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 is `read_only`, so a builder's per-turn call cap doesn't count it: a\n// read changes nothing a later call in the turn could depend on.\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 read_only: true,\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 read_only: true,\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 regex = build_regex(input.pattern, input.ignore_case === true ? 'i' : '');\n const files = scoped_files(workspace, input.path, 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 read_only: true,\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 let files = scoped_files(workspace, input.path, 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 * 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 { command_env } from '../engine.js';\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. A command runs with\n * volley's environment less the seats' keys, so nothing the builder runs can\n * read the key its seat spends. `status` is null when a signal (the timeout\n * 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 env: command_env(process.env),\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 return [...read_only_tools(workspace), write_file, edit_file, bash, fetch, finish_tool()];\n}\n\n/** The terminal `finish` tool, on its own for a builder set that brings its\n * own file and command tools (`../acp_tools.ts`). */\nexport function finish_tool(): Tool {\n return {\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","/**\n * checkride runner: spawn `pnpm exec checkride --json --digest`, 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. The digest checkride writes on a red\n * run is kept beside them for the next builder, which needs a short list of\n * what to fix more than the whole of every slot's output.\n */\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { isAbsolute, join, relative, sep } from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { aborted_error } from 'fascicle';\nimport { command_env } from '../engine.js';\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\n/** How long a check's output may stay open after its shell exits, while\n * something that escaped its process group still holds it, before the reads\n * stop so the check can finish. */\nconst OUTPUT_GRACE_MS = 2000;\n\n/** Kill a check's whole process group with SIGKILL. A test runner's workers,\n * and anything the check started in the background, sit in the shell's group,\n * so killing the shell alone would leave them running. Windows has no process\n * groups to signal, so there only the shell goes. */\nfunction kill_group(proc: ChildProcess): void {\n if (proc.pid === undefined) return;\n try {\n if (process.platform === 'win32') proc.kill('SIGKILL');\n else process.kill(-proc.pid, 'SIGKILL');\n } catch {\n // The group is gone: every process in it has exited.\n }\n}\n\n/** What a check runs with beside its command. */\nexport type CheckSpawnOptions = {\n abort?: AbortSignal;\n /** The whole environment the check runs with, in place of volley's own;\n * nothing is merged in, so it carries the `PATH` the check needs. Absent,\n * the check gets volley's less the seats' keys. */\n env?: Readonly<Record<string, string>>;\n};\n\n/** Run a check to its end in a process group of its own, capturing its\n * output. The abort kills the whole group and rejects with `aborted_error`,\n * and the shell's exit kills whatever it left behind, so a stopped run leaves\n * no test workers or servers running. */\nexport function spawn_capture(\n cmd: string,\n args: string[],\n options: CheckSpawnOptions & { cwd: string },\n): Promise<SpawnCaptureResult> {\n const { abort } = options;\n if (abort?.aborted === true) return Promise.reject(new aborted_error('check aborted'));\n return new Promise((resolve_promise, reject) => {\n const proc = spawn(cmd, args, {\n cwd: options.cwd,\n env: options.env ?? command_env(process.env),\n detached: process.platform !== 'win32',\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n let grace: NodeJS.Timeout | undefined;\n const on_abort = (): void => {\n kill_group(proc);\n reject(new aborted_error('check aborted'));\n };\n const finish = (): void => {\n clearTimeout(grace);\n abort?.removeEventListener('abort', on_abort);\n };\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 finish();\n reject(check_error(`check command failed to start: ${err.message}`));\n });\n proc.on('exit', () => {\n kill_group(proc);\n grace = setTimeout(() => {\n proc.stdout.destroy();\n proc.stderr.destroy();\n }, OUTPUT_GRACE_MS);\n });\n proc.on('close', (code) => {\n finish();\n resolve_promise({ exit_code: code, stdout, stderr });\n });\n abort?.addEventListener('abort', on_abort, { once: true });\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/** Whether `path` sits under `dir`. */\nfunction within(dir: string, path: string): boolean {\n const from_dir = relative(dir, path);\n return from_dir !== '..' && !from_dir.startsWith(`..${sep}`) && !isAbsolute(from_dir);\n}\n\n/** Per failing slot: the raw artifact (`<output_file>` when present, else\n * `<slot>.stdout.txt`) in `check_dir`, a workspace's `.check/` or an archived\n * iteration's copy of it, truncated with a pointer to the file. The names come\n * from a summary the builder could have written, so a path that leaves\n * `check_dir` has no artifact, rather than putting a file from elsewhere in\n * front of a model. */\nexport function read_failing_artifacts(\n check_dir: 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(check_dir, file);\n if (!within(check_dir, path) || !existsSync(path) || !statSync(path).isFile()) {\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\n/** checkride's digest of a red run (`.check/digest.md`, written under\n * `--digest` and removed on a green one), or undefined when there is none. It\n * is capped by checkride itself, at 8 kB. */\nfunction read_digest(workspace: string): string | undefined {\n const path = join(workspace, '.check', 'digest.md');\n return existsSync(path) ? readFileSync(path, 'utf8') : undefined;\n}\n\nexport type CheckrideOpts = CheckSpawnOptions & {\n workspace: string;\n};\n\nexport async function run_checkride(opts: CheckrideOpts): Promise<CheckResult> {\n const { workspace, ...spawn_options } = opts;\n const proc = await spawn_capture('pnpm', ['exec', 'checkride', '--json', '--digest'], {\n ...spawn_options,\n cwd: workspace,\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 // Only a red run writes a digest; on a green one checkride removes any\n // stale one, and volley doesn't look.\n const digest = summary.ok ? undefined : read_digest(opts.workspace);\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(join(opts.workspace, '.check'), failing),\n summary,\n ...(digest !== undefined ? { digest } : {}),\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, CheckRunnerKind } from '../types.js';\nimport { spawn_capture } from './checkride.js';\nimport type { CheckSpawnOptions } from './checkride.js';\n\nexport type CommandCheckOpts = CheckSpawnOptions & {\n command: string;\n workspace: string;\n};\n\nexport async function run_command_check(opts: CommandCheckOpts): Promise<CheckResult> {\n const { command, workspace, ...spawn_options } = opts;\n const started = Date.now();\n const proc = await spawn_capture('sh', ['-c', command], { ...spawn_options, cwd: workspace });\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)}): ${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/** What a rejected check says in place of its output. */\nexport const CHECK_REJECTED = 'the check was rejected when it asked to run, so it never ran';\n\n/** A check the user rejected when it asked to run: recorded as a failed\n * check, with the refusal as its output, so a round can't converge on work\n * nothing checked, and the critic hears why there's no result. */\nexport function rejected_check(runner: CheckRunnerKind): CheckResult {\n return {\n ran: true,\n runner,\n ok: false,\n exit_code: null,\n duration_ms: 0,\n failing_slots: [],\n detail: [],\n log: CHECK_REJECTED,\n };\n}\n","/**\n * What a `claude_cli` seat may touch. The CLI runs in the build root (its\n * session cwd), and two layers keep its file tools there:\n *\n * - The allowlist names only path rules the CLI matches. It checks file\n * permissions against `Edit(path)` and `Read(path)` alone (an `Edit` rule\n * governs the Write tool too; a `Write(path)` or `MultiEdit(path)` rule is\n * accepted and never matched), and a bare `Write` or `Read` approves every\n * path on the machine. `/` anchors a rule at the session's working\n * directory. Reads, searches, and globs inside the working directory need no\n * rule at all, so `Grep` and `Glob` aren't listed: a bare entry for either\n * would only reach outside it.\n * - `--settings` turns on the CLI's own blocks, which refuse file tools outside\n * the working directories in every permission mode, `bypassPermissions`\n * included, where allow rules decide nothing. The write block needs Claude\n * Code 2.1.314, the read block 2.1.257; an older CLI ignores the key, which\n * the dry run warns about.\n *\n * `Bash` stays unconfined: the blocks cover file tools only.\n */\nimport type { ResolvedConfig } from './types.js';\n\n/** Whether a seat this run drives runs on the Claude CLI. A critique has no\n * builder, whatever its provider resolved to. */\nexport function uses_claude_cli(config: ResolvedConfig): boolean {\n return (\n (config.mode !== 'critique' && config.builder_provider === 'claude_cli') ||\n config.critic_provider === 'claude_cli'\n );\n}\n\nexport const BUILDER_ALLOWED_TOOLS = ['Read(/**)', 'Edit(/**)', 'Bash', 'WebFetch'] as const;\n\nexport const CRITIC_ALLOWED_TOOLS = ['Read(/**)'] as const;\n\nexport const CRITIC_DISALLOWED_TOOLS = 'Write,Edit,MultiEdit,NotebookEdit,Bash';\n\nconst PERMISSION_BLOCKS = {\n permissions: {\n blockWritesOutsideWorkingDirectories: true,\n blockReadsOutsideWorkingDirectories: true,\n },\n} as const;\n\n/** The CLI flags that turn on `PERMISSION_BLOCKS`. */\nexport function settings_args(): string[] {\n return ['--settings', JSON.stringify(PERMISSION_BLOCKS)];\n}\n\nexport type ClaudeVersion = readonly [number, number, number];\n\nexport const MIN_CLAUDE_WRITE_BLOCK: ClaudeVersion = [2, 1, 314];\n\nexport const MIN_CLAUDE_READ_BLOCK: ClaudeVersion = [2, 1, 257];\n\n/** The version `claude --version` printed (`2.1.316 (Claude Code)`), or null\n * when it printed something else. */\nexport function parse_claude_version(stdout: string): ClaudeVersion | null {\n const match = /^\\s*(\\d+)\\.(\\d+)\\.(\\d+)\\b/.exec(stdout);\n if (match === null) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\nexport function version_below(version: ClaudeVersion, min: ClaudeVersion): boolean {\n const [major, minor, patch] = version;\n const [min_major, min_minor, min_patch] = min;\n if (major !== min_major) return major < min_major;\n if (minor !== min_minor) return minor < min_minor;\n return patch < min_patch;\n}\n\nexport function format_version(version: ClaudeVersion): string {\n return version.join('.');\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, StepRecord, ToolCallRecord, UsageTotals } from 'fascicle';\nimport type {\n BuilderStepRecord,\n CostSource,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n StepTimingBasis,\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\n/** The providers whose calls carry the charge they report, which fascicle\n * records as the call's cost in place of a pricing table's estimate: the\n * Claude CLI's own total, and OpenRouter's per-response charge. */\nconst REPORTING_PROVIDERS: ReadonlySet<string> = new Set(['claude_cli', 'openrouter']);\n\nexport function cost_source_of(result: GenerateResult<unknown>): CostSource {\n if (result.cost === undefined) return 'unknown';\n return REPORTING_PROVIDERS.has(result.model_resolved.provider)\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 const truncated = result.steps.filter((step) => step.truncated === true).length;\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 ...(truncated > 0 ? { truncated_turns: truncated } : {}),\n ...(rate !== undefined ? { throughput: rate } : {}),\n };\n}\n\ntype StepSplit = { prefill_ms?: number; decode_ms?: number; timing_basis: StepTimingBasis };\n\nconst NS_PER_MS = 1e6;\n\nfunction ns_field(payload: Record<string, unknown>, name: string): number | undefined {\n const value = payload[name];\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\n/** A turn's prefill and decode times: Ollama's own durations when it reported\n * them (in ns), else the time to the first streamed chunk, else none. */\nfunction step_split(step: StepRecord): StepSplit {\n const reported = step.provider_reported?.['ollama'];\n if (typeof reported === 'object' && reported !== null) {\n const ollama = reported as Record<string, unknown>;\n const evaluated = ns_field(ollama, 'eval_duration');\n const prompt = ns_field(ollama, 'prompt_eval_duration');\n if (evaluated !== undefined && prompt !== undefined) {\n return {\n prefill_ms: Math.round(prompt / NS_PER_MS),\n decode_ms: Math.round(evaluated / NS_PER_MS),\n timing_basis: 'ollama_reported',\n };\n }\n const total = ns_field(ollama, 'total_duration');\n const load = ns_field(ollama, 'load_duration');\n if (evaluated !== undefined && total !== undefined && load !== undefined && total >= load + evaluated) {\n return {\n prefill_ms: Math.round((total - load - evaluated) / NS_PER_MS),\n decode_ms: Math.round(evaluated / NS_PER_MS),\n timing_basis: 'ollama_derived',\n };\n }\n }\n const timing = step.timing;\n if (timing?.first_chunk_ms !== undefined && timing.whole_tool_call !== true) {\n return {\n prefill_ms: timing.first_chunk_ms,\n decode_ms: Math.max(0, timing.duration_ms - timing.first_chunk_ms),\n timing_basis: 'first_chunk',\n };\n }\n return { timing_basis: 'none' };\n}\n\n/** How much a tool call's result put into the transcript: its output as the\n * loop serializes it, or the error text it fed back. */\nfunction output_chars(call: ToolCallRecord): number {\n if (call.output === undefined) return call.error?.message.length ?? 0;\n return typeof call.output === 'string' ? call.output.length : (JSON.stringify(call.output) ?? '').length;\n}\n\n/** Each turn of a session as the archive records it, or undefined when the\n * result has none. */\nexport function step_records(result: GenerateResult<unknown>): BuilderStepRecord[] | undefined {\n if (result.steps.length === 0) return undefined;\n return result.steps.map((step) => ({\n index: step.index,\n input_tokens: step.usage.input_tokens,\n output_tokens: step.usage.output_tokens,\n duration_ms: step.timing?.duration_ms ?? 0,\n ...step_split(step),\n finish_reason: step.finish_reason,\n ...(step.truncated === true ? { truncated: true as const } : {}),\n tool_calls: step.tool_calls.map((call) => ({ name: call.name, output_chars: output_chars(call) })),\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. The\n * builder's record also carries its session's turns. */\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 steps = role === 'builder' ? step_records(result) : undefined;\n const cost = record.cost_usd ?? 0;\n return {\n ...state,\n [role]: steps !== undefined ? { ...record, steps } : 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 * `seat_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 { command_env } from './engine.js';\nimport { check_error, config_error } from './types.js';\nimport { backup_stamp, commit_identity } 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. The check, the change report, and the checkpoints\n * follow it there; the run's state stays wherever `state_dir` puts it.\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, env: command_env(process.env), 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, env: command_env(process.env), 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 (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_identity(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 * 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 model driving volley's tools on any other provider, local or hosted.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { basename, 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 PrepareStepHook,\n RunContext,\n Step,\n StreamChunk,\n Tool,\n ToolApprovalHandler,\n} from 'fascicle';\nimport { warn_small_local_context } from './builder/context_check.js';\nimport { step_countdown } from './builder/countdown.js';\nimport { compose_prepare_steps } from './builder/prepare_step.js';\nimport { step_trim } from './builder/trim.js';\nimport { builder_tools, type BashExecutor } from './builder/tools.js';\nimport { CHECK_REJECTED } from './check/command.js';\nimport { BUILDER_ALLOWED_TOOLS, settings_args } from './claude_cli_permissions.js';\nimport { accumulate } from './cost.js';\nimport { seat_base_url } from './engine.js';\nimport { prewarm_ollama_model } from './prewarm.js';\nimport { config_error, phase_error } from './types.js';\nimport type { CheckResult, LoopState, ResolvedConfig } from './types.js';\nimport type { ToolSet } from './workspace_tools.js';\nimport { build_root } from './worktree.js';\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 builder_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 harness append each tool set's builder reads: one naming volley's own\n * tools, or one naming fascicle's workspace tools under `volley acp` and\n * saying what a call the user refused means. */\nconst HARNESS_APPENDS: Record<ToolSet, string> = {\n volley: 'harness_append_local.md',\n acp: 'harness_append_acp.md',\n};\n\n/** Step 2 of \"Work this way\", as both harness appends word it for a builder\n * held to one tool call a turn. */\nconst ONE_CALL_A_TURN = '2. Call one tool at a time and read its result before deciding the next\\n call.';\n\n/** Step 2 for a builder that may make several calls a turn: fascicle runs a\n * turn's calls in order, so a read can't race an edit, but each change or\n * command is still worth reading before the next. Reads don't count toward\n * the cap, so the step names no number. */\nconst BATCHED_CALLS = [\n '2. Batch independent reads into one turn, but make one change or command per',\n ' turn, and read its result before deciding the next call.',\n].join('\\n');\n\n// The CLI system prompt assumes CLI semantics (built-in tools, implicit\n// cwd), so the local builder gets its own — its tool set, the\n// workspace-is-cwd convention, and the harness-enforced `finish` stop.\nexport function compose_builder_system_local(\n tool_set: ToolSet = 'volley',\n max_tool_calls = 1,\n): 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(builder_presets_dir(), HARNESS_APPENDS[tool_set]), 'utf8');\n const worded =\n max_tool_calls > 1 ? append.replace(ONE_CALL_A_TURN, BATCHED_CALLS) : append;\n return `${identity}\\n\\n${worded.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, which never takes an injected set, or the local prompt naming\n * the seat's tool set for every provider that runs volley's tool loop,\n * `openrouter` included. Mirrors the critic's `resolve_critic_prompt`. */\nfunction resolve_builder_system(config: ResolvedConfig, tool_set?: ToolSet): string {\n return config.builder_provider === 'claude_cli'\n ? compose_builder_system()\n : compose_builder_system_local(tool_set, config.builder_max_tool_calls);\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/** How the step countdown tells the builder to run the check: the command\n * volley gates on, with the digest and without `--json`, the configured\n * command, or the project's own tests when no check gates the run. A\n * workspace can hold checkride with no `check` script, so not `pnpm check`. */\nfunction check_hint(config: ResolvedConfig): string {\n if (config.check_resolved === 'checkride') return 'the check (`pnpm exec checkride --digest`)';\n if (config.check_resolved === 'command') return `the check (\\`${config.check}\\`)`;\n return \"the project's tests\";\n}\n\n/** The builder's `prepare_step`: the countdown, after the history trim when\n * `--builder-trim-history` turns it on, so the countdown's note still goes\n * last. */\nfunction builder_prepare_step(config: ResolvedConfig): PrepareStepHook {\n const countdown = step_countdown(config.builder_max_steps, check_hint(config));\n if (config.builder_trim_history === null) return countdown;\n return compose_prepare_steps([step_trim(config.builder_trim_history), countdown]);\n}\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, and takes no injected tools or approval handler. Every other\n * builder, local or `openrouter`, brings none, so volley supplies its whole\n * workspace tool surface (or the set the caller injected in its place, with\n * the handler that answers its approvals), the per-call loop knobs, the step\n * countdown (`./builder/countdown.ts`) and the history trim when it's on\n * (`./builder/trim.ts`), the output cap when one is set, and\n * **no** schema (it produces a workspace, not a verdict); per-call values win\n * over engine defaults. */\nfunction builder_tool_options(\n deps: BuilderDeps,\n): Pick<\n GenerateOptions,\n | 'tools'\n | 'on_tool_approval'\n | 'provider_options'\n | 'max_steps'\n | 'tool_error_policy'\n | 'tool_call_repair_attempts'\n | 'max_tool_calls_per_step'\n | 'prepare_step'\n | 'max_tokens'\n | 'truncated_turn_policy'\n> {\n const { config } = deps;\n const bash_executor = deps.bash_executor ?? null;\n if (config.builder_provider === 'claude_cli') {\n // The file tools stay in the build root, the session's cwd: the allowlist\n // scopes them under `acceptEdits`, and the settings blocks hold under\n // `bypassPermissions` too, where allow rules decide nothing.\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...BUILDER_ALLOWED_TOOLS],\n extra_args: ['--permission-mode', config.builder_permission_mode, ...settings_args()],\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:\n deps.tools === undefined\n ? builder_tools(\n build_root(config.workspace, config.worktree),\n bash_executor !== null ? { bash_executor } : {},\n )\n : [...deps.tools],\n ...(deps.on_tool_approval !== undefined ? { on_tool_approval: deps.on_tool_approval } : {}),\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: config.builder_max_tool_calls,\n prepare_step: builder_prepare_step(config),\n // A capped turn that runs out before it calls a tool goes on to the next\n // step instead of ending the session; with no cap, a turn cut off at the\n // provider's own limit still ends it, as one cut off at a full context\n // window would only be cut off again.\n ...(config.builder_max_output_tokens !== null\n ? { max_tokens: config.builder_max_output_tokens, truncated_turn_policy: 'continue' as const }\n : {}),\n };\n}\n\n/** What the builder is told about the iteration before its own, besides the\n * critic's feedback. */\nexport type PreviousRound = {\n /** That iteration's check. Its output goes in the prompt when it failed. */\n check: CheckResult | null;\n /** The step limit that iteration's builder hit before it called finish, or\n * null when it stopped on its own. */\n step_limit_hit: number | null;\n};\n\nexport type BuilderPromptInput = {\n task: string;\n criteria: string;\n feedback: string | null;\n iteration: number;\n checkride: boolean;\n previous: PreviousRound | null;\n};\n\n/** How much of the last check's output the builder's prompt carries: a few KB,\n * whatever the runner. checkride's digest already fits in 8 kB, and the builder\n * can run the check again for the rest. */\nexport const PREVIOUS_CHECK_MAX_CHARS = 6000;\n\n/** The first `max` characters of `text`, saying where it was cut. */\nfunction head(text: string, max: number, rest: string): string {\n return text.length <= max ? text : `${text.slice(0, max)}\\n… (cut at ${String(max)} characters; ${rest})`;\n}\n\n/** The last `max` characters of `text`, saying what came before was cut. */\nfunction tail(text: string, max: number): string {\n return text.length <= max\n ? text\n : `… (the last ${String(max)} characters of ${String(text.length)})\\n${text.slice(-max)}`;\n}\n\n/** The part of a failed check the builder reads first: checkride's digest,\n * else the start of each failing slot's raw output, else the end of a\n * command's output, where test runners and compilers sum up. */\nfunction check_excerpt(check: CheckResult): string {\n const max = PREVIOUS_CHECK_MAX_CHARS;\n if (check.digest !== undefined) {\n return head(check.digest.trimEnd(), max, '.check/digest.md has the rest');\n }\n if (check.detail.length > 0) {\n const slots = check.detail.map((artifact) => {\n const source = artifact.path === null ? '' : ` (.check/${basename(artifact.path)})`;\n return `${artifact.slot}${source}:\\n${artifact.content.trimEnd()}`;\n });\n return head(slots.join('\\n\\n'), max, 'each slot\\'s raw output under .check/ has the rest');\n }\n return tail((check.log ?? '').trimEnd(), max);\n}\n\n/** The check section of a later iteration's prompt: what the deterministic\n * gate itself said about the last session's work, so the builder starts from\n * its words rather than the critic's account of them, or re-running it to\n * find out. Empty unless that check ran and failed. A check the user rejected\n * when it asked to run is recorded as failed but said nothing, and the\n * section says so rather than call the work failed. */\nfunction previous_check_section(check: CheckResult | null): string[] {\n if (check === null || !check.ran || check.ok) return [];\n const heading = ['', 'PREVIOUS CHECK RESULT', '---------------------'];\n if (check.log === CHECK_REJECTED) {\n return [\n ...heading,\n 'The check never ran on the work your last session left: it was rejected when it',\n 'asked to run, so nothing has verified that work yet.',\n ];\n }\n const runner = check.runner === 'checkride' ? 'checkride, ' : '';\n const exit = check.exit_code === null ? 'no exit code' : `exit ${String(check.exit_code)}`;\n const lines = [\n ...heading,\n `The check failed on the work your last session left (${runner}${exit}).`,\n ];\n if (check.failing_slots.length > 0) {\n lines.push(`Failing slots: ${check.failing_slots.join(', ')}.`);\n }\n const excerpt = check_excerpt(check);\n if (excerpt.length > 0) lines.push('', excerpt);\n return lines;\n}\n\n/** The line a later iteration's prompt carries when the last session ran out\n * of steps: it never got to verify, so this one should check first. */\nfunction step_limit_lines(step_limit_hit: number | null): string[] {\n if (step_limit_hit === null) return [];\n return [\n '',\n `Your last session hit its ${String(step_limit_hit)}-step limit before it called finish, so`,\n 'it may never have verified its work. Run the check first this time, and keep',\n 'enough steps in hand to verify again before you finish.',\n ];\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.iteration > 1 && input.previous !== null) {\n parts.push(\n ...previous_check_section(input.previous.check),\n ...step_limit_lines(input.previous.step_limit_hit),\n );\n }\n if (input.checkride) {\n parts.push(\n '',\n 'The definition of done for this workspace includes checkride exiting 0. Run',\n '`pnpm exec checkride --digest`, the check volley gates on, after each batch of',\n 'edits and again before you finish. When it fails, read .check/digest.md',\n 'first: it lists each failing slot\\'s first findings. Open a slot\\'s raw',\n 'output under .check/ only if the digest isn\\'t enough, then 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 /** Tools to hand the builder in place of volley's own set; absent, it gets\n * that set. A `claude_cli` builder brings its own tools and never takes\n * these. */\n tools?: ReadonlyArray<Tool>;\n /** Which set `tools` is, so the prompt names the tools the builder holds;\n * absent, volley's own. */\n tool_set?: ToolSet;\n /** Answers each call to a tool that asks first (`needs_approval`). Like\n * `tools`, it reaches every builder but `claude_cli`. Absent, such a call\n * fails closed. */\n on_tool_approval?: ToolApprovalHandler;\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, deps.tool_set),\n on_chunk: deps.on_chunk,\n ...builder_tool_options(deps),\n });\n}\n\nexport type BuilderRunDeps = {\n builder: BuilderStep;\n config: ResolvedConfig;\n warn: (message: string) => void;\n};\n\n/** Run one builder session on the opened iteration `state`, told what the\n * iteration before it left behind (`previous`, null on the first). */\nexport async function run_builder(\n deps: BuilderRunDeps,\n state: LoopState,\n previous: PreviousRound | null,\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. Both go to the builder seat's own server.\n if (config.builder_provider === 'ollama') {\n const base_url = seat_base_url('ollama', config.builder_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 previous,\n }),\n );\n const built = accumulate(state, 'builder', result, config.builder_model);\n // `max_steps` is a backstop, not a failure — surface it, count it, and\n // carry on.\n if (result.finish_reason !== 'max_steps') return built;\n deps.warn(builder_max_steps_warning(config.builder_max_steps));\n return { ...built, builder_max_steps_hits: built.builder_max_steps_hits + 1 };\n } catch (err) {\n throw phase_error('builder', 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, isAbsolute, join, relative, sep } 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';\nimport { state_path } from '../workspace.js';\nimport type { ToolSet } from '../workspace_tools.js';\nimport { build_root } from '../worktree.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\n/** The harness append that names the critic's reads. The CLI critic reads\n * via built-in Read/Grep/Glob and never takes an injected set; every other\n * critic, local or `openrouter`, reads via volley's read_file/search_files/\n * list_files, or under `volley acp` via fascicle's read_file/list_files/\n * search. */\nfunction harness_append_file(config: ResolvedConfig, tool_set: ToolSet): string {\n if (config.critic_provider === 'claude_cli') return 'harness_append.md';\n return tool_set === 'acp' ? 'harness_append_acp.md' : 'harness_append_local.md';\n}\n\nexport function resolve_critic_prompt(config: ResolvedConfig, tool_set: ToolSet = 'volley'): 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 const append = readFileSync(join(presets_dir(), harness_append_file(config, tool_set)), 'utf8');\n return `${base.trimEnd()}\\n\\n${place_iterations_dir(append, config).trimEnd()}`;\n}\n\nconst ITERATIONS_DIR = '{{iterations_dir}}';\n\n/** Fill the harness append's line about prior iteration state with where the\n * run's `iterations/` sits, relative to the build root the critic reads from,\n * or drop the line when the run's state is outside that root: a confined\n * critic can't reach it, and naming it would only spend the critic's steps on\n * a path it can't open. */\nfunction place_iterations_dir(append: string, config: ResolvedConfig): string {\n const path = relative(\n build_root(config.workspace, config.worktree),\n state_path(config, 'iterations'),\n );\n const outside = path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path);\n return append\n .split('\\n')\n .filter((line) => !(outside && line.includes(ITERATIONS_DIR)))\n .join('\\n')\n .replaceAll(ITERATIONS_DIR, `${path}/`);\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 * Critic invocation: a read-only session (`claude_cli`, or a local or\n * `openrouter` model with volley's read tools) returning a schema-validated\n * structured verdict. The\n * harness — not the critic — writes the run's `feedback.md` and `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 Tool,\n} from 'fascicle';\nimport {\n CRITIC_ALLOWED_TOOLS,\n CRITIC_DISALLOWED_TOOLS,\n settings_args,\n} from '../claude_cli_permissions.js';\nimport { accumulate } from '../cost.js';\nimport { seat_base_url } from '../engine.js';\nimport { prewarm_ollama_model } from '../prewarm.js';\nimport { error_kind, phase_error } from '../types.js';\nimport type { CauseKind, DegradeCause, LoopState, ResolvedConfig } from '../types.js';\nimport type { ToolSet } from '../workspace_tools.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\n/** A critic that holds tools isn't constrain-decoded, so nothing stops it\n * answering null for the feedback or the unmet list, as GLM did on approving.\n * Both fields allow null and read it as empty, so that answer is a verdict\n * rather than a schema failure that ends the run. fascicle sends the schema's\n * input side, so the model sees each field as its type or null, still\n * required; `.describe()` comes last so the description stays on the field. */\nexport const verdict_schema = z.object({\n verdict: z.enum(['approved', 'changes_requested']),\n feedback: z\n .string()\n .nullable()\n .transform((feedback) => feedback ?? '')\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 .nullable()\n .transform((unmet) => unmet ?? [])\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 /** Tools to hand the critic's tool-bearing call in place of volley's reads;\n * absent, it gets those. A `claude_cli` critic reads through the CLI's own\n * tools and never takes these. The critic takes no approval handler, since\n * nothing it reads with should ever ask. */\n tools?: ReadonlyArray<Tool>;\n /** Which set `tools` is, so the harness append names the reads the critic\n * holds; absent, volley's own. */\n tool_set?: ToolSet;\n};\n\n/** Read-only tool wiring per provider. The claude_cli critic is confined at\n * the CLI permission layer (allowlist + explicit disallow, and the settings\n * blocks that keep its reads in the build root); every other critic,\n * local or `openrouter`, gets volley's own workspace-scoped read-only tools (or\n * the set the caller injected in their place) and no write path at all.\n *\n * The providers also enforce `verdict_schema` by different paths, the first\n * two verified live. The claude_cli critic compiles the schema for\n * `claude --json-schema`; that only works because fascicle 0.14.0'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). An `openrouter`\n * critic rides fascicle's native OpenAI-compatible core, which has no\n * constrained decode: the schema travels in the prompt, and the reply is parsed\n * and repaired. */\nfunction critic_tool_options(\n config: ResolvedConfig,\n tools?: ReadonlyArray<Tool>,\n): Pick<GenerateOptions<VerdictOutput>, 'tools' | 'provider_options' | 'max_steps'> {\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, ...settings_args()],\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 {\n tools:\n tools === undefined\n ? read_only_tools(build_root(config.workspace, config.worktree))\n : [...tools],\n max_steps: CRITIC_MAX_STEPS,\n };\n}\n\n/** The local critic's step budget for its tool-bearing call: reads plus the\n * verdict. Set explicitly rather than inherited from fascicle's engine default\n * (also 10), so a change to that default can't move it silently. */\nexport const CRITIC_MAX_STEPS = 10;\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 provider stream death the ladder\n * retries? Every provider but `claude_cli` (that 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/** Did a schema call end without a verdict because the tool loop ran out —\n * its step budget spent, or its last turn a tool call — rather than because\n * the response was cut off or blocked? fascicle throws\n * `incomplete_generation_error` for every such finish; only these two are\n * fixed by taking the tools away. Matched on `kind` and `finish_reason`. */\nfunction is_step_exhaustion(err: unknown): boolean {\n if (error_kind(err) !== 'incomplete_generation_error') return false;\n const finish = (err as { finish_reason?: unknown }).finish_reason;\n return finish === 'max_steps' || finish === 'tool_calls';\n}\n\n/** Does this failure send a local critic to the tool-less rung? A stream death\n * the retry rung gave up on, or step exhaustion, which no retry would fix. A\n * `length` or `content_filter` finish is neither, and stays fatal. */\nfunction is_degradable_critic_error(config: ResolvedConfig, err: unknown): boolean {\n if (config.critic_provider === 'claude_cli') return false;\n return error_kind(err) === 'provider_error' || is_step_exhaustion(err);\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 degrade_cause?: DegradeCause;\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 ...(mark.degrade_cause !== undefined ? { degrade_cause: mark.degrade_cause } : {}),\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, deps.tool_set),\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, deps.tools),\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/** What the retry rung knew about the error that ended it: the attempt it\n * died on, and the cause of the stream death it last retried. fascicle's\n * `retry` rethrows that error untouched, so the fallback's projection looks it\n * up here to count the retries behind a degraded verdict. */\ntype LadderTrace = { attempt: number; retried_cause: CauseKind | undefined };\n\nconst ladder_traces = new WeakMap<object, LadderTrace>();\n\n/** The ladder's retry predicate for this run's critic provider: stream deaths\n * only. It also traces every failure it sees, so a degraded verdict can say how\n * many retries preceded it and why. A first attempt starts a fresh critique, so\n * it forgets the last one's retries. */\nexport function critic_retryable(\n config: ResolvedConfig,\n): (err: unknown, attempt: number) => boolean {\n let retried_cause: CauseKind | undefined;\n return (err, attempt) => {\n if (attempt === 1) retried_cause = undefined;\n if (typeof err === 'object' && err !== null) {\n ladder_traces.set(err, { attempt, retried_cause });\n }\n const retryable = is_retryable_critic_error(config, err);\n if (retryable) retried_cause = retry_cause_kind_of(err);\n return retryable;\n };\n}\n\n/** The ladder's fallback predicate: a stream death the retry rung gave up on,\n * or step exhaustion, which it never retries. */\nexport function critic_degradable(config: ResolvedConfig): (err: unknown) => boolean {\n return (err) => is_degradable_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, marked degraded so it never passes silently as a full\n * critique. Why it degraded, and the retries before it, are the ladder's to\n * stamp (`with_fallback_cause`), since the tool-less call can't see them. */\nexport function as_degraded(result: GenerateResult<VerdictOutput>): CriticAnswer {\n return {\n result,\n mark: { retries: 0, 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 * mark comes from the error that sent it there.\n *\n * - A stream death the retry rung gave up on: every retry was spent, and the\n * cause is that error's own.\n * - Step exhaustion, never retried: the retries are the stream deaths before\n * it, usually none, and the cause is the last of those.\n *\n * An error the retry rung never traced reads as one that spent every retry. */\nexport function with_fallback_cause(outcome: FallbackOutcome<CriticAnswer>): CriticAnswer {\n if (outcome.source === 'primary') return outcome.value;\n const err = outcome.primary_error;\n const trace =\n typeof err === 'object' && err !== null ? ladder_traces.get(err) : undefined;\n const retries = trace === undefined ? MAX_CRITIC_RETRIES : trace.attempt - 1;\n const exhausted = is_step_exhaustion(err);\n const retry_cause_kind = exhausted ? trace?.retried_cause : retry_cause_kind_of(err);\n return {\n ...outcome.value,\n mark: {\n ...outcome.value.mark,\n retries,\n retry_cause_kind,\n degrade_cause: exhausted ? 'step_exhaustion' : 'stream_error',\n },\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 or ran out of steps, but a tool-less\n * pass survived, so a real run will likely finish via the fallback ladder\n * (`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 and `openrouter`'s cost real money.\n *\n * A tool-bearing death is classified by the same discriminant as the run-time\n * ladder's fallback (a typed `provider_error`, or step exhaustion), then probed\n * tool-less exactly as rung 2 would run, so the canary *predicts the ladder*\n * 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(\n seat_base_url('ollama', config.critic_url, env),\n config.critic_model,\n );\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 (!is_degradable_critic_error(config, err)) {\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 on\n // the critic seat's own server so a cold multi-GB load doesn't blow the real\n // call's first-byte timeout. Best-effort; when both seats share a server and\n // a model, the builder's warm-up already loaded it and this returns at once.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(\n seat_base_url('ollama', config.critic_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 * 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 builder_max_steps_hits: 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 * 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\n/** Controls, format characters (bidi overrides, zero-widths), and line and\n * paragraph separators: what can move the cursor, hide text, or reorder a line\n * in a terminal. */\nconst UNSAFE_CHARACTERS = /[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]/gu;\n\n/** A value from a file volley can't vouch for, quoted for a person to judge,\n * with every character that could redraw or reorder the line escaped, so a\n * rewritten config can't make the warning about it say something else. JSON\n * quoting escapes the C0 controls, the quote, and the backslash; the rest are\n * written as `\\u{…}`. */\nexport function shown(value: string): string {\n return JSON.stringify(value).replace(\n UNSAFE_CHARACTERS,\n (character) => `\\\\u{${(character.codePointAt(0) ?? 0).toString(16)}}`,\n );\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 * 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 lstatSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join, resolve } from 'node:path';\nimport { read_failing_artifacts } from './check/checkride.js';\nimport type { CheckrideSummary, CheckrideSummaryCheck } from './check/checkride.js';\nimport { EMPTY_USAGE } from './cost.js';\nimport { shown } from './render/format.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CheckArtifact,\n CheckResult,\n CriticProvider,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n RunResult,\n RunStatus,\n Verdict,\n VolleyConfig,\n} from './types.js';\nimport { detect_containment } from './containment.js';\nimport { config_signed } from './trust.js';\nimport {\n CONFIG_SIGNATURE,\n iteration_dir,\n RUN_ID_PATTERN,\n run_state_dir,\n state_path,\n} from './workspace.js';\nimport type { StateLocation } 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 config: ResolvedConfig,\n feedback: string,\n verdict: Verdict,\n): void {\n writeFileSync(state_path(config, 'feedback.md'), feedback.endsWith('\\n') ? feedback : `${feedback}\\n`);\n writeFileSync(state_path(config, '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 // Turns cut off at the builder's output cap before a tool call. Emitted\n // only when there were any. Additive.\n ...(record.truncated_turns !== undefined ? { truncated_turns: record.truncated_turns } : {}),\n // Degradation-ladder bookkeeping, critic-only: the provider-error\n // retries that preceded this verdict, their cause, whether it was rendered\n // by the tool-less fallback, and why. Emitted only when set, so the builder\n // record and old summary consumers are untouched. `critic_degraded` and\n // `degrade_cause` are the on-disk half of the contract — the comparison\n // block reads them 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 ...(record.degrade_cause !== undefined ? { degrade_cause: record.degrade_cause } : {}),\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 // Each builder turn's request size, timing split, and tool output sizes,\n // so a session's growth can be read back (#7). Builder-only. Additive.\n ...(record.steps !== undefined ? { steps: record.steps } : {}),\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, state.iteration);\n mkdirSync(join(dir, 'check'), { recursive: true });\n\n if (state.verdict !== null && state.feedback !== null) {\n persist_verdict_files(config, state.feedback, state.verdict);\n writeFileSync(join(dir, 'feedback.md'), readFileSync(state_path(config, '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 if (check.digest !== undefined) {\n writeFileSync(join(dir, 'check', 'digest.md'), check.digest);\n }\n // A checkride check has a log only when it was rejected, and the log\n // says so.\n if (check.log !== undefined) {\n writeFileSync(join(dir, 'check', 'check.log'), check.log);\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 builder_max_steps_hits: state.builder_max_steps_hits,\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 run_state_dir: run_state_dir(config),\n mode: config.mode,\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 /** Whether this machine's signature held over the run's config: false only\n * when `trust_config` let an unsigned one through, and null inside the\n * sandbox, where nothing is checked. */\n config_signed: boolean | null;\n};\n\nexport type ResumeOptions = {\n /** Resume a config this machine didn't sign (`--trust-config`): another\n * machine's, an older volley's, one edited by hand, or a contained run's,\n * whose builder could have rewritten it. */\n trust_config?: boolean;\n env?: Readonly<Record<string, string | undefined>>;\n};\n\n/** Why a host-side resume won't run a config this machine didn't sign. */\nfunction untrusted_config(run_id: string, config_path: string): Error {\n return config_error(\n `run ${run_id}'s config.json has no signature from volley on this machine, so a resume here ` +\n \"won't run it: inside the sandbox a run's builder can rewrite its config, and a resume runs \" +\n 'the check and the seats it names. Resume a contained run inside its container, with the same ' +\n `mount. If ${config_path} is another machine's, an older volley's, or one you edited, read it, ` +\n 'then pass --trust-config.',\n );\n}\n\n/** Whether a host-side resume may run the config in `text`: signed by this\n * machine, or trusted by the caller. Inside the sandbox nothing is checked: a\n * resume there runs only within the container, as the builder already does. */\nfunction check_config_trust(\n text: string,\n run: StateLocation,\n options: ResumeOptions,\n): boolean | null {\n const env = options.env ?? process.env;\n if (detect_containment(env)) return null;\n const signature_path = state_path(run, CONFIG_SIGNATURE);\n const signature = existsSync(signature_path) ? readFileSync(signature_path, 'utf8') : null;\n const signed = config_signed(text, signature, env);\n if (!signed && options.trust_config !== true) {\n throw untrusted_config(run.run_id, state_path(run, 'config.json'));\n }\n return signed;\n}\n\n/** The run id an older volley's `.volley/config.json` records, or null when\n * there is none to read. */\nfunction legacy_run_id(workspace: string): string | null {\n try {\n const recorded = JSON.parse(readFileSync(join(workspace, '.volley', 'config.json'), 'utf8')) as {\n run_id?: unknown;\n };\n return typeof recorded.run_id === 'string' ? recorded.run_id : null;\n } catch {\n return null;\n }\n}\n\n/** Where `volley resume <run_id>` finds a run: under `root` (`--state-dir`,\n * else the default root) at `<root>/<run_id>/`, returned as that root, or, for\n * a run an older volley kept in the workspace, `.volley/`, returned as null so\n * the resumed run stays there. Finding neither is a config error naming both\n * places it looked. The id becomes a path, so it must be one a run could have\n * had. */\nexport function find_run_state(workspace: string, run_id: string, root: string): string | null {\n if (!RUN_ID_PATTERN.test(run_id)) {\n throw config_error(`not a run id: ${run_id} (letters, digits, '-', and '_', starting with a letter or digit)`);\n }\n if (existsSync(join(root, run_id, 'config.json'))) return root;\n const legacy = legacy_run_id(workspace);\n if (legacy === run_id) return null;\n // Read from a file nothing has vouched for, so quoted and escaped.\n const holds = legacy === null ? '' : ` (it holds run ${shown(legacy)})`;\n throw config_error(\n `run ${run_id} not found in ${join(root, run_id)} or in ${join(resolve(workspace), '.volley')}${holds}; ` +\n 'pass --state-dir for the root it ran under, or --workspace for a run kept in .volley/',\n );\n}\n\n/** A resumed run writes into its state directory, and a contained run's\n * builder could have written there first, so a symlink anywhere in it would\n * aim the resume's writes, or its pruning of a half-finished iteration, at a\n * file of the host's. volley never makes one, so any is refused. The walk\n * reads each entry's own type and never descends a link, which Node's\n * recursive `readdirSync` would. */\nfunction refuse_symlinks(dir: string): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const path = join(dir, entry.name);\n if (entry.isSymbolicLink()) {\n throw config_error(`refusing to resume: ${path} is a symbolic link, which volley never writes`);\n }\n if (entry.isDirectory()) refuse_symlinks(path);\n }\n}\n\n/** The part of an archived iteration's `summary.json` a resumed run reads\n * back. Every field is unknown until checked, since the archive could be torn\n * or older than this volley. */\ntype ArchivedRound = {\n builder?: unknown;\n check?: {\n ran?: unknown;\n runner?: unknown;\n ok?: unknown;\n exit_code?: unknown;\n duration_ms?: unknown;\n failing_slots?: unknown;\n } | null;\n};\n\n/** An archived file's text, or undefined when there's no file to read there. */\nfunction read_text(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8');\n } catch {\n return undefined;\n }\n}\n\nfunction read_json(path: string): unknown {\n const text = read_text(path);\n if (text === undefined) return null;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n}\n\n/** The failing slots' raw artifacts from an archived iteration's `check/`,\n * which holds each under its base name, found through the archived checkride\n * summary. */\nfunction archived_artifacts(check_dir: string, failing_slots: string[]): CheckArtifact[] {\n const summary = read_json(join(check_dir, 'summary.json')) as Partial<CheckrideSummary> | null;\n const checks = Array.isArray(summary?.checks) ? summary.checks : [];\n const failing = failing_slots.map((name): CheckrideSummaryCheck => {\n const output_file = checks.find((check) => check.name === name)?.output_file;\n return {\n name,\n adapter: null,\n ok: false,\n exit_code: null,\n duration_ms: 0,\n output_file: typeof output_file === 'string' ? basename(output_file) : null,\n };\n });\n return read_failing_artifacts(check_dir, failing);\n}\n\n/** The check an archived iteration ran, rebuilt from its directory with the\n * output its failure is shown by: the digest and the failing slots' artifacts\n * for checkride, the log for a command or a rejected check. Null when it ran\n * none. */\nfunction archived_check(dir: string, recorded: ArchivedRound['check']): CheckResult | null {\n if (recorded?.ran !== true || typeof recorded.ok !== 'boolean') return null;\n const runner = recorded.runner === 'checkride' ? 'checkride' : 'command';\n const failing_slots = Array.isArray(recorded.failing_slots)\n ? recorded.failing_slots.filter((slot): slot is string => typeof slot === 'string')\n : [];\n const check: CheckResult = {\n ran: true,\n runner,\n ok: recorded.ok,\n exit_code: typeof recorded.exit_code === 'number' ? recorded.exit_code : null,\n duration_ms: typeof recorded.duration_ms === 'number' ? recorded.duration_ms : 0,\n failing_slots,\n detail: [],\n };\n if (check.ok) return check;\n const check_dir = join(dir, 'check');\n const log = read_text(join(check_dir, 'check.log'));\n const logged = log === undefined ? check : { ...check, log };\n if (runner === 'command') return logged;\n const digest = read_text(join(check_dir, 'digest.md'));\n return {\n ...logged,\n detail: archived_artifacts(check_dir, failing_slots),\n ...(digest !== undefined ? { digest } : {}),\n };\n}\n\n/** An archived builder record, as `archive_iteration` wrote it from the\n * phase's own, or null when there is none with a finish reason. */\nfunction archived_builder(recorded: unknown): PhaseRecord | null {\n if (typeof recorded !== 'object' || recorded === null) return null;\n return typeof (recorded as Partial<PhaseRecord>).finish_reason === 'string'\n ? (recorded as PhaseRecord)\n : null;\n}\n\n/** What the last completed iteration left for the next build: its check and\n * its builder's record, which tell the resumed run's first builder what the\n * gate said and whether the last session ran out of steps, as a run that never\n * stopped would have. Null for both before the first iteration. */\nfunction archived_round(\n run: StateLocation,\n completed: number,\n): Pick<LoopState, 'check' | 'builder'> {\n if (completed === 0) return { check: null, builder: null };\n const dir = iteration_dir(run, completed);\n const recorded = read_json(join(dir, 'summary.json')) as ArchivedRound | null;\n return {\n check: archived_check(dir, recorded?.check),\n builder: archived_builder(recorded?.builder),\n };\n}\n\n/** Recover a resumable run from its state directory (`.volley/`, or\n * `<state_dir>/<run_id>/` under a state root): settings from config.json,\n * totals from summary.json, feedback from feedback.md. An iteration directory\n * without a summary.json was interrupted mid-phase and is discarded. A\n * directory with a symlink in it is refused before anything is read. */\nexport function load_resume_state(\n workspace: string,\n run_id: string,\n state_dir: string | null = null,\n options: ResumeOptions = {},\n): ResumeState {\n const run = { workspace, state_dir, run_id };\n const run_dir = run_state_dir(run);\n if (existsSync(run_dir)) {\n if (lstatSync(run_dir).isSymbolicLink()) {\n throw config_error(`refusing to resume: ${run_dir} is a symbolic link, which volley never writes`);\n }\n refuse_symlinks(run_dir);\n }\n const config_path = state_path(run, 'config.json');\n if (!existsSync(config_path)) {\n throw config_error(`no resumable run found: ${config_path} missing`);\n }\n const config_text = readFileSync(config_path, 'utf8');\n const signed = check_config_trust(config_text, run, options);\n const recorded = JSON.parse(config_text) as Record<string, unknown>;\n if (recorded['run_id'] !== run_id) {\n throw config_error(\n `run ${run_id} not found in ${run_state_dir(run)} (recorded run: ${String(recorded['run_id'])})`,\n );\n }\n if (recorded['mode'] === 'critique') {\n throw config_error(\n `run ${run_id} is a critique, which has one round and nothing to resume; run volley critique again`,\n );\n }\n\n const iterations_root = state_path(run, '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 = state_path(run, 'summary.json');\n const summary = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : null;\n\n const feedback_path = state_path(run, '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 ...(typeof recorded['builder_url'] === 'string'\n ? { builder_url: recorded['builder_url'] }\n : {}),\n ...(recorded['builder_max_steps'] === undefined\n ? {}\n : { builder_max_steps: Number(recorded['builder_max_steps']) }),\n ...(recorded['builder_max_tool_calls'] === undefined\n ? {}\n : { builder_max_tool_calls: Number(recorded['builder_max_tool_calls']) }),\n // Null when the run left it unset, as any run before it was recorded did.\n ...(typeof recorded['builder_max_output_tokens'] === 'number'\n ? { builder_max_output_tokens: recorded['builder_max_output_tokens'] }\n : {}),\n // Null (off) when the run left it unset, as any run before it was recorded did.\n ...(typeof recorded['builder_trim_history'] === 'number'\n ? { builder_trim_history: recorded['builder_trim_history'] }\n : {}),\n critic_model: String(recorded['critic_model']),\n critic_provider: (recorded['critic_provider'] ?? 'claude_cli') as CriticProvider,\n ...(typeof recorded['critic_url'] === 'string' ? { critic_url: recorded['critic_url'] } : {}),\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 ...(typeof recorded['state_dir'] === 'string' ? { state_dir: recorded['state_dir'] } : {}),\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 ...archived_round(run, completed),\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 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 // An older volley's summary has no count.\n builder_max_steps_hits: summary?.builder_max_steps_hits ?? 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 config_signed: signed,\n };\n}\n","/**\n * Enriched run summary (the run's `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 * the run's `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 DegradeCause,\n ResolvedConfig,\n RunResult,\n Verdict,\n} from './types.js';\nimport { state_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.14.0 defaults `transport` to `'ai_sdk'`, so\n * volley sets no field); `openrouter` runs on fascicle's `native` transport\n * (`src/engine.ts` sets it); `claude_cli` drives Claude through its own CLI\n * subprocess, not an ai-sdk transport at all. Recording each keeps the\n * transport a clean second variable in the comparison (model vs transport). */\nexport type Transport = 'ai_sdk' | 'native' | 'claude_cli';\n\nexport function transport_of(provider: BuilderProvider | CriticProvider): Transport {\n switch (provider) {\n case 'claude_cli':\n return 'claude_cli';\n case 'openrouter':\n return 'native';\n case 'ollama':\n case 'lmstudio':\n return 'ai_sdk';\n }\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 /** Null for a critique, which has no builder. */\n builder_transport: Transport | null;\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 /** Why the degraded verdicts degraded, each cause once, in the order the\n * iterations first hit it. Empty when no verdict degraded. Additive. */\n critic_degrade_causes: DegradeCause[];\n};\n\n/** `RunResult` plus the comparison block; the run's `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; degrade_cause?: DegradeCause } | 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(config: ResolvedConfig): IterationArchive[] {\n const root = state_path(config, '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 = state_path(config, '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/** Each distinct reason an archived critic verdict degraded. An archive from\n * before the cause was recorded reads as a stream error, the only way a verdict\n * could degrade then. */\nfunction critic_degrade_causes(archives: IterationArchive[]): DegradeCause[] {\n const causes = archives\n .filter((archive) => archive.critic?.critic_degraded === true)\n .map((archive) => archive.critic?.degrade_cause ?? 'stream_error');\n return [...new Set(causes)];\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);\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: config.mode === 'critique' ? null : 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 critic_degrade_causes: critic_degrade_causes(archives),\n },\n };\n}\n\n/** Write the enriched summary to the run's `summary.json` (the projection the\n * examples' comparison is read from). */\nexport function write_run_summary(config: ResolvedConfig, result: RunResult): void {\n writeFileSync(\n state_path(config, '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, the per-iteration archive, and the progress events a\n * trajectory reader follows the run by.\n */\nimport { aborted_error } from 'fascicle';\nimport type { RunContext, StreamChunk, ToolApprovalHandler } from 'fascicle';\nimport { run_builder } from './builder.js';\nimport type { BuilderStep, PreviousRound } from './builder.js';\nimport { collect_changes } from './changes.js';\nimport { run_checkride } from './check/checkride.js';\nimport { CHECK_REJECTED, rejected_check, run_command_check, skipped_check } from './check/command.js';\nimport { run_critic } from './critic/run.js';\nimport { command_env } from './engine.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, Verdict } from './types.js';\nimport { git_checkpoint, state_root_within } from './workspace.js';\nimport { build_root } from './worktree.js';\n\n/** A round starting, emitted as the build opens it. */\nexport type RoundStartEvent = { volley: 'round_start'; round: number };\n\n/** The check starting, with the command line it runs. */\nexport type CheckStartEvent = { volley: 'check_start'; round: number; command: string };\n\n/** The check's outcome. */\nexport type CheckEndEvent = {\n volley: 'check_end';\n round: number;\n ok: boolean;\n exit_code: number | null;\n failing_slots: string[];\n duration_ms: number;\n};\n\n/** The critic's verdict, with what it still found missing, and whether it\n * came from the tool-less fallback. */\nexport type VerdictEvent = {\n volley: 'verdict';\n round: number;\n verdict: Verdict;\n feedback: string;\n unmet_criteria: string[];\n degraded: boolean;\n};\n\n/** The progress events the phases emit through `ctx.emit`, discriminated by\n * `volley`, since `ctx.emit` overwrites `kind` with `'emit'`. A CLI run's\n * trajectory keeps them for a viewer, and under acp they become the round\n * lines, the verdict thought, and the rest of what the editor shows. */\nexport type PhaseEvent = RoundStartEvent | CheckStartEvent | CheckEndEvent | VerdictEvent;\n\n/** The step id the check's card is recorded under: the check step's own, in\n * `./flow.ts`, so each round's check counts as a fresh run of it and opens a\n * card of its own. */\nexport const CHECK_STEP_ID = 'check';\n\n/** The raw call id and tool name of the check's card. The name sits outside\n * the workspace tools, so nothing dresses the card as one of theirs. */\nconst CHECK_CALL = { id: 'check', name: 'check' } as const;\n\nfunction emit(ctx: RunContext, event: PhaseEvent): void {\n ctx.emit(event);\n}\n\n/** Record one chunk of the check's card, the way `model_call` records a tool\n * call's, under a streamed run only, since nothing reads a card otherwise. */\nfunction record_check_chunk(ctx: RunContext, chunk: StreamChunk): void {\n if (ctx.streaming) ctx.trajectory.record({ kind: 'model_chunk', step_id: CHECK_STEP_ID, chunk });\n}\n\n/** The command line the check runs, or null when no check is configured. */\nfunction check_command(config: ResolvedConfig): string | null {\n if (config.check_resolved === 'checkride') return 'pnpm exec checkride --json --digest';\n if (config.check_resolved === 'command') return config.check;\n return null;\n}\n\n/** How the check runs when the caller sets it, as `volley acp` does. Left\n * out, the check runs unasked with volley's environment less the seats' keys,\n * as on the CLI. */\nexport type CheckGate = {\n /** The whole environment the check runs with, in place of volley's own less\n * the seats' keys. */\n env?: Readonly<Record<string, string>>;\n /** Asked on the check's card before each check, the way a model call asks\n * before a gated tool runs. Anything short of an allow keeps the check from\n * running, and it's recorded as failed. */\n on_approval?: ToolApprovalHandler;\n};\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 check?: CheckGate;\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 // A critique's change has no builder behind it, as far as volley knows.\n const [who, whose, edits] =\n config.mode === 'critique'\n ? ['the change under review touches', 'whether it passes', 'the change edits']\n : ['the builder changed', 'whether its work passes', 'the builder can edit'];\n renderer.warn(\n `gate edit: ${who} ${String(changes.gate_edits.length)} file(s) that decide ` +\n `${whose} — ${listed}${hidden > 0 ? ` (+${String(hidden)} more)` : ''}. ` +\n `A green check proves less when ${edits} 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\n/** Run the configured check, checkride or a command, with the environment\n * the caller set for it, else volley's own less the seats' keys, since the\n * check runs code the builder wrote. */\nasync function execute_check(deps: PhaseDeps, abort: AbortSignal): Promise<CheckResult> {\n const { config } = deps;\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 const options = { abort, env: deps.check?.env ?? command_env(process.env) };\n return config.check_resolved === 'checkride'\n ? run_checkride({ ...options, workspace: root })\n : run_command_check({ ...options, command: config.check, workspace: root });\n}\n\n/** Whether the check may run `command`: yes, unless the caller set an\n * approval and it answers no. It asks on the check's card under the command\n * line as its tool name, which titles the prompt the way the card is titled,\n * and which names none of fascicle's gated tools, so the prompt offers Allow\n * and Reject alone, never an \"always\" that would cover the builder's commands\n * too. A stop while it asks ends the check as a stop, not a rejection. */\nasync function check_allowed(\n deps: PhaseDeps,\n command: string,\n abort: AbortSignal,\n): Promise<boolean> {\n const approve = deps.check?.on_approval;\n if (approve === undefined) return true;\n const allowed = await approve({\n tool_name: command,\n input: { command },\n tool_call_id: CHECK_CALL.id,\n step_index: 0,\n abort,\n });\n if (abort.aborted) throw new aborted_error('check aborted');\n return allowed;\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/** What the builder of the iteration after `s` hears about it beyond the\n * critic's feedback: its check, and whether its builder ran out of steps. Null\n * before the first iteration. A resumed run's state carries both, read back\n * from the last archived iteration. */\nfunction previous_round(config: ResolvedConfig, s: LoopState): PreviousRound | null {\n if (s.iteration === 0) return null;\n return {\n check: s.check,\n step_limit_hit: s.builder?.finish_reason === 'max_steps' ? config.builder_max_steps : null,\n };\n}\n\n/** What changed in the build root since the baseline, reported as it's\n * measured: the count, and a warning for any gate edit. A run measures the\n * builder's work this way after every build, and a critique measures the\n * change under review the same way, so the critic is shown one shape either\n * way. */\nfunction measure_changes(deps: PhaseDeps, root: string): ChangeSet | null {\n const { config, renderer } = deps;\n const changes = collect_changes({\n root,\n baseline: deps.baseline,\n gate_patterns: config.gate_paths,\n excluded_dir: state_root_within(root, config.state_dir),\n });\n report_changes(config, renderer, changes);\n return changes;\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 emit(ctx, { volley: 'round_start', round: next.iteration });\n renderer.phase_start(next.iteration, 'builder');\n const built = await run_builder(\n { builder, config, warn: renderer.warn },\n next,\n previous_round(config, s),\n ctx,\n );\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 root = build_root(config.workspace, config.worktree);\n const changes = measure_changes(deps, root);\n if (config.git_checkpoints) {\n git_checkpoint(\n root,\n `volley iter ${String(built.iteration)}: build`,\n state_root_within(root, config.state_dir),\n );\n }\n return { ...built, changes };\n}\n\n/** `measure`: a critique's one round opens, and the change under review is\n * measured from the baseline, as a run measures the builder's work. */\nexport function measure_phase(deps: PhaseDeps, s: LoopState, ctx: RunContext): LoopState {\n const next = next_iteration(s);\n emit(ctx, { volley: 'round_start', round: next.iteration });\n const root = build_root(deps.config.workspace, deps.config.worktree);\n return { ...next, changes: measure_changes(deps, root) };\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/** Open the check's card on a streamed run: the call's start, then the\n * command as its input, the two chunks `model_call` records for a tool call\n * before it runs. */\nfunction open_check_card(ctx: RunContext, command: string): void {\n record_check_chunk(ctx, { kind: 'tool_call_start', ...CHECK_CALL, step_index: 0 });\n record_check_chunk(ctx, { kind: 'tool_call_end', id: CHECK_CALL.id, input: { command }, step_index: 0 });\n}\n\n/** Close the check's card with its result, which the card's reader renders,\n * or with the error that stopped the check before it had one. */\nfunction close_check_card(ctx: RunContext, outcome: { result: CheckResult } | { error: unknown }): void {\n record_check_chunk(\n ctx,\n 'result' in outcome\n ? { kind: 'tool_result', id: CHECK_CALL.id, output: outcome.result, step_index: 0 }\n : {\n kind: 'tool_result',\n id: CHECK_CALL.id,\n error: {\n message: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n },\n step_index: 0,\n },\n );\n}\n\n/** `check`: the deterministic gate over the tree the builder wrote. A check\n * that runs a command emits its start and end, and on a streamed run also\n * records its card as a tool call, so a reader of the stream shows it running\n * while it runs. When the caller set an approval, the check asks on that card\n * first, and a rejected check closes it failed and is recorded as failed. */\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 const command = check_command(config);\n if (command === null) {\n renderer.info('no deterministic check configured; loop is critic-gated only');\n return { ...s, check: skipped_check('none') };\n }\n emit(ctx, { volley: 'check_start', round: s.iteration, command });\n open_check_card(ctx, command);\n try {\n const allowed = await check_allowed(deps, command, ctx.abort);\n const result = allowed\n ? await execute_check(deps, ctx.abort)\n : rejected_check(config.check_resolved);\n close_check_card(ctx, allowed ? { result } : { error: CHECK_REJECTED });\n emit(ctx, {\n volley: 'check_end',\n round: s.iteration,\n ok: result.ok,\n exit_code: result.exit_code,\n failing_slots: result.failing_slots,\n duration_ms: result.duration_ms,\n });\n renderer.phase_end(\n s.iteration,\n 'check',\n result.ok,\n !allowed\n ? 'rejected'\n : result.failing_slots.length > 0\n ? `failing: ${result.failing_slots.join(', ')}`\n : undefined,\n );\n return {\n ...s,\n check: result,\n check_duration_ms: s.check_duration_ms + result.duration_ms,\n };\n } catch (err) {\n close_check_card(ctx, { error: 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 if (critiqued.verdict !== null) {\n emit(ctx, {\n volley: 'verdict',\n round: critiqued.iteration,\n verdict: critiqued.verdict,\n feedback: critiqued.feedback ?? '',\n unmet_criteria: critiqued.unmet_criteria,\n degraded: critiqued.critic?.critic_degraded === true,\n });\n }\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 const root = build_root(config.workspace, config.worktree);\n git_checkpoint(\n root,\n `volley iter ${String(s.iteration)}: critique (${s.verdict ?? 'skipped'})`,\n state_root_within(root, config.state_dir),\n );\n }\n return s;\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 * A critique (`build_critique_flow`) is one round over a change already made,\n * so it has no builder, no loop, and no guard: `measure`, which opens the\n * round and measures the change from its baseline, then the same `check`,\n * `critique`, and `record` a run's round ends with.\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 critic on any provider but claude_cli keeps dying or runs out of steps\n * │ │ ├─ retry one more try after a stream death, on any provider but claude_cli\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 { Step } from 'fascicle';\nimport { make_builder_step } from './builder.js';\nimport type { BuilderDeps } from './builder.js';\nimport type { BashExecutor } from './builder/tools.js';\nimport { cost_cap_hit } from './cost.js';\nimport {\n as_degraded,\n critic_degradable,\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 measure_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/** The builder seat: the engine its calls go through, and, when the caller\n * injects them, the tools that replace volley's own set, the name of that set\n * (which its prompt names), and the handler that answers their approval\n * requests. */\nexport type BuilderSeat = Pick<BuilderDeps, 'engine' | 'tools' | 'tool_set' | 'on_tool_approval'>;\n\n/** The critic seat: its engine and, when injected, the tools that replace its\n * reads and the name of their set. It takes no approval handler, since its\n * reads never ask. */\nexport type CriticSeat = Pick<CriticDeps, 'engine' | 'tools' | 'tool_set'>;\n\n/** What the flow is built from: the step bodies' dependencies, plus each\n * seat's model wiring and the builder's `bash` executor. The two seats share\n * one engine unless they reach one provider at different URLs. */\nexport type FlowDeps = PhaseDeps & {\n seats: { builder: BuilderSeat; critic: CriticSeat };\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 critic on any provider but\n * `claude_cli` whose tool-bearing stream dies is retried at once (the death is\n * stochastic parser failure, not load, so waiting buys nothing), then judged\n * once without tools. One that runs out of steps skips the retry, since\n * another identical tool loop would only run out again, and goes straight to\n * the tool-less pass. Anything else 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, on any provider but claude_cli',\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 critic on any provider but claude_cli keeps dying or runs out of steps',\n when: critic_degradable(deps.config),\n handoff: (prompt) => toolless_critic_prompt(deps.config, prompt),\n project: with_fallback_cause,\n },\n );\n}\n\n/** The steps a run and a critique share, built one way for both. */\nfunction check_step(deps: PhaseDeps): Step<LoopState, LoopState> {\n return step('check', (s: LoopState, ctx) => check_phase(deps, s, ctx), {\n description: 'the deterministic gate: checkride, a command, or none',\n });\n}\n\nfunction critique_step(deps: PhaseDeps, seat: CriticSeat): Step<LoopState, LoopState> {\n const critic = build_critic({ ...seat, config: deps.config, on_chunk: deps.renderer.critic_chunk });\n return step('critique', (s: LoopState, ctx) => critique_phase(deps, critic, s, ctx), {\n description: \"the read-only critic's verdict and feedback\",\n arm: critic,\n });\n}\n\nfunction record_step(deps: PhaseDeps): Step<LoopState, LoopState> {\n return step('record', (s: LoopState) => record_phase(deps, s), {\n description: 'archive the iteration and rewrite the run summary',\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 ...deps.seats.builder,\n config,\n on_chunk: renderer.builder_chunk,\n bash_executor: deps.bash_executor,\n });\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 = check_step(deps);\n const critique = critique_step(deps, deps.seats.critic);\n const record = record_step(deps);\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/** What a critique's flow is built from: the step bodies' dependencies and the\n * critic seat. There's no builder seat, so no builder is ever constructed. */\nexport type CritiqueFlowDeps = PhaseDeps & { critic: CriticSeat };\n\n/** A critique: one round over a change already made. `measure` opens it and\n * measures the change from the baseline, then the check, the critic, and the\n * record, as in a run's round. No loop and no guard: there is nothing to\n * iterate on, and the caller reads the outcome off the final state. */\nexport function build_critique_flow(deps: CritiqueFlowDeps): Step<LoopState, LoopState> {\n const measure = step('measure', (s: LoopState, ctx) => measure_phase(deps, s, ctx), {\n description: 'open the round and measure the change under review',\n });\n return sequence([measure, check_step(deps), critique_step(deps, deps.critic), record_step(deps)], {\n name: 'critique_run',\n });\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 run's state (or preserve it, on resume)\n * ├─ with_worktree off unless --worktree\n * │ ├─ capture the change baseline\n * │ ├─ run_loop run the flow (streamed when a sink is given), 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 *\n * run_critique\n * ├─ resolve the baseline --baseline, else HEAD; a bad revision exits 5\n * ├─ initialize the run's state\n * └─ run the critique flow one round on the critic's engine alone, then the final summary\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { run } from 'fascicle';\nimport { filesystem_logger, tee_logger } from 'fascicle/adapters';\nimport type { Engine, RunOptions, Step, TrajectoryLogger } from 'fascicle';\nimport type { BashExecutor } from './builder/tools.js';\nimport { capture_baseline, resolve_baseline } from './changes.js';\nimport { detect_containment } from './containment.js';\nimport { create_seat_engines, create_volley_engine, dispose_seat_engines } from './engine.js';\nimport type { SeatEngines } from './engine.js';\nimport { build_critique_flow, build_flow } from './flow.js';\nimport type { BuilderSeat, CriticSeat } from './flow.js';\nimport type { CheckGate } from './phases.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 { trust_key_path } from './trust.js';\nimport type { Renderer } from './render/renderer.js';\nimport { config_error, error_kind } from './types.js';\nimport type { LoopState, ResolvedConfig, RunResult, RunStatus } from './types.js';\nimport {\n initialize_run_state,\n integrate_worktree,\n run_state_dir,\n state_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 /** An engine to run both seats on in place of the ones built from the\n * config. It serves both seats as-is, so the seat URLs then steer only\n * volley's own requests (prewarm and the context probe), not model calls. */\n engine?: Engine;\n /** What to hand each seat in place of volley's own wiring: the builder's\n * tools and the handler that answers their approval requests, and the\n * critic's tools. A seat or a field left out keeps today's wiring, and a\n * `claude_cli` seat, which brings its own tools, takes none of it. */\n seats?: {\n builder?: Omit<BuilderSeat, 'engine'>;\n critic?: Omit<CriticSeat, 'engine'>;\n };\n /** A second sink for the run's trajectory, beside the run's\n * `trajectory.jsonl`. With one, the flow runs through `run.stream`, so the\n * sink also receives each model call's streamed chunks as `model_chunk`\n * events, which the file never keeps. */\n trajectory?: TrajectoryLogger;\n /** The environment the check runs with and the approval it asks first, in\n * place of inheriting volley's environment and running unasked. */\n check?: CheckGate;\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_run_state(config);\n // Unsigned on the host only when the machine's key can't be read or made.\n if (!write_resolved_config(config) && !detect_containment(process.env)) {\n renderer.warn(\n `could not sign this run's config with this machine's key (${trust_key_path(process.env)}), ` +\n 'so resuming it here will need --trust-config',\n );\n }\n } else {\n initialize_run_state(config, { preserve: true });\n }\n renderer.info(`state: ${run_state_dir(config)}`);\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: the run's `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. The run's state stays where `state_dir` puts it either\n // way. The seats share one engine unless they reach one provider at\n // different URLs.\n const engines: SeatEngines =\n deps.engine === undefined\n ? await create_seat_engines({\n workspace: build_root(config.workspace, config.worktree),\n builder_provider: config.builder_provider,\n builder_url: config.builder_url,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\n })\n : { builder: deps.engine, critic: deps.engine };\n\n const seats = {\n builder: { ...deps.seats?.builder, engine: engines.builder },\n critic: { ...deps.seats?.critic, engine: engines.critic },\n };\n const flow = build_flow(\n {\n seats,\n config,\n renderer,\n bash_executor,\n baseline,\n ...(deps.check !== undefined ? { check: deps.check } : {}),\n },\n resume_from,\n );\n\n try {\n const { value, converged } = await execute_flow(config, deps, flow, { resume_from });\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 dispose_seat_engines(engines);\n }\n}\n\n/** Run the flow into its file trajectory and, when the caller passed one, its\n * own sink. Without a sink this is the one `run` it has always been. With one,\n * it goes through `run.stream`, because only a streamed run records each model\n * call's chunks as `model_chunk` events, which are what an outer consumer maps\n * to text, tool cards, and approval prompts. The sink is that consumer, so the\n * handle's own event stream is closed at once rather than left to buffer, and\n * the file skips the chunks, so it holds the same kinds of event either way.\n *\n * The file goes first in the tee because the first sink's span ids are the\n * ones the run hands out as parents, so the file's parent links stay whole.\n * The sink sees parent ids it never issued, which costs an ACP consumer\n * nothing: it counts a step's runs by the `id` on each `span_start`. */\nfunction execute_flow<I, O>(\n config: ResolvedConfig,\n deps: Pick<OrchestratorDeps, 'trajectory' | 'abort' | 'install_signal_handlers'>,\n flow: Step<I, O>,\n input: I,\n): Promise<O> {\n const file = filesystem_logger({\n output_path: state_path(config, 'trajectory.jsonl'),\n });\n const options: RunOptions = {\n ...(deps.abort !== undefined ? { abort: deps.abort } : {}),\n ...(deps.install_signal_handlers !== undefined\n ? { install_signal_handlers: deps.install_signal_handlers }\n : {}),\n };\n if (deps.trajectory === undefined) return run(flow, input, { ...options, trajectory: file });\n const handle = run.stream(flow, input, {\n ...options,\n trajectory: tee_logger(without_model_chunks(file), deps.trajectory),\n });\n void handle.events[Symbol.asyncIterator]().return?.();\n return handle.result;\n}\n\n/** A logger that passes `inner` every event but a model call's streamed\n * chunks. */\nfunction without_model_chunks(inner: TrajectoryLogger): TrajectoryLogger {\n return {\n ...inner,\n record: (event) => {\n if (event.kind !== 'model_chunk') inner.record(event);\n },\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 = state_path(config, '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 // A summary an older volley wrote, resumed here, has no run_state_dir\n // and no step-limit count.\n write_run_summary(config, {\n ...prior,\n builder_max_steps_hits: (prior.builder_max_steps_hits as number | undefined) ?? 0,\n run_state_dir: run_state_dir(config),\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/** What a critique runs with: what a run does, less the builder's seat, plus\n * the revision its change is measured from. */\nexport type CritiqueDeps = Omit<OrchestratorDeps, 'seats'> & {\n /** The revision the change under review is measured from (`--baseline`):\n * everything that differs from it, committed or not, untracked files\n * included. HEAD when absent, so the uncommitted edits are the change. */\n baseline?: string;\n /** The critic's tools in place of volley's reads, as for a run's critic. */\n critic?: Omit<CriticSeat, 'engine'>;\n};\n\n/**\n * `volley critique`: the check and the critic, once, over a change already\n * made. No builder is constructed, and the engine serves the critic's seat\n * alone, so a critic can be measured on fixed, labeled changes without paying\n * for builder turns. It writes the state a one-round run does, with the mode\n * recorded, and ends `success` on approval over a green check, else\n * `rejected`.\n */\nexport async function run_critique(config: ResolvedConfig, deps: CritiqueDeps): Promise<RunResult> {\n if (config.mode !== 'critique') {\n throw config_error(\"run_critique needs a config resolved with mode 'critique'\");\n }\n const { renderer } = deps;\n // First, so a revision that isn't a commit fails before any state is written.\n const baseline = resolve_baseline(config.workspace, deps.baseline);\n initialize_run_state(config);\n write_resolved_config(config);\n renderer.info(`state: ${run_state_dir(config)}`);\n renderer.info(\n baseline === null\n ? 'baseline: none (not a git repository, or no commit yet); the critic reviews the tree'\n : `baseline: ${baseline}`,\n );\n\n const engine =\n deps.engine ??\n create_volley_engine({\n workspace: config.workspace,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\n });\n const flow = build_critique_flow({\n config,\n renderer,\n baseline,\n critic: { ...deps.critic, engine },\n ...(deps.check !== undefined ? { check: deps.check } : {}),\n });\n try {\n const value = await execute_flow(config, deps, flow, initial_state());\n const passed = value.check?.ok === true && value.verdict === 'approved';\n const result = run_result_from_state(\n config,\n value,\n passed ? 'success' : 'rejected',\n new Date().toISOString(),\n );\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 * 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 /** Where the run's trajectory is written, named when verbose output is cut\n * short (default: \"the run's trajectory.jsonl\"). */\n trajectory_path?: string;\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 see_trajectory = `see ${options.trajectory_path ?? \"the run's trajectory.jsonl\"}`;\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_trajectory,\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_trajectory)}`);\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 line(`state: ${result.run_state_dir}`);\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 a parent harness 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 { join, resolve } from 'node:path';\nimport { config_error } from './types.js';\nimport { default_state_root, RUN_ID_PATTERN } from './workspace.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/** Where volley inside the container keeps each run's state when no\n * `--state-dir` names a root: the default root under the pinned `HOME`, since\n * the image sets no `XDG_STATE_HOME`. `sandbox_run_args`'s `run_state` binds one\n * run's host directory at that run's directory under it, so the state outlives\n * the `--rm` container. Exported so a harness can map a contained run's\n * `run_state_dir` back to the directory it mounted. */\nexport const SANDBOX_STATE_ROOT = default_state_root({}, SANDBOX_HOME);\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 * `seat_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 and a parent harness 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 * `run_state` binds the run's own state directory on the host,\n * `<root>/<run_id>/`, at `<SANDBOX_STATE_ROOT>/<run_id>/`, where volley inside\n * keeps that run's state when no `--state-dir` names a root, so it outlives the\n * container at the path a run on the host would use. Only the one directory\n * is mounted, never the root: the builder inside runs arbitrary commands, so\n * it can rewrite its own run's state but can't read another run's trajectory\n * or plant a check in another run's config. Its own run's state is still the\n * builder's to rewrite, config.json included, so a host-side resume refuses\n * that config, which volley signs only outside the sandbox (`./trust.ts`), and\n * a directory holding a symlink: resume a contained run inside the container,\n * with the same mount. Create the\n * directory on the host first, empty (Docker on Linux makes a missing bind\n * source owned by root, which the container's user can't write), and pass the\n * same id to volley as `--run-id`. Keep it outside `build_root`, so the check\n * never reads it, and pass no `XDG_STATE_HOME` in `env`, which would move the\n * root off the mount. Omit it and no state is mounted: a contained run keeping\n * its state under the default root then stops before spending (exit 5),\n * since the read-only root filesystem leaves it nowhere to write.\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 * and, when one is named, the state root are the host-visible write paths.\n */\nexport function sandbox_run_args(options: {\n image: string;\n build_root: string;\n uid: number | null;\n gid: number | null;\n run_state?: { root: string; run_id: string } | 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 state =\n options.run_state !== undefined && options.run_state !== null\n ? ['-v', run_state_mount(options.run_state)]\n : [];\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 state root and the\n // persistent pnpm store.\n '-v',\n `${resolve(options.build_root)}:${SANDBOX_WORKDIR}`,\n ...state,\n ...store,\n '-w',\n SANDBOX_WORKDIR,\n ...entrypoint,\n options.image,\n ...(options.command ?? []),\n ];\n}\n\n/** The `-v` value for one run's state directory. The run id becomes a path on\n * both sides, so it is held to volley's own `--run-id` rule, which keeps it to\n * one directory name. */\nfunction run_state_mount(run_state: { root: string; run_id: string }): string {\n if (!RUN_ID_PATTERN.test(run_state.run_id)) {\n throw config_error(\n `run_state.run_id must be letters, digits, '-', and '_', starting with a letter or digit; got: ${run_state.run_id}`,\n );\n }\n return `${join(resolve(run_state.root), run_state.run_id)}:${SANDBOX_STATE_ROOT}/${run_state.run_id}`;\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, the run's\n * own host state directory mounted where volley inside keeps it, 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 /** The run's host state directory, `<root>/<run_id>/` (`run_state` on\n * `sandbox_run_args`), usually under the host's `default_state_root`;\n * `command` must pass the same `--run-id`. */\n run_state: { root: string; run_id: 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 run_state: options.run_state,\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 * Minimal POSIX quoting: single-quote any token with whitespace or\n * 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 // A critique that didn't pass exits as a run that didn't converge does.\n case 'rejected':\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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"}
1
+ {"version":3,"file":"index.js","names":["git"],"sources":["../src/types.ts","../src/engine.ts","../src/changes.ts","../src/check/detect.ts","../src/containment.ts","../src/workspace_tools.ts","../src/tester/tools.ts","../src/trust.ts","../src/workspace.ts","../src/config.ts","../src/builder/context_check.ts","../src/builder/countdown.ts","../src/builder/prepare_step.ts","../src/builder/trim.ts","../src/builder/tools.ts","../src/check/checkride.ts","../src/check/command.ts","../src/claude_cli_permissions.ts","../src/cost.ts","../src/prewarm.ts","../src/worktree.ts","../src/builder.ts","../src/critic/prompt.ts","../src/critic/run.ts","../src/loop_state.ts","../src/render/format.ts","../src/iteration.ts","../src/summary.ts","../src/tester/prompt.ts","../src/tester/run.ts","../src/phases.ts","../src/flow.ts","../src/orchestrator.ts","../src/render/renderer.ts","../src/sandbox.ts","../src/exit_codes.ts"],"sourcesContent":["/**\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 { EffortLevel, FinishReason, Throughput, UsageTotals } from 'fascicle';\n\nexport type Verdict = 'approved' | 'changes_requested';\n\n/** One rung of the effort ladder, and the critic's effort: fascicle's\n * per-call `effort` levels less `none`, which on `claude_cli` sets nothing and\n * leaves Claude Code at its own default, possibly above `low`, so it can't\n * stand on a ladder that climbs. */\nexport type EffortRung = Exclude<EffortLevel, 'none'>;\n\nexport type CriticPreset = 'reviewer' | 'optimizer' | 'researcher';\n\n/** `--tester`: whether a tester writes a failing test from the criteria\n * before the first build. */\nexport type TesterSetting = 'on' | 'off';\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. `openrouter` reaches a\n * hosted model over one API key and takes the local critic's tools and\n * degradation ladder. */\nexport type CriticProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';\n\n/** Transport for the builder role. `claude_cli` is a full agentic Claude Code\n * session; every other provider runs the builder as a volley-driven tool loop\n * (write/exec tools supplied by the harness), whether its model is local\n * (`ollama`, `lmstudio`) or hosted (`openrouter`). */\nexport type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';\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\n/** Why a local critic's verdict came from the tool-less fallback:\n * `stream_error`, the tool-bearing call kept dying on the provider's stream\n * after the bounded retry; `step_exhaustion`, it spent its step budget (or\n * stopped on a tool call) without producing a verdict. */\nexport type DegradeCause = 'stream_error' | 'step_exhaustion';\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 /** The check passed right after the tester wrote its test, before any\n * build: the test is vacuous or the work is already done, and either way no\n * builder is paid to find out (move 1's D6, D17). */\n | 'tester_passed_early'\n /** A critique's other outcome: the critic requested changes, or the check\n * failed, on the one change it reviewed. A run never ends this way. */\n | 'rejected'\n | 'interrupted'\n | 'error';\n\n/** What a run does: the builder/critic loop (`run`), or one check and one\n * critique of a change already made, with no builder at all (`critique`). */\nexport type RunMode = 'run' | 'critique';\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_url?: string;\n builder_max_steps?: number;\n builder_max_tool_calls?: number;\n builder_max_output_tokens?: number;\n builder_trim_history?: number;\n effort_ladder?: EffortRung[];\n allow_unsandboxed_builder?: boolean;\n critic_model?: string;\n critic_provider?: CriticProvider;\n critic_url?: string;\n critic_effort?: EffortRung;\n tester?: TesterSetting;\n tester_model?: string;\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 state_dir?: 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; the run's `config.json` mirrors this. */\nexport type ResolvedConfig = {\n version: 2;\n run_id: string;\n started_at: string;\n /** A run, or a critique (`volley critique`). A critique's builder fields\n * hold the defaults, untouched by flags and the environment, since no\n * builder is ever constructed, and its loop settings are one round with\n * nothing isolated or committed. */\n mode: RunMode;\n /** The task. A critique needs none, since a critic judges against the\n * criteria alone, so it's empty unless one was given to record. */\n prompt: string;\n criteria: string;\n check: CheckMode;\n check_resolved: CheckRunnerKind;\n builder_model: string;\n builder_provider: BuilderProvider;\n /** The builder seat's own model server base URL (`--builder-url`), as given.\n * It is normalized, and crossed to the host LLM endpoint when contained, only\n * where it is used, because the crossing depends on where the run executes.\n * Null falls back to the provider's env var (`VOLLEY_OLLAMA_URL` /\n * `VOLLEY_LMSTUDIO_URL` / `VOLLEY_OPENROUTER_URL`), then its default, never to\n * the critic's URL. Only a provider volley reaches at a base URL (ollama,\n * lmstudio, openrouter) takes one. */\n builder_url: string | null;\n builder_max_steps: number;\n /** How many tool calls a tool-loop builder may make in one turn, reads\n * aside (`read_file`, `search_files`, `list_files` are `read_only` and\n * don't count); fascicle runs a turn's calls in order up to the first one\n * past the cap, drops the rest, and tells the model which it dropped. 1 by\n * default, since some model and runtime pairs return parallel calls badly;\n * raise it for a pair that handles them. Ignored by the `claude_cli`\n * builder. */\n builder_max_tool_calls: number;\n /** The most output tokens a tool-loop builder may generate in one turn,\n * reasoning included, or null to leave each turn to the provider's own\n * limit. 16384 by default on a local builder (ollama, lmstudio), null on\n * openrouter. A turn cut off at it before it made a tool call costs that\n * one step, not the session: fascicle feeds back that it hit the limit and\n * the loop goes on. Ignored by the `claude_cli` builder. */\n builder_max_output_tokens: number | null;\n /** The estimated request size, in tokens, above which a tool-loop builder's\n * turns send older tool results as one-line stubs (#7), or null to send\n * every turn whole. Null by default, until a long local session is shown\n * to run faster with it on. Ignored by the `claude_cli` builder. */\n builder_trim_history: number | null;\n /** The efforts the builder climbs (`--effort-ladder`): each build runs one\n * rung further up than the last, and the top rung repeats. Null, the\n * default, passes no effort at all, so the builder's call is today's. On\n * `ollama` and `lmstudio`, whose transports drop effort, every rung is the\n * same and the ladder is flat. */\n effort_ladder: EffortRung[] | null;\n /** Operator opt-out permitting a non-`claude_cli` builder to run without a\n * sandbox — it gets a real host bash. Refused by default. */\n allow_unsandboxed_builder: boolean;\n critic_model: string;\n critic_provider: CriticProvider;\n /** The critic seat's own model server base URL (`--critic-url`), as given;\n * resolved like `builder_url`, and null never falls back to the builder's. */\n critic_url: string | null;\n /** The critic's effort on every call (`--critic-effort`), apart from the\n * builder's ladder: `high` when a ladder is set and nothing names one, since\n * the critic is what makes a cheap build safe, else null, which passes no\n * effort, as before there was a ladder. */\n critic_effort: EffortRung | null;\n /** Whether a tester runs before the first build (`--tester on`), writing a\n * failing test from the criteria under the test and fixture gate paths. Off\n * by default. It takes the critic's provider, URL and effort. */\n tester: boolean;\n /** The tester's model: `--tester-model`, else the critic's. Null with the\n * tester off. */\n tester_model: string | null;\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 * the run's state stays where `state_dir` puts it (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 /** The root that holds each run's state at `<state_dir>/<run_id>/`, as an\n * absolute path: `--state-dir`, else the default root,\n * `$XDG_STATE_HOME/volley` or `~/.local/state/volley`. `resolve_config`\n * always sets one. Null is the layout older runs used, `<workspace>/.volley/`,\n * rotated aside by the next fresh run: a run an older volley started\n * resumes in it, and a hand-built config can still ask for it. */\n state_dir: string | null;\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 /** checkride's capped excerpt of the failing slots (`.check/digest.md`),\n * when the check failed and checkride wrote one. */\n digest?: string;\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 /** What the critic found wrong with the tester's test, when it found\n * anything. Critic-only. Additive. */\n test_findings?: string[];\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 /** Turns the provider cut off at the output cap before they made a tool\n * call (`--builder-max-output-tokens`), each of which cost a step and went\n * on. Set on a builder record when any was; absent otherwise. Additive. */\n truncated_turns?: 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, or ran out of steps before its verdict, so the\n * critic judged with no read access — grounded only by the criteria, the raw\n * check artifacts, and a workspace file inventory. Set (true) on a degraded\n * critic record; absent on a full critique and on the builder. Additive, and a\n * degraded verdict is *always* marked so it never passes silently as a full\n * one. */\n critic_degraded?: boolean;\n /** Why the verdict degraded, set with `critic_degraded`. Additive. */\n degrade_cause?: DegradeCause;\n /** The seat asked for an effort its provider drops (ollama, lmstudio), so\n * the call ran at the provider's own and a ladder there is flat. Set on a\n * builder record that ran at a rung and a critic record that ran at\n * `critic_effort`, when either was ignored; absent otherwise. Additive. */\n effort_ignored?: true;\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 *\n * On Ollama, `decode` holds only while a turn's first chunk arrives as its\n * first token is generated. Ollama sends a tool call whole, so a turn whose\n * only output is a tool call dispatches nothing until generation ends, and\n * its tokens are divided by the last few milliseconds: a non-thinking seat's\n * rate reads far too high until robmclarty/fascicle#12 times those turns\n * another way. A thinking seat needs ai-sdk-ollama 4.3.0 or later, which\n * streams the reasoning even though volley never sets `think`. */\n throughput?: Throughput;\n /** Each turn of a builder session, in order, so a long session's growth\n * and where its time went can be read off the archive (#7). Set on a builder\n * record whose provider reported steps (every tool-loop builder); absent on\n * the critic and on a session with none. Additive. */\n steps?: BuilderStepRecord[];\n};\n\n/** Where a builder turn's prefill and decode times came from.\n * `ollama_reported`: Ollama's own `prompt_eval_duration` and `eval_duration`\n * (native transport). `ollama_derived`: prefill as `total_duration` less\n * `load_duration` and `eval_duration`, the ai_sdk transport's metadata, which\n * leaves `prompt_eval_duration` out; slightly high, since the total includes\n * Ollama's own overhead. `first_chunk`: prefill as the time to the first\n * streamed chunk, decode as the rest of the round trip. `none`: no split. */\nexport type StepTimingBasis = 'ollama_reported' | 'ollama_derived' | 'first_chunk' | 'none';\n\n/** One turn of a builder session. */\nexport type BuilderStepRecord = {\n index: number;\n /** The whole request this turn sent, so the session's growth reads as the\n * sequence of these. */\n input_tokens: number;\n output_tokens: number;\n /** The turn's provider round trip, tool execution excluded. */\n duration_ms: number;\n prefill_ms?: number;\n decode_ms?: number;\n timing_basis: StepTimingBasis;\n finish_reason: FinishReason;\n truncated?: true;\n /** Each tool call the turn made, and how many characters its result put\n * into the transcript every later turn resends. */\n tool_calls: Array<{ name: string; output_chars: number }>;\n};\n\nexport type HaltReason = 'cost_cap' | 'gate_edit' | 'tester_passed_early' | null;\n\n/** Why a build ran one rung up the ladder from the build before it: that\n * build's check failed, or its check passed and the critic sent it back. */\nexport type ClimbReason = 'check_failed' | 'critic_rejected';\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 /** This iteration's tester session, or null: the tester runs in iteration 1\n * only, before its build. */\n tester: PhaseRecord | null;\n /** The check run right after the tester, which must fail; null in an\n * iteration the tester didn't open. Apart from `check`, which is the check\n * after the build. */\n tester_check: CheckResult | null;\n /** What the tester wrote, measured as the builder's changes are; null in an\n * iteration the tester didn't open, or outside a git repository. */\n tester_changes: ChangeSet | null;\n /** Each file the tester wrote, by its hash right after the test phase. A\n * build that leaves one at that hash didn't edit the gate there (move 1's\n * D22). Kept for the whole run, and read back on resume. */\n tester_hashes: Record<string, string>;\n total_usage: UsageTotals;\n total_cost_usd: number;\n builder_cost_usd: number;\n critic_cost_usd: number;\n /** The tester's spend, apart from the other two seats' (D21). */\n tester_cost_usd: number;\n check_duration_ms: number;\n /** How many of the run's builder sessions ended on the step limit\n * (`max_steps`) rather than calling finish. */\n builder_max_steps_hits: number;\n /** Builder sessions the run has started, this iteration's included: build\n * *k* runs at `effort_ladder[min(k, len) - 1]`. A resumed run reads it back\n * from the last archived iteration. */\n builds: number;\n /** The effort this iteration's build ran at, or null with no ladder. */\n rung: EffortRung | null;\n /** Why this iteration's build ran a rung above the last one's, or null when\n * it didn't: the first build, the top rung repeating, or no ladder. */\n climbed: ClimbReason | null;\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; the run's `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 /** The tester's spend; 0 with the tester off. Additive. */\n tester_cost_usd: number;\n check_duration_ms: number;\n /** How many of the run's builder sessions hit the step limit before they\n * called finish: work handed to the check and critic unverified. The\n * warning a run prints for each goes to stderr, which `--json` silences, so\n * a harness reads it here. Always 0 for a `claude_cli` builder, which has\n * no step limit, and for a critique. */\n builder_max_steps_hits: 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; the run's `summary.json` mirrors it. */\n salvaged_branch: string | null;\n /** A run, or a critique, which runs no builder. */\n mode: RunMode;\n /** Where this run keeps its config, summary, trajectory, feedback, verdict,\n * and iterations: `<state_dir>/<run_id>/` under a state root, else the\n * workspace's `.volley/`. Inside the sandbox container it is the container's\n * path, which a harness maps back to the directory it mounted. */\n run_state_dir: string;\n};\n\nexport type VolleyPhase = 'builder' | 'critic' | 'tester' | '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 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/** OpenRouter's API root, the one fascicle's openrouter adapter defaults to. */\nexport const DEFAULT_OPENROUTER_URL = 'https://openrouter.ai/api/v1';\n\n/** The variable an `openrouter` seat's API key is read from. */\nconst OPENROUTER_KEY_VAR = 'OPENROUTER_API_KEY';\n\n/** The variable a `claude_cli` seat's API key is read from, which the Claude\n * CLI also reads on its own. */\nconst ANTHROPIC_KEY_VAR = 'ANTHROPIC_API_KEY';\n\n/** Every variable a seat reads a credential from. Every process volley starts\n * runs without them (the check, the builder's commands, and volley's own git\n * and checkride calls, which run hooks and filters the builder can write), so\n * nothing the builder writes can read the keys its seats spend. */\nexport const SEAT_CREDENTIAL_VARS: ReadonlyArray<string> = [OPENROUTER_KEY_VAR, ANTHROPIC_KEY_VAR];\n\n/** The environment every process volley starts runs with: `env`, `PATH`\n * included, less every variable a seat reads a credential from. */\nexport function command_env(env: Readonly<Record<string, string | undefined>>): Record<string, string> {\n const stripped: ReadonlySet<string> = new Set(SEAT_CREDENTIAL_VARS);\n return Object.fromEntries(\n Object.entries(env).filter(\n (entry): entry is [string, string] => entry[1] !== undefined && !stripped.has(entry[0]),\n ),\n );\n}\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`. `URL.hostname` keeps an\n * IPv6 literal's brackets, so the IPv6 loopback is spelled `[::1]`. */\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 providers a seat reaches at a base URL volley configures. `claude_cli`\n * picks its own endpoint, so it never appears here. */\ntype UrlProvider = 'ollama' | 'lmstudio' | 'openrouter';\n\n/** Where a URL-taking provider's base URL comes from when a seat names none of\n * its own: the provider's env var, then its default. `normalize` canonicalizes\n * a URL from any source, so two spellings of one server compare equal. */\ntype SeatUrlSource = {\n env: string;\n default_url: string;\n normalize: (url: string) => string;\n};\n\nfunction strip_trailing_slashes(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\nconst SEAT_URL_SOURCES: Readonly<Record<UrlProvider, SeatUrlSource>> = {\n // A trailing `/api` (the pre-v0.3.1 documented default, and a natural mistake\n // since Ollama's REST paths all start with it) is stripped rather than left\n // to 404 every request.\n ollama: {\n env: 'VOLLEY_OLLAMA_URL',\n default_url: DEFAULT_OLLAMA_URL,\n normalize: (url) => strip_trailing_slashes(url).replace(/\\/api$/, ''),\n },\n // LM Studio's base URL keeps its `/v1`: the OpenAI-compatible client appends\n // `/chat/completions` to it.\n lmstudio: {\n env: 'VOLLEY_LMSTUDIO_URL',\n default_url: DEFAULT_LMSTUDIO_URL,\n normalize: strip_trailing_slashes,\n },\n // OpenRouter's base URL keeps its `/api/v1` the same way, so a seat URL can\n // name a proxy or another OpenAI-compatible gateway.\n openrouter: {\n env: 'VOLLEY_OPENROUTER_URL',\n default_url: DEFAULT_OPENROUTER_URL,\n normalize: strip_trailing_slashes,\n },\n};\n\n/** The providers that take a seat URL (`--builder-url` / `--critic-url`), and\n * so get their endpoint probed by `--dry-run`. */\nexport const SEAT_URL_PROVIDERS = Object.keys(SEAT_URL_SOURCES) as ReadonlyArray<UrlProvider>;\n\n/** Whether a seat on `provider` reaches its model at a base URL volley\n * configures, and so takes a URL of its own. */\nexport function takes_seat_url(\n provider: BuilderProvider | CriticProvider | undefined,\n): provider is UrlProvider {\n return (SEAT_URL_PROVIDERS as ReadonlyArray<string | undefined>).includes(provider);\n}\n\n/** An absent, empty, or all-whitespace value counts as unset. */\nfunction present(value: string | null | undefined): string | null {\n const trimmed = value?.trim() ?? '';\n return trimmed === '' ? null : trimmed;\n}\n\n/** The base URL a seat's model calls go to: the seat's own URL, else the\n * provider's env var (`VOLLEY_OLLAMA_URL` / `VOLLEY_LMSTUDIO_URL` /\n * `VOLLEY_OPENROUTER_URL`), else its default. A seat never falls back to the\n * other seat's URL. The result is normalized, then a loopback authority is\n * crossed to the host LLM endpoint when volley runs contained. Both seats can\n * be loopback URLs on different ports, and each crosses on its own port. */\nexport function seat_base_url(\n provider: UrlProvider,\n seat_url: string | null,\n env: Record<string, string | undefined>,\n): string {\n const source = SEAT_URL_SOURCES[provider];\n const raw = present(seat_url) ?? present(env[source.env]) ?? source.default_url;\n return cross_to_host_gateway(source.normalize(raw), env);\n}\n\n/** The API key an `openrouter` seat sends, from `OPENROUTER_API_KEY`. An unset\n * or blank key is a config error naming the variable, which `resolve_config`\n * raises before any work, because fascicle's own \"requires a non-empty\n * api_key\" doesn't say where the key comes from. */\nexport function openrouter_api_key(env: Record<string, string | undefined>): string {\n const key = present(env[OPENROUTER_KEY_VAR]);\n if (key === null) {\n throw config_error(\n `${OPENROUTER_KEY_VAR} is not set: an openrouter seat sends it as its API key`,\n );\n }\n return key;\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 URL-taking provider, that provider is\n * configured alongside claude_cli so one engine drives both roles. */\n builder_provider?: BuilderProvider;\n /** The builder seat's own base URL (`--builder-url`); null or absent falls\n * back to the provider's env var, then its default. */\n builder_url?: string | null;\n /** When the critic runs on a URL-taking provider, that provider is\n * configured alongside claude_cli so one engine drives both roles. */\n critic_provider?: CriticProvider;\n /** The critic seat's own base URL (`--critic-url`), resolved the same way. */\n critic_url?: string | null;\n env?: Record<string, string | undefined>;\n};\n\n/** A seat's provider entry, with the base URL resolved for that seat. The ai-sdk\n * peer (`ai-sdk-ollama` / `@ai-sdk/openai-compatible`) is loaded lazily by\n * fascicle only when the provider actually runs. The entry is complete, because\n * `Engine.with_providers` replaces a provider's whole entry: whatever this\n * returns is all a seat's derived engine knows about the provider, so an\n * `openrouter` entry carries its key and its transport along with its URL.\n *\n * `openrouter` runs on fascicle's native transport, its OpenAI-compatible core,\n * so no ai-sdk peer gets installed for it, and its `X-Title` attributes the\n * traffic to volley.\n *\n * For the local providers, native transport is the deferred future bridge, not\n * adopted here: they stay on the ai_sdk transport, which fascicle 0.14.0 already\n * selects by default (`transport?: 'ai_sdk' | 'native'` defaults to `'ai_sdk'`),\n * so no field is needed today. Flipping later is a one-line change — add\n * `transport: 'native'` to the ollama/lmstudio entry returned below, which both\n * seats' engines then share. No URL re-pointing is required: `seat_base_url`\n * already yields the daemon-root URL the native `/api/chat` transport wants\n * (its adapter appends `/api/chat` itself), which is exactly what the v0.3.1\n * base-URL fix produces.\n * Kept as a proven-once-then-reverted option so the transport stays a clean\n * second variable in the model-vs-transport comparison. Flipping it today would\n * also lose the reasoning: fascicle's native Ollama adapter drops\n * `message.thinking`, with `think` unset or true (robmclarty/fascicle#12), so a\n * thinking seat's reasoning would vanish from the terminal and the trajectory.\n *\n * Every provider's base URL crosses a loopback authority to `VOLLEY_MODEL_HOST`\n * when 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 seat_provider_config(\n provider: UrlProvider,\n seat_url: string | null,\n env: Record<string, string | undefined>,\n): ProviderConfigMap {\n const base_url = seat_base_url(provider, seat_url, env);\n switch (provider) {\n case 'ollama':\n return { ollama: { base_url } };\n case 'lmstudio':\n return { lmstudio: { base_url } };\n case 'openrouter':\n return {\n openrouter: {\n api_key: openrouter_api_key(env),\n base_url,\n transport: 'native',\n x_title: 'volley',\n },\n };\n }\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 URL-taking provider selected\n * by the builder or critic role is wired in alongside it, at that seat's URL,\n * so one engine drives both roles. An engine holds one URL per provider, so on\n * a provider both seats share it carries the builder's; `create_seat_engines`\n * gives the critic its own engine when its URL differs. Binary, auth mode,\n * fallback 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 const providers: ProviderConfigMap = {\n claude_cli: {\n default_cwd: options.workspace,\n setting_sources: ['project', 'local'],\n auth_mode,\n // Under `oauth` the CLI inherits the whole environment to reach its\n // login, and hands it on to every command it runs; this keeps the other\n // seat's key out. fascicle drops these before it applies the auth mode,\n // so a configured `api_key` still reaches the CLI.\n omit_env: SEAT_CREDENTIAL_VARS,\n ...(binary !== undefined && binary.length > 0 ? { binary } : {}),\n ...(auth_mode === 'api_key' && env[ANTHROPIC_KEY_VAR] !== undefined\n ? { api_key: env[ANTHROPIC_KEY_VAR] }\n : {}),\n },\n };\n // A run may select a URL-taking provider for the builder, the critic, or both\n // (even two different ones). The critic's goes in first, so a critic-only\n // engine (the dry-run canary's) gets the critic's URL, and on a provider both\n // seats share, the builder's URL wins.\n if (takes_seat_url(options.critic_provider)) {\n Object.assign(\n providers,\n seat_provider_config(options.critic_provider, options.critic_url ?? null, env),\n );\n }\n if (takes_seat_url(options.builder_provider)) {\n Object.assign(\n providers,\n seat_provider_config(options.builder_provider, options.builder_url ?? null, env),\n );\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 engine each seat's model calls go through. */\nexport type SeatEngines = { builder: Engine; critic: Engine };\n\n/** One engine per seat, shared unless it can't be. fascicle fixes one base URL\n * per provider when it builds an engine, so two seats on the same provider at\n * different URLs need two engines: the critic's is derived from the builder's\n * with `with_providers`, which keeps claude_cli, auth, and pricing and\n * overrides only the shared provider's entry. Every other pairing, including a\n * run that sets no seat URL at all, gets the one engine a run has always had. */\nexport async function create_seat_engines(options: EngineOptions): Promise<SeatEngines> {\n const env = options.env ?? process.env;\n const builder = create_volley_engine(options);\n const provider = options.critic_provider;\n if (\n provider !== options.builder_provider ||\n !takes_seat_url(provider) ||\n seat_base_url(provider, options.builder_url ?? null, env) ===\n seat_base_url(provider, options.critic_url ?? null, env)\n ) {\n return { builder, critic: builder };\n }\n try {\n const critic = builder.with_providers(\n seat_provider_config(provider, options.critic_url ?? null, env),\n );\n return { builder, critic };\n } catch (err) {\n // Nothing has run on the builder's engine yet; release it, not leak it.\n await builder.dispose();\n throw err;\n }\n}\n\n/** Dispose each distinct seat engine once. Both disposals start together, so\n * one that fails doesn't keep the other from running. */\nexport async function dispose_seat_engines(engines: SeatEngines): Promise<void> {\n const distinct =\n engines.critic === engines.builder ? [engines.builder] : [engines.builder, engines.critic];\n await Promise.all(distinct.map((engine) => engine.dispose()));\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 { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { command_env } from './engine.js';\nimport { config_error } from './types.js';\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 env: command_env(process.env),\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/**\n * The commit a critique's change is measured from: `rev` (`--baseline`)\n * resolved in `root`, so the change is everything that differs from it,\n * committed or not, untracked files included. With no revision named it's\n * HEAD, so the uncommitted and untracked edits are the change, and, as for a\n * run, null where there's no repository or no commit yet. A named revision\n * that isn't a commit there, or one named where there's no repository, is a\n * config error.\n */\nexport function resolve_baseline(root: string, rev: string | undefined): string | null {\n if (rev === undefined) return capture_baseline(root);\n if (!in_git_repo(root)) {\n throw config_error(`--baseline needs the workspace to be a git repository: ${root}`);\n }\n // `--end-of-options` keeps a revision that starts with `-` from reading as a flag.\n const resolved = git(root, ['rev-parse', '--verify', '--quiet', '--end-of-options', `${rev}^{commit}`]);\n const sha = resolved.stdout.trim();\n if (resolved.status !== 0 || sha.length === 0) {\n throw config_error(`--baseline names no commit in ${root}: ${rev}`);\n }\n return sha;\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, excluded_dir: string | null): boolean {\n if (excluded_dir !== null && path.startsWith(`${excluded_dir}/`)) return true;\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 /** A state root inside `root`, relative to it (`state_root_within`): the\n * harness's files, never the builder's. */\n excluded_dir?: string | null;\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 excluded_dir = options.excluded_dir ?? null;\n const seen = new Set<string>();\n const files: ChangedFile[] = [];\n for (const change of [...tracked, ...untracked]) {\n if (excluded(change.path, excluded_dir) || 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/** A file's content hash under `root`, or null when it can't be read (gone,\n * or a directory). */\nfunction hash_file(root: string, path: string): string | null {\n try {\n return createHash('sha256').update(readFileSync(join(root, path))).digest('hex');\n } catch {\n return null;\n }\n}\n\n/** Every changed path in `root` since the baseline, by its content hash: what\n * the build root holds before the tester writes, so what it writes can be told\n * from a workspace that was dirty to begin with. Empty outside a git\n * repository, where nothing is measured. */\nexport function snapshot_changes(options: CollectChangesOptions): Map<string, string | null> {\n const changes = collect_changes({ ...options, limit: Number.POSITIVE_INFINITY });\n return new Map((changes?.files ?? []).map((file) => [file.path, hash_file(options.root, file.path)]));\n}\n\n/** What the tester wrote: the changes since the baseline whose content isn't\n * what the snapshot taken before it held, as a change set of their own, and\n * each written file's hash, which a later build is measured against (move 1's\n * D9, D22). Null and none outside a git repository. */\nexport function tester_written(\n options: CollectChangesOptions,\n before: ReadonlyMap<string, string | null>,\n): { changes: ChangeSet | null; hashes: Record<string, string> } {\n const after = collect_changes({ ...options, limit: Number.POSITIVE_INFINITY });\n if (after === null) return { changes: null, hashes: {} };\n const hashes: Record<string, string> = {};\n const files = after.files.filter((file) => {\n const hash = hash_file(options.root, file.path);\n if (before.has(file.path) && before.get(file.path) === hash) return false;\n if (hash !== null) hashes[file.path] = hash;\n return true;\n });\n return {\n changes: {\n baseline: after.baseline,\n gate_edits: files.filter((file) => file.gate).map((file) => file.path),\n total: files.length,\n files,\n truncated: false,\n },\n hashes,\n };\n}\n\n/** `changes` with the tester's files taken out of its gate edits, unless the\n * build changed one from the hash it had after the tester: the tester editing\n * the gate is the point, and a builder that left its test alone didn't (D9).\n * A file the build deleted no longer hashes as it did, so it stays an edit. */\nexport function without_tester_edits(\n changes: ChangeSet | null,\n root: string,\n hashes: Readonly<Record<string, string>>,\n): ChangeSet | null {\n if (changes === null || Object.keys(hashes).length === 0) return changes;\n return {\n ...changes,\n gate_edits: changes.gate_edits.filter(\n (path) => hashes[path] === undefined || hash_file(root, path) !== hashes[path],\n ),\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 * Whether volley is running inside its sandbox container. A leaf, so the\n * config resolution, the preflight, and the run-config signing can all ask\n * without importing one another.\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: Readonly<Record<string, string | undefined>>): boolean {\n const value = env['VOLLEY_CONTAINED'];\n return value === '1' || value === 'true';\n}\n","/**\n * Shared workspace tools: `contain()` path confinement, the read-only tool set\n * (`read_file`, `search_files`, `list_files`), and the two file writers\n * (`write_file`, `edit_file`).\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 `src/builder/tools.ts` adds the\n * writers and its exec surface; the tester's (`src/tester/tools.ts`) adds the\n * writers held to the test and fixture paths, which is why they live here\n * rather than in the builder's module. Every path is resolved and confined to\n * the workspace root.\n */\nimport { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';\nimport { dirname, 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 WRITE_FILE_MAX_BYTES = 1_000_000;\nexport const SEARCH_MAX_MATCHES = 200;\nconst LIST_MAX_ENTRIES = 2000;\n\n/** Directories never worth handing a seat; they bury signal and blow the\n * traversal budget. The acp seats' `list_files` and `search` skip the same\n * names (`./acp_tools.ts`), so a seat sees one tree under acp and on the CLI. */\nexport const IGNORED_DIRS: ReadonlySet<string> = new Set([\n 'node_modules',\n '.git',\n '.volley',\n '.check',\n 'dist',\n '.cache',\n]);\n\n/** Which tool set a seat holds, so its prompt names the tools it has: volley's\n * own (`'volley'`), or fascicle's workspace tools under `volley acp`\n * (`'acp'`). */\nexport type ToolSet = 'volley' | 'acp';\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 * workspace the run was started on. */\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\n/** The files a read tool's optional `path` covers: the whole tree, the tree\n * under a directory, or the one file it names. A path that doesn't exist\n * throws, so the seat reads why rather than an empty result that looks like\n * \"nothing matched\". */\nfunction scoped_files(workspace: string, path: string | undefined, limit: number): WalkEntry[] {\n const root = resolve(workspace);\n if (path === undefined) return walk(root, root, limit);\n const start = contain(workspace, path);\n let is_dir: boolean;\n try {\n is_dir = statSync(start).isDirectory();\n } catch (err) {\n throw new Error(`no such file or directory: ${path}`, { cause: err });\n }\n return is_dir ? walk(root, start, limit) : [{ rel: relative(root, start), abs: start }];\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 directory or file 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 directory or file. 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 is `read_only`, so a builder's per-turn call cap doesn't count it: a\n// read changes nothing a later call in the turn could depend on.\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 read_only: true,\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 read_only: true,\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 regex = build_regex(input.pattern, input.ignore_case === true ? 'i' : '');\n const files = scoped_files(workspace, input.path, 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 read_only: true,\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 let files = scoped_files(workspace, input.path, 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\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\nfunction count_occurrences(haystack: string, needle: string): number {\n return haystack.split(needle).length - 1;\n}\n\n/** A writer's guard: given the contained absolute path and the path as the\n * model named it, it throws to refuse the write, naming why. */\nexport type WriteGuard = (abs: string, path: string) => void;\n\n/** `write_file` and `edit_file`, confined to the workspace, and to whatever\n * `guard` allows besides. A wrong-but-recoverable edit (0 or N matches) is\n * returned for the model to read; a refused path or an over-cap write throws,\n * as a containment violation does. */\nexport function write_tools(workspace: string, guard?: WriteGuard): Tool[] {\n const target = (path: string): string => {\n const abs = contain(workspace, path);\n guard?.(abs, path);\n return abs;\n };\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 = target(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 = target(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 return [write_file, edit_file];\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 * The tester's tools on any provider but `claude_cli`: the shared reads, and\n * `write_file` and `edit_file` held to the test and fixture gate paths.\n *\n * The tester writes a failing test from the criteria before the first build,\n * and its whole job is the test (move 1's D5). So a write must match a gate\n * pattern, and must not touch the gate's other half: `package.json`, a\n * `*.config.*` file, or anything under `.github/`. A tester that could rewrite\n * the check's configuration could make its own result red or green (D20). It\n * has no `bash` either, though the check runs what it writes, which is why a\n * tester on a local model is contained as a builder is (D14).\n *\n * A path that reaches through a symbolic link is refused too: `contain()` is\n * lexical, so `test/` linked to `src/` would otherwise let a write the\n * patterns allow land in the source.\n */\nimport { lstatSync, realpathSync } from 'node:fs';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport type { Tool } from 'fascicle';\nimport { matches_any } from '../changes.js';\nimport { contain, read_only_tools, write_tools } from '../workspace_tools.js';\n\n/** Why the tester may not write `rel` (a `/`-separated workspace path) though\n * a gate pattern matches it, or null when it may. */\nfunction excluded_reason(rel: string): string | null {\n const segments = rel.split('/');\n const name = segments.at(-1) ?? '';\n if (name === 'package.json') return 'package.json decides which scripts and tests run';\n if (name.includes('.config.')) return 'a *.config.* file configures the check';\n if (segments.includes('.github')) return 'a path under .github/ is CI configuration';\n return null;\n}\n\n/** Whether a gate pattern can only ever name files the tester may not write:\n * `**\\/package.json`, `**\\/vitest.config.*`, `.github/workflows/**`. */\nfunction names_only_excluded(pattern: string): boolean {\n return excluded_reason(pattern.replace(/\\*+$/, 'x')) !== null;\n}\n\n/** The gate patterns the tester may write under: the gate's tests and\n * fixtures, its check configuration and manifest left out. Its prompt names\n * these, and a `claude_cli` tester's `Edit` rules are made from them. */\nexport function writable_gate_patterns(gate_paths: ReadonlyArray<string>): string[] {\n return gate_paths.filter((pattern) => !names_only_excluded(pattern));\n}\n\n/** Whether `path` exists as itself, a dangling link included. */\nfunction lexists(path: string): boolean {\n try {\n lstatSync(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Whether `abs` (inside `root`) resolves somewhere other than where it reads:\n * its nearest existing ancestor's real path isn't that ancestor's place under\n * the root's real path, or can't be read (a dangling link). */\nfunction resolves_elsewhere(root: string, abs: string): boolean {\n let probe = abs;\n while (!lexists(probe) && probe !== root) probe = dirname(probe);\n try {\n return realpathSync(probe) !== join(realpathSync(root), relative(root, probe));\n } catch {\n return true;\n }\n}\n\n/** Why the tester may not write `abs` (named `path` by the model) in\n * `workspace`, or null when it may. */\nfunction tester_write_refusal(\n workspace: string,\n gate_paths: ReadonlyArray<string>,\n abs: string,\n): string | null {\n const root = resolve(workspace);\n const rel = relative(root, abs).split(sep).join('/');\n if (rel === '' || !matches_any(rel, [...gate_paths])) {\n const writable = writable_gate_patterns(gate_paths);\n return writable.length === 0\n ? 'no gate pattern names a test or fixture path'\n : `it matches none of the test and fixture gate patterns (${writable.join(', ')})`;\n }\n const excluded = excluded_reason(rel);\n if (excluded !== null) return excluded;\n if (resolves_elsewhere(root, abs)) return 'it reaches through a symbolic link';\n return null;\n}\n\n/** The error a tester's write to `path` (named `path`, contained at `abs`)\n * is refused with, or null when it may write there. */\nfunction refusal_message(\n workspace: string,\n gate_paths: ReadonlyArray<string>,\n abs: string,\n path: string,\n): string | null {\n const refusal = tester_write_refusal(workspace, gate_paths, abs);\n return refusal === null\n ? null\n : `the tester can't write ${path}: ${refusal}. It writes tests and fixtures only.`;\n}\n\n/** Why the tester may not write `path` in `workspace`, as the message its\n * writers refuse with, or null when it may: for a tool set the tester takes\n * from elsewhere, as under `volley acp`, whose writers volley wraps. */\nexport function tester_refusal(\n workspace: string,\n gate_paths: ReadonlyArray<string>,\n path: string,\n): string | null {\n let abs: string;\n try {\n abs = contain(workspace, path);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n return refusal_message(workspace, gate_paths, abs, path);\n}\n\n/** The tester's tool set: the read trio, then `write_file` and `edit_file`\n * confined to the test and fixture gate paths. A refused write throws, naming\n * the path and why; fascicle feeds that back to the model. */\nexport function tester_tools(workspace: string, gate_paths: ReadonlyArray<string>): Tool[] {\n return [\n ...read_only_tools(workspace),\n ...write_tools(workspace, (abs, path) => {\n const refusal = refusal_message(workspace, gate_paths, abs, path);\n if (refusal !== null) throw new Error(refusal);\n }),\n ];\n}\n","/**\n * Which run configs a host-side resume may trust. A resume runs what a run's\n * `config.json` says: its check, a shell command, and its seats, permission\n * mode and prompt included. Inside the sandbox the builder runs arbitrary\n * commands with write access to its own run's state, so a contained run's\n * config is the builder's to rewrite, and resuming it on the host would run\n * whatever the builder left there.\n *\n * So volley on the host signs each config it writes, an HMAC under a key of\n * this machine's that never enters the container, and a host-side resume\n * trusts only a config whose signature holds. Inside the sandbox nothing is\n * signed, since the key isn't there and one made there would be in the\n * builder's reach, so a contained run's config never carries a signature the\n * host accepts, and the builder can't forge one without the key.\n */\nimport { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport { detect_containment } from './containment.js';\n\ntype Env = Readonly<Record<string, string | undefined>>;\n\n/** Prefixed to what is signed, so a signature over a run config can't pass for\n * one over anything else under the same key. */\nconst DOMAIN = 'volley run config v1\\n';\n\n/** Where this machine's key lives: `$XDG_CONFIG_HOME/volley/run-key`, else\n * `~/.config/volley/run-key`, outside every state root, so a container a run\n * root is mounted into still can't read it. A relative `XDG_CONFIG_HOME` is\n * ignored, as the XDG spec says. */\nexport function trust_key_path(env: Env, home: string = homedir()): string {\n const xdg = env['XDG_CONFIG_HOME'];\n const base = xdg !== undefined && isAbsolute(xdg) ? xdg : join(home, '.config');\n return join(base, 'volley', 'run-key');\n}\n\nfunction error_code(err: unknown): unknown {\n return (err as { code?: unknown }).code;\n}\n\n/** The key as stored, or null when there is none or it isn't one. */\nfunction read_key(path: string): Buffer | null {\n try {\n const hex = readFileSync(path, 'utf8').trim();\n return /^[0-9a-f]{64}$/.test(hex) ? Buffer.from(hex, 'hex') : null;\n } catch {\n return null;\n }\n}\n\n/** The key, created on first use: 32 random bytes in a file only its user can\n * read, in a directory only its user can enter. Two runs that start together\n * race to create it; the loser reads the winner's. */\nfunction machine_key(env: Env): Buffer | null {\n const path = trust_key_path(env);\n const existing = read_key(path);\n if (existing !== null) return existing;\n try {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, `${randomBytes(32).toString('hex')}\\n`, { flag: 'wx', mode: 0o600 });\n } catch (err) {\n if (error_code(err) !== 'EEXIST') return null;\n }\n return read_key(path);\n}\n\nfunction hmac(key: Buffer, config_text: string): string {\n return createHmac('sha256', key).update(DOMAIN).update(config_text).digest('hex');\n}\n\n/** This machine's signature over a run's `config.json` text, or null where\n * there's none to give: inside the sandbox, or when the key can't be read or\n * created. */\nexport function sign_config(config_text: string, env: Env = process.env): string | null {\n if (detect_containment(env)) return null;\n const key = machine_key(env);\n return key === null ? null : hmac(key, config_text);\n}\n\n/** Does `signature` hold for `config_text` under this machine's key? Never\n * creates the key: with none there's nothing it could hold under. */\nexport function config_signed(\n config_text: string,\n signature: string | null,\n env: Env = process.env,\n): boolean {\n if (signature === null) return false;\n const key = read_key(trust_key_path(env));\n if (key === null) return false;\n const expected = Buffer.from(hmac(key, config_text), 'hex');\n const given = Buffer.from(signature.trim(), 'hex');\n return given.length === expected.length && timingSafeEqual(given, expected);\n}\n","/**\n * Workspace lifecycle: run-state initialization, stale-run\n * backup rotation, path helpers, and optional git checkpoints.\n */\nimport { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { command_env } from './engine.js';\nimport { sign_config } from './trust.js';\nimport { check_error, config_error } from './types.js';\nimport type { ResolvedConfig } from './types.js';\n\n/** A run id names the run's `volley/<run id>` branch and its state directory,\n * so it is held to what both take without quoting: letters, digits, `-`, and\n * `_`, starting with a letter or digit, so it never reads as an option and\n * never climbs out of the directory it names. */\nexport const RUN_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;\n\n/** The root each run's state sits under when `--state-dir` names none:\n * `$XDG_STATE_HOME/volley`, else `<home>/.local/state/volley`. A relative\n * `XDG_STATE_HOME` is ignored, as the XDG spec says. `home` is the host's by\n * default; the sandbox passes its container's to spell the same root inside. */\nexport function default_state_root(\n env: Readonly<Record<string, string | undefined>>,\n home: string = homedir(),\n): string {\n const xdg = env['XDG_STATE_HOME'];\n const base = xdg !== undefined && isAbsolute(xdg) ? xdg : join(home, '.local', 'state');\n return join(base, 'volley');\n}\n\n/** What locates a run's state, as a structural subset of `ResolvedConfig` so a\n * resume can find a run before it has a whole config. */\nexport type StateLocation = Pick<ResolvedConfig, 'workspace' | 'state_dir' | 'run_id'>;\n\n/** Where a run keeps its config, summary, trajectory, feedback, verdict, and\n * iterations: `<state_dir>/<run_id>/` under its state root, or, in the layout\n * older runs used (`state_dir` null), `<workspace>/.volley/`. */\nexport function run_state_dir(run: StateLocation): string {\n return run.state_dir === null ? join(run.workspace, '.volley') : join(run.state_dir, run.run_id);\n}\n\nexport function state_path(run: StateLocation, ...parts: string[]): string {\n return join(run_state_dir(run), ...parts);\n}\n\nexport function iteration_dir(run: StateLocation, iteration: number): string {\n return state_path(run, 'iterations', String(iteration).padStart(3, '0'));\n}\n\n/** A state root that sits inside `root` (the build root), as the path from\n * there in git's `/`-separated vocabulary, or null when it sits outside. A\n * root inside the tree would otherwise pass for the builder's work: listed in\n * the changes the critic reads, and committed by every `--git` checkpoint.\n * The legacy `.volley/` (`state_dir` null) is excluded by name already. */\nexport function state_root_within(root: string, state_dir: string | null): string | null {\n if (state_dir === null) return null;\n const path = relative(resolve(root), resolve(state_dir));\n if (path === '' || path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path)) return null;\n return path.split(sep).join('/');\n}\n\n/** Filesystem-safe timestamp for `.bak.<stamp>` rotation names. Shared by the\n * run-state 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 state directory aside (a prior\n * `.volley/` becomes `.volley.bak.<stamp>`), then create the directory tree.\n * Under a state root each run has a directory of its own, so only a reused\n * `--run-id` ever finds one to rotate. An empty one is used as it is: that is\n * what a contained run is handed when its run directory is the mount, which\n * can't be renamed. Resume runs skip rotation (`preserve: true`). */\nexport function initialize_run_state(\n run: StateLocation,\n options: { preserve?: boolean } = {},\n): void {\n const dir = run_state_dir(run);\n if (existsSync(dir) && options.preserve !== true && readdirSync(dir).length > 0) {\n renameSync(dir, `${dir}.bak.${backup_stamp()}`);\n }\n if (run.state_dir !== null && !existsSync(run.state_dir)) {\n // Trajectories hold prompts and tool output, so a root volley creates is\n // its user's alone, as the XDG spec asks of a state directory.\n mkdirSync(run.state_dir, { recursive: true, mode: 0o700 });\n }\n mkdirSync(join(dir, 'iterations'), { recursive: true });\n}\n\n/** Beside a run's `config.json`: this machine's signature over it\n * (`./trust.ts`), which a host-side resume checks before it trusts the\n * config. */\nexport const CONFIG_SIGNATURE = 'config.sig';\n\n/** Record the run's config, signed when volley runs on the host. Returns\n * whether it was signed: inside the sandbox it never is, and on the host only\n * when the machine's key can't be read or created. A signature a reused run\n * directory held from before is removed rather than left to vouch for this\n * config. */\nexport function write_resolved_config(\n config: ResolvedConfig,\n env: Readonly<Record<string, string | undefined>> = process.env,\n): boolean {\n const record = {\n version: config.version,\n run_id: config.run_id,\n started_at: config.started_at,\n mode: config.mode,\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_url: config.builder_url,\n builder_max_steps: config.builder_max_steps,\n builder_max_tool_calls: config.builder_max_tool_calls,\n builder_max_output_tokens: config.builder_max_output_tokens,\n builder_trim_history: config.builder_trim_history,\n effort_ladder: config.effort_ladder,\n critic_model: config.critic_model,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\n critic_effort: config.critic_effort,\n tester: config.tester,\n tester_model: config.tester_model,\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 state_dir: config.state_dir,\n workspace: config.workspace,\n };\n const text = `${JSON.stringify(record, null, 2)}\\n`;\n writeFileSync(state_path(config, 'config.json'), text);\n const signature = sign_config(text, env);\n if (signature === null) {\n rmSync(state_path(config, CONFIG_SIGNATURE), { force: true });\n return false;\n }\n writeFileSync(state_path(config, CONFIG_SIGNATURE), `${signature}\\n`);\n return true;\n}\n\n/** The identity volley's own commits fall back to. git won't commit without a\n * name and an email, and the sandbox image carries no git config, so inside\n * it a checkpoint or a worktree's salvage commit failed outright; a machine\n * never set up for git can be the same. `.invalid` is reserved, so the email\n * can't reach anyone. */\nconst FALLBACK_IDENTITY: ReadonlyArray<readonly [string, string]> = [\n ['user.name', 'volley'],\n ['user.email', 'volley@volley.invalid'],\n];\n\n/** The `-c` flags that give a commit in `cwd` the fallback identity for each\n * part git has no value for. One the repo or the user configured wins, and so\n * does a `GIT_AUTHOR_*` or `GIT_COMMITTER_*` variable, which git ranks above\n * any config. Put them ahead of the subcommand. */\nexport function commit_identity(cwd: string): string[] {\n return FALLBACK_IDENTITY.flatMap(([key, value]) => {\n const set = spawnSync('git', ['config', '--get', key], {\n cwd,\n env: command_env(process.env),\n encoding: 'utf8',\n });\n return set.status === 0 && set.stdout.trim() !== '' ? [] : ['-c', `${key}=${value}`];\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. `excluded_dir` (from `state_root_within`) keeps a state root inside the\n * tree out of the commit; `:/` keeps the rest of the staging repo-wide, as a\n * bare `git add -A` is, and `literal` reads the path as written, wildcards and\n * all.\n */\nexport function git_checkpoint(root: string, message: string, excluded_dir: string | null = null): 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 pathspec = excluded_dir === null ? [] : ['--', ':/', `:(exclude,literal)${excluded_dir}`];\n const add = spawnSync('git', ['add', '-A', ...pathspec], { cwd: root, env: command_env(process.env) });\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_identity(root), 'commit', '-m', message, '--no-verify'], {\n cwd: root,\n env: command_env(process.env),\n });\n // Exit 1 with \"nothing to commit\" is a no-op iteration, not a failure. So is\n // \"nothing added to commit\", which git says instead when the only untracked\n // files left are the state root `excluded_dir` kept out.\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 && !/nothing (?:added )?to commit/.test(out)) {\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 env: command_env(process.env),\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_identity(workspace), 'commit', '-m', message, '--no-verify'], {\n cwd: workspace,\n env: command_env(process.env),\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 * Config resolution: merge CLI flags over an optional config file\n * over defaults, expand `@file` references, validate, and produce the\n * immutable `ResolvedConfig` that the run's `config.json` records.\n */\nimport { accessSync, constants, existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, 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 { detect_containment } from './containment.js';\nimport { openrouter_api_key, SEAT_URL_PROVIDERS, takes_seat_url } from './engine.js';\nimport { writable_gate_patterns } from './tester/tools.js';\nimport { config_error } from './types.js';\nimport { default_state_root, RUN_ID_PATTERN } from './workspace.js';\nimport type {\n CheckRunnerKind,\n RunMode,\n BuilderPermissionMode,\n BuilderProvider,\n CriticPreset,\n CriticProvider,\n EffortRung,\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_BUILDER_MAX_TOOL_CALLS = 1;\nexport const DEFAULT_BUILDER_MAX_OUTPUT_TOKENS = 16384;\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 'openrouter',\n];\n\n/** Builder providers that drive their model through volley's own tool loop —\n * a real `bash` (write + exec), wherever the model runs. Refused unless volley\n * is running inside a container (the correct blast-radius default) or the\n * operator explicitly opts out; `claude_cli` has its own permission model and\n * is exempt. */\nconst TOOL_LOOP_BUILDER_PROVIDERS: ReadonlyArray<BuilderProvider> = [\n 'ollama',\n 'lmstudio',\n 'openrouter',\n];\n\nconst CRITIC_PROVIDERS: ReadonlyArray<CriticProvider> = [\n 'claude_cli',\n 'ollama',\n 'lmstudio',\n 'openrouter',\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/** The efforts a rung or the critic may take, lowest first. */\nexport const EFFORT_RUNGS: ReadonlyArray<EffortRung> = ['low', 'medium', 'high', 'xhigh', 'max'];\n\n/** The critic's effort when a ladder is set and nothing names one: reading a\n * diff costs far less than writing it, and the critic is what makes a cheap\n * build safe. */\nconst DEFAULT_LADDER_CRITIC_EFFORT: EffortRung = 'high';\n\n/** Builder providers whose fascicle transport drops `effort` and records\n * `effort_ignored`, so every rung of a ladder runs the same there. */\nconst EFFORT_IGNORED_PROVIDERS: ReadonlyArray<BuilderProvider> = ['ollama', 'lmstudio'];\n\n/** Whether a builder on `provider` ignores the effort a rung sets. */\nexport function ignores_effort(provider: BuilderProvider): boolean {\n return EFFORT_IGNORED_PROVIDERS.includes(provider);\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 /** What happens to a tool-loop builder with nothing between its commands\n * and the host (`unguarded_builder`): the CLI `refuse`s it, the default,\n * while under `volley acp` each of its commands `ask`s a person first, which\n * takes the container's place. */\n uncontained_builder?: 'refuse' | 'ask';\n /** Where the run's state goes, in place of what the config says: `volley\n * resume` passes the root it found the run under, or null for a run an older\n * volley kept in the workspace's `.volley/`, which resumes there. */\n state_dir?: string | null;\n /** A run (the default), or a critique, which has no builder or loop. */\n mode?: RunMode;\n};\n\n/** What only a builder, or the loop around it, uses, with the flag that sets\n * each: a critique has no use for any of them, so naming one is an error\n * rather than something quietly ignored. */\nconst CRITIQUE_REFUSED: ReadonlyArray<readonly [keyof VolleyConfig, string]> = [\n ['builder_model', '--builder-model'],\n ['builder_provider', '--builder-provider'],\n ['builder_url', '--builder-url'],\n ['builder_max_steps', '--builder-max-steps'],\n ['builder_max_tool_calls', '--builder-max-tool-calls'],\n ['builder_max_output_tokens', '--builder-max-output-tokens'],\n ['builder_trim_history', '--builder-trim-history'],\n ['effort_ladder', '--effort-ladder'],\n ['tester', '--tester'],\n ['tester_model', '--tester-model'],\n ['builder_permission_mode', '--builder-permission-mode'],\n ['allow_unsandboxed_builder', '--allow-unsandboxed-builder'],\n ['sandbox_image', '--sandbox-image'],\n ['max_iterations', '--max-iterations'],\n ['max_cost_usd', '--max-cost-usd'],\n ['git_checkpoints', '--git'],\n ['worktree', '--worktree'],\n ['discard_worktree', '--discard-worktree'],\n ['fail_on_gate_edit', '--fail-on-gate-edit'],\n];\n\nfunction refuse_builder_settings(raw: VolleyConfig): void {\n for (const [field, flag] of CRITIQUE_REFUSED) {\n if (raw[field] !== undefined && raw[field] !== false && raw[field] !== 'off') {\n throw config_error(\n `volley critique refuses ${flag} (${field}): a critique runs no builder and no loop`,\n );\n }\n }\n}\n\n/** A tool-loop builder's count: its step cap, its tool calls per turn, or\n * its output tokens per turn, with the value it takes when nothing sets it. */\ntype BuilderCount<fallback extends number | null = number> = {\n flag: string;\n env_var: string;\n fallback: fallback;\n};\n\nconst BUILDER_MAX_STEPS: BuilderCount = {\n flag: '--builder-max-steps',\n env_var: 'VOLLEY_BUILDER_MAX_STEPS',\n fallback: DEFAULT_BUILDER_MAX_STEPS,\n};\n\nconst BUILDER_MAX_TOOL_CALLS: BuilderCount = {\n flag: '--builder-max-tool-calls',\n env_var: 'VOLLEY_BUILDER_MAX_TOOL_CALLS',\n fallback: DEFAULT_BUILDER_MAX_TOOL_CALLS,\n};\n\n/** The builders whose turns are capped when nothing sets a cap: the local\n * ones, where nothing else bounds a turn. Ollama's MLX runner lets an unset\n * `num_predict` run to the model's trained context less the prompt, which is\n * how one qwen3.8 turn spent 30,847 tokens thinking. A hosted model on\n * OpenRouter has its own output limit, and a request for more than it allows\n * can be refused, so it's capped only when asked. */\nconst CAPPED_BY_DEFAULT: ReadonlyArray<BuilderProvider> = ['ollama', 'lmstudio'];\n\n/** The output cap's flag and env var, and its default for `provider`: 16k\n * tokens on a local builder, else the provider's own limit (null). */\nfunction builder_max_output_tokens_count(provider: BuilderProvider): BuilderCount<number | null> {\n return {\n flag: '--builder-max-output-tokens',\n env_var: 'VOLLEY_BUILDER_MAX_OUTPUT_TOKENS',\n fallback: CAPPED_BY_DEFAULT.includes(provider) ? DEFAULT_BUILDER_MAX_OUTPUT_TOKENS : null,\n };\n}\n\n/** The history trim's size: off unless something sets it. */\nconst BUILDER_TRIM_HISTORY: BuilderCount<null> = {\n flag: '--builder-trim-history',\n env_var: 'VOLLEY_BUILDER_TRIM_HISTORY',\n fallback: null,\n};\n\n/** A builder count's flag or config value wins over its env var, which wins\n * over the default, and either must be a positive integer. Local builder\n * only; ignored by the `claude_cli` arm. */\nfunction resolve_builder_count<fallback extends number | null>(\n value: number | undefined,\n env: Record<string, string | undefined>,\n count: BuilderCount<fallback>,\n): number | fallback {\n if (value !== undefined) return positive_count(value, value, count);\n const env_value = env[count.env_var];\n if (env_value !== undefined && env_value !== '') {\n return positive_count(Number(env_value), env_value, count);\n }\n return count.fallback;\n}\n\nfunction positive_count(\n value: number,\n original: unknown,\n count: Pick<BuilderCount, 'flag' | 'env_var'>,\n): number {\n if (!Number.isInteger(value) || value < 1) {\n throw config_error(\n `${count.flag} / ${count.env_var} must be a positive integer; got: ${String(original)}`,\n );\n }\n return value;\n}\n\n/** An effort setting's flag, config key and env var, for its errors. */\ntype EffortSetting = { flag: string; field: string; env_var: string };\n\nconst EFFORT_LADDER: EffortSetting = {\n flag: '--effort-ladder',\n field: 'effort_ladder',\n env_var: 'VOLLEY_EFFORT_LADDER',\n};\n\nconst CRITIC_EFFORT: EffortSetting = {\n flag: '--critic-effort',\n field: 'critic_effort',\n env_var: 'VOLLEY_CRITIC_EFFORT',\n};\n\n/** One effort, held to the five from `low` to `max`. `none` gets its own\n * reason, since it's fascicle's level and the likeliest to be tried. */\nfunction effort_rung(value: unknown, setting: EffortSetting): EffortRung {\n const rung = typeof value === 'string' ? value.trim() : value;\n if ((EFFORT_RUNGS as ReadonlyArray<unknown>).includes(rung)) return rung as EffortRung;\n const why =\n rung === 'none' ? \" (none sets no effort, and on claude_cli leaves Claude Code at its own default)\" : '';\n throw config_error(\n `${setting.flag} (${setting.field}) / ${setting.env_var} takes ${EFFORT_RUNGS.join(', ')}; ` +\n `got: ${String(value)}${why}`,\n );\n}\n\n/** `--effort-ladder` (`effort_ladder`), as a list or the flag's comma-separated\n * form, wins over `VOLLEY_EFFORT_LADDER`; an empty variable counts as unset.\n * Unset is null, which passes no effort. A value that names no rung is refused\n * rather than read as unset, since it was asked for. */\nfunction resolve_effort_ladder(\n value: unknown,\n env: Record<string, string | undefined>,\n): EffortRung[] | null {\n const env_value = env[EFFORT_LADDER.env_var];\n const given = value ?? (env_value === '' ? undefined : env_value);\n if (given === undefined || given === null) return null;\n const items = typeof given === 'string' ? given.split(',') : given;\n if (!Array.isArray(items)) {\n throw config_error(\n `${EFFORT_LADDER.flag} (${EFFORT_LADDER.field}) must be a list of rungs; got a ${typeof given}`,\n );\n }\n const named = items.filter((item) => typeof item !== 'string' || item.trim() !== '');\n if (named.length === 0) {\n throw config_error(\n `${EFFORT_LADDER.flag} (${EFFORT_LADDER.field}) / ${EFFORT_LADDER.env_var} names no rung; ` +\n `give one or more of ${EFFORT_RUNGS.join(', ')}, comma-separated`,\n );\n }\n return named.map((item) => effort_rung(item, EFFORT_LADDER));\n}\n\n/** `--critic-effort` (`critic_effort`) wins over `VOLLEY_CRITIC_EFFORT`; an\n * empty variable counts as unset. Unset is `high` when a ladder is set, else\n * null, so a run without a ladder sends the critic what it always has. */\nfunction resolve_critic_effort(\n value: unknown,\n env: Record<string, string | undefined>,\n ladder: EffortRung[] | null,\n): EffortRung | null {\n const env_value = env[CRITIC_EFFORT.env_var];\n const given = value ?? (env_value === '' ? undefined : env_value);\n if (given !== undefined && given !== null) return effort_rung(given, CRITIC_EFFORT);\n return ladder === null ? null : DEFAULT_LADDER_CRITIC_EFFORT;\n}\n\n/** `--tester` (`tester`) wins over `VOLLEY_TESTER`, and takes `on` or `off`;\n * an empty variable counts as unset, and unset is off (move 1's D8). */\nfunction resolve_tester(value: unknown, env: Record<string, string | undefined>): boolean {\n const env_value = env['VOLLEY_TESTER'];\n const given = value ?? (env_value === '' ? undefined : env_value);\n if (given === undefined || given === null) return false;\n const setting = typeof given === 'string' ? given.trim() : given;\n if (setting === 'on' || setting === 'off') return setting === 'on';\n throw config_error(`--tester (tester) / VOLLEY_TESTER takes on or off; got: ${JSON.stringify(given)}`);\n}\n\n/** The tester's model with the tester on: `--tester-model` (`tester_model`),\n * else `VOLLEY_TESTER_MODEL`, else the critic's. With it off, null, and a\n * model named by flag or config is refused rather than ignored; the variable,\n * which may be set for every run, is left unread. */\nfunction resolve_tester_model(\n tester: boolean,\n value: unknown,\n env: Record<string, string | undefined>,\n critic_model: string,\n): string | null {\n const named = typeof value === 'string' ? value.trim() : value;\n if (!tester) {\n if (named === undefined || named === null || named === '') return null;\n throw config_error('--tester-model (tester_model) applies only with --tester on');\n }\n if (named !== undefined && named !== null && named !== '') {\n if (typeof named !== 'string') {\n throw config_error(`--tester-model (tester_model) must be a model name; got a ${typeof named}`);\n }\n return named;\n }\n const env_value = env['VOLLEY_TESTER_MODEL']?.trim();\n return env_value === undefined || env_value === '' ? critic_model : env_value;\n}\n\n/** Refuse a tester that can't do its job, or can't be contained, before any\n * spend (P1). It needs a check to go red (D18), a test or fixture gate pattern\n * to write under, and, on any provider but `claude_cli`, the containment a\n * builder needs, since the check runs what it writes (D14). Under acp, where\n * a person approves each edit, a local tester isn't refused here. */\nfunction refuse_unready_tester(\n check_resolved: CheckRunnerKind,\n gate_paths: ReadonlyArray<string>,\n critic_provider: CriticProvider,\n guarded: boolean,\n): void {\n if (check_resolved === 'none') {\n throw config_error(\n '--tester on needs a check for its test to fail: set --check to a command, or to auto ' +\n 'in a workspace with checkride, rather than none',\n );\n }\n if (writable_gate_patterns(gate_paths).length === 0) {\n throw config_error(\n '--tester on needs a test or fixture gate pattern to write under; gate_paths names none',\n );\n }\n if (critic_provider !== 'claude_cli' && !guarded) {\n throw config_error(\n `a tester on '${critic_provider}' writes tests the check then runs, so it is contained as a ` +\n `builder is: launch volley inside its sandbox container (VOLLEY_CONTAINED=1), or pass ` +\n `--allow-unsandboxed-builder (VOLLEY_ALLOW_UNSANDBOXED_BUILDER=1). A claude_cli builder ` +\n `stays on the host, so with one, the opt-out is the only way.`,\n );\n }\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 a tool-loop builder refused unless\n * contained. */\nfunction resolve_allow_unsandboxed_builder(\n raw: Pick<VolleyConfig, 'allow_unsandboxed_builder'>,\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/** A seat's own model server URL (`--builder-url` / `--critic-url`), trimmed,\n * or null when unset; an empty value counts as unset, as it does for the env\n * vars it overrides. Only a provider volley reaches at a base URL takes one: on\n * a `claude_cli` seat the setting would silently do nothing, so it is refused.\n * The URL must be plain http(s), with no credentials, query, or fragment:\n * volley appends API paths to it for prewarm and the context probe, which a\n * query or fragment would break, and it is persisted and printed, which\n * credentials must never be. */\nfunction resolve_seat_url(\n seat: 'builder' | 'critic',\n value: unknown,\n provider: BuilderProvider | CriticProvider,\n): string | null {\n const setting = `--${seat}-url (${seat}_url)`;\n if (value === undefined || value === null) return null;\n if (typeof value !== 'string') {\n throw config_error(`${setting} must be a URL string; got a ${typeof value}`);\n }\n const url = value.trim();\n if (url === '') return null;\n if (!takes_seat_url(provider)) {\n const url_providers = new Intl.ListFormat('en', { type: 'disjunction' }).format(\n SEAT_URL_PROVIDERS,\n );\n throw config_error(\n `${setting} applies only to a ${seat} on ${url_providers}; ` +\n `${seat}-provider is ${provider}`,\n );\n }\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw config_error(`${setting} must be an http(s) URL; got: ${url}`);\n }\n // Checked first, so no later message echoes the credentials back.\n if (parsed.username !== '' || parsed.password !== '') {\n throw config_error(`${setting} must not carry credentials`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw config_error(`${setting} must be an http(s) URL; got: ${url}`);\n }\n if (parsed.search !== '' || parsed.hash !== '') {\n throw config_error(`${setting} must not carry a query or fragment; got: ${url}`);\n }\n return url;\n}\n\n/** `--state-dir` (`state_dir`): the root each run's state sits under at\n * `<root>/<run_id>/`, resolved against `cwd` so a resumed run finds the same\n * place. Unset, or empty as a seat URL may be, it's the default root,\n * `$XDG_STATE_HOME/volley`, else `~/.local/state/volley`: outside the\n * workspace, where no check that reads every file can trip over the run's own\n * feedback. */\nfunction resolve_state_dir(\n value: unknown,\n cwd: string,\n env: Record<string, string | undefined>,\n): string {\n if (value === undefined || value === null) return default_state_root(env);\n if (typeof value !== 'string') {\n throw config_error(`--state-dir (state_dir) must be a path string; got a ${typeof value}`);\n }\n const path = value.trim();\n return path === '' ? default_state_root(env) : resolve(cwd, path);\n}\n\nfunction is_writable_dir(path: string): boolean {\n try {\n if (!statSync(path).isDirectory()) return false;\n accessSync(path, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** The run's state directory must be one volley can write: the directory\n * itself when it's there, as a contained run's mount is, else the nearest\n * directory above it, where volley creates it. Checked before any spend,\n * because otherwise the run dies as it starts on a raw EROFS or EACCES. Inside\n * the sandbox the root filesystem is read-only, so that is what an unmounted\n * run directory looks like, and the message says what to mount. */\nfunction validate_run_state_dir(dir: string, contained: boolean): void {\n let existing = dir;\n while (!existsSync(existing) && dirname(existing) !== existing) existing = dirname(existing);\n if (is_writable_dir(existing)) return;\n throw config_error(\n contained\n ? `run state directory not writable: ${dir}. Inside the sandbox, mount the run's own host ` +\n `directory there (sandbox_run_args run_state, or -v <root>/<run id>:${dir}), created on the ` +\n 'host first, and pass volley the same --run-id; or point --state-dir at a writable mount'\n : `run state directory not writable: ${dir}. Point --state-dir at a directory volley can write`,\n );\n}\n\n/** Whether a tool-loop builder's commands would reach the host with nothing in\n * between: volley isn't contained, and the operator hasn't opted out with\n * `--allow-unsandboxed-builder` or `VOLLEY_ALLOW_UNSANDBOXED_BUILDER`. */\nexport function unguarded_builder(\n raw: Pick<VolleyConfig, 'allow_unsandboxed_builder'>,\n env: Record<string, string | undefined>,\n): boolean {\n return !detect_containment(env) && !resolve_allow_unsandboxed_builder(raw, env);\n}\n\n/** A caller's run id, held to `RUN_ID_PATTERN`; none gets a fresh UUID. */\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 // A critique runs no builder, so it reads nothing a run reads for one: the\n // builder's settings are refused, its env vars go unread, and its seat keeps\n // the defaults.\n const critique = options.mode === 'critique';\n if (critique) refuse_builder_settings(raw);\n const builder_env = critique ? {} : env;\n\n const has_prompt = typeof raw.prompt === 'string' && raw.prompt.length > 0;\n if (!has_prompt && !critique) {\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 = has_prompt ? expand_at_file(raw.prompt, cwd) : '';\n const criteria = expand_at_file(raw.criteria, cwd);\n\n const max_iterations = raw.max_iterations ?? (critique ? 1 : 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 tool-loop builder gets a real `bash` (write + exec), local\n // model or hosted, so refuse it — before any model spend — unless volley is\n // running *inside* a container (the correct blast-radius default) or the\n // operator explicitly opts out to run uncontained on the host. Under acp,\n // a person approves each command instead, so nothing is refused here.\n const allow_unsandboxed_builder = resolve_allow_unsandboxed_builder(raw, builder_env);\n const contained = detect_containment(env);\n if (\n TOOL_LOOP_BUILDER_PROVIDERS.includes(builder_provider) &&\n options.uncontained_builder !== 'ask' &&\n unguarded_builder(raw, builder_env)\n ) {\n throw config_error(\n `builder-provider '${builder_provider}' runs volley's tool loop 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_count(raw.builder_max_steps, builder_env, BUILDER_MAX_STEPS);\n const builder_max_tool_calls = resolve_builder_count(\n raw.builder_max_tool_calls,\n builder_env,\n BUILDER_MAX_TOOL_CALLS,\n );\n const builder_max_output_tokens = resolve_builder_count(\n raw.builder_max_output_tokens,\n builder_env,\n builder_max_output_tokens_count(builder_provider),\n );\n const builder_trim_history = resolve_builder_count(\n raw.builder_trim_history,\n builder_env,\n BUILDER_TRIM_HISTORY,\n );\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 const builder_url = resolve_seat_url('builder', raw.builder_url, builder_provider);\n const critic_url = resolve_seat_url('critic', raw.critic_url, critic_provider);\n\n // The builder's ladder and the critic's effort are set apart: a critique has\n // no builder, so it reads no ladder, but its critic takes an effort as a\n // run's does.\n const effort_ladder = resolve_effort_ladder(raw.effort_ladder, builder_env);\n const critic_effort = resolve_critic_effort(raw.critic_effort, env, effort_ladder);\n\n // An openrouter seat sends `OPENROUTER_API_KEY`, so an unset key is refused\n // here, naming the variable, before any work rather than at the first call.\n if (builder_provider === 'openrouter' || critic_provider === 'openrouter') {\n openrouter_api_key(env);\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' && !critique ? '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 check = raw.check ?? DEFAULT_CHECK;\n const check_resolved = resolve_check_runner(check, workspace);\n const tester = resolve_tester(raw.tester, builder_env);\n if (tester) {\n refuse_unready_tester(\n check_resolved,\n gate_paths,\n critic_provider,\n options.uncontained_builder === 'ask' || !unguarded_builder(raw, builder_env),\n );\n }\n const critic_model = raw.critic_model ?? DEFAULT_CRITIC_MODEL;\n const tester_model = resolve_tester_model(tester, raw.tester_model, builder_env, critic_model);\n\n const sandbox_image = resolve_sandbox_image(raw, builder_env);\n const state_dir =\n options.state_dir !== undefined ? options.state_dir : resolve_state_dir(raw.state_dir, cwd, env);\n // Each run's folder would land among the workspace's own files, where no\n // exclusion can tell earlier runs' state from the builder's work.\n if (state_dir === workspace) {\n throw config_error(`--state-dir (state_dir) can't be the workspace itself: ${workspace}`);\n }\n const run_id = resolve_run_id(options.run_id);\n // A legacy `.volley/` lives in the workspace, already checked writable.\n if (state_dir !== null) validate_run_state_dir(join(state_dir, run_id), contained);\n\n return {\n version: 2,\n run_id,\n started_at: options.started_at ?? new Date().toISOString(),\n mode: critique ? 'critique' : 'run',\n prompt,\n criteria,\n check,\n check_resolved,\n builder_model: raw.builder_model ?? DEFAULT_BUILDER_MODEL,\n builder_provider,\n builder_url,\n builder_max_steps,\n builder_max_tool_calls,\n builder_max_output_tokens,\n builder_trim_history,\n effort_ladder,\n allow_unsandboxed_builder,\n critic_model,\n critic_provider,\n critic_url,\n critic_effort,\n tester,\n tester_model,\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 state_dir,\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 * 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 * The tool-loop builder's step countdown. A model that explores first can\n * spend its whole budget before it verifies: in volley-41806476 the builder's\n * 50th step was a `bash` call fascicle refused, and the half-fixed tree went to\n * the check and critic. So for the last few steps of a session, each turn's\n * request ends with a note of how many are left and what to do with them.\n *\n * The note goes in through fascicle's `prepare_step`, which reshapes only what\n * one turn sends, so the transcript stays as the model wrote it, and the note\n * sits after everything a local runtime has cached, so its cached prefix holds.\n */\nimport type { PrepareStepHook } from 'fascicle';\n\n/** How many of a session's last steps carry the countdown: five, or a tenth\n * of a long budget, but never more than half of it, so a short session still\n * starts without one. */\nexport function countdown_window(max_steps: number): number {\n return Math.min(Math.max(5, Math.ceil(max_steps / 10)), Math.floor(max_steps / 2));\n}\n\n/** The note for a turn with `steps_left` steps left, this one included.\n * `check` names how to run the check. On the last step fascicle runs only a\n * call that ends the session, which for the builder is `finish`. */\nexport function countdown_note(steps_left: number, check: string): string {\n if (steps_left <= 1) {\n return (\n '[volley] This is the last step of this session, and only finish runs on it. ' +\n \"Call finish now, with a summary that says what's done and what isn't verified.\"\n );\n }\n return (\n `[volley] ${String(steps_left)} steps left in this session, this one included, ` +\n 'and on the last one only finish runs. ' +\n `If you haven't run ${check} since your last edit, run it now, ` +\n 'then fix what it reports or call finish.'\n );\n}\n\n/** The `prepare_step` hook that adds the countdown to a session of\n * `max_steps` steps. */\nexport function step_countdown(max_steps: number, check: string): PrepareStepHook {\n const window = countdown_window(max_steps);\n return ({ step_index, messages }) => {\n const steps_left = max_steps - step_index;\n if (steps_left > window) return undefined;\n return {\n messages: [...messages, { role: 'user', content: countdown_note(steps_left, check) }],\n };\n };\n}\n","/**\n * The tool-loop builder's one `prepare_step` slot, shared by the hooks that\n * reshape a turn's request: the history trim, then the step countdown, whose\n * note goes last so it sits after everything a local runtime has cached.\n */\nimport type { PrepareStepHook } from 'fascicle';\n\n/** One hook that runs `hooks` in order, each on the request the one before it\n * made, and reports no change when none of them made one. */\nexport function compose_prepare_steps(hooks: ReadonlyArray<PrepareStepHook>): PrepareStepHook {\n return async ({ step_index, messages }) => {\n let request = messages;\n let changed = false;\n for (const hook of hooks) {\n const prepared = await hook({ step_index, messages: request });\n if (prepared?.messages !== undefined) {\n request = prepared.messages;\n changed = true;\n }\n }\n return changed ? { messages: request } : undefined;\n };\n}\n","/**\n * Trimming a long tool-loop session's history (#7). Every turn resends the\n * whole session, every earlier `read_file` result included, even for files the\n * builder has rewritten since, so a long local session's requests grow\n * linearly and each turn's latency grows with them: volley-41806476's input\n * went from 2.6k to 57k tokens over 50 steps, and its turns from 3 s to as\n * much as 120 s.\n *\n * Above a size the operator sets (`--builder-trim-history`), each turn's\n * request replaces the older tool results with one-line stubs: a read of a\n * file a later call wrote, edited, or read whole says so, and any other result\n * names its call and size. The last `TRIM_KEEP_TURNS` turns, every assistant\n * and user message, every failed call's result, and anything short stay as\n * they are. It goes in through fascicle's `prepare_step`, which reshapes only\n * what one turn sends, so the transcript stays as the model wrote it.\n *\n * A local runtime reuses the KV cache for the prefix a request shares with\n * the last one, and rewriting an earlier message breaks that prefix, so the\n * window is prefilled again. So the trim moves in coarse steps: it stubs\n * everything before a turn boundary, boundaries fall every\n * `TRIM_STRIDE_TURNS` turns, and the boundary moves on only when the trimmed\n * request has grown past the size again. Between moves each request starts\n * with the same bytes as the last, since a stub depends only on what came\n * before its boundary and never on the step. The trim keeps no state:\n * `trim_cutoff` works the boundary out again from the transcript each turn.\n */\nimport { posix } from 'node:path';\nimport type { Message, PrepareStepHook } from 'fascicle';\n\n/** A rough token count per character: the hook sees no token counts, so a\n * request's size is estimated from its text. */\nconst CHARS_PER_TOKEN = 4;\n\n/** Turns at the end of a session whose tool results are never stubbed. */\nexport const TRIM_KEEP_TURNS = 6;\n\n/** How many turns apart the boundaries the trim may cut at fall. */\nexport const TRIM_STRIDE_TURNS = 8;\n\n/** Results this short are kept, since a stub would save next to nothing. */\nexport const STUB_MIN_CHARS = 200;\n\n/** What a message costs beyond its text: its role and framing. */\nconst MESSAGE_OVERHEAD_TOKENS = 8;\n\n/** The calls that change a file, whose success makes an earlier read of it\n * stale. Both volley's tools and fascicle's ACP tools use these names and a\n * `path` input. */\nconst FILE_WRITERS: ReadonlySet<string> = new Set(['write_file', 'edit_file']);\n\nconst COMMAND_TOOLS: ReadonlySet<string> = new Set(['bash', 'run_command']);\n\nfunction message_chars(message: Message): number {\n if (typeof message.content === 'string') return message.content.length;\n let chars = 0;\n for (const part of message.content) {\n if (part.type === 'text' || part.type === 'reasoning') chars += part.text.length;\n else if (part.type === 'tool_call') chars += part.name.length + (JSON.stringify(part.input) ?? '').length;\n }\n return chars;\n}\n\n/** A request's size in tokens, estimated from its characters. */\nexport function estimate_tokens(messages: ReadonlyArray<Message>): number {\n let tokens = 0;\n for (const message of messages) {\n tokens += Math.ceil(message_chars(message) / CHARS_PER_TOKEN) + MESSAGE_OVERHEAD_TOKENS;\n }\n return tokens;\n}\n\n/** What a tool call asked for, as far as the trim reads it. */\ntype CallInput = { path: string | null; whole: boolean };\n\nfunction call_input(input: unknown): CallInput {\n if (typeof input !== 'object' || input === null) return { path: null, whole: true };\n const fields = input as Record<string, unknown>;\n const path = typeof fields['path'] === 'string' ? posix.normalize(fields['path']) : null;\n // An ACP read names a range with `offset` or `limit`; volley's never does.\n return { path, whole: fields['offset'] === undefined && fields['limit'] === undefined };\n}\n\n/** Each tool call's input, by call id, from the assistant messages in\n * `messages`. */\nfunction call_inputs(messages: ReadonlyArray<Message>): Map<string, CallInput> {\n const inputs = new Map<string, CallInput>();\n for (const message of messages) {\n if (message.role !== 'assistant' || typeof message.content === 'string') continue;\n for (const part of message.content) {\n if (part.type === 'tool_call') inputs.set(part.id, call_input(part.input));\n }\n }\n return inputs;\n}\n\ntype ToolMessage = Extract<Message, { role: 'tool' }>;\n\n/** A later call on a path that makes an earlier read of it stale. */\ntype Supersession = { tool: string; changed: boolean };\n\n/** Whether this result is one whose call changed its file or read it whole. */\nfunction supersession_of(message: ToolMessage, input: CallInput | undefined): Supersession | null {\n if (input === undefined || input.path === null || message.is_error === true) return null;\n if (FILE_WRITERS.has(message.name)) {\n return message.content.startsWith('error:') ? null : { tool: message.name, changed: true };\n }\n if (message.name === 'read_file' && input.whole) return { tool: 'read_file', changed: false };\n return null;\n}\n\nfunction exit_code_of(content: string): number | null {\n try {\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed === 'object' && parsed !== null) {\n const code = (parsed as Record<string, unknown>)['exit_code'];\n if (typeof code === 'number') return code;\n }\n } catch {\n // Not JSON: a command result without an exit code to keep.\n }\n return null;\n}\n\nfunction stub(message: ToolMessage, input: CallInput | undefined, later: Supersession | undefined): string {\n const size = `${String(message.content.length)} chars`;\n if (later !== undefined && input !== undefined && input.path !== null) {\n return later.changed\n ? `[volley] read_file ${input.path} (${size}) elided: a later ${later.tool} changed this file. Read it again for its current content.`\n : `[volley] read_file ${input.path} (${size}) elided: it was read again later in this session.`;\n }\n const exit_code = COMMAND_TOOLS.has(message.name) ? exit_code_of(message.content) : null;\n const detail = exit_code === null ? size : `${size}, exit ${String(exit_code)}`;\n return `[volley] ${message.name} output (${detail}) elided from an earlier turn. Run it again if you need it.`;\n}\n\n/**\n * The request with every tool result before `cutoff` that is long enough to\n * matter and didn't fail replaced by a stub. Every message keeps its place,\n * role, id, and name. A stub reads only what comes before `cutoff`, so the\n * same transcript prefix always gives the same bytes.\n */\nexport function trim_view(messages: ReadonlyArray<Message>, cutoff: number): Message[] {\n const window = messages.slice(0, cutoff);\n const inputs = call_inputs(window);\n // Walk back from the boundary so each read meets the nearest later call on\n // its path.\n const next_on_path = new Map<string, Supersession>();\n const later_for = new Map<number, Supersession>();\n for (let i = window.length - 1; i >= 0; i -= 1) {\n const message = window[i];\n if (message?.role !== 'tool') continue;\n const input = inputs.get(message.tool_call_id);\n const path = input?.path ?? null;\n if (path === null) continue;\n if (message.name === 'read_file') {\n const later = next_on_path.get(path);\n if (later !== undefined) later_for.set(i, later);\n }\n const supersedes = supersession_of(message, input);\n if (supersedes !== null) next_on_path.set(path, supersedes);\n }\n return messages.map((message, i) => {\n if (i >= cutoff || message.role !== 'tool' || message.is_error === true) return message;\n if (message.content.length <= STUB_MIN_CHARS) return message;\n return { ...message, content: stub(message, inputs.get(message.tool_call_id), later_for.get(i)) };\n });\n}\n\n/**\n * Where to cut this turn's request, as a message index, or null to send it\n * whole. Boundaries are the starts of turns `TRIM_STRIDE_TURNS`,\n * `2 * TRIM_STRIDE_TURNS`, and so on, short of the last `TRIM_KEEP_TURNS`.\n * The cut moves to the next boundary only while the request, trimmed at the\n * last one, is still over `threshold`. A trimmed request only grows as the\n * session goes on, so a boundary once taken is kept.\n */\nexport function trim_cutoff(messages: ReadonlyArray<Message>, threshold: number): number | null {\n const turn_starts = messages.flatMap((message, i) => (message.role === 'assistant' ? [i] : []));\n let cutoff: number | null = null;\n for (let turn = TRIM_STRIDE_TURNS; turn <= turn_starts.length - TRIM_KEEP_TURNS; turn += TRIM_STRIDE_TURNS) {\n const view = cutoff === null ? messages : trim_view(messages, cutoff);\n if (estimate_tokens(view) <= threshold) break;\n cutoff = turn_starts[turn] ?? null;\n }\n return cutoff;\n}\n\n/** The `prepare_step` hook that trims a request estimated above `threshold`\n * tokens. */\nexport function step_trim(threshold: number): PrepareStepHook {\n return ({ messages }) => {\n const cutoff = trim_cutoff(messages, threshold);\n return cutoff === null ? undefined : { messages: trim_view(messages, cutoff) };\n };\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 type { LookupFunction } from 'node:net';\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 { command_env } from '../engine.js';\nimport { read_only_tools, write_tools } from '../workspace_tools.js';\n\nexport { WRITE_FILE_MAX_BYTES } from '../workspace_tools.js';\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 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\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. A command runs with\n * volley's environment less the seats' keys, so nothing the builder runs can\n * read the key its seat spends. `status` is null when a signal (the timeout\n * 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 env: command_env(process.env),\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 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 return [...read_only_tools(workspace), ...write_tools(workspace), bash, fetch, finish_tool()];\n}\n\n/** The terminal `finish` tool, on its own for a builder set that brings its\n * own file and command tools (`../acp_tools.ts`). */\nexport function finish_tool(): Tool {\n return {\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","/**\n * checkride runner: spawn `pnpm exec checkride --json --digest`, 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. The digest checkride writes on a red\n * run is kept beside them for the next builder, which needs a short list of\n * what to fix more than the whole of every slot's output.\n */\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { isAbsolute, join, relative, sep } from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { aborted_error } from 'fascicle';\nimport { command_env } from '../engine.js';\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\n/** How long a check's output may stay open after its shell exits, while\n * something that escaped its process group still holds it, before the reads\n * stop so the check can finish. */\nconst OUTPUT_GRACE_MS = 2000;\n\n/** Kill a check's whole process group with SIGKILL. A test runner's workers,\n * and anything the check started in the background, sit in the shell's group,\n * so killing the shell alone would leave them running. Windows has no process\n * groups to signal, so there only the shell goes. */\nfunction kill_group(proc: ChildProcess): void {\n if (proc.pid === undefined) return;\n try {\n if (process.platform === 'win32') proc.kill('SIGKILL');\n else process.kill(-proc.pid, 'SIGKILL');\n } catch {\n // The group is gone: every process in it has exited.\n }\n}\n\n/** What a check runs with beside its command. */\nexport type CheckSpawnOptions = {\n abort?: AbortSignal;\n /** The whole environment the check runs with, in place of volley's own;\n * nothing is merged in, so it carries the `PATH` the check needs. Absent,\n * the check gets volley's less the seats' keys. */\n env?: Readonly<Record<string, string>>;\n};\n\n/** Run a check to its end in a process group of its own, capturing its\n * output. The abort kills the whole group and rejects with `aborted_error`,\n * and the shell's exit kills whatever it left behind, so a stopped run leaves\n * no test workers or servers running. */\nexport function spawn_capture(\n cmd: string,\n args: string[],\n options: CheckSpawnOptions & { cwd: string },\n): Promise<SpawnCaptureResult> {\n const { abort } = options;\n if (abort?.aborted === true) return Promise.reject(new aborted_error('check aborted'));\n return new Promise((resolve_promise, reject) => {\n const proc = spawn(cmd, args, {\n cwd: options.cwd,\n env: options.env ?? command_env(process.env),\n detached: process.platform !== 'win32',\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n let grace: NodeJS.Timeout | undefined;\n const on_abort = (): void => {\n kill_group(proc);\n reject(new aborted_error('check aborted'));\n };\n const finish = (): void => {\n clearTimeout(grace);\n abort?.removeEventListener('abort', on_abort);\n };\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 finish();\n reject(check_error(`check command failed to start: ${err.message}`));\n });\n proc.on('exit', () => {\n kill_group(proc);\n grace = setTimeout(() => {\n proc.stdout.destroy();\n proc.stderr.destroy();\n }, OUTPUT_GRACE_MS);\n });\n proc.on('close', (code) => {\n finish();\n resolve_promise({ exit_code: code, stdout, stderr });\n });\n abort?.addEventListener('abort', on_abort, { once: true });\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/** Whether `path` sits under `dir`. */\nfunction within(dir: string, path: string): boolean {\n const from_dir = relative(dir, path);\n return from_dir !== '..' && !from_dir.startsWith(`..${sep}`) && !isAbsolute(from_dir);\n}\n\n/** Per failing slot: the raw artifact (`<output_file>` when present, else\n * `<slot>.stdout.txt`) in `check_dir`, a workspace's `.check/` or an archived\n * iteration's copy of it, truncated with a pointer to the file. The names come\n * from a summary the builder could have written, so a path that leaves\n * `check_dir` has no artifact, rather than putting a file from elsewhere in\n * front of a model. */\nexport function read_failing_artifacts(\n check_dir: 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(check_dir, file);\n if (!within(check_dir, path) || !existsSync(path) || !statSync(path).isFile()) {\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\n/** checkride's digest of a red run (`.check/digest.md`, written under\n * `--digest` and removed on a green one), or undefined when there is none. It\n * is capped by checkride itself, at 8 kB. */\nfunction read_digest(workspace: string): string | undefined {\n const path = join(workspace, '.check', 'digest.md');\n return existsSync(path) ? readFileSync(path, 'utf8') : undefined;\n}\n\nexport type CheckrideOpts = CheckSpawnOptions & {\n workspace: string;\n};\n\nexport async function run_checkride(opts: CheckrideOpts): Promise<CheckResult> {\n const { workspace, ...spawn_options } = opts;\n const proc = await spawn_capture('pnpm', ['exec', 'checkride', '--json', '--digest'], {\n ...spawn_options,\n cwd: workspace,\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 // Only a red run writes a digest; on a green one checkride removes any\n // stale one, and volley doesn't look.\n const digest = summary.ok ? undefined : read_digest(opts.workspace);\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(join(opts.workspace, '.check'), failing),\n summary,\n ...(digest !== undefined ? { digest } : {}),\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, CheckRunnerKind } from '../types.js';\nimport { spawn_capture } from './checkride.js';\nimport type { CheckSpawnOptions } from './checkride.js';\n\nexport type CommandCheckOpts = CheckSpawnOptions & {\n command: string;\n workspace: string;\n};\n\nexport async function run_command_check(opts: CommandCheckOpts): Promise<CheckResult> {\n const { command, workspace, ...spawn_options } = opts;\n const started = Date.now();\n const proc = await spawn_capture('sh', ['-c', command], { ...spawn_options, cwd: workspace });\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)}): ${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/** What a rejected check says in place of its output. */\nexport const CHECK_REJECTED = 'the check was rejected when it asked to run, so it never ran';\n\n/** A check the user rejected when it asked to run: recorded as a failed\n * check, with the refusal as its output, so a round can't converge on work\n * nothing checked, and the critic hears why there's no result. */\nexport function rejected_check(runner: CheckRunnerKind): CheckResult {\n return {\n ran: true,\n runner,\n ok: false,\n exit_code: null,\n duration_ms: 0,\n failing_slots: [],\n detail: [],\n log: CHECK_REJECTED,\n };\n}\n","/**\n * What a `claude_cli` seat may touch. The CLI runs in the build root (its\n * session cwd), and two layers keep its file tools there:\n *\n * - The allowlist names only path rules the CLI matches. It checks file\n * permissions against `Edit(path)` and `Read(path)` alone (an `Edit` rule\n * governs the Write tool too; a `Write(path)` or `MultiEdit(path)` rule is\n * accepted and never matched), and a bare `Write` or `Read` approves every\n * path on the machine. `/` anchors a rule at the session's working\n * directory. Reads, searches, and globs inside the working directory need no\n * rule at all, so `Grep` and `Glob` aren't listed: a bare entry for either\n * would only reach outside it.\n * - `--settings` turns on the CLI's own blocks, which refuse file tools outside\n * the working directories in every permission mode, `bypassPermissions`\n * included, where allow rules decide nothing. The write block needs Claude\n * Code 2.1.314, the read block 2.1.257; an older CLI ignores the key, which\n * the dry run warns about.\n *\n * `Bash` stays unconfined: the blocks cover file tools only.\n */\nimport type { ResolvedConfig } from './types.js';\n\n/** Whether a seat this run drives runs on the Claude CLI. A critique has no\n * builder, whatever its provider resolved to. */\nexport function uses_claude_cli(config: ResolvedConfig): boolean {\n return (\n (config.mode !== 'critique' && config.builder_provider === 'claude_cli') ||\n config.critic_provider === 'claude_cli'\n );\n}\n\nexport const BUILDER_ALLOWED_TOOLS = ['Read(/**)', 'Edit(/**)', 'Bash', 'WebFetch'] as const;\n\nexport const CRITIC_ALLOWED_TOOLS = ['Read(/**)'] as const;\n\nexport const CRITIC_DISALLOWED_TOOLS = 'Write,Edit,MultiEdit,NotebookEdit,Bash';\n\n/** A gate pattern an `Edit(...)` rule can carry: one with no space, comma or\n * parenthesis, which the CLI would read as the rule list's own syntax. One\n * that can't be carried is left out, so the tester can write less, never\n * more. */\nfunction rule_safe(pattern: string): boolean {\n return !/[\\s,()]/.test(pattern);\n}\n\n/** A `claude_cli` tester's allowlist (move 1's D19): reads anywhere in the\n * build root, and one `Edit` rule per writable gate pattern\n * (`writable_gate_patterns`), anchored at the build root. The tester runs in\n * the CLI's default permission mode, where an edit no rule allows is refused,\n * since `-p` has no one to ask. */\nexport function tester_allowed_tools(writable: ReadonlyArray<string>): string[] {\n return [\n 'Read(/**)',\n ...writable.filter(rule_safe).map((pattern) => `Edit(/${pattern.replace(/^\\/+/, '')})`),\n ];\n}\n\n/** What a `claude_cli` tester is refused outright: a shell and notebooks, and\n * an edit to the files the gate patterns cover that configure the check rather\n * than test the work (D20). A deny rule wins over the allowlist in every\n * permission mode. */\nexport const TESTER_DISALLOWED_TOOLS = [\n 'Bash',\n 'NotebookEdit',\n 'Edit(/**/package.json)',\n 'Edit(/**/*.config.*)',\n 'Edit(/**/.github/**)',\n].join(',');\n\nconst PERMISSION_BLOCKS = {\n permissions: {\n blockWritesOutsideWorkingDirectories: true,\n blockReadsOutsideWorkingDirectories: true,\n },\n} as const;\n\n/** The CLI flags that turn on `PERMISSION_BLOCKS`. */\nexport function settings_args(): string[] {\n return ['--settings', JSON.stringify(PERMISSION_BLOCKS)];\n}\n\nexport type ClaudeVersion = readonly [number, number, number];\n\nexport const MIN_CLAUDE_WRITE_BLOCK: ClaudeVersion = [2, 1, 314];\n\nexport const MIN_CLAUDE_READ_BLOCK: ClaudeVersion = [2, 1, 257];\n\n/** The version `claude --version` printed (`2.1.316 (Claude Code)`), or null\n * when it printed something else. */\nexport function parse_claude_version(stdout: string): ClaudeVersion | null {\n const match = /^\\s*(\\d+)\\.(\\d+)\\.(\\d+)\\b/.exec(stdout);\n if (match === null) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\nexport function version_below(version: ClaudeVersion, min: ClaudeVersion): boolean {\n const [major, minor, patch] = version;\n const [min_major, min_minor, min_patch] = min;\n if (major !== min_major) return major < min_major;\n if (minor !== min_minor) return minor < min_minor;\n return patch < min_patch;\n}\n\nexport function format_version(version: ClaudeVersion): string {\n return version.join('.');\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, StepRecord, ToolCallRecord, UsageTotals } from 'fascicle';\nimport type {\n BuilderStepRecord,\n CostSource,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n StepTimingBasis,\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\n/** The providers whose calls carry the charge they report, which fascicle\n * records as the call's cost in place of a pricing table's estimate: the\n * Claude CLI's own total, and OpenRouter's per-response charge. */\nconst REPORTING_PROVIDERS: ReadonlySet<string> = new Set(['claude_cli', 'openrouter']);\n\nexport function cost_source_of(result: GenerateResult<unknown>): CostSource {\n if (result.cost === undefined) return 'unknown';\n return REPORTING_PROVIDERS.has(result.model_resolved.provider)\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 const truncated = result.steps.filter((step) => step.truncated === true).length;\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 ...(truncated > 0 ? { truncated_turns: truncated } : {}),\n ...(rate !== undefined ? { throughput: rate } : {}),\n };\n}\n\ntype StepSplit = { prefill_ms?: number; decode_ms?: number; timing_basis: StepTimingBasis };\n\nconst NS_PER_MS = 1e6;\n\nfunction ns_field(payload: Record<string, unknown>, name: string): number | undefined {\n const value = payload[name];\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\n/** A turn's prefill and decode times: Ollama's own durations when it reported\n * them (in ns), else the time to the first streamed chunk, else none. */\nfunction step_split(step: StepRecord): StepSplit {\n const reported = step.provider_reported?.['ollama'];\n if (typeof reported === 'object' && reported !== null) {\n const ollama = reported as Record<string, unknown>;\n const evaluated = ns_field(ollama, 'eval_duration');\n const prompt = ns_field(ollama, 'prompt_eval_duration');\n if (evaluated !== undefined && prompt !== undefined) {\n return {\n prefill_ms: Math.round(prompt / NS_PER_MS),\n decode_ms: Math.round(evaluated / NS_PER_MS),\n timing_basis: 'ollama_reported',\n };\n }\n const total = ns_field(ollama, 'total_duration');\n const load = ns_field(ollama, 'load_duration');\n if (evaluated !== undefined && total !== undefined && load !== undefined && total >= load + evaluated) {\n return {\n prefill_ms: Math.round((total - load - evaluated) / NS_PER_MS),\n decode_ms: Math.round(evaluated / NS_PER_MS),\n timing_basis: 'ollama_derived',\n };\n }\n }\n const timing = step.timing;\n if (timing?.first_chunk_ms !== undefined && timing.whole_tool_call !== true) {\n return {\n prefill_ms: timing.first_chunk_ms,\n decode_ms: Math.max(0, timing.duration_ms - timing.first_chunk_ms),\n timing_basis: 'first_chunk',\n };\n }\n return { timing_basis: 'none' };\n}\n\n/** How much a tool call's result put into the transcript: its output as the\n * loop serializes it, or the error text it fed back. */\nfunction output_chars(call: ToolCallRecord): number {\n if (call.output === undefined) return call.error?.message.length ?? 0;\n return typeof call.output === 'string' ? call.output.length : (JSON.stringify(call.output) ?? '').length;\n}\n\n/** Each turn of a session as the archive records it, or undefined when the\n * result has none. */\nexport function step_records(result: GenerateResult<unknown>): BuilderStepRecord[] | undefined {\n if (result.steps.length === 0) return undefined;\n return result.steps.map((step) => ({\n index: step.index,\n input_tokens: step.usage.input_tokens,\n output_tokens: step.usage.output_tokens,\n duration_ms: step.timing?.duration_ms ?? 0,\n ...step_split(step),\n finish_reason: step.finish_reason,\n ...(step.truncated === true ? { truncated: true as const } : {}),\n tool_calls: step.tool_calls.map((call) => ({ name: call.name, output_chars: output_chars(call) })),\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. The\n * builder's record also carries its session's turns. */\nexport function accumulate(\n state: LoopState,\n role: 'builder' | 'critic' | 'tester',\n result: GenerateResult<unknown>,\n model: string,\n duration_ms?: number,\n): LoopState {\n const record = phase_record(result, model, duration_ms);\n const steps = role === 'builder' ? step_records(result) : undefined;\n const cost = record.cost_usd ?? 0;\n return {\n ...state,\n [role]: steps !== undefined ? { ...record, steps } : 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 tester_cost_usd: state.tester_cost_usd + (role === 'tester' ? 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 * `seat_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 { command_env } from './engine.js';\nimport { check_error, config_error } from './types.js';\nimport { backup_stamp, commit_identity } 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. The check, the change report, and the checkpoints\n * follow it there; the run's state stays wherever `state_dir` puts it.\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, env: command_env(process.env), 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, env: command_env(process.env), 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 (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_identity(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 * 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 model driving volley's tools on any other provider, local or hosted.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { basename, 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 PrepareStepHook,\n RunContext,\n Step,\n StreamChunk,\n Tool,\n ToolApprovalHandler,\n} from 'fascicle';\nimport { warn_small_local_context } from './builder/context_check.js';\nimport { step_countdown } from './builder/countdown.js';\nimport { compose_prepare_steps } from './builder/prepare_step.js';\nimport { step_trim } from './builder/trim.js';\nimport { builder_tools, type BashExecutor } from './builder/tools.js';\nimport { CHECK_REJECTED } from './check/command.js';\nimport { BUILDER_ALLOWED_TOOLS, settings_args } from './claude_cli_permissions.js';\nimport { ignores_effort } from './config.js';\nimport { accumulate } from './cost.js';\nimport { seat_base_url } from './engine.js';\nimport { prewarm_ollama_model } from './prewarm.js';\nimport { config_error, phase_error } from './types.js';\nimport type { CheckResult, EffortRung, LoopState, ResolvedConfig } from './types.js';\nimport type { ToolSet } from './workspace_tools.js';\nimport { build_root } from './worktree.js';\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 builder_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 harness append each tool set's builder reads: one naming volley's own\n * tools, or one naming fascicle's workspace tools under `volley acp` and\n * saying what a call the user refused means. */\nconst HARNESS_APPENDS: Record<ToolSet, string> = {\n volley: 'harness_append_local.md',\n acp: 'harness_append_acp.md',\n};\n\n/** Step 2 of \"Work this way\", as both harness appends word it for a builder\n * held to one tool call a turn. */\nconst ONE_CALL_A_TURN = '2. Call one tool at a time and read its result before deciding the next\\n call.';\n\n/** Step 2 for a builder that may make several calls a turn: fascicle runs a\n * turn's calls in order, so a read can't race an edit, but each change or\n * command is still worth reading before the next. Reads don't count toward\n * the cap, so the step names no number. */\nconst BATCHED_CALLS = [\n '2. Batch independent reads into one turn, but make one change or command per',\n ' turn, and read its result before deciding the next call.',\n].join('\\n');\n\n// The CLI system prompt assumes CLI semantics (built-in tools, implicit\n// cwd), so the local builder gets its own — its tool set, the\n// workspace-is-cwd convention, and the harness-enforced `finish` stop.\nexport function compose_builder_system_local(\n tool_set: ToolSet = 'volley',\n max_tool_calls = 1,\n): 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(builder_presets_dir(), HARNESS_APPENDS[tool_set]), 'utf8');\n const worded =\n max_tool_calls > 1 ? append.replace(ONE_CALL_A_TURN, BATCHED_CALLS) : append;\n return `${identity}\\n\\n${worded.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, which never takes an injected set, or the local prompt naming\n * the seat's tool set for every provider that runs volley's tool loop,\n * `openrouter` included. Mirrors the critic's `resolve_critic_prompt`. */\nfunction resolve_builder_system(config: ResolvedConfig, tool_set?: ToolSet): string {\n return config.builder_provider === 'claude_cli'\n ? compose_builder_system()\n : compose_builder_system_local(tool_set, config.builder_max_tool_calls);\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/** How the step countdown tells the builder to run the check: the command\n * volley gates on, with the digest and without `--json`, the configured\n * command, or the project's own tests when no check gates the run. A\n * workspace can hold checkride with no `check` script, so not `pnpm check`. */\nfunction check_hint(config: ResolvedConfig): string {\n if (config.check_resolved === 'checkride') return 'the check (`pnpm exec checkride --digest`)';\n if (config.check_resolved === 'command') return `the check (\\`${config.check}\\`)`;\n return \"the project's tests\";\n}\n\n/** The builder's `prepare_step`: the countdown, after the history trim when\n * `--builder-trim-history` turns it on, so the countdown's note still goes\n * last. */\nfunction builder_prepare_step(config: ResolvedConfig): PrepareStepHook {\n const countdown = step_countdown(config.builder_max_steps, check_hint(config));\n if (config.builder_trim_history === null) return countdown;\n return compose_prepare_steps([step_trim(config.builder_trim_history), countdown]);\n}\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, and takes no injected tools or approval handler. Every other\n * builder, local or `openrouter`, brings none, so volley supplies its whole\n * workspace tool surface (or the set the caller injected in its place, with\n * the handler that answers its approvals), the per-call loop knobs, the step\n * countdown (`./builder/countdown.ts`) and the history trim when it's on\n * (`./builder/trim.ts`), the output cap when one is set, and\n * **no** schema (it produces a workspace, not a verdict); per-call values win\n * over engine defaults. */\nfunction builder_tool_options(\n deps: BuilderDeps,\n): Pick<\n GenerateOptions,\n | 'tools'\n | 'on_tool_approval'\n | 'provider_options'\n | 'max_steps'\n | 'tool_error_policy'\n | 'tool_call_repair_attempts'\n | 'max_tool_calls_per_step'\n | 'prepare_step'\n | 'max_tokens'\n | 'truncated_turn_policy'\n> {\n const { config } = deps;\n const bash_executor = deps.bash_executor ?? null;\n if (config.builder_provider === 'claude_cli') {\n // The file tools stay in the build root, the session's cwd: the allowlist\n // scopes them under `acceptEdits`, and the settings blocks hold under\n // `bypassPermissions` too, where allow rules decide nothing.\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: [...BUILDER_ALLOWED_TOOLS],\n extra_args: ['--permission-mode', config.builder_permission_mode, ...settings_args()],\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:\n deps.tools === undefined\n ? builder_tools(\n build_root(config.workspace, config.worktree),\n bash_executor !== null ? { bash_executor } : {},\n )\n : [...deps.tools],\n ...(deps.on_tool_approval !== undefined ? { on_tool_approval: deps.on_tool_approval } : {}),\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: config.builder_max_tool_calls,\n prepare_step: builder_prepare_step(config),\n // A capped turn that runs out before it calls a tool goes on to the next\n // step instead of ending the session; with no cap, a turn cut off at the\n // provider's own limit still ends it, as one cut off at a full context\n // window would only be cut off again.\n ...(config.builder_max_output_tokens !== null\n ? { max_tokens: config.builder_max_output_tokens, truncated_turn_policy: 'continue' as const }\n : {}),\n };\n}\n\n/** What the builder is told about the iteration before its own, besides the\n * critic's feedback. */\nexport type PreviousRound = {\n /** That iteration's check. Its output goes in the prompt when it failed. */\n check: CheckResult | null;\n /** The step limit that iteration's builder hit before it called finish, or\n * null when it stopped on its own. */\n step_limit_hit: number | null;\n};\n\n/** The tester's test, as the builder hears of it: the files it wrote, and,\n * in the iteration it opened, the check that failed on them. */\nexport type TesterTest = {\n paths: string[];\n check: CheckResult | null;\n};\n\nexport type BuilderPromptInput = {\n task: string;\n criteria: string;\n feedback: string | null;\n iteration: number;\n checkride: boolean;\n previous: PreviousRound | null;\n /** Absent, or null, when no tester ran: the prompt is what it always was. */\n tester?: TesterTest | null;\n};\n\n/** How much of the last check's output the builder's prompt carries: a few KB,\n * whatever the runner. checkride's digest already fits in 8 kB, and the builder\n * can run the check again for the rest. */\nexport const PREVIOUS_CHECK_MAX_CHARS = 6000;\n\n/** The first `max` characters of `text`, saying where it was cut. */\nfunction head(text: string, max: number, rest: string): string {\n return text.length <= max ? text : `${text.slice(0, max)}\\n… (cut at ${String(max)} characters; ${rest})`;\n}\n\n/** The last `max` characters of `text`, saying what came before was cut. */\nfunction tail(text: string, max: number): string {\n return text.length <= max\n ? text\n : `… (the last ${String(max)} characters of ${String(text.length)})\\n${text.slice(-max)}`;\n}\n\n/** The part of a failed check the builder reads first: checkride's digest,\n * else the start of each failing slot's raw output, else the end of a\n * command's output, where test runners and compilers sum up. */\nfunction check_excerpt(check: CheckResult): string {\n const max = PREVIOUS_CHECK_MAX_CHARS;\n if (check.digest !== undefined) {\n return head(check.digest.trimEnd(), max, '.check/digest.md has the rest');\n }\n if (check.detail.length > 0) {\n const slots = check.detail.map((artifact) => {\n const source = artifact.path === null ? '' : ` (.check/${basename(artifact.path)})`;\n return `${artifact.slot}${source}:\\n${artifact.content.trimEnd()}`;\n });\n return head(slots.join('\\n\\n'), max, 'each slot\\'s raw output under .check/ has the rest');\n }\n return tail((check.log ?? '').trimEnd(), max);\n}\n\n/** The check section of a later iteration's prompt: what the deterministic\n * gate itself said about the last session's work, so the builder starts from\n * its words rather than the critic's account of them, or re-running it to\n * find out. Empty unless that check ran and failed. A check the user rejected\n * when it asked to run is recorded as failed but said nothing, and the\n * section says so rather than call the work failed. */\nfunction previous_check_section(check: CheckResult | null): string[] {\n if (check === null || !check.ran || check.ok) return [];\n const heading = ['', 'PREVIOUS CHECK RESULT', '---------------------'];\n if (check.log === CHECK_REJECTED) {\n return [\n ...heading,\n 'The check never ran on the work your last session left: it was rejected when it',\n 'asked to run, so nothing has verified that work yet.',\n ];\n }\n const runner = check.runner === 'checkride' ? 'checkride, ' : '';\n const exit = check.exit_code === null ? 'no exit code' : `exit ${String(check.exit_code)}`;\n const lines = [\n ...heading,\n `The check failed on the work your last session left (${runner}${exit}).`,\n ];\n if (check.failing_slots.length > 0) {\n lines.push(`Failing slots: ${check.failing_slots.join(', ')}.`);\n }\n const excerpt = check_excerpt(check);\n if (excerpt.length > 0) lines.push('', excerpt);\n return lines;\n}\n\n/** The tester's test, in every build after it: its files, which the builder\n * makes pass rather than edits, and in the build it ran before, the check\n * that failed on them. A tester outside a git repository wrote files volley\n * can't name, so only the check is said. */\nfunction tester_section(tester: TesterTest | null | undefined): string[] {\n if (tester === null || tester === undefined) return [];\n const lines = ['', \"THE TESTER'S TEST\", '-----------------'];\n if (tester.paths.length > 0) {\n lines.push(\n 'Before the first build, a tester wrote these tests from the acceptance',\n 'criteria:',\n ...tester.paths.map((path) => ` ${path}`),\n 'Do the work that makes them pass. Never weaken, skip or delete one: an edit',\n 'to any of them is reported as a gate edit.',\n );\n } else {\n lines.push('Before the first build, a tester wrote a test from the acceptance criteria.');\n }\n const check = tester.check;\n if (check !== null && check.ran && !check.ok) {\n const exit = check.exit_code === null ? 'no exit code' : `exit ${String(check.exit_code)}`;\n lines.push('', `The check fails on it now, as it must (${exit}).`);\n if (check.failing_slots.length > 0) lines.push(`Failing slots: ${check.failing_slots.join(', ')}.`);\n const excerpt = check_excerpt(check);\n if (excerpt.length > 0) lines.push('', excerpt);\n }\n return lines;\n}\n\n/** The line a later iteration's prompt carries when the last session ran out\n * of steps: it never got to verify, so this one should check first. */\nfunction step_limit_lines(step_limit_hit: number | null): string[] {\n if (step_limit_hit === null) return [];\n return [\n '',\n `Your last session hit its ${String(step_limit_hit)}-step limit before it called finish, so`,\n 'it may never have verified its work. Run the check first this time, and keep',\n 'enough steps in hand to verify again before you finish.',\n ];\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.iteration > 1 && input.previous !== null) {\n parts.push(\n ...previous_check_section(input.previous.check),\n ...step_limit_lines(input.previous.step_limit_hit),\n );\n }\n parts.push(...tester_section(input.tester));\n if (input.checkride) {\n parts.push(\n '',\n 'The definition of done for this workspace includes checkride exiting 0. Run',\n '`pnpm exec checkride --digest`, the check volley gates on, after each batch of',\n 'edits and again before you finish. When it fails, read .check/digest.md',\n 'first: it lists each failing slot\\'s first findings. Open a slot\\'s raw',\n 'output under .check/ only if the digest isn\\'t enough, then 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 /** Tools to hand the builder in place of volley's own set; absent, it gets\n * that set. A `claude_cli` builder brings its own tools and never takes\n * these. */\n tools?: ReadonlyArray<Tool>;\n /** Which set `tools` is, so the prompt names the tools the builder holds;\n * absent, volley's own. */\n tool_set?: ToolSet;\n /** Answers each call to a tool that asks first (`needs_approval`). Like\n * `tools`, it reaches every builder but `claude_cli`. Absent, such a call\n * fails closed. */\n on_tool_approval?: ToolApprovalHandler;\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 at `effort`. Everything but the prompt\n * is fixed for the whole run, so it is wired once here: the provider's system\n * prompt, its tool surface, the live chunk stream to the renderer, and the\n * effort, which fascicle's `model_call` takes only as it's built. Null passes\n * no effort at all, so a run with no ladder makes the call it always has. */\nexport function make_builder_step(deps: BuilderDeps, effort: EffortRung | null = null): 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, deps.tool_set),\n on_chunk: deps.on_chunk,\n ...(effort !== null ? { effort } : {}),\n ...builder_tool_options(deps),\n });\n}\n\n/** The builder leaf at each rung of the run's ladder: `at(rung)` is the leaf a\n * build at that effort calls, built the first time it's asked for and reused\n * after, and `arm` is the first build's, which the flow declares. Every leaf\n * keeps the id `builder`, so the stream routes each the same way. */\nexport type BuilderLadder = {\n arm: BuilderStep;\n at: (rung: EffortRung | null) => BuilderStep;\n};\n\nexport function make_builder_ladder(deps: BuilderDeps): BuilderLadder {\n const built = new Map<EffortRung | null, BuilderStep>();\n const at = (rung: EffortRung | null): BuilderStep => {\n const cached = built.get(rung);\n if (cached !== undefined) return cached;\n const leaf = make_builder_step(deps, rung);\n built.set(rung, leaf);\n return leaf;\n };\n return { arm: at(deps.config.effort_ladder?.[0] ?? null), at };\n}\n\n/** The tester's test as `state` carries it, or null when no tester ran: its\n * files' hashes outlive the iteration it opened, its check doesn't. */\nfunction tester_test(state: LoopState): TesterTest | null {\n const paths = Object.keys(state.tester_hashes).toSorted();\n if (paths.length === 0 && state.tester_check === null) return null;\n return { paths, check: state.tester_check };\n}\n\n/** Mark the builder record as having asked for an effort its provider drops. */\nfunction with_effort_ignored(state: LoopState, ignored: boolean): LoopState {\n if (!ignored || state.builder === null) return state;\n return { ...state, builder: { ...state.builder, effort_ignored: true } };\n}\n\nexport type BuilderRunDeps = {\n builder: BuilderStep;\n config: ResolvedConfig;\n warn: (message: string) => void;\n};\n\n/** Run one builder session on the opened iteration `state`, told what the\n * iteration before it left behind (`previous`, null on the first). */\nexport async function run_builder(\n deps: BuilderRunDeps,\n state: LoopState,\n previous: PreviousRound | null,\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. Both go to the builder seat's own server.\n if (config.builder_provider === 'ollama') {\n const base_url = seat_base_url('ollama', config.builder_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 previous,\n tester: tester_test(state),\n }),\n );\n const built = with_effort_ignored(\n accumulate(state, 'builder', result, config.builder_model),\n state.rung !== null && ignores_effort(config.builder_provider),\n );\n // `max_steps` is a backstop, not a failure — surface it, count it, and\n // carry on.\n if (result.finish_reason !== 'max_steps') return built;\n deps.warn(builder_max_steps_warning(config.builder_max_steps));\n return { ...built, builder_max_steps_hits: built.builder_max_steps_hits + 1 };\n } catch (err) {\n throw phase_error('builder', 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, isAbsolute, join, relative, sep } 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';\nimport { state_path } from '../workspace.js';\nimport type { ToolSet } from '../workspace_tools.js';\nimport { build_root } from '../worktree.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\n/** The harness append that names the critic's reads. The CLI critic reads\n * via built-in Read/Grep/Glob and never takes an injected set; every other\n * critic, local or `openrouter`, reads via volley's read_file/search_files/\n * list_files, or under `volley acp` via fascicle's read_file/list_files/\n * search. */\nfunction harness_append_file(config: ResolvedConfig, tool_set: ToolSet): string {\n if (config.critic_provider === 'claude_cli') return 'harness_append.md';\n return tool_set === 'acp' ? 'harness_append_acp.md' : 'harness_append_local.md';\n}\n\nexport function resolve_critic_prompt(config: ResolvedConfig, tool_set: ToolSet = 'volley'): 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 const append = readFileSync(join(presets_dir(), harness_append_file(config, tool_set)), 'utf8');\n return `${base.trimEnd()}\\n\\n${place_iterations_dir(append, config).trimEnd()}`;\n}\n\nconst ITERATIONS_DIR = '{{iterations_dir}}';\n\n/** Fill the harness append's line about prior iteration state with where the\n * run's `iterations/` sits, relative to the build root the critic reads from,\n * or drop the line when the run's state is outside that root: a confined\n * critic can't reach it, and naming it would only spend the critic's steps on\n * a path it can't open. */\nfunction place_iterations_dir(append: string, config: ResolvedConfig): string {\n const path = relative(\n build_root(config.workspace, config.worktree),\n state_path(config, 'iterations'),\n );\n const outside = path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path);\n return append\n .split('\\n')\n .filter((line) => !(outside && line.includes(ITERATIONS_DIR)))\n .join('\\n')\n .replaceAll(ITERATIONS_DIR, `${path}/`);\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 /** The files a tester wrote before the first build (move 1's step 7), or\n * none: absent or empty, the prompt is what it was before there was a\n * tester. */\n tester_paths?: ReadonlyArray<string>;\n};\n\n/** The tester's test, for the critic to judge as well as the work: whether it\n * tests the criteria at all, since a check is only as good as what it runs.\n * Null when no tester wrote one. */\nfunction format_tester_section(paths: ReadonlyArray<string> | undefined): string | null {\n if (paths === undefined || paths.length === 0) return null;\n return [\n \"THE TESTER'S TEST\",\n '-----------------',\n 'Before the first build, a tester wrote these tests from the acceptance',\n 'criteria, and the check failed on them then:',\n '',\n ...paths.map((path) => ` ${path}`),\n '',\n 'Read them, and judge whether they test the criteria: a test a wrong',\n 'implementation would pass, or one that leaves out a criterion a test could',\n 'check, does not. Name each problem in test_findings, one per entry, and leave',\n 'it empty when the test is sound. Judge the work against the criteria either',\n 'way, not against the test alone.',\n ].join('\\n');\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 const tester = format_tester_section(input.tester_paths);\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 ...(tester === null ? [] : ['', tester]),\n '',\n 'Review the workspace against the acceptance criteria and return your',\n 'structured verdict.',\n ].join('\\n');\n}\n","/**\n * Critic invocation: a read-only session (`claude_cli`, or a local or\n * `openrouter` model with volley's read tools) returning a schema-validated\n * structured verdict. The\n * harness — not the critic — writes the run's `feedback.md` and `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 Tool,\n} from 'fascicle';\nimport {\n CRITIC_ALLOWED_TOOLS,\n CRITIC_DISALLOWED_TOOLS,\n settings_args,\n} from '../claude_cli_permissions.js';\nimport { ignores_effort } from '../config.js';\nimport { accumulate } from '../cost.js';\nimport { seat_base_url } from '../engine.js';\nimport { prewarm_ollama_model } from '../prewarm.js';\nimport { error_kind, phase_error } from '../types.js';\nimport type { CauseKind, DegradeCause, LoopState, ResolvedConfig } from '../types.js';\nimport type { ToolSet } from '../workspace_tools.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\n/** A critic that holds tools isn't constrain-decoded, so nothing stops it\n * answering null for the feedback or the unmet list, as GLM did on approving.\n * Both fields allow null and read it as empty, so that answer is a verdict\n * rather than a schema failure that ends the run. fascicle sends the schema's\n * input side, so the model sees each field as its type or null, still\n * required; `.describe()` comes last so the description stays on the field. */\nexport const verdict_schema = z.object({\n verdict: z.enum(['approved', 'changes_requested']),\n feedback: z\n .string()\n .nullable()\n .transform((feedback) => feedback ?? '')\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 .nullable()\n .transform((unmet) => unmet ?? [])\n .describe(\n 'The specific acceptance criteria judged unmet, verbatim. Empty when approved.',\n ),\n // Optional, unlike the rest: only a run with a tester has a test to judge.\n test_findings: z\n .array(z.string())\n .nullable()\n .optional()\n .describe(\n \"Problems with the tester's test, one per entry: a criterion it leaves out, or an \" +\n 'assertion a wrong implementation would pass. Empty or omitted when no tester ' +\n 'ran or its test is sound.',\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 /** Tools to hand the critic's tool-bearing call in place of volley's reads;\n * absent, it gets those. A `claude_cli` critic reads through the CLI's own\n * tools and never takes these. The critic takes no approval handler, since\n * nothing it reads with should ever ask. */\n tools?: ReadonlyArray<Tool>;\n /** Which set `tools` is, so the harness append names the reads the critic\n * holds; absent, volley's own. */\n tool_set?: ToolSet;\n};\n\n/** Read-only tool wiring per provider. The claude_cli critic is confined at\n * the CLI permission layer (allowlist + explicit disallow, and the settings\n * blocks that keep its reads in the build root); every other critic,\n * local or `openrouter`, gets volley's own workspace-scoped read-only tools (or\n * the set the caller injected in their place) and no write path at all.\n *\n * The providers also enforce `verdict_schema` by different paths, the first\n * two verified live. The claude_cli critic compiles the schema for\n * `claude --json-schema`; that only works because fascicle 0.14.0'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). An `openrouter`\n * critic rides fascicle's native OpenAI-compatible core, which has no\n * constrained decode: the schema travels in the prompt, and the reply is parsed\n * and repaired. */\nfunction critic_tool_options(\n config: ResolvedConfig,\n tools?: ReadonlyArray<Tool>,\n): Pick<GenerateOptions<VerdictOutput>, 'tools' | 'provider_options' | 'max_steps'> {\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, ...settings_args()],\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 {\n tools:\n tools === undefined\n ? read_only_tools(build_root(config.workspace, config.worktree))\n : [...tools],\n max_steps: CRITIC_MAX_STEPS,\n };\n}\n\n/** The local critic's step budget for its tool-bearing call: reads plus the\n * verdict. Set explicitly rather than inherited from fascicle's engine default\n * (also 10), so a change to that default can't move it silently. */\nexport const CRITIC_MAX_STEPS = 10;\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 provider stream death the ladder\n * retries? Every provider but `claude_cli` (that 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/** Did a schema call end without a verdict because the tool loop ran out —\n * its step budget spent, or its last turn a tool call — rather than because\n * the response was cut off or blocked? fascicle throws\n * `incomplete_generation_error` for every such finish; only these two are\n * fixed by taking the tools away. Matched on `kind` and `finish_reason`. */\nfunction is_step_exhaustion(err: unknown): boolean {\n if (error_kind(err) !== 'incomplete_generation_error') return false;\n const finish = (err as { finish_reason?: unknown }).finish_reason;\n return finish === 'max_steps' || finish === 'tool_calls';\n}\n\n/** Does this failure send a local critic to the tool-less rung? A stream death\n * the retry rung gave up on, or step exhaustion, which no retry would fix. A\n * `length` or `content_filter` finish is neither, and stays fatal. */\nfunction is_degradable_critic_error(config: ResolvedConfig, err: unknown): boolean {\n if (config.critic_provider === 'claude_cli') return false;\n return error_kind(err) === 'provider_error' || is_step_exhaustion(err);\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 degrade_cause?: DegradeCause;\n};\n\n/** The critic's findings about the tester's test, for its record, when it\n * named any. */\nfunction test_findings_of(verdict: VerdictOutput): { test_findings?: string[] } {\n const findings = verdict.test_findings ?? [];\n return findings.length > 0 ? { test_findings: findings } : {};\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 ...(mark.degrade_cause !== undefined ? { degrade_cause: mark.degrade_cause } : {}),\n ...test_findings_of(result.content),\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\n/** What both of the critic's calls share, its effort included when one is set\n * (`critic_effort`); unset, no effort is passed, as before there was one. */\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, deps.tool_set),\n schema: verdict_schema,\n on_chunk: deps.on_chunk,\n ...(config.critic_effort !== null ? { effort: config.critic_effort } : {}),\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, deps.tools),\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/** What the retry rung knew about the error that ended it: the attempt it\n * died on, and the cause of the stream death it last retried. fascicle's\n * `retry` rethrows that error untouched, so the fallback's projection looks it\n * up here to count the retries behind a degraded verdict. */\ntype LadderTrace = { attempt: number; retried_cause: CauseKind | undefined };\n\nconst ladder_traces = new WeakMap<object, LadderTrace>();\n\n/** The ladder's retry predicate for this run's critic provider: stream deaths\n * only. It also traces every failure it sees, so a degraded verdict can say how\n * many retries preceded it and why. A first attempt starts a fresh critique, so\n * it forgets the last one's retries. */\nexport function critic_retryable(\n config: ResolvedConfig,\n): (err: unknown, attempt: number) => boolean {\n let retried_cause: CauseKind | undefined;\n return (err, attempt) => {\n if (attempt === 1) retried_cause = undefined;\n if (typeof err === 'object' && err !== null) {\n ladder_traces.set(err, { attempt, retried_cause });\n }\n const retryable = is_retryable_critic_error(config, err);\n if (retryable) retried_cause = retry_cause_kind_of(err);\n return retryable;\n };\n}\n\n/** The ladder's fallback predicate: a stream death the retry rung gave up on,\n * or step exhaustion, which it never retries. */\nexport function critic_degradable(config: ResolvedConfig): (err: unknown) => boolean {\n return (err) => is_degradable_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, marked degraded so it never passes silently as a full\n * critique. Why it degraded, and the retries before it, are the ladder's to\n * stamp (`with_fallback_cause`), since the tool-less call can't see them. */\nexport function as_degraded(result: GenerateResult<VerdictOutput>): CriticAnswer {\n return {\n result,\n mark: { retries: 0, 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 * mark comes from the error that sent it there.\n *\n * - A stream death the retry rung gave up on: every retry was spent, and the\n * cause is that error's own.\n * - Step exhaustion, never retried: the retries are the stream deaths before\n * it, usually none, and the cause is the last of those.\n *\n * An error the retry rung never traced reads as one that spent every retry. */\nexport function with_fallback_cause(outcome: FallbackOutcome<CriticAnswer>): CriticAnswer {\n if (outcome.source === 'primary') return outcome.value;\n const err = outcome.primary_error;\n const trace =\n typeof err === 'object' && err !== null ? ladder_traces.get(err) : undefined;\n const retries = trace === undefined ? MAX_CRITIC_RETRIES : trace.attempt - 1;\n const exhausted = is_step_exhaustion(err);\n const retry_cause_kind = exhausted ? trace?.retried_cause : retry_cause_kind_of(err);\n return {\n ...outcome.value,\n mark: {\n ...outcome.value.mark,\n retries,\n retry_cause_kind,\n degrade_cause: exhausted ? 'step_exhaustion' : 'stream_error',\n },\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 or ran out of steps, but a tool-less\n * pass survived, so a real run will likely finish via the fallback ladder\n * (`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 and `openrouter`'s cost real money.\n *\n * A tool-bearing death is classified by the same discriminant as the run-time\n * ladder's fallback (a typed `provider_error`, or step exhaustion), then probed\n * tool-less exactly as rung 2 would run, so the canary *predicts the ladder*\n * 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(\n seat_base_url('ollama', config.critic_url, env),\n config.critic_model,\n );\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 (!is_degradable_critic_error(config, err)) {\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 on\n // the critic seat's own server so a cold multi-GB load doesn't blow the real\n // call's first-byte timeout. Best-effort; when both seats share a server and\n // a model, the builder's warm-up already loaded it and this returns at once.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(\n seat_base_url('ollama', config.critic_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 tester_paths: Object.keys(state.tester_hashes).toSorted(),\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 const critiqued = finalize_critic(state, result, config.critic_model, mark, Date.now() - started);\n // A critic effort its provider drops (ollama, lmstudio) is said on the record.\n if (config.critic_effort === null || !ignores_effort(config.critic_provider)) return critiqued;\n return critiqued.critic === null\n ? critiqued\n : { ...critiqued, critic: { ...critiqued.critic, effort_ignored: true } };\n } catch (err) {\n throw phase_error('critic', state.iteration, err);\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 { ClimbReason, EffortRung, 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 tester: null,\n tester_check: null,\n tester_changes: null,\n tester_hashes: {},\n total_usage: EMPTY_USAGE,\n total_cost_usd: 0,\n builder_cost_usd: 0,\n critic_cost_usd: 0,\n tester_cost_usd: 0,\n check_duration_ms: 0,\n builder_max_steps_hits: 0,\n builds: 0,\n rung: null,\n climbed: null,\n iteration_cost_usd: 0,\n halt: null,\n cost_warned: false,\n };\n}\n\n/** The effort build `build` (counted from 1) runs at: one rung further up the\n * ladder per build before it, the top rung repeating once it's reached. Null\n * with no ladder, which passes no effort at all. */\nexport function rung_for_build(ladder: ReadonlyArray<EffortRung> | null, build: number): EffortRung | null {\n if (ladder === null || ladder.length === 0) return null;\n return ladder[Math.min(Math.max(build, 1), ladder.length) - 1] ?? null;\n}\n\n/** Why build `build` runs a rung above the build before it, read off the state\n * that build left (`previous`). That build didn't end the run, so its check\n * failed or the critic sent it back: a check that didn't fail means the critic,\n * which is also how a resumed run reads it, since a resume keeps the last\n * check but not the last verdict. Null when it doesn't climb, because it's the\n * first build, the ladder's top has been reached, or there is no ladder. */\nexport function climb_reason(\n ladder: ReadonlyArray<EffortRung> | null,\n build: number,\n previous: LoopState,\n): ClimbReason | null {\n if (ladder === null || build < 2 || build > ladder.length) return null;\n return previous.check?.ok === false ? 'check_failed' : 'critic_rejected';\n}\n\n/** Whether the tester opens the iteration after `s`: it's on, and this is the\n * run's first (move 1's D17). A run resumed before iteration 1 completed runs\n * it again. */\nexport function tester_opens(config: ResolvedConfig, s: LoopState): boolean {\n return config.tester && s.iteration === 0;\n}\n\n/** Whether the test phase opened this iteration and no build has run in it\n * yet: the tester ran, and the run has started no build. The build then works\n * in the iteration the tester opened rather than opening the next. */\nexport function tester_opened(s: LoopState): boolean {\n return s.tester !== null && s.builds === 0;\n}\n\n/** Whether the check passed right after the tester, before any build. A check\n * skipped for the cost cap didn't run, so it never counts. */\nexport function tester_passed_early(s: LoopState): boolean {\n return tester_opened(s) && s.tester_check?.ran === true && s.tester_check.ok;\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, a tester's test passing before any build, and — implicitly\n * 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 passed_early = tester_passed_early(state);\n const halt = gate_edit\n ? 'gate_edit'\n : passed_early\n ? 'tester_passed_early'\n : !success && cap\n ? 'cost_cap'\n : null;\n return {\n stop: success || cap || gate_edit || passed_early,\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 === 'tester_passed_early') return 'tester_passed_early';\n if (value.halt === 'cost_cap') return 'cost_cap_reached';\n return converged ? 'success' : 'budget_exhausted';\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';\nimport type { ClimbReason, EffortRung } from '../types.js';\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' | 'tester' | '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 'tester':\n return pc.blue(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\n/** Controls, format characters (bidi overrides, zero-widths), and line and\n * paragraph separators: what can move the cursor, hide text, or reorder a line\n * in a terminal. */\nconst UNSAFE_CHARACTERS = /[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]/gu;\n\n/** A value from a file volley can't vouch for, quoted for a person to judge,\n * with every character that could redraw or reorder the line escaped, so a\n * rewritten config can't make the warning about it say something else. JSON\n * quoting escapes the C0 controls, the quote, and the backslash; the rest are\n * written as `\\u{…}`. */\nexport function shown(value: string): string {\n return JSON.stringify(value).replace(\n UNSAFE_CHARACTERS,\n (character) => `\\\\u{${(character.codePointAt(0) ?? 0).toString(16)}}`,\n );\n}\n\n/** The rung a build runs at, and why it's above the last build's when it is:\n * `rung medium (climbed: check_failed)`. */\nexport function format_rung(rung: EffortRung, climbed: ClimbReason | null): string {\n return `rung ${rung}${climbed === null ? '' : ` (climbed: ${climbed})`}`;\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 * 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 lstatSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join, resolve } from 'node:path';\nimport { read_failing_artifacts } from './check/checkride.js';\nimport type { CheckrideSummary, CheckrideSummaryCheck } from './check/checkride.js';\nimport { EFFORT_RUNGS } from './config.js';\nimport { EMPTY_USAGE } from './cost.js';\nimport { shown } from './render/format.js';\nimport { config_error } from './types.js';\nimport type {\n BuilderPermissionMode,\n BuilderProvider,\n CheckArtifact,\n CheckResult,\n ClimbReason,\n CriticProvider,\n EffortRung,\n LoopState,\n PhaseRecord,\n ResolvedConfig,\n RunResult,\n RunStatus,\n Verdict,\n VolleyConfig,\n} from './types.js';\nimport { detect_containment } from './containment.js';\nimport { config_signed } from './trust.js';\nimport {\n CONFIG_SIGNATURE,\n iteration_dir,\n RUN_ID_PATTERN,\n run_state_dir,\n state_path,\n} from './workspace.js';\nimport type { StateLocation } 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 config: ResolvedConfig,\n feedback: string,\n verdict: Verdict,\n): void {\n writeFileSync(state_path(config, 'feedback.md'), feedback.endsWith('\\n') ? feedback : `${feedback}\\n`);\n writeFileSync(state_path(config, '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 // Turns cut off at the builder's output cap before a tool call. Emitted\n // only when there were any. Additive.\n ...(record.truncated_turns !== undefined ? { truncated_turns: record.truncated_turns } : {}),\n // Degradation-ladder bookkeeping, critic-only: the provider-error\n // retries that preceded this verdict, their cause, whether it was rendered\n // by the tool-less fallback, and why. Emitted only when set, so the builder\n // record and old summary consumers are untouched. `critic_degraded` and\n // `degrade_cause` are the on-disk half of the contract — the comparison\n // block reads them 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 ...(record.degrade_cause !== undefined ? { degrade_cause: record.degrade_cause } : {}),\n // The critic's findings about the tester's test. Emitted only when it named\n // any. Additive.\n ...(record.test_findings !== undefined ? { test_findings: record.test_findings } : {}),\n // The seat asked for an effort its provider drops. Emitted only when it\n // did. Additive.\n ...(record.effort_ignored === true ? { effort_ignored: 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 // Each builder turn's request size, timing split, and tool output sizes,\n // so a session's growth can be read back (#7). Builder-only. Additive.\n ...(record.steps !== undefined ? { steps: record.steps } : {}),\n };\n}\n\n/** A check as the iteration archive records it, its artifacts aside. */\nfunction check_summary(check: CheckResult | null): Record<string, unknown> | null {\n return 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}\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, state.iteration);\n mkdirSync(join(dir, 'check'), { recursive: true });\n\n if (state.verdict !== null && state.feedback !== null) {\n persist_verdict_files(config, state.feedback, state.verdict);\n writeFileSync(join(dir, 'feedback.md'), readFileSync(state_path(config, '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 if (check.digest !== undefined) {\n writeFileSync(join(dir, 'check', 'digest.md'), check.digest);\n }\n // A checkride check has a log only when it was rejected, and the log\n // says so.\n if (check.log !== undefined) {\n writeFileSync(join(dir, 'check', 'check.log'), check.log);\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 // The builds the run has started, and the effort this one ran at and why\n // it climbed, which a resumed run reads back to pick its next rung.\n // Additive.\n builds: state.builds,\n rung: state.rung,\n climbed: state.climbed,\n // This build asked for an effort its provider drops (ollama, lmstudio), so\n // it ran at the provider's own whatever its rung. Additive.\n effort_ignored: state.builder?.effort_ignored === true,\n builder: phase_summary(state.builder),\n check: check_summary(check),\n critic: phase_summary(state.critic),\n // The tester's session, the check right after it, which had to fail, and\n // what it wrote, in the iteration it opened; null in every other. Its\n // files' hashes ride in every iteration, since a resume reads them back\n // to tell a builder's edit to the tester's test from the test itself.\n // Additive.\n tester: phase_summary(state.tester),\n tester_check: check_summary(state.tester_check),\n tester_changes: state.tester_changes,\n tester_hashes: state.tester_hashes,\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 tester_cost_usd: state.tester_cost_usd,\n check_duration_ms: state.check_duration_ms,\n builder_max_steps_hits: state.builder_max_steps_hits,\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 run_state_dir: run_state_dir(config),\n mode: config.mode,\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 /** Whether this machine's signature held over the run's config: false only\n * when `trust_config` let an unsigned one through, and null inside the\n * sandbox, where nothing is checked. */\n config_signed: boolean | null;\n};\n\nexport type ResumeOptions = {\n /** Resume a config this machine didn't sign (`--trust-config`): another\n * machine's, an older volley's, one edited by hand, or a contained run's,\n * whose builder could have rewritten it. */\n trust_config?: boolean;\n env?: Readonly<Record<string, string | undefined>>;\n};\n\n/** Why a host-side resume won't run a config this machine didn't sign. */\nfunction untrusted_config(run_id: string, config_path: string): Error {\n return config_error(\n `run ${run_id}'s config.json has no signature from volley on this machine, so a resume here ` +\n \"won't run it: inside the sandbox a run's builder can rewrite its config, and a resume runs \" +\n 'the check and the seats it names. Resume a contained run inside its container, with the same ' +\n `mount. If ${config_path} is another machine's, an older volley's, or one you edited, read it, ` +\n 'then pass --trust-config.',\n );\n}\n\n/** Whether a host-side resume may run the config in `text`: signed by this\n * machine, or trusted by the caller. Inside the sandbox nothing is checked: a\n * resume there runs only within the container, as the builder already does. */\nfunction check_config_trust(\n text: string,\n run: StateLocation,\n options: ResumeOptions,\n): boolean | null {\n const env = options.env ?? process.env;\n if (detect_containment(env)) return null;\n const signature_path = state_path(run, CONFIG_SIGNATURE);\n const signature = existsSync(signature_path) ? readFileSync(signature_path, 'utf8') : null;\n const signed = config_signed(text, signature, env);\n if (!signed && options.trust_config !== true) {\n throw untrusted_config(run.run_id, state_path(run, 'config.json'));\n }\n return signed;\n}\n\n/** The run id an older volley's `.volley/config.json` records, or null when\n * there is none to read. */\nfunction legacy_run_id(workspace: string): string | null {\n try {\n const recorded = JSON.parse(readFileSync(join(workspace, '.volley', 'config.json'), 'utf8')) as {\n run_id?: unknown;\n };\n return typeof recorded.run_id === 'string' ? recorded.run_id : null;\n } catch {\n return null;\n }\n}\n\n/** Where `volley resume <run_id>` finds a run: under `root` (`--state-dir`,\n * else the default root) at `<root>/<run_id>/`, returned as that root, or, for\n * a run an older volley kept in the workspace, `.volley/`, returned as null so\n * the resumed run stays there. Finding neither is a config error naming both\n * places it looked. The id becomes a path, so it must be one a run could have\n * had. */\nexport function find_run_state(workspace: string, run_id: string, root: string): string | null {\n if (!RUN_ID_PATTERN.test(run_id)) {\n throw config_error(`not a run id: ${run_id} (letters, digits, '-', and '_', starting with a letter or digit)`);\n }\n if (existsSync(join(root, run_id, 'config.json'))) return root;\n const legacy = legacy_run_id(workspace);\n if (legacy === run_id) return null;\n // Read from a file nothing has vouched for, so quoted and escaped.\n const holds = legacy === null ? '' : ` (it holds run ${shown(legacy)})`;\n throw config_error(\n `run ${run_id} not found in ${join(root, run_id)} or in ${join(resolve(workspace), '.volley')}${holds}; ` +\n 'pass --state-dir for the root it ran under, or --workspace for a run kept in .volley/',\n );\n}\n\n/** A resumed run writes into its state directory, and a contained run's\n * builder could have written there first, so a symlink anywhere in it would\n * aim the resume's writes, or its pruning of a half-finished iteration, at a\n * file of the host's. volley never makes one, so any is refused. The walk\n * reads each entry's own type and never descends a link, which Node's\n * recursive `readdirSync` would. */\nfunction refuse_symlinks(dir: string): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const path = join(dir, entry.name);\n if (entry.isSymbolicLink()) {\n throw config_error(`refusing to resume: ${path} is a symbolic link, which volley never writes`);\n }\n if (entry.isDirectory()) refuse_symlinks(path);\n }\n}\n\n/** The part of an archived iteration's `summary.json` a resumed run reads\n * back. Every field is unknown until checked, since the archive could be torn\n * or older than this volley. */\ntype ArchivedRound = {\n builds?: unknown;\n rung?: unknown;\n climbed?: unknown;\n builder?: unknown;\n tester_hashes?: unknown;\n check?: {\n ran?: unknown;\n runner?: unknown;\n ok?: unknown;\n exit_code?: unknown;\n duration_ms?: unknown;\n failing_slots?: unknown;\n } | null;\n};\n\n/** An archived file's text, or undefined when there's no file to read there. */\nfunction read_text(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8');\n } catch {\n return undefined;\n }\n}\n\nfunction read_json(path: string): unknown {\n const text = read_text(path);\n if (text === undefined) return null;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n}\n\n/** The failing slots' raw artifacts from an archived iteration's `check/`,\n * which holds each under its base name, found through the archived checkride\n * summary. */\nfunction archived_artifacts(check_dir: string, failing_slots: string[]): CheckArtifact[] {\n const summary = read_json(join(check_dir, 'summary.json')) as Partial<CheckrideSummary> | null;\n const checks = Array.isArray(summary?.checks) ? summary.checks : [];\n const failing = failing_slots.map((name): CheckrideSummaryCheck => {\n const output_file = checks.find((check) => check.name === name)?.output_file;\n return {\n name,\n adapter: null,\n ok: false,\n exit_code: null,\n duration_ms: 0,\n output_file: typeof output_file === 'string' ? basename(output_file) : null,\n };\n });\n return read_failing_artifacts(check_dir, failing);\n}\n\n/** The check an archived iteration ran, rebuilt from its directory with the\n * output its failure is shown by: the digest and the failing slots' artifacts\n * for checkride, the log for a command or a rejected check. Null when it ran\n * none. */\nfunction archived_check(dir: string, recorded: ArchivedRound['check']): CheckResult | null {\n if (recorded?.ran !== true || typeof recorded.ok !== 'boolean') return null;\n const runner = recorded.runner === 'checkride' ? 'checkride' : 'command';\n const failing_slots = Array.isArray(recorded.failing_slots)\n ? recorded.failing_slots.filter((slot): slot is string => typeof slot === 'string')\n : [];\n const check: CheckResult = {\n ran: true,\n runner,\n ok: recorded.ok,\n exit_code: typeof recorded.exit_code === 'number' ? recorded.exit_code : null,\n duration_ms: typeof recorded.duration_ms === 'number' ? recorded.duration_ms : 0,\n failing_slots,\n detail: [],\n };\n if (check.ok) return check;\n const check_dir = join(dir, 'check');\n const log = read_text(join(check_dir, 'check.log'));\n const logged = log === undefined ? check : { ...check, log };\n if (runner === 'command') return logged;\n const digest = read_text(join(check_dir, 'digest.md'));\n return {\n ...logged,\n detail: archived_artifacts(check_dir, failing_slots),\n ...(digest !== undefined ? { digest } : {}),\n };\n}\n\n/** An archived builder record, as `archive_iteration` wrote it from the\n * phase's own, or null when there is none with a finish reason. */\nfunction archived_builder(recorded: unknown): PhaseRecord | null {\n if (typeof recorded !== 'object' || recorded === null) return null;\n return typeof (recorded as Partial<PhaseRecord>).finish_reason === 'string'\n ? (recorded as PhaseRecord)\n : null;\n}\n\n/** An archived rung, or null for none, or one this volley doesn't know. */\nfunction archived_rung(recorded: unknown): EffortRung | null {\n return (EFFORT_RUNGS as ReadonlyArray<unknown>).includes(recorded) ? (recorded as EffortRung) : null;\n}\n\n/** Archived tester hashes, path to hash; anything else in the record is\n * dropped, and an archive older than them has none. */\nfunction archived_hashes(recorded: unknown): Record<string, string> {\n if (typeof recorded !== 'object' || recorded === null) return {};\n return Object.fromEntries(\n Object.entries(recorded).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction archived_climb(recorded: unknown): ClimbReason | null {\n return recorded === 'check_failed' || recorded === 'critic_rejected' ? recorded : null;\n}\n\n/** What the last completed iteration left for the next build: its check and\n * its builder's record, which tell the resumed run's first builder what the\n * gate said and whether the last session ran out of steps, as a run that never\n * stopped would have, and the builds so far with the last one's rung, which\n * set the next build's rung. Null and none before the first iteration. An\n * archive older than the count had one build an iteration. */\nfunction archived_round(\n run: StateLocation,\n completed: number,\n): Pick<LoopState, 'check' | 'builder' | 'builds' | 'rung' | 'climbed' | 'tester_hashes'> {\n if (completed === 0) {\n return { check: null, builder: null, builds: 0, rung: null, climbed: null, tester_hashes: {} };\n }\n const dir = iteration_dir(run, completed);\n const recorded = read_json(join(dir, 'summary.json')) as ArchivedRound | null;\n const builds = recorded?.builds;\n return {\n check: archived_check(dir, recorded?.check),\n builder: archived_builder(recorded?.builder),\n builds: typeof builds === 'number' && Number.isInteger(builds) && builds >= 0 ? builds : completed,\n rung: archived_rung(recorded?.rung),\n climbed: archived_climb(recorded?.climbed),\n tester_hashes: archived_hashes(recorded?.tester_hashes),\n };\n}\n\n/** Recover a resumable run from its state directory (`.volley/`, or\n * `<state_dir>/<run_id>/` under a state root): settings from config.json,\n * totals from summary.json, feedback from feedback.md. An iteration directory\n * without a summary.json was interrupted mid-phase and is discarded. A\n * directory with a symlink in it is refused before anything is read. */\nexport function load_resume_state(\n workspace: string,\n run_id: string,\n state_dir: string | null = null,\n options: ResumeOptions = {},\n): ResumeState {\n const run = { workspace, state_dir, run_id };\n const run_dir = run_state_dir(run);\n if (existsSync(run_dir)) {\n if (lstatSync(run_dir).isSymbolicLink()) {\n throw config_error(`refusing to resume: ${run_dir} is a symbolic link, which volley never writes`);\n }\n refuse_symlinks(run_dir);\n }\n const config_path = state_path(run, 'config.json');\n if (!existsSync(config_path)) {\n throw config_error(`no resumable run found: ${config_path} missing`);\n }\n const config_text = readFileSync(config_path, 'utf8');\n const signed = check_config_trust(config_text, run, options);\n const recorded = JSON.parse(config_text) as Record<string, unknown>;\n if (recorded['run_id'] !== run_id) {\n throw config_error(\n `run ${run_id} not found in ${run_state_dir(run)} (recorded run: ${String(recorded['run_id'])})`,\n );\n }\n if (recorded['mode'] === 'critique') {\n throw config_error(\n `run ${run_id} is a critique, which has one round and nothing to resume; run volley critique again`,\n );\n }\n\n const iterations_root = state_path(run, '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 = state_path(run, 'summary.json');\n const summary = existsSync(summary_path)\n ? (JSON.parse(readFileSync(summary_path, 'utf8')) as RunResult)\n : null;\n\n const feedback_path = state_path(run, '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 ...(typeof recorded['builder_url'] === 'string'\n ? { builder_url: recorded['builder_url'] }\n : {}),\n ...(recorded['builder_max_steps'] === undefined\n ? {}\n : { builder_max_steps: Number(recorded['builder_max_steps']) }),\n ...(recorded['builder_max_tool_calls'] === undefined\n ? {}\n : { builder_max_tool_calls: Number(recorded['builder_max_tool_calls']) }),\n // Null when the run left it unset, as any run before it was recorded did.\n ...(typeof recorded['builder_max_output_tokens'] === 'number'\n ? { builder_max_output_tokens: recorded['builder_max_output_tokens'] }\n : {}),\n // Null (off) when the run left it unset, as any run before it was recorded did.\n ...(typeof recorded['builder_trim_history'] === 'number'\n ? { builder_trim_history: recorded['builder_trim_history'] }\n : {}),\n // Null (no ladder) when the run set none, as any run before it was\n // recorded did. A recorded ladder wins over `VOLLEY_EFFORT_LADDER`, as a\n // config file's does, and resolving it checks each rung again.\n ...(Array.isArray(recorded['effort_ladder'])\n ? { effort_ladder: recorded['effort_ladder'] as EffortRung[] }\n : {}),\n critic_model: String(recorded['critic_model']),\n critic_provider: (recorded['critic_provider'] ?? 'claude_cli') as CriticProvider,\n ...(typeof recorded['critic_url'] === 'string' ? { critic_url: recorded['critic_url'] } : {}),\n // Recorded resolved, so a ladder's default `high` comes back as itself.\n ...(typeof recorded['critic_effort'] === 'string'\n ? { critic_effort: recorded['critic_effort'] as EffortRung }\n : {}),\n // Off when the run left it off, as any run before it was recorded did,\n // whatever VOLLEY_TESTER says now: a resume interrupted in iteration 1 runs\n // the tester again only if the run had one.\n tester: recorded['tester'] === true ? 'on' : 'off',\n ...(recorded['tester'] === true && typeof recorded['tester_model'] === 'string'\n ? { tester_model: recorded['tester_model'] }\n : {}),\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 ...(typeof recorded['state_dir'] === 'string' ? { state_dir: recorded['state_dir'] } : {}),\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 ...archived_round(run, completed),\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 critic: null,\n // The tester ran in iteration 1, which a resume past it never repeats.\n tester: null,\n tester_check: null,\n tester_changes: 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 // An older volley's summary has none.\n tester_cost_usd: summary?.tester_cost_usd ?? 0,\n check_duration_ms: summary?.check_duration_ms ?? 0,\n // An older volley's summary has no count.\n builder_max_steps_hits: summary?.builder_max_steps_hits ?? 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 config_signed: signed,\n };\n}\n","/**\n * Enriched run summary (the run's `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 * the run's `iterations/`, so the trajectory grows as the run does.\n */\nimport { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';\nimport { EFFORT_RUNGS } from './config.js';\nimport type {\n BuilderProvider,\n CriticProvider,\n DegradeCause,\n EffortRung,\n ResolvedConfig,\n RunResult,\n Verdict,\n} from './types.js';\nimport { state_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.14.0 defaults `transport` to `'ai_sdk'`, so\n * volley sets no field); `openrouter` runs on fascicle's `native` transport\n * (`src/engine.ts` sets it); `claude_cli` drives Claude through its own CLI\n * subprocess, not an ai-sdk transport at all. Recording each keeps the\n * transport a clean second variable in the comparison (model vs transport). */\nexport type Transport = 'ai_sdk' | 'native' | 'claude_cli';\n\nexport function transport_of(provider: BuilderProvider | CriticProvider): Transport {\n switch (provider) {\n case 'claude_cli':\n return 'claude_cli';\n case 'openrouter':\n return 'native';\n case 'ollama':\n case 'lmstudio':\n return 'ai_sdk';\n }\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 /** Null for a critique, which has no builder. */\n builder_transport: Transport | null;\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 /** The tester's spend; 0 with the tester off. Additive. */\n tester_cost_usd: number;\n /** The check passed on the tester's test before any build, so the run ended\n * with nothing built: its test was vacuous, or the work was done already.\n * Additive. */\n tester_passed_early: boolean;\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 /** Why the degraded verdicts degraded, each cause once, in the order the\n * iterations first hit it. Empty when no verdict degraded. Additive. */\n critic_degrade_causes: DegradeCause[];\n /** Each iteration's build effort, in run order: its rung on the ladder, or\n * null for a build with none. Empty for a critique, which builds nothing.\n * Additive. */\n rungs: Array<EffortRung | null>;\n /** Every build ran at one effort, counting a build whose provider ignored\n * its effort as running at the provider's own: the ladder never climbed, or\n * climbed on a seat where it changes nothing, or there was no ladder.\n * Additive. */\n ladder_flat: boolean;\n};\n\n/** `RunResult` plus the comparison block; the run's `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 rung?: unknown;\n effort_ignored?: boolean;\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; degrade_cause?: DegradeCause } | 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(config: ResolvedConfig): IterationArchive[] {\n const root = state_path(config, '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 = state_path(config, '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/** Each distinct reason an archived critic verdict degraded. An archive from\n * before the cause was recorded reads as a stream error, the only way a verdict\n * could degrade then. */\nfunction critic_degrade_causes(archives: IterationArchive[]): DegradeCause[] {\n const causes = archives\n .filter((archive) => archive.critic?.critic_degraded === true)\n .map((archive) => archive.critic?.degrade_cause ?? 'stream_error');\n return [...new Set(causes)];\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\n/** An archived build's rung, or null for none, or one this volley doesn't\n * know. */\nfunction archived_rung(archive: IterationArchive): EffortRung | null {\n const rung = archive.rung;\n return (EFFORT_RUNGS as ReadonlyArray<unknown>).includes(rung) ? (rung as EffortRung) : null;\n}\n\n/** Whether every build ran at one effort: each build's rung, or the provider's\n * own where the provider ignored it, taking one value across the run. */\nfunction ladder_flat(archives: IterationArchive[]): boolean {\n const efforts = archives.map((archive) =>\n archive.effort_ignored === true ? 'ignored' : archived_rung(archive),\n );\n return new Set(efforts).size <= 1;\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);\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: config.mode === 'critique' ? null : 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 tester_cost_usd: result.tester_cost_usd,\n tester_passed_early: result.status === 'tester_passed_early',\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 critic_degrade_causes: critic_degrade_causes(archives),\n rungs: config.mode === 'critique' ? [] : archives.map(archived_rung),\n ladder_flat: config.mode === 'critique' || ladder_flat(archives),\n },\n };\n}\n\n/** Write the enriched summary to the run's `summary.json` (the projection the\n * examples' comparison is read from). */\nexport function write_run_summary(config: ResolvedConfig, result: RunResult): void {\n writeFileSync(\n state_path(config, 'summary.json'),\n `${JSON.stringify(build_run_summary(config, result), null, 2)}\\n`,\n );\n}\n","/**\n * The tester's prompts: its system prompt, the `tester.md` preset and a line\n * naming the tools its seat holds, and the prompt of its one call, composed\n * from the criteria, where it may write, the check that will run its test, and\n * the workspace inventory.\n *\n * The tester writes from the criteria rather than the task (move 1's Frame): a\n * critic can be argued with about prose criteria, a test can't, so the test\n * is the criteria made executable. The inventory saves its first turns on\n * finding where the tests live.\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 { CriticProvider } from '../types.js';\nimport type { ToolSet } from '../workspace_tools.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/tester/presets). */\nexport function tester_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', 'tester', 'presets');\n if (existsSync(candidate)) return candidate;\n const local = join(dir, 'presets');\n if (existsSync(join(local, 'tester.md'))) return local;\n dir = dirname(dir);\n }\n throw config_error('tester presets directory not found');\n}\n\n/** The tools a tester on `provider` holds, as its system prompt names them:\n * the Claude CLI's own, under the tester's permission list, fascicle's under\n * `volley acp`, whose writes ask the person in the editor first, or\n * volley's. */\nfunction tools_paragraph(provider: CriticProvider, tool_set: ToolSet): string {\n if (provider === 'claude_cli') {\n return [\n 'Read the workspace with Read, Grep and Glob. Write and Edit work only on the',\n 'paths your prompt lists as writable, and are refused anywhere else. You',\n 'cannot run commands.',\n ].join('\\n');\n }\n if (tool_set === 'acp') {\n return [\n 'You have five tools, every path relative to the workspace root:',\n '- read_file, list_files and search read the workspace.',\n '- write_file(path, content) and edit_file(path, old_text, new_text) write',\n ' only the paths your prompt lists as writable; anywhere else they refuse,',\n ' naming why. The person in the editor may be asked before each write, and',\n ' a write they decline is not made.',\n 'You cannot run commands; no other tools are available to you.',\n ].join('\\n');\n }\n return [\n 'You have five tools, every path workspace-relative:',\n '- read_file(path), search_files(pattern, path?, ignore_case?) and',\n ' list_files(path?, contains?) read the workspace.',\n '- write_file(path, content) and edit_file(path, old_str, new_str) write',\n ' only the paths your prompt lists as writable; anywhere else they refuse,',\n ' naming why.',\n 'You cannot run commands; no other tools are available to you.',\n ].join('\\n');\n}\n\n/** The tester's system prompt for a seat on `provider` holding `tool_set`. */\nexport function resolve_tester_prompt(provider: CriticProvider, tool_set: ToolSet = 'volley'): string {\n const base = readFileSync(join(tester_presets_dir(), 'tester.md'), 'utf8');\n return `${base.trimEnd()}\\n\\n${tools_paragraph(provider, tool_set)}`;\n}\n\nexport type TesterPromptInput = {\n criteria: string;\n /** The gate patterns the tester may write under (`writable_gate_patterns`). */\n writable: ReadonlyArray<string>;\n /** The check that runs after the tester, as configured (`auto`, a command). */\n check: string;\n /** The build root's paths and sizes (`workspace_inventory`). */\n inventory: string;\n};\n\nexport function compose_tester_prompt(input: TesterPromptInput): string {\n const check = input.check === 'auto' ? 'checkride, found by --check auto' : `\\`${input.check}\\``;\n return [\n 'ACCEPTANCE CRITERIA',\n '-------------------',\n input.criteria,\n '',\n 'WHERE YOU MAY WRITE',\n '-------------------',\n 'Paths matching these patterns, except package.json, *.config.* files and',\n 'anything under .github/:',\n ...input.writable.map((pattern) => ` ${pattern}`),\n '',\n 'THE CHECK',\n '---------',\n `${check} runs once you finish. It must fail then, on your test.`,\n '',\n 'WORKSPACE FILE INVENTORY',\n '------------------------',\n input.inventory,\n '',\n 'Write the failing test now.',\n ].join('\\n');\n}\n","/**\n * The tester seat: one session before the first build that writes a failing\n * test from the criteria under the test and fixture gate paths (move 1's D5,\n * D20). It takes the critic's provider, URL and effort, and the critic's model\n * unless `--tester-model` names one (D7, D15), since writing the right test is\n * reading work and the critic seat is on every run.\n *\n * Confinement is per provider, as the critic's is. A `claude_cli` tester runs\n * under its own permission list (`tester_allowed_tools`,\n * `TESTER_DISALLOWED_TOOLS`) in the CLI's default mode; every other tester gets\n * volley's `tester_tools`, with no shell. This module builds the call and the\n * dry run's probe of it; the flow runs it.\n */\nimport { model_call } from 'fascicle';\nimport type {\n Engine,\n GenerateOptions,\n GenerateResult,\n RunContext,\n Step,\n StreamChunk,\n Tool,\n ToolApprovalHandler,\n} from 'fascicle';\nimport {\n settings_args,\n tester_allowed_tools,\n TESTER_DISALLOWED_TOOLS,\n} from '../claude_cli_permissions.js';\nimport { ignores_effort } from '../config.js';\nimport { accumulate } from '../cost.js';\nimport { seat_base_url } from '../engine.js';\nimport { prewarm_ollama_model } from '../prewarm.js';\nimport { phase_error } from '../types.js';\nimport type { LoopState, ResolvedConfig } from '../types.js';\nimport { read_only_tools, workspace_inventory } from '../workspace_tools.js';\nimport type { ToolSet } from '../workspace_tools.js';\nimport { build_root } from '../worktree.js';\nimport { compose_tester_prompt, resolve_tester_prompt } from './prompt.js';\nimport { tester_tools, writable_gate_patterns } from './tools.js';\n\n/** The tester's step budget on a tool-loop provider: reading the workspace,\n * then a test file or two. Its own constant, so a change to the builder's or\n * fascicle's default can't move it. */\nconst TESTER_MAX_STEPS = 30;\n\n/** One write a turn, as a local builder makes by default: some model and\n * runtime pairs return parallel calls badly. Reads don't count. */\nconst TESTER_MAX_TOOL_CALLS = 1;\n\n/** The model the tester runs: `--tester-model`, else the critic's. */\nexport function tester_model(config: ResolvedConfig): string {\n return config.tester_model ?? config.critic_model;\n}\n\nexport type TesterDeps = {\n engine: Engine;\n config: ResolvedConfig;\n on_chunk: (chunk: StreamChunk) => void;\n /** Tools in place of `tester_tools`, as the critic takes them. A\n * `claude_cli` tester uses the CLI's own and never takes these. */\n tools?: ReadonlyArray<Tool>;\n /** Which set `tools` is, so the system prompt names what the tester holds;\n * absent, volley's own. */\n tool_set?: ToolSet;\n /** Answers each call to a tool that asks first, as under `volley acp`,\n * where the tester's writes ask as the builder's do. Absent, such a call\n * fails closed. */\n on_tool_approval?: ToolApprovalHandler;\n};\n\n/** The tester's tool wiring for its provider. */\nfunction tester_tool_options(\n config: ResolvedConfig,\n deps: Pick<TesterDeps, 'tools' | 'on_tool_approval'>,\n): Pick<\n GenerateOptions,\n | 'tools'\n | 'provider_options'\n | 'max_steps'\n | 'tool_error_policy'\n | 'max_tool_calls_per_step'\n | 'on_tool_approval'\n> {\n const { tools } = deps;\n if (config.critic_provider === 'claude_cli') {\n return {\n provider_options: {\n claude_cli: {\n allowed_tools: tester_allowed_tools(writable_gate_patterns(config.gate_paths)),\n extra_args: ['--disallowedTools', TESTER_DISALLOWED_TOOLS, ...settings_args()],\n },\n },\n };\n }\n return {\n tools:\n tools === undefined\n ? tester_tools(build_root(config.workspace, config.worktree), config.gate_paths)\n : [...tools],\n ...(deps.on_tool_approval !== undefined ? { on_tool_approval: deps.on_tool_approval } : {}),\n max_steps: TESTER_MAX_STEPS,\n // A refused write is the tester's to read and route around, not the run's\n // end.\n tool_error_policy: 'feed_back',\n max_tool_calls_per_step: TESTER_MAX_TOOL_CALLS,\n };\n}\n\n/** The tester's model boundary: one session, its output the whole result,\n * from which the phase records its usage, cost and timing. */\nexport type TesterStep = Step<string, GenerateResult<string>>;\n\n/** The tester's one call: its system prompt, its tools, the critic's effort. */\nexport function make_tester_step(deps: TesterDeps): TesterStep {\n const { config } = deps;\n return model_call({\n engine: deps.engine,\n id: 'tester',\n description: 'model call writing a failing test under the test and fixture gate paths',\n provider: config.critic_provider,\n model: tester_model(config),\n system: resolve_tester_prompt(config.critic_provider, deps.tool_set),\n on_chunk: deps.on_chunk,\n ...(config.critic_effort !== null ? { effort: config.critic_effort } : {}),\n ...tester_tool_options(config, deps),\n });\n}\n\n/** The prompt of the tester's call, from the run's criteria, writable\n * patterns, check, and the build root as it stands. */\nexport function tester_prompt(config: ResolvedConfig): string {\n return compose_tester_prompt({\n criteria: config.criteria,\n writable: writable_gate_patterns(config.gate_paths),\n check: config.check,\n inventory: workspace_inventory(build_root(config.workspace, config.worktree)),\n });\n}\n\n/** Run the tester's session on the iteration `state` opened, folding its\n * record and spend into the state as `tester` (D21). A failure is a phase\n * error of its own, which exits as a provider error does. */\nexport async function run_tester(\n tester: TesterStep,\n config: ResolvedConfig,\n state: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n try {\n // The cold-load guard every Ollama seat takes, on the critic's server.\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(\n seat_base_url('ollama', config.critic_url, process.env),\n tester_model(config),\n ctx.abort,\n );\n }\n const result = await ctx.call(tester, tester_prompt(config));\n const tested = accumulate(state, 'tester', result, tester_model(config));\n // An effort its provider drops (ollama, lmstudio) is said on the record.\n if (config.critic_effort === null || !ignores_effort(config.critic_provider)) return tested;\n return tested.tester === null\n ? tested\n : { ...tested, tester: { ...tested.tester, effort_ignored: true } };\n } catch (err) {\n throw phase_error('tester', state.iteration, err);\n }\n}\n\n/** What the dry run learned about a local tester seat. */\nexport type TesterCanary = { outcome: 'ok' } | { outcome: 'failed'; detail: string };\n\nconst TESTER_CANARY_PROMPT = [\n 'CANARY CHECK: a tiny wiring probe, not a real task. Write nothing.',\n 'Call the read_file tool on the path \"package.json\", then, whatever it',\n 'returns, reply with the one word \"canary\".',\n].join('\\n');\n\n/**\n * The `--dry-run` probe of a local tester: one $0 call with the tester's model\n * and system prompt that must make a tool call, as the critic's canary does,\n * since a tool-call death is how a local seat fails. It holds the read tools\n * only, so a dry run never writes; preflight runs it for an `ollama` or\n * `lmstudio` tester, whose calls cost nothing.\n */\nexport async function tester_canary(\n engine: Engine,\n config: ResolvedConfig,\n env: Record<string, string | undefined> = process.env,\n): Promise<TesterCanary> {\n if (config.critic_provider === 'ollama') {\n await prewarm_ollama_model(seat_base_url('ollama', config.critic_url, env), tester_model(config));\n }\n try {\n await engine.generate({\n provider: config.critic_provider,\n model: tester_model(config),\n system: resolve_tester_prompt(config.critic_provider),\n prompt: TESTER_CANARY_PROMPT,\n tools: read_only_tools(build_root(config.workspace, config.worktree)),\n max_steps: 3,\n tool_error_policy: 'feed_back',\n });\n return { outcome: 'ok' };\n } catch (err) {\n return { outcome: 'failed', detail: err instanceof Error ? err.message : String(err) };\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, the per-iteration archive, and the progress events a\n * trajectory reader follows the run by.\n */\nimport { aborted_error } from 'fascicle';\nimport type { RunContext, StreamChunk, ToolApprovalHandler } from 'fascicle';\nimport { run_builder } from './builder.js';\nimport type { BuilderLadder, PreviousRound } from './builder.js';\nimport { collect_changes, snapshot_changes, tester_written, without_tester_edits } from './changes.js';\nimport type { CollectChangesOptions } from './changes.js';\nimport { run_checkride } from './check/checkride.js';\nimport { CHECK_REJECTED, rejected_check, run_command_check, skipped_check } from './check/command.js';\nimport { run_critic } from './critic/run.js';\nimport { command_env } from './engine.js';\nimport type { CriticStep } from './critic/run.js';\nimport { archive_iteration, run_result_from_state } from './iteration.js';\nimport { climb_reason, rung_for_build, tester_opened } from './loop_state.js';\nimport type { Renderer } from './render/renderer.js';\nimport { write_run_summary } from './summary.js';\nimport { run_tester } from './tester/run.js';\nimport type { TesterStep } from './tester/run.js';\nimport { error_kind, phase_error } from './types.js';\nimport type { ChangeSet, CheckResult, LoopState, ResolvedConfig, Verdict } from './types.js';\nimport { git_checkpoint, state_root_within } from './workspace.js';\nimport { build_root } from './worktree.js';\n\n/** A round's build starting. `after_test` marks the build of the round the\n * tester opened, which its `test_start` announced first. */\nexport type RoundStartEvent = { volley: 'round_start'; round: number; after_test?: true };\n\n/** A round opening with the tester's test, before its build (move 1's D17). */\nexport type TestStartEvent = { volley: 'test_start'; round: number };\n\n/** The check starting, with the command line it runs. */\nexport type CheckStartEvent = { volley: 'check_start'; round: number; command: string };\n\n/** The check's outcome. */\nexport type CheckEndEvent = {\n volley: 'check_end';\n round: number;\n ok: boolean;\n exit_code: number | null;\n failing_slots: string[];\n duration_ms: number;\n};\n\n/** The critic's verdict, with what it still found missing, and whether it\n * came from the tool-less fallback. */\nexport type VerdictEvent = {\n volley: 'verdict';\n round: number;\n verdict: Verdict;\n feedback: string;\n unmet_criteria: string[];\n degraded: boolean;\n};\n\n/** The progress events the phases emit through `ctx.emit`, discriminated by\n * `volley`, since `ctx.emit` overwrites `kind` with `'emit'`. A CLI run's\n * trajectory keeps them for a viewer, and under acp they become the round\n * lines, the verdict thought, and the rest of what the editor shows. */\nexport type PhaseEvent =\n | RoundStartEvent\n | TestStartEvent\n | CheckStartEvent\n | CheckEndEvent\n | VerdictEvent;\n\n/** The step id the check's card is recorded under: the check step's own, in\n * `./flow.ts`, so each round's check counts as a fresh run of it and opens a\n * card of its own. */\nexport const CHECK_STEP_ID = 'check';\n\n/** The raw call id and tool name of the check's card. The name sits outside\n * the workspace tools, so nothing dresses the card as one of theirs. */\nconst CHECK_CALL = { id: 'check', name: 'check' } as const;\n\nfunction emit(ctx: RunContext, event: PhaseEvent): void {\n ctx.emit(event);\n}\n\n/** Record one chunk of the check's card, the way `model_call` records a tool\n * call's, under a streamed run only, since nothing reads a card otherwise. */\nfunction record_check_chunk(ctx: RunContext, chunk: StreamChunk): void {\n if (ctx.streaming) ctx.trajectory.record({ kind: 'model_chunk', step_id: CHECK_STEP_ID, chunk });\n}\n\n/** The command line the check runs, or null when no check is configured. */\nfunction check_command(config: ResolvedConfig): string | null {\n if (config.check_resolved === 'checkride') return 'pnpm exec checkride --json --digest';\n if (config.check_resolved === 'command') return config.check;\n return null;\n}\n\n/** How the check runs when the caller sets it, as `volley acp` does. Left\n * out, the check runs unasked with volley's environment less the seats' keys,\n * as on the CLI. */\nexport type CheckGate = {\n /** The whole environment the check runs with, in place of volley's own less\n * the seats' keys. */\n env?: Readonly<Record<string, string>>;\n /** Asked on the check's card before each check, the way a model call asks\n * before a gated tool runs. Anything short of an allow keeps the check from\n * running, and it's recorded as failed. */\n on_approval?: ToolApprovalHandler;\n};\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 check?: CheckGate;\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 // A critique's change has no builder behind it, as far as volley knows.\n const [who, whose, edits] =\n config.mode === 'critique'\n ? ['the change under review touches', 'whether it passes', 'the change edits']\n : ['the builder changed', 'whether its work passes', 'the builder can edit'];\n renderer.warn(\n `gate edit: ${who} ${String(changes.gate_edits.length)} file(s) that decide ` +\n `${whose} — ${listed}${hidden > 0 ? ` (+${String(hidden)} more)` : ''}. ` +\n `A green check proves less when ${edits} 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\n/** Run the configured check, checkride or a command, with the environment\n * the caller set for it, else volley's own less the seats' keys, since the\n * check runs code the builder wrote. */\nasync function execute_check(deps: PhaseDeps, abort: AbortSignal): Promise<CheckResult> {\n const { config } = deps;\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 const options = { abort, env: deps.check?.env ?? command_env(process.env) };\n return config.check_resolved === 'checkride'\n ? run_checkride({ ...options, workspace: root })\n : run_command_check({ ...options, command: config.check, workspace: root });\n}\n\n/** Whether the check may run `command`: yes, unless the caller set an\n * approval and it answers no. It asks on the check's card under the command\n * line as its tool name, which titles the prompt the way the card is titled,\n * and which names none of fascicle's gated tools, so the prompt offers Allow\n * and Reject alone, never an \"always\" that would cover the builder's commands\n * too. A stop while it asks ends the check as a stop, not a rejection. */\nasync function check_allowed(\n deps: PhaseDeps,\n command: string,\n abort: AbortSignal,\n): Promise<boolean> {\n const approve = deps.check?.on_approval;\n if (approve === undefined) return true;\n const allowed = await approve({\n tool_name: command,\n input: { command },\n tool_call_id: CHECK_CALL.id,\n step_index: 0,\n abort,\n });\n if (abort.aborted) throw new aborted_error('check aborted');\n return allowed;\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 tester: null,\n tester_check: null,\n tester_changes: null,\n };\n}\n\n/** What the builder of the iteration after `s` hears about it beyond the\n * critic's feedback: its check, and whether its builder ran out of steps. Null\n * before the first iteration. A resumed run's state carries both, read back\n * from the last archived iteration. */\nfunction previous_round(config: ResolvedConfig, s: LoopState): PreviousRound | null {\n if (s.iteration === 0) return null;\n return {\n check: s.check,\n step_limit_hit: s.builder?.finish_reason === 'max_steps' ? config.builder_max_steps : null,\n };\n}\n\n/** What changed in the build root since the baseline, reported as it's\n * measured: the count, and a warning for any gate edit. A run measures the\n * builder's work this way after every build, and a critique measures the\n * change under review the same way, so the critic is shown one shape either\n * way. */\nfunction measure_changes(\n deps: PhaseDeps,\n root: string,\n tester_hashes: Readonly<Record<string, string>> = {},\n): ChangeSet | null {\n const { config, renderer } = deps;\n const changes = without_tester_edits(collect_changes(change_options(deps, root)), root, tester_hashes);\n report_changes(config, renderer, changes);\n return changes;\n}\n\n/** How the build root's changes are collected: from the run's baseline,\n * against the gate, leaving out a state root inside it. */\nfunction change_options(deps: PhaseDeps, root: string): CollectChangesOptions {\n return {\n root,\n baseline: deps.baseline,\n gate_patterns: deps.config.gate_paths,\n excluded_dir: state_root_within(root, deps.config.state_dir),\n };\n}\n\n/** The next build counted, with the rung it runs at and why that rung is\n * above the last build's, read off the state the last build left. */\nfunction climb(config: ResolvedConfig, s: LoopState, next: LoopState): LoopState {\n const builds = s.builds + 1;\n return {\n ...next,\n builds,\n rung: rung_for_build(config.effort_ladder, builds),\n climbed: climb_reason(config.effort_ladder, builds, s),\n };\n}\n\n/** `test`: the tester opens iteration 1 and writes its failing test, then\n * volley records what it wrote, by hash, and under `--git` checkpoints it, so\n * the build that follows is measured apart from it (move 1's D9, D22). */\nexport async function test_phase(\n deps: PhaseDeps,\n tester: TesterStep,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n const next = next_iteration(s);\n emit(ctx, { volley: 'test_start', round: next.iteration });\n renderer.phase_start(next.iteration, 'tester');\n const root = build_root(config.workspace, config.worktree);\n const before = snapshot_changes(change_options(deps, root));\n const tested = await run_tester(tester, config, next, ctx);\n renderer.phase_end(tested.iteration, 'tester', true);\n renderer.cost_line(tested.iteration, 'tester', tested.tester?.cost_usd ?? null, tested.total_cost_usd);\n if (tested.cost_warned && !s.cost_warned) {\n renderer.warn('cost unavailable for this phase; recording null (run totals sum what is known)');\n }\n const written = tester_written(change_options(deps, root), before);\n if (written.changes !== null) {\n const paths = written.changes.files.map((file) => file.path);\n renderer.info(\n paths.length === 0\n ? 'tester: wrote no file'\n : `tester: wrote ${String(paths.length)} file(s): ${paths.join(', ')}`,\n );\n }\n if (config.git_checkpoints) {\n git_checkpoint(\n root,\n `volley iter ${String(tested.iteration)}: test`,\n state_root_within(root, config.state_dir),\n );\n }\n return { ...tested, tester_changes: written.changes, tester_hashes: written.hashes };\n}\n\n/** `red_check`: the check right after the tester, which must fail on its\n * test. It's recorded apart from the check after the build. A pass ends the\n * run before any build, at the loop guard (D6). */\nexport async function red_check_phase(\n deps: PhaseDeps,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const checked = await check_phase(deps, s, ctx);\n const result = checked.check;\n if (result?.ok === true) {\n deps.renderer.warn(\n \"the check passed on the tester's test before any build: the test is vacuous, or the \" +\n 'work is already done. Ending the run with no build (tester_passed_early, exit 2).',\n );\n } else {\n deps.renderer.info(\"the check fails on the tester's test, as it must; building\");\n }\n return { ...checked, check: null, tester_check: result };\n}\n\n/** `skip_red`: the tester alone crossed the cost cap, so the check is recorded\n * as skipped, and the guard halts the run on the cap with no build (D21). */\nexport function skip_red_phase(deps: PhaseDeps, s: LoopState): LoopState {\n deps.renderer.warn('cost cap crossed during the tester; skipping the check, the build and the critic');\n return { ...s, tester_check: skipped_check('cost_cap') };\n}\n\n/** `build`: one builder session at the build's rung edits the build root, then\n * volley measures what it changed, its tester's untouched test aside, and,\n * under `--git`, checkpoints it. It opens the iteration, unless the tester\n * already did. */\nexport async function build_phase(\n deps: PhaseDeps,\n builders: BuilderLadder,\n s: LoopState,\n ctx: RunContext,\n): Promise<LoopState> {\n const { config, renderer } = deps;\n const opened = tester_opened(s);\n const next = climb(config, s, opened ? s : next_iteration(s));\n emit(ctx, { volley: 'round_start', round: next.iteration, ...(opened ? { after_test: true as const } : {}) });\n renderer.phase_start(next.iteration, 'builder');\n if (next.rung !== null) renderer.rung(next.iteration, next.rung, next.climbed);\n const built = await run_builder(\n { builder: builders.at(next.rung), config, warn: renderer.warn },\n next,\n previous_round(config, s),\n ctx,\n );\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 root = build_root(config.workspace, config.worktree);\n const changes = measure_changes(deps, root, built.tester_hashes);\n if (config.git_checkpoints) {\n git_checkpoint(\n root,\n `volley iter ${String(built.iteration)}: build`,\n state_root_within(root, config.state_dir),\n );\n }\n return { ...built, changes };\n}\n\n/** `measure`: a critique's one round opens, and the change under review is\n * measured from the baseline, as a run measures the builder's work. */\nexport function measure_phase(deps: PhaseDeps, s: LoopState, ctx: RunContext): LoopState {\n const next = next_iteration(s);\n emit(ctx, { volley: 'round_start', round: next.iteration });\n const root = build_root(deps.config.workspace, deps.config.worktree);\n return { ...next, changes: measure_changes(deps, root) };\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/** Open the check's card on a streamed run: the call's start, then the\n * command as its input, the two chunks `model_call` records for a tool call\n * before it runs. */\nfunction open_check_card(ctx: RunContext, command: string): void {\n record_check_chunk(ctx, { kind: 'tool_call_start', ...CHECK_CALL, step_index: 0 });\n record_check_chunk(ctx, { kind: 'tool_call_end', id: CHECK_CALL.id, input: { command }, step_index: 0 });\n}\n\n/** Close the check's card with its result, which the card's reader renders,\n * or with the error that stopped the check before it had one. */\nfunction close_check_card(ctx: RunContext, outcome: { result: CheckResult } | { error: unknown }): void {\n record_check_chunk(\n ctx,\n 'result' in outcome\n ? { kind: 'tool_result', id: CHECK_CALL.id, output: outcome.result, step_index: 0 }\n : {\n kind: 'tool_result',\n id: CHECK_CALL.id,\n error: {\n message: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n },\n step_index: 0,\n },\n );\n}\n\n/** `check`: the deterministic gate over the tree the builder wrote. A check\n * that runs a command emits its start and end, and on a streamed run also\n * records its card as a tool call, so a reader of the stream shows it running\n * while it runs. When the caller set an approval, the check asks on that card\n * first, and a rejected check closes it failed and is recorded as failed. */\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 const command = check_command(config);\n if (command === null) {\n renderer.info('no deterministic check configured; loop is critic-gated only');\n return { ...s, check: skipped_check('none') };\n }\n emit(ctx, { volley: 'check_start', round: s.iteration, command });\n open_check_card(ctx, command);\n try {\n const allowed = await check_allowed(deps, command, ctx.abort);\n const result = allowed\n ? await execute_check(deps, ctx.abort)\n : rejected_check(config.check_resolved);\n close_check_card(ctx, allowed ? { result } : { error: CHECK_REJECTED });\n emit(ctx, {\n volley: 'check_end',\n round: s.iteration,\n ok: result.ok,\n exit_code: result.exit_code,\n failing_slots: result.failing_slots,\n duration_ms: result.duration_ms,\n });\n renderer.phase_end(\n s.iteration,\n 'check',\n result.ok,\n !allowed\n ? 'rejected'\n : result.failing_slots.length > 0\n ? `failing: ${result.failing_slots.join(', ')}`\n : undefined,\n );\n return {\n ...s,\n check: result,\n check_duration_ms: s.check_duration_ms + result.duration_ms,\n };\n } catch (err) {\n close_check_card(ctx, { error: 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 if (critiqued.verdict !== null) {\n emit(ctx, {\n volley: 'verdict',\n round: critiqued.iteration,\n verdict: critiqued.verdict,\n feedback: critiqued.feedback ?? '',\n unmet_criteria: critiqued.unmet_criteria,\n degraded: critiqued.critic?.critic_degraded === true,\n });\n }\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 const root = build_root(config.workspace, config.worktree);\n git_checkpoint(\n root,\n `volley iter ${String(s.iteration)}: critique (${s.verdict ?? 'skipped'})`,\n state_root_within(root, config.state_dir),\n );\n }\n return s;\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 * With `--tester on`, the run's first iteration opens with the test phase: the\n * tester writes a failing test, then the check must fail on it. A green check\n * there, or a tester that crossed the cost cap, holds the iteration with no\n * build, and the guard ends the run. Every other iteration, and every run with\n * the tester off, passes through `test` and `work` to today's build and verify.\n *\n * A critique (`build_critique_flow`) is one round over a change already made,\n * so it has no builder, no loop, and no guard: `measure`, which opens the\n * round and measures the change from its baseline, then the same `check`,\n * `critique`, and `record` a run's round ends with.\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 * │ ├─ test branch: does the tester open this iteration? (--tester on, the run's first)\n * │ │ ├─ then sequence\n * │ │ │ ├─ write_test open the iteration, run the tester, record what it wrote\n * │ │ │ │ └─ tester model call writing a failing test under the test and fixture gate paths\n * │ │ │ └─ red branch: did the tester alone cross the cost cap?\n * │ │ │ ├─ then skip_red record the check as skipped and build nothing\n * │ │ │ └─ else red_check the check, which must fail on the tester's test\n * │ │ └─ else no_test no tester this iteration\n * │ ├─ work branch: did the test phase end the run: a green check, or the cost cap?\n * │ │ ├─ then hold build nothing, and leave the run to the guard\n * │ │ └─ else sequence\n * │ │ ├─ build open the iteration unless the tester did, 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 critic on any provider but claude_cli keeps dying or runs out of steps\n * │ │ ├─ retry one more try after a stream death, on any provider but claude_cli\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, a gate edit, or a green check before any build\n */\nimport { branch, fallback, loop, pipe, retry, sequence, step } from 'fascicle';\nimport type { Step } from 'fascicle';\nimport { make_builder_ladder } from './builder.js';\nimport type { BuilderDeps } from './builder.js';\nimport type { BashExecutor } from './builder/tools.js';\nimport { cost_cap_hit } from './cost.js';\nimport {\n as_degraded,\n critic_degradable,\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 {\n gate,\n initial_state,\n remaining_iterations,\n tester_opened,\n tester_opens,\n tester_passed_early,\n} from './loop_state.js';\nimport {\n build_phase,\n check_phase,\n critique_phase,\n measure_phase,\n record_phase,\n red_check_phase,\n skip_red_phase,\n skip_verify_phase,\n test_phase,\n} from './phases.js';\nimport type { PhaseDeps } from './phases.js';\nimport { make_tester_step } from './tester/run.js';\nimport type { TesterDeps } from './tester/run.js';\nimport type { LoopState, ResolvedConfig, RunInput } from './types.js';\n\n/** The builder seat: the engine its calls go through, and, when the caller\n * injects them, the tools that replace volley's own set, the name of that set\n * (which its prompt names), and the handler that answers their approval\n * requests. */\nexport type BuilderSeat = Pick<BuilderDeps, 'engine' | 'tools' | 'tool_set' | 'on_tool_approval'>;\n\n/** The critic seat: its engine and, when injected, the tools that replace its\n * reads and the name of their set. It takes no approval handler, since its\n * reads never ask. */\nexport type CriticSeat = Pick<CriticDeps, 'engine' | 'tools' | 'tool_set'>;\n\n/** The tester seat: its engine and, when injected, the tools that replace\n * volley's tester tools, the name of their set, and the handler that answers\n * their approval requests. Absent, it rides the critic's engine, whose\n * provider and URL it takes. */\nexport type TesterSeat = Pick<TesterDeps, 'engine' | 'tools' | 'tool_set' | 'on_tool_approval'>;\n\n/** What the flow is built from: the step bodies' dependencies, plus each\n * seat's model wiring and the builder's `bash` executor. The two seats share\n * one engine unless they reach one provider at different URLs. */\nexport type FlowDeps = PhaseDeps & {\n seats: { builder: BuilderSeat; critic: CriticSeat; tester?: TesterSeat };\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 critic on any provider but\n * `claude_cli` whose tool-bearing stream dies is retried at once (the death is\n * stochastic parser failure, not load, so waiting buys nothing), then judged\n * once without tools. One that runs out of steps skips the retry, since\n * another identical tool loop would only run out again, and goes straight to\n * the tool-less pass. Anything else 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, on any provider but claude_cli',\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 critic on any provider but claude_cli keeps dying or runs out of steps',\n when: critic_degradable(deps.config),\n handoff: (prompt) => toolless_critic_prompt(deps.config, prompt),\n project: with_fallback_cause,\n },\n );\n}\n\n/** The steps a run and a critique share, built one way for both. */\nfunction check_step(deps: PhaseDeps): Step<LoopState, LoopState> {\n return step('check', (s: LoopState, ctx) => check_phase(deps, s, ctx), {\n description: 'the deterministic gate: checkride, a command, or none',\n });\n}\n\nfunction critique_step(deps: PhaseDeps, seat: CriticSeat): Step<LoopState, LoopState> {\n const critic = build_critic({ ...seat, config: deps.config, on_chunk: deps.renderer.critic_chunk });\n return step('critique', (s: LoopState, ctx) => critique_phase(deps, critic, s, ctx), {\n description: \"the read-only critic's verdict and feedback\",\n arm: critic,\n });\n}\n\nfunction record_step(deps: PhaseDeps): Step<LoopState, LoopState> {\n return step('record', (s: LoopState) => record_phase(deps, s), {\n description: 'archive the iteration and rewrite the run summary',\n });\n}\n\n/** The test phase (move 1's D6, D17, D21): with the tester on, the run's\n * first iteration opens with the tester writing a failing test, then the\n * check, which must fail on it, unless the tester alone crossed the cost cap.\n * Every other iteration passes straight through. */\nfunction test_step(deps: FlowDeps): Step<LoopState, LoopState> {\n const { config } = deps;\n const tester = make_tester_step({\n ...(deps.seats.tester ?? { engine: deps.seats.critic.engine }),\n config,\n on_chunk: deps.renderer.tester_chunk,\n });\n const write_test = step('write_test', (s: LoopState, ctx) => test_phase(deps, tester, s, ctx), {\n description: 'open the iteration, run the tester, record what it wrote',\n arm: tester,\n });\n const red: Step<LoopState, LoopState> = branch({\n name: 'red',\n description: 'did the tester alone cross the cost cap?',\n when: (s: LoopState) => cost_cap_hit(config, s),\n // oxlint-disable-next-line unicorn/no-thenable\n then: step('skip_red', (s: LoopState) => skip_red_phase(deps, s), {\n description: 'record the check as skipped and build nothing',\n }),\n otherwise: step('red_check', (s: LoopState, ctx) => red_check_phase(deps, s, ctx), {\n description: \"the check, which must fail on the tester's test\",\n }),\n });\n return branch({\n name: 'test',\n description: \"does the tester open this iteration? (--tester on, the run's first)\",\n when: (s: LoopState) => tester_opens(config, s),\n // oxlint-disable-next-line unicorn/no-thenable\n then: sequence([write_test, red]),\n otherwise: step('no_test', (s: LoopState) => s, { description: 'no tester this iteration' }),\n });\n}\n\n/** Whether the test phase ended the run before its build: the check passed on\n * the tester's test, or the tester crossed the cost cap. */\nfunction test_ended_run(config: ResolvedConfig, s: LoopState): boolean {\n return tester_opened(s) && (tester_passed_early(s) || cost_cap_hit(config, s));\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 builders = make_builder_ladder({\n ...deps.seats.builder,\n config,\n on_chunk: renderer.builder_chunk,\n bash_executor: deps.bash_executor,\n });\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. The\n // build picks its leaf by the build's rung; the arm is the first build's.\n const build = step('build', (s: LoopState, ctx) => build_phase(deps, builders, s, ctx), {\n description: 'open the iteration unless the tester did, run the builder, measure the change',\n arm: builders.arm,\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 = check_step(deps);\n const critique = critique_step(deps, deps.seats.critic);\n const record = record_step(deps);\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 work: Step<LoopState, LoopState> = branch({\n name: 'work',\n description: 'did the test phase end the run: a green check, or the cost cap?',\n when: (s: LoopState) => test_ended_run(config, s),\n // oxlint-disable-next-line unicorn/no-thenable\n then: step('hold', (s: LoopState) => s, {\n description: 'build nothing, and leave the run to the guard',\n }),\n otherwise: sequence([build, verify]),\n });\n\n const iteration: Step<LoopState, LoopState> = sequence([test_step(deps), work, 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, a gate edit, or a green check before any build\",\n }),\n finish: (s, { converged }) => ({ value: s, converged }),\n max_rounds: remaining_iterations(config, resume_from),\n });\n}\n\n/** What a critique's flow is built from: the step bodies' dependencies and the\n * critic seat. There's no builder seat, so no builder is ever constructed. */\nexport type CritiqueFlowDeps = PhaseDeps & { critic: CriticSeat };\n\n/** A critique: one round over a change already made. `measure` opens it and\n * measures the change from the baseline, then the check, the critic, and the\n * record, as in a run's round. No loop and no guard: there is nothing to\n * iterate on, and the caller reads the outcome off the final state. */\nexport function build_critique_flow(deps: CritiqueFlowDeps): Step<LoopState, LoopState> {\n const measure = step('measure', (s: LoopState, ctx) => measure_phase(deps, s, ctx), {\n description: 'open the round and measure the change under review',\n });\n return sequence([measure, check_step(deps), critique_step(deps, deps.critic), record_step(deps)], {\n name: 'critique_run',\n });\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 run's state (or preserve it, on resume)\n * ├─ with_worktree off unless --worktree\n * │ ├─ capture the change baseline\n * │ ├─ run_loop run the flow (streamed when a sink is given), 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 *\n * run_critique\n * ├─ resolve the baseline --baseline, else HEAD; a bad revision exits 5\n * ├─ initialize the run's state\n * └─ run the critique flow one round on the critic's engine alone, then the final summary\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { run } from 'fascicle';\nimport { filesystem_logger, tee_logger } from 'fascicle/adapters';\nimport type { Engine, RunOptions, Step, TrajectoryLogger } from 'fascicle';\nimport type { BashExecutor } from './builder/tools.js';\nimport { capture_baseline, resolve_baseline } from './changes.js';\nimport { detect_containment } from './containment.js';\nimport { create_seat_engines, create_volley_engine, dispose_seat_engines } from './engine.js';\nimport type { SeatEngines } from './engine.js';\nimport { build_critique_flow, build_flow } from './flow.js';\nimport type { BuilderSeat, CriticSeat, TesterSeat } from './flow.js';\nimport type { CheckGate } from './phases.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 { trust_key_path } from './trust.js';\nimport type { Renderer } from './render/renderer.js';\nimport { config_error, error_kind } from './types.js';\nimport type { LoopState, ResolvedConfig, RunResult, RunStatus } from './types.js';\nimport {\n initialize_run_state,\n integrate_worktree,\n run_state_dir,\n state_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 /** An engine to run both seats on in place of the ones built from the\n * config. It serves both seats as-is, so the seat URLs then steer only\n * volley's own requests (prewarm and the context probe), not model calls. */\n engine?: Engine;\n /** What to hand each seat in place of volley's own wiring: the builder's\n * tools and the handler that answers their approval requests, and the\n * critic's tools. A seat or a field left out keeps today's wiring, and a\n * `claude_cli` seat, which brings its own tools, takes none of it. */\n seats?: {\n builder?: Omit<BuilderSeat, 'engine'>;\n critic?: Omit<CriticSeat, 'engine'>;\n /** The tester's, which rides the critic's engine. */\n tester?: Omit<TesterSeat, 'engine'>;\n };\n /** A second sink for the run's trajectory, beside the run's\n * `trajectory.jsonl`. With one, the flow runs through `run.stream`, so the\n * sink also receives each model call's streamed chunks as `model_chunk`\n * events, which the file never keeps. */\n trajectory?: TrajectoryLogger;\n /** The environment the check runs with and the approval it asks first, in\n * place of inheriting volley's environment and running unasked. */\n check?: CheckGate;\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_run_state(config);\n // Unsigned on the host only when the machine's key can't be read or made.\n if (!write_resolved_config(config) && !detect_containment(process.env)) {\n renderer.warn(\n `could not sign this run's config with this machine's key (${trust_key_path(process.env)}), ` +\n 'so resuming it here will need --trust-config',\n );\n }\n } else {\n initialize_run_state(config, { preserve: true });\n }\n renderer.info(`state: ${run_state_dir(config)}`);\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: the run's `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. The run's state stays where `state_dir` puts it either\n // way. The seats share one engine unless they reach one provider at\n // different URLs.\n const engines: SeatEngines =\n deps.engine === undefined\n ? await create_seat_engines({\n workspace: build_root(config.workspace, config.worktree),\n builder_provider: config.builder_provider,\n builder_url: config.builder_url,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\n })\n : { builder: deps.engine, critic: deps.engine };\n\n const seats = {\n builder: { ...deps.seats?.builder, engine: engines.builder },\n critic: { ...deps.seats?.critic, engine: engines.critic },\n tester: { ...deps.seats?.tester, engine: engines.critic },\n };\n const flow = build_flow(\n {\n seats,\n config,\n renderer,\n bash_executor,\n baseline,\n ...(deps.check !== undefined ? { check: deps.check } : {}),\n },\n resume_from,\n );\n\n try {\n const { value, converged } = await execute_flow(config, deps, flow, { resume_from });\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 dispose_seat_engines(engines);\n }\n}\n\n/** Run the flow into its file trajectory and, when the caller passed one, its\n * own sink. Without a sink this is the one `run` it has always been. With one,\n * it goes through `run.stream`, because only a streamed run records each model\n * call's chunks as `model_chunk` events, which are what an outer consumer maps\n * to text, tool cards, and approval prompts. The sink is that consumer, so the\n * handle's own event stream is closed at once rather than left to buffer, and\n * the file skips the chunks, so it holds the same kinds of event either way.\n *\n * The file goes first in the tee because the first sink's span ids are the\n * ones the run hands out as parents, so the file's parent links stay whole.\n * The sink sees parent ids it never issued, which costs an ACP consumer\n * nothing: it counts a step's runs by the `id` on each `span_start`. */\nfunction execute_flow<I, O>(\n config: ResolvedConfig,\n deps: Pick<OrchestratorDeps, 'trajectory' | 'abort' | 'install_signal_handlers'>,\n flow: Step<I, O>,\n input: I,\n): Promise<O> {\n const file = filesystem_logger({\n output_path: state_path(config, 'trajectory.jsonl'),\n });\n const options: RunOptions = {\n ...(deps.abort !== undefined ? { abort: deps.abort } : {}),\n ...(deps.install_signal_handlers !== undefined\n ? { install_signal_handlers: deps.install_signal_handlers }\n : {}),\n };\n if (deps.trajectory === undefined) return run(flow, input, { ...options, trajectory: file });\n const handle = run.stream(flow, input, {\n ...options,\n trajectory: tee_logger(without_model_chunks(file), deps.trajectory),\n });\n void handle.events[Symbol.asyncIterator]().return?.();\n return handle.result;\n}\n\n/** A logger that passes `inner` every event but a model call's streamed\n * chunks. */\nfunction without_model_chunks(inner: TrajectoryLogger): TrajectoryLogger {\n return {\n ...inner,\n record: (event) => {\n if (event.kind !== 'model_chunk') inner.record(event);\n },\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 = state_path(config, '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 // A summary an older volley wrote, resumed here, has no run_state_dir\n // and no step-limit count.\n write_run_summary(config, {\n ...prior,\n builder_max_steps_hits: (prior.builder_max_steps_hits as number | undefined) ?? 0,\n run_state_dir: run_state_dir(config),\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/** What a critique runs with: what a run does, less the builder's seat, plus\n * the revision its change is measured from. */\nexport type CritiqueDeps = Omit<OrchestratorDeps, 'seats'> & {\n /** The revision the change under review is measured from (`--baseline`):\n * everything that differs from it, committed or not, untracked files\n * included. HEAD when absent, so the uncommitted edits are the change. */\n baseline?: string;\n /** The critic's tools in place of volley's reads, as for a run's critic. */\n critic?: Omit<CriticSeat, 'engine'>;\n};\n\n/**\n * `volley critique`: the check and the critic, once, over a change already\n * made. No builder is constructed, and the engine serves the critic's seat\n * alone, so a critic can be measured on fixed, labeled changes without paying\n * for builder turns. It writes the state a one-round run does, with the mode\n * recorded, and ends `success` on approval over a green check, else\n * `rejected`.\n */\nexport async function run_critique(config: ResolvedConfig, deps: CritiqueDeps): Promise<RunResult> {\n if (config.mode !== 'critique') {\n throw config_error(\"run_critique needs a config resolved with mode 'critique'\");\n }\n const { renderer } = deps;\n // First, so a revision that isn't a commit fails before any state is written.\n const baseline = resolve_baseline(config.workspace, deps.baseline);\n initialize_run_state(config);\n write_resolved_config(config);\n renderer.info(`state: ${run_state_dir(config)}`);\n renderer.info(\n baseline === null\n ? 'baseline: none (not a git repository, or no commit yet); the critic reviews the tree'\n : `baseline: ${baseline}`,\n );\n\n const engine =\n deps.engine ??\n create_volley_engine({\n workspace: config.workspace,\n critic_provider: config.critic_provider,\n critic_url: config.critic_url,\n });\n const flow = build_critique_flow({\n config,\n renderer,\n baseline,\n critic: { ...deps.critic, engine },\n ...(deps.check !== undefined ? { check: deps.check } : {}),\n });\n try {\n const value = await execute_flow(config, deps, flow, initial_state());\n const passed = value.check?.ok === true && value.verdict === 'approved';\n const result = run_result_from_state(\n config,\n value,\n passed ? 'success' : 'rejected',\n new Date().toISOString(),\n );\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 * 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 { ClimbReason, EffortRung, 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_rung,\n format_usd,\n paint,\n summarize_value,\n truncate,\n} from './format.js';\nimport type { Role } from './format.js';\n\n/** `protocol` is `volley run --protocol runciter.run/1`: the quiet mode's\n * human lines, with runciter's typed lines (`runciter.progress` for each\n * phase, `runciter.usage` for each iteration) in place of the phase and cost\n * lines. */\nexport type RenderMode = 'default' | 'verbose' | 'quiet' | 'json' | 'protocol';\n\nexport type RendererOptions = {\n mode: RenderMode;\n show_thinking: boolean;\n color: boolean;\n max_cost_usd: number | null;\n /** The run's iteration cap, the `total` of each `runciter.progress` line in\n * protocol mode. */\n max_iterations?: number;\n /** Where the run's trajectory is written, named when verbose output is cut\n * short (default: \"the run's trajectory.jsonl\"). */\n trajectory_path?: string;\n write?: (text: string) => void;\n};\n\nexport type Renderer = {\n builder_chunk: (chunk: StreamChunk) => void;\n critic_chunk: (chunk: StreamChunk) => void;\n tester_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 /** The effort this iteration's build runs at, one line per build when a\n * ladder is set. */\n rung: (iteration: number, rung: EffortRung, climbed: ClimbReason | null) => 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 see_trajectory = `see ${options.trajectory_path ?? \"the run's trajectory.jsonl\"}`;\n const silent = mode === 'json';\n const streaming = mode === 'default' || mode === 'verbose';\n const protocol = mode === 'protocol';\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 // In protocol mode, the iteration the phases are in and the run's spend so\n // far, for the `runciter.usage` line each iteration ends on.\n let current_iteration = 0;\n let run_spend = 0;\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 /** One of runciter's typed stderr lines (its spec §5.4), which it reads into\n * the run's live state. */\n const typed = (value: Record<string, unknown>): void => {\n line(JSON.stringify(value));\n };\n\n const progress = (n: number, message: string): void => {\n typed({\n type: 'runciter.progress',\n message: `iteration ${String(n)}: ${message}`,\n done: n - 1,\n ...(options.max_iterations !== undefined ? { total: options.max_iterations } : {}),\n });\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_trajectory,\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_trajectory)}`);\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 tester_chunk: chunk_renderer('tester'),\n phase_start: (n, phase) => {\n if (mode === 'json') return;\n if (protocol) {\n // A phase of the next iteration: the last one has ended, with its spend.\n if (n > current_iteration && current_iteration > 0) {\n typed({ type: 'runciter.usage', cost_usd: run_spend });\n }\n current_iteration = Math.max(current_iteration, n);\n progress(n, phase);\n return;\n }\n line(paint(phase, `${GLYPH_PHASE_START} [iter ${String(n)}] ${phase}`, color));\n },\n phase_end: (n, phase, ok, detail) => {\n if (mode === 'json') return;\n if (protocol) {\n progress(n, `${phase} ${detail ?? (ok ? 'done' : 'failed')}`);\n return;\n }\n const glyph = ok ? GLYPH_PHASE_OK : GLYPH_PHASE_FAIL;\n const suffix = detail !== undefined ? ` — ${detail}` : '';\n line(paint(phase, `${glyph} [iter ${String(n)}] ${phase}${suffix}`, color));\n },\n rung: (iteration, rung, climbed) => {\n line(paint('builder', ` [iter ${String(iteration)}] ${format_rung(rung, climbed)}`, color));\n },\n cost_line: (iteration, phase, phase_cost, run_total) => {\n if (mode === 'json') return;\n if (protocol) {\n run_spend = run_total;\n return;\n }\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 if (protocol) {\n // The last iteration's end, with the run's tokens beside its spend.\n typed({\n type: 'runciter.usage',\n cost_usd: result.total_cost_usd,\n input_tokens: result.total_usage.input_tokens,\n output_tokens: result.total_usage.output_tokens,\n });\n }\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 `${result.tester_cost_usd > 0 ? `, tester ${format_usd(result.tester_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 line(`state: ${result.run_state_dir}`);\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 a parent harness 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 { join, resolve } from 'node:path';\nimport { config_error } from './types.js';\nimport { default_state_root, RUN_ID_PATTERN } from './workspace.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/** Where volley inside the container keeps each run's state when no\n * `--state-dir` names a root: the default root under the pinned `HOME`, since\n * the image sets no `XDG_STATE_HOME`. `sandbox_run_args`'s `run_state` binds one\n * run's host directory at that run's directory under it, so the state outlives\n * the `--rm` container. Exported so a harness can map a contained run's\n * `run_state_dir` back to the directory it mounted. */\nexport const SANDBOX_STATE_ROOT = default_state_root({}, SANDBOX_HOME);\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 * `seat_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 and a parent harness 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 * `run_state` binds the run's own state directory on the host,\n * `<root>/<run_id>/`, at `<SANDBOX_STATE_ROOT>/<run_id>/`, where volley inside\n * keeps that run's state when no `--state-dir` names a root, so it outlives the\n * container at the path a run on the host would use. Only the one directory\n * is mounted, never the root: the builder inside runs arbitrary commands, so\n * it can rewrite its own run's state but can't read another run's trajectory\n * or plant a check in another run's config. Its own run's state is still the\n * builder's to rewrite, config.json included, so a host-side resume refuses\n * that config, which volley signs only outside the sandbox (`./trust.ts`), and\n * a directory holding a symlink: resume a contained run inside the container,\n * with the same mount. Create the\n * directory on the host first, empty (Docker on Linux makes a missing bind\n * source owned by root, which the container's user can't write), and pass the\n * same id to volley as `--run-id`. Keep it outside `build_root`, so the check\n * never reads it, and pass no `XDG_STATE_HOME` in `env`, which would move the\n * root off the mount. Omit it and no state is mounted: a contained run keeping\n * its state under the default root then stops before spending (exit 5),\n * since the read-only root filesystem leaves it nowhere to write.\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 * and, when one is named, the state root are the host-visible write paths.\n */\nexport function sandbox_run_args(options: {\n image: string;\n build_root: string;\n uid: number | null;\n gid: number | null;\n run_state?: { root: string; run_id: string } | 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 state =\n options.run_state !== undefined && options.run_state !== null\n ? ['-v', run_state_mount(options.run_state)]\n : [];\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 state root and the\n // persistent pnpm store.\n '-v',\n `${resolve(options.build_root)}:${SANDBOX_WORKDIR}`,\n ...state,\n ...store,\n '-w',\n SANDBOX_WORKDIR,\n ...entrypoint,\n options.image,\n ...(options.command ?? []),\n ];\n}\n\n/** The `-v` value for one run's state directory. The run id becomes a path on\n * both sides, so it is held to volley's own `--run-id` rule, which keeps it to\n * one directory name. */\nfunction run_state_mount(run_state: { root: string; run_id: string }): string {\n if (!RUN_ID_PATTERN.test(run_state.run_id)) {\n throw config_error(\n `run_state.run_id must be letters, digits, '-', and '_', starting with a letter or digit; got: ${run_state.run_id}`,\n );\n }\n return `${join(resolve(run_state.root), run_state.run_id)}:${SANDBOX_STATE_ROOT}/${run_state.run_id}`;\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, the run's\n * own host state directory mounted where volley inside keeps it, 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 /** The run's host state directory, `<root>/<run_id>/` (`run_state` on\n * `sandbox_run_args`), usually under the host's `default_state_root`;\n * `command` must pass the same `--run-id`. */\n run_state: { root: string; run_id: 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 run_state: options.run_state,\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 * Minimal POSIX quoting: single-quote any token with whitespace or\n * 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\n/** `volley run --protocol runciter.run/1` exits by the protocol's table, not\n * the one above (move 1's D11): 0 with one `RunOutput` on stdout, whatever the\n * run's outcome, a builder, check or critic error included (D28); 1 when\n * volley failed with no `RunOutput` to write; 2 for bad input or a config\n * error, which runciter records as a contract violation. */\nexport const PROTOCOL_EXIT_OUTPUT = 0;\nexport const PROTOCOL_EXIT_RUNNER_ERROR = 1;\nexport const PROTOCOL_EXIT_CONTRACT_VIOLATION = 2;\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 // A critique that didn't pass exits as a run that didn't converge does.\n case 'rejected':\n // The check passed before any build: nothing converged, and nothing was\n // built to (move 1's D17).\n case 'tester_passed_early':\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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"}