# User's guide This guide is for people who want to run Dakar's Open Dynamic Workflow (ODW) code-review workflow on a branch. It explains the supported command, what the workflow reviews, where review history is stored, and how to interpret the result. ## Installing the CLI Agents can install Dakar's review command from a checkout with Bun: ```bash ./install.sh ``` The installer calls Bun with the absolute checkout path and exposes `dakar-review`. The package remains private; the command is meant for local or git-based installation, not npm publication. `install.sh` accepts no install arguments; run `./install.sh --help` for its short usage text. On each repeated installer run, `install.sh` first executes `bun remove -g dakar` before reinstalling, preventing an interrupted installation from leaving duplicate `dakar` entries while keeping the shared Bun lockfile and other global packages intact. For direct Bun invocation, use an absolute path or `file:` URL: ```bash bun install -g "$PWD" bun install -g "file:$PWD" ``` Do not use `bun install -g .` for this local install path. In Bun 1.3.11, bare `.` is parsed as an empty package spec before Dakar's `package.json` is read, so Bun installs `@` and creates no `dakar-review` bin link. ## Running a branch review Dakar reviews only commits that have not already been recorded for the current branch. From the repository root, the preferred command is: ```bash dakar-review --repo-root "$PWD" --base origin/main ``` The CLI runs the installed Dakar workflow and passes the reviewed checkout as `repoRoot`, which is required because ODW normally gives agents copied workspaces without `.git`. Before invoking ODW, the CLI resolves configuration and prepares the review range itself, host-side, with no model calls: it calls `scripts/review-state.mjs prepare` in-process and passes the result as the workflow's `prepared` argument. If nothing is unreviewed, the CLI prints the skip result and exits without invoking ODW at all. The equivalent direct ODW invocation therefore also needs a `prepared` object built the same way; it is shown here for illustration only, and `dakar-review` is the supported path: ```bash odw run workflows/dakar-review.js --source . --wait --timeout 3600 \ --args '{"config":"examples/df12-code-review.yaml","base":"origin/main", "repoRoot":"/path/to/dakar","prepared":{"...":"see prepare output"}}' ``` `workflows/dakar-review.js` is a pre-generated runtime artefact included with Dakar. Running the CLI or invoking that file directly does not require TypeScript, esbuild, or a contributor build step. Set `OPENAI_API_KEY` before running a live review. The default `deterministic-flex-v1` route dispatches finder and audit calls through the `pi` coding agent (`@earendil-works/pi-coding-agent`) with Dakar's own `adapters/pi/` extension and provider catalogue; `pi` must be installed and on `PATH`. The CLI sets `PI_CODING_AGENT_DIR` to point `pi` at that catalogue and warns on stderr, without failing, if `OPENAI_API_KEY` is unset. ADR 002's staged-cutover guideline for this default was superseded by a recorded operator decision (see roadmap task 7.5.3). The `config` argument points at the CodeRabbit YAML file whose review tone, path instructions, and pre-merge checks should guide the review. The `base` argument is the branch or ref used to compute the merge base when there is no previous review history. The `repoRoot` argument points at the real git checkout being reviewed. ## Command-line options `dakar-review` accepts the following options: - `--repo-root ` selects the Git checkout to review. The default is the current working directory. - `--config ` selects a CodeRabbit YAML file relative to the repository root. - `--base ` selects the base ref for the first review. The default is `origin/main`. - `--head ` selects the head ref to review. The default is `HEAD`. - `--state-root ` overrides the review-history root. - `--max-tasks ` caps the planned review tasks. Under the `deterministic-flex-v1` route it composes with `--max-luna-calls`: the effective finder-pack cap is the smaller of the two, so `--max-tasks 1 --max-luna-calls 4` dispatches at most one finder pack. See the review-tuning flags below. - `--max-candidates ` and `--max-findings ` override the workflow limits described below. - `--synthesis-model ` and `--synthesis-reasoning ` are accepted for backward compatibility and still appear in the dry-run contract's `synthesisModel`/`synthesisAdapter` fields, but under the `deterministic-flex-v1` route the audit call always runs on the fixed Terra Flex lane (`gpt-5.6-terra`, medium reasoning); these flags no longer change which model or adapter performs the audit. - `--timeout ` sets the ODW wait timeout. The default is `3600`. Operators overriding this should keep it above the review's `worstCaseReviewSeconds` (2,020 s at default limits; see the dry-run example below), the worst-case wall clock the retry schedule can take. - `--runs-root ` selects the ODW runs directory used for the run, logs, and result. - `--format ` selects the output format. The default is `json`. - `--odw-bin ` selects the ODW executable. The default is `odw`. - `--telemetry` streams ODW logs to standard error while preserving the final result on standard output. - `--dry-run` returns the workflow contract without launching review agents. - `--help` prints command usage, and `--version` prints the Dakar version. The following review-tuning flags forward directly to the workflow arguments. The CLI only parses and forwards them; the workflow enforces every bound, so values outside the documented range clamp to the nearest permitted value rather than fail. See "Cost, budget, and the ledger" and "Retries, downgrades, and deferral" below for what each knob controls. - `--budget-gbp ` sets the hard admission budget in GBP. The default is `0.1`. - `--max-luna-calls ` caps the Luna Flex finder calls. The default is `4`. It composes with `--max-tasks`: the effective finder-pack cap is the smaller of the two. - `--transaction-max-files ` sets the maximum files per finder pack. The default is `5`. - `--transaction-max-input-tokens ` and `--transaction-max-output-tokens ` set the per-finder token estimates used for admission. The defaults are `12000` and `750`. - `--terra-max-input-tokens ` and `--terra-max-output-tokens ` set the audit-call token estimates. The defaults are `48000` and `2500`. - `--adapter-overhead-tokens ` sets the per-call adapter overhead added to every admission estimate. The default is `13000`; raising it towards `28000` better models the cache pi's agentic loop writes on first, uncached calls. - `--max-audit-candidates ` caps the candidates forwarded to the audit. The default is `30`. - `--luna-reasoning ` selects the Luna finder reasoning effort. The default is `low`. - `--routing-policy ` selects the routing policy. The default and sole live value is `deterministic-flex-v1`. - `--flex-attempts ` sets the Flex retry attempts per call. The default is `3`. - `--per-call-timeout ` sets the per-model-call timeout. The default is `300`. When `--config` is omitted, Dakar resolves review configuration in this order: 1. Repository-local `.coderabbit.yaml`. 2. Repository-local `.coderabbit.yml`. 3. Repository-local `coderabbit.yaml`. 4. Repository-local `coderabbit.yml`. 5. User-level `$XDG_CONFIG_HOME/dakar/config.yaml`, or `~/.config/dakar/config.yaml` when `XDG_CONFIG_HOME` is unset. 6. Dakar's bundled example config. The user-level config is treated as the current repository's CodeRabbit config only when no repository-local CodeRabbit YAML exists. It is useful for agents that should apply one house review policy across repositories without copying a `.coderabbit.yaml` into every checkout. ### How much of the CodeRabbit format is honoured Dakar uses the resolved file at two boundaries. Host code deterministically discovers the path, safely parses the YAML without constructing custom tags, and validates Dakar's supported policy subset before preparation or any ODW, Luna, or Terra dispatch. The normalized serializable policy is then passed to the workflow. Models never parse the YAML file. The host rejects a missing explicit `--config` path, malformed YAML, and an invalid shape or value for any supported field. Diagnostics identify both the resolved configuration path and the invalid field. Unsupported keys are reported in the result's `ignoredPolicyKeys` list and have no routing, gating, budget, retry, or recording effect. | Support level | What it covers | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Host-enforced | Path discovery and precedence; safe YAML parsing; supported-field validation; fail-closed handling of missing explicit paths and malformed policy; deterministic changed-path matching for `reviews.path_instructions`; per-finder-pack instruction slicing; and `pre_merge_checks.custom_checks[].command` execution. An omitted mode or `mode: error` blocks on failure; `mode: warning` is non-blocking. Review limits, budget, and ranges remain Dakar CLI and workflow arguments rather than CodeRabbit keys. | | Model-mediated | `language`, `tone_instructions`, `reviews.profile`, path-instruction prose selected by the host for the current evidence pack, and custom-check `instructions`. These fields guide judgement and phrasing; their semantic interpretation remains model-mediated. | | Ignored | Unsupported keys including `early_access`; `chat.integrations`; `knowledge_base`; `issue_enrichment`; `code_generation`; pull-request surface options such as `auto_title_instructions`, `high_level_summary_*`, walkthrough and labelling options, `request_changes_workflow`, `abort_on_close`, `auto_review`, and `estimate_code_review_effort`; and `tools` integrations such as github-checks, languagetool, clippy, and presidio. They are reported as ignored and do not affect deterministic execution. | _Table: CodeRabbit configuration support levels in the current route._ Executable custom checks use this validated subset: ```yaml pre_merge_checks: custom_checks: - name: Test mode: error command: make test - name: Advisory analysis mode: warning command: make advisory ``` Commands run in configuration order from the reviewed repository after range preparation and before ODW starts. A failed `mode: error` check returns `stage: "deterministic-gates"` with redacted evidence and launches no Luna or Terra calls; a failed non-error check is retained in SARIF and semantic review continues. Commands must not embed credentials. Output is bounded, common credential forms and sensitive environment values are redacted, and full streams are represented by SHA-256 digests. For repository-local configuration, executable commands are loaded from the prepared trusted base commit, not the head under review. A pull request cannot grant itself host command execution by adding or changing a custom check. User-level and bundled configurations are outside the reviewed repository and are read from their resolved operator-controlled paths. Each `reviews.path_instructions` entry requires non-empty string `path` and `instructions` fields. Dakar matches the glob against normalized changed paths and includes an instruction only in finder packs containing a matching path. General language, tone, profile, and natural-language custom-check guidance is included without exposing executable commands or ignored keys. A root `AGENTS.md` is loaded through its own dedicated path (described below), independently of unsupported `knowledge_base.code_guidelines` patterns. ODW normally runs agents in copied workspaces. Those copies may not contain the repository's `.git` directory, so live review runs should pass `repoRoot` as an absolute path. Finder and verifier prompts use `git -C ` for diff evidence, and the prepare step passes the same path to the state helper. If the reviewed repository has a root `AGENTS.md`, `dakar-review` passes it to the workflow as repository-local review context. Workflow schema rules, machine-readable output requirements, and Dakar safety rules still take precedence over repository instructions. For a syntax and contract check that does not call review agents, run either: ```bash dakar-review --dry-run --repo-root "$PWD" npm run odw:dry-run ``` Dry-run output includes the workflow version, default finder model set, synthesis model and adapter, task kinds, limits, default task graph, and JSON Schemas used for candidate, verifier, and synthesis handoffs. By default, `dakar-review` stays quiet until the workflow finishes so standard output is easy to parse. To watch ODW progress while keeping the final result machine-readable, pass `--telemetry`: ```bash dakar-review --repo-root "$PWD" --base origin/main --telemetry ``` Telemetry follows `odw logs --follow` and writes the live ODW event stream to standard error. The final JSON or Markdown result still goes to standard output, so callers can redirect the channels independently: ```bash dakar-review --repo-root "$PWD" --telemetry > review.json ``` ## Review history Review history is stored outside the repository under the XDG state directory: ```plaintext $XDG_STATE_HOME/dakar////reviews.toml ``` When `XDG_STATE_HOME` is unset, Dakar uses: ```plaintext ~/.local/state/dakar////reviews.toml ``` The CLI records the reviewed head commit in-process, after the workflow returns a completed result, stamping `recorded.recordedBy: "dakar-review"`. A later run on the same branch reviews only commits after the last recorded head. If the current `HEAD` has already been recorded, the CLI's host-side prepare step detects this before invoking ODW at all: it prints the skip result (`skipped: true`) directly and never launches a model call. To isolate a trial run from normal review history, pass `stateRoot`: ```bash dakar-review \ --repo-root "$PWD" \ --base origin/main \ --state-root /tmp/dakar-review-state ``` The equivalent direct ODW invocation, once a matching `prepared` object has been produced by `scripts/review-state.mjs prepare`, is: ```bash odw run workflows/dakar-review.js --source . --wait --timeout 3600 \ --args '{"config":"examples/df12-code-review.yaml","base":"origin/main", "repoRoot":"/path/to/dakar","stateRoot":"/tmp/dakar-review-state", "prepared":{"...":"see prepare output"}}' ``` ## What the workflow returns In the default JSON output mode, a successful live run prints one JSON object on standard output (the `--format markdown` case is described below). Important fields are: - `ok`: whether the workflow itself completed. - `workflowVersion`: the machine-readable workflow contract version. - `verdict`: `changes-requested` when at least one finding was accepted, otherwise `pass`. - `config`: the CodeRabbit-compatible config file used for the run. - `reviewBase`, `headCommit`, and `commitCount`: the reviewed commit range. - `changedFiles`: files covered by the review. - `sarif`: the canonical SARIF 2.1.0 evidence document. Semantic candidates, Terra dispositions, deterministic gates, provenance, lane/tier data, and estimated/reported usage metadata live under namespaced `properties.dakar`. - `reportMarkdown`: the human-readable review report. - `findings`: compatibility projection of accepted SARIF results. - `discarded`: compatibility projection of suppressed/rejected SARIF results. - `taskGraph`, `taskResults`, `candidates`, and `verdicts`: audit data from the finder fan-out and the audit call. - `admissionRefusals`: finder packs the budget controller refused before dispatch, each with a reason and its estimated worst-case cost. - `lunaDowngrades`: finder packs whose Flex retries were exhausted; the review continues with the surviving candidates rather than failing. - `metrics`: counts for tasks, candidates, accepted and discarded findings, model assignments, the cost ledger, and audit-routing tallies (see "Cost, budget, and the ledger" below). - `recordInput`: the deterministic data the CLI records to review history; present only until the CLI has appended it. - `recordWithheld`: the reason and coverage counts when truncated, refused, or downgraded finder coverage makes a successful review ineligible for recording; `recordInput` is absent in this case. - `recorded`: stamped by the CLI, not the workflow, after a successful append: `{ ok, stateFile, headCommit, recordedBy: "dakar-review" }`. `sarif` is the authoritative automation contract. The `findings`, `discarded`, and `reportMarkdown` fields remain for existing CLI consumers, but are derived from that document and must not evolve independently. Raw `candidates`, `verdicts`, and task data remain compatibility/debug evidence. If the branch has already been reviewed, the CLI's host-side prepare step prints the skip result without invoking ODW: ```json { "ok": true, "skipped": true, "reason": "No unreviewed commits remain for this branch.", "config": ".../config.yaml", "stateFile": ".../reviews.toml", "headCommit": "..." } ``` Dry-run output is also JSON, but it describes the contract instead of a review: ```json { "ok": true, "dryRun": true, "workflowVersion": "divide-and-conquer-v1", "config": ".../df12-code-review.yaml", "repoRoot": "/path/to/repo", "models": [ "gpt-5.5/low", "gpt-5.5/medium", "gpt-5.5/high", "gpt-5.4-mini/medium", "gpt-5.3-codex-spark/medium" ], "synthesisModel": "gpt-5.5/high", "synthesisAdapter": "codex-high", "routingPolicy": "deterministic-flex-v1", "taskKinds": ["docs", "config", "tests", "source", "review-summary"], "limits": { "maxTasks": 8, "maxCandidates": 30, "maxFindings": 20, "maxAuditCandidates": 30 }, "lanes": { "luna": { "role": "luna", "model": "gpt-5.6-luna", "adapter": "pi-luna-flex", "serviceTier": "flex", "reasoning": "low" }, "luna-medium": { "role": "luna-medium", "model": "gpt-5.6-luna", "adapter": "pi-luna-flex-medium", "serviceTier": "flex", "reasoning": "medium" }, "terra": { "role": "terra", "model": "gpt-5.6-terra", "adapter": "pi-terra-flex", "serviceTier": "flex", "reasoning": "medium" } }, "budgetGbp": 0.1, "budgetUsd": 0.127, "pricingTableVersion": "2026-07-18", "reservedAuditUsd": 0.1140625, "reservedAuditChainUsd": 0.3421875, "flexLimits": { "maxLunaFlexCalls": 4, "transactionMaxFiles": 5, "transactionMaxInputTokens": 12000, "transactionMaxOutputTokens": 750, "terraMaxInputTokens": 48000, "terraMaxOutputTokens": 2500, "adapterOverheadTokens": 13000 }, "flexRetry": { "flexAttempts": 3, "flexInitialBackoffSeconds": 30, "flexMaxBackoffSeconds": 120, "flexJitterSeconds": 10, "perCallTimeoutSeconds": 300 }, "worstCaseReviewSeconds": 2020, "defaultTaskGraph": [ { "taskId": "source-1", "kind": "source", "assignedModel": "gpt-5.5/high", "adapter": "codex-high", "model": "gpt-5.5", "role": "high", "maxFindings": 6, "verificationPolicy": "verify-all" } ], "candidateSchema": { "type": "object" }, "verdictSchema": { "type": "object" }, "auditSchema": { "type": "object" } } ``` The schemas, lanes, and task graph above are shown abbreviated; the real dry-run emits the full `candidateSchema`, `verdictSchema`, and `auditSchema`, plus one task per changed-file group (source, tests, config, docs). The dry-run no longer includes `synthesisSchema`: the report is rendered by deterministic host code, not a model call. `synthesisModel` and `synthesisAdapter` remain in the dry run for the `--synthesis-model` and `--synthesis-reasoning` flags, but, as noted above, they no longer select the model or adapter used for the audit call. `dakar-review --format markdown` prints `reportMarkdown` when a live result has one. Machine users should prefer the default `--format json`. On CLI or ODW process failures, `dakar-review` exits non-zero and prints a JSON error object to standard error: ```json { "ok": false, "stage": "cli", "error": "..." } ``` If the workflow returns `ok: false`, the CLI prints that workflow JSON and exits non-zero. Accepted findings do not make the CLI exit non-zero; they mean the review succeeded and found actionable issues. Recording is now CLI-owned, not workflow-owned: after ODW returns a successful, non-skipped result, the CLI calls Dakar's state helper directly and stamps `recorded: { ok, stateFile, headCommit, recordedBy: "dakar-review" }` onto the result before printing it. If that append fails, the CLI sets `ok: false` and `stage: "record"` on the result, exits non-zero, and preserves `recordInput` so the review can be recorded manually later; the same commit range will be reviewed again on the next run because the history file was not updated. The destination is always derived from the CLI's trusted `repo-root`/`state-root`, never from workflow-supplied data. A successful partial-coverage result is not appended. If files were truncated or a finder pack was refused or downgraded, the result contains `recordWithheld` rather than `recordInput`; the CLI leaves review history unchanged. The same head remains eligible and is reviewed again on a later run. ## Routing and limits The workflow groups changed files into bounded finder evidence packs (`buildFlexFinderPlan`) of at most `transactionMaxFiles` files each, up to `maxLunaFlexCalls` packs. Each admitted pack is reviewed by the Luna Flex lane (`gpt-5.6-luna`, low reasoning by default, escalating to the pre-registered `pi-luna-flex-medium` medium-reasoning adapter when `lunaReasoning` is set to `medium`). Files beyond the `maxLunaFlexCalls x transactionMaxFiles` coverage window are not packed and are listed in `metrics.truncatedFiles`. Deterministic host code then deduplicates and severity-orders the resulting candidates and caps them at `maxAuditCandidates`; the surviving set goes to a single Terra Flex audit call (`gpt-5.6-terra`, medium reasoning) that returns one verdict per candidate. Findings that survive the audit are accepted; the rest are discarded with a reason. The following optional limits are supported: - `maxTasks`: maximum planned finder tasks, default `8`. - `maxCandidates`: maximum candidates kept after normalization, default `30`. - `maxFindings`: maximum accepted findings in the final result, default `20`. - `maxAuditCandidates`: maximum candidates sent to the single audit call, default `30`; candidates beyond the cap are discarded with reason `over_audit_cap`. - `maxLunaFlexCalls`: maximum finder evidence packs, default `4`. - `transactionMaxFiles`: maximum files per finder pack, default `5`. - `budgetGbp`: hard per-review budget in GBP, default `0.10`, converted to USD through the pricing table's `usdPerGbp` snapshot. - `routingPolicy`: recorded in metrics and the dry run; the only supported value is `deterministic-flex-v1`. - `lunaReasoning`: `low` (default) or `medium`, selecting the Luna escalation adapter. - `flexAttempts`, `flexInitialBackoffSeconds`, `flexMaxBackoffSeconds`, `flexJitterSeconds`, and `perCallTimeoutSeconds`: the Flex retry schedule (see "Retries, downgrades, and deferral" below). - `transactionMaxInputTokens`, `transactionMaxOutputTokens`, `terraMaxInputTokens`, `terraMaxOutputTokens`, and `adapterOverheadTokens`: token bounds feeding the cost estimator. Example: ```bash odw run workflows/dakar-review.js --source . --wait --timeout 3600 \ --args '{"config":"examples/df12-code-review.yaml","base":"origin/main", "repoRoot":"/path/to/dakar","prepared":{"...":"see prepare output"}, "maxTasks":4,"maxFindings":5}' ``` ## Cost, budget, and the ledger Every finder and audit call runs through an admission controller that enforces the hard `budgetGbp` before any model call is dispatched. The audit's worst-case cost is reserved first, before any Luna finder call, so an unaffordable review refuses outright (`stage: "admission"`) rather than spending on finders it cannot afford to conclude. Refused finder packs are listed in `admissionRefusals` and never consume any budget. Retries are not free: each retry attempt is admitted against the remaining budget before it runs, and every admitted attempt is charged to the ledger. The reserve-first audit reservation stays one attempt's worst case, so the ordinary defaults keep working, while the hard ceiling still bounds the actual worst-case spend including retries. A retry refused by the remaining budget stops retrying: the finder pack downgrades or the audit defers rather than exceeding the ceiling (see "Retries, downgrades, and deferral" below). Because admission refuses any finder pack beyond the ordinary budget, a gate reviewing a large task branch may need to raise `--budget-gbp` to admit more finder packs and so cover the full diff. The ordinary default deliberately forces refusals on multi-pack large reviews; lift the budget only for the runs that warrant the extra coverage. `metrics` carries the cost accounting: - `ledger`: one entry per admitted call, with `lane`, `model`, `serviceTier`, `reasoningEffort`, `estimatedWorstCaseUsd`, `pricingTableVersion`, and `attempts`. `estimatedWorstCaseUsd` is the total admitted for the call across its attempts, so a call that retried carries the summed worst case of each admitted attempt while `attempts` records the observed count. - `ledgerTotalEstimatedUsd`: the sum of admitted worst-case estimates. - `budgetUsd`, `reservedAuditUsd`, and `spentUsd`: the admission trail for this run. - `routingPolicy` and `pricingTableVersion`: which routing policy and pricing snapshot produced this ledger. - `auditCandidateCount`, `overAuditCapCount`, `unknownAuditVerdictCount`, and `duplicateAuditVerdictCount`: audit compaction and verdict-pairing tallies. - `lunaDowngradeCount` and `truncatedFiles`: partial-coverage indicators. ## Retries, downgrades, and deferral Flex calls retry under bounded exponential backoff (`flexAttempts`, default `3`; backoff from `flexInitialBackoffSeconds` (`30`) up to `flexMaxBackoffSeconds` (`120`), with up to `flexJitterSeconds` (`10`) of deterministic jitter). Each retry attempt is admitted against the remaining budget before it runs and charged when admitted, so retries can stop for either of two reasons: exhausting the attempt count, or the remaining budget refusing the next attempt. A finder pack that exhausts its retries — or whose next retry the budget refuses — downgrades: it is recorded in `lunaDowngrades` and `metrics.lunaDowngradeCount`, and the review continues with the surviving candidates. An audit call that exhausts its retries, or whose next retry the budget refuses, defers the whole review instead: the result is `ok: false`, `stage: "deferred"`, no `recordInput` is present, and the CLI exits non-zero without recording anything, so the head remains unreviewed. A budget-refused retry keeps the actual spend within the hard ceiling rather than overrunning it; the deferral or downgrade reason names the budget so operators can tell it apart from a capacity exhaustion. The dry run reports `reservedAuditChainUsd` alongside `reservedAuditUsd`: the former is the audit's chain-level worst case (one attempt's reserve times `flexAttempts`), shown so operators can see the full retry cost, while admission only ever reserves the single-attempt `reservedAuditUsd`. A deferred review retried later re-pays its Luna finder calls: Luna output is not cached across separate `dakar-review` invocations, so a retry after a deferral repeats the finder phase's spend (roughly USD 0.04 worst case at default limits). Operators should space retries after a deferral rather than tight-looping them. `worstCaseReviewSeconds` (2,020 s at default limits, shown in the dry run) is the worst-case wall clock for one review's finder and audit retry chains. Operators overriding `--timeout` should keep it above this figure. ## Error and skip behaviour Configuration resolution and range preparation are deterministic host code run by the CLI before ODW is invoked; a failure there is reported by the CLI with stage `config` or `prepare` and never launches ODW. Within the workflow, an admission refusal for the audit's own reservation returns `stage: "admission"` before any model call; an incomplete audit (a missing or invalid verdict) fails closed with `stage: "audit"` so nothing is recorded; an exhausted audit retry defers with `stage: "deferred"` (see above). If the CLI's own append to review history fails after a completed review, the result carries `stage: "record"` with `recordInput` preserved for manual retry, and the same commit range will be reviewed again on the next run. If `origin/main` is not available, pass a different `base`. If prepare reports that the workspace is not a git repository, pass `repoRoot` as an absolute path to the real checkout.