What the workflow returns

Updated Jul 27, 2026

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:

{
  "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:

{
  "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:

{
  "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.