メインコンテンツまでスキップ

Artifact Input Contract

River Review is a review agent that consumes artifacts produced by upstream workflows such as PlanGate as external inputs and performs review, QA, and double-check operations. This document defines the input contract that River Review can read stably.

Related issues: #516 (Task) / #508 (Capability) / #507 (Epic)

Policy​

  • River Review operates artifact-driven and does not depend on PlanGate-internal commands or on a specific directory layout.
  • Inputs are consumed on a file path basis; only the content format (Markdown / JSON / XML / plain) is contracted.
  • Behavior when a file is missing (skip / degrade / error) is defined per artifact.
  • When adding a new artifact, update this document and preserve backward compatibility.

Artifact Catalog​

The input artifacts recognized by River Review are listed below. See "Legend" at the end for column semantics.

IDExample filenameFormatRequiredSchema / referenceRole
pbi-inputpbi-input.mdMarkdownOptional (rec.)Free-formInput spec / background of the Product Backlog Item
planplan.mdMarkdownOptional (rec.)Free-formImplementation plan and design rationale
design— (no default)MarkdownOptional (rec.)Free-formDesign document (architecture and technical premises)
todotodo.mdMarkdownOptionalFree-form (checklist)Implementation tasks and progress
test-casestest-cases.mdMarkdownOptionalFree-form (bullets or tables)Test case design
review-selfreview-self.mdMarkdownOptionalFree-formSelf-review by the author
review-externalreview-external.mdMarkdownOptionalFree-formExternal review (AI or human)
diffdiff.patchunified diffRequired (alt.)git diff compatibleReview target diff; falls back to git diff when absent
junitjunit.xmlXMLOptionalJUnit XMLUnit/integration test results
coveragecoverage.xml etc.XML / JSONOptionalOne of Cobertura / LCOV / Istanbul JSONCoverage report
lintlint.json etc.JSON / plainOptionalESLint JSON, stylelint JSON, or tool-specific plainLint result
typechecktypecheck.txt etc.plain / JSONOptionaltsc --pretty=false or tool-specific plainType checker result
findings-poolfindings-pool.jsonJSONOptionalfindings-pool section in this documentAggregated findings[] history from multiple Review Artifacts
tdd-ledgertdd-ledger.jsonJSONOptionaltdd-ledger section in this documentRED/GREEN/REFACTOR VERIFY phase execution evidence for TDD

Legend​

  • Required
    • Required: Without this input River Review aborts.
    • Required (alt.): If absent, an alternative (e.g. git diff) is used automatically.
    • Optional: Missing files are tolerated; related skills are skipped or degraded.
    • Optional (rec.): Missing is allowed, but review quality drops meaningfully.
  • Format: Encoding and syntax. Multiple accepted formats are comma-separated.
  • Example filename: The well-known filename probed by current-directory detection, the third channel described in "Input channels" below. An artifact marked — (no default) is excluded from that probe and resolves only when supplied explicitly via a CLI argument or the config file.

Per-artifact Contract​

pbi-input / plan / todo / test-cases​

  • Format: UTF-8 Markdown. Heading structure and bullets are unconstrained.
  • Size guideline: 100 KB or less per file recommended. Beyond that, River Review may apply diff optimization (summarization / trimming).
  • When absent: Skills referencing the artifact skip their observation and record it in skippedSkills.
  • reviewSignals (optional): Structured signals for automatic reviewer selection, supplied as a field on the review plan object rather than in the Markdown body. See the next section.

reviewSignals (optional signals carried on the review plan)​

reviewSignals is an optional input that gives extra hints to reviewer role auto-selection under --reviewers auto. It is supplied as a field on the review plan object, not in the Markdown body of plan.md (the implementation reads it at context.plan.reviewSignals). River Review owns the vocabulary; it is not tied to the format of any particular upstream workflow.

  • Format: JSON object with a stage string and a set of boolean signal keys.
  • Supply channel: Programmatic embedding — the review plan passed to runLocalReview({ context }). It is not exposed as a CLI flag or a dedicated file.
  • Producer: No producer exists in this repository; supplying the value is the host's responsibility. PlanGate is only one possible supplier, and River Review acts purely as a consumer.
  • When absent: Absence is the default. --reviewers auto selects roles from file types and risk assessment alone, behaving exactly as it did before reviewSignals existed.

stage vocabulary​

stageRoles added
requirements(none)
plansecurity-scanner, test-gap
designfrontend-reviewer
execsecurity-scanner
verifytest-gap
releasesecurity-scanner

An unknown stage value is ignored and adds no role.

Signal keys​

Signal keyRole added
touchesAuthsecurity-scanner
changesPermissionssecurity-scanner
handlesSensitiveDatasecurity-scanner
databaseMigrationsecurity-scanner
breakingChangesecurity-scanner
changesUifrontend-reviewer
changesUserFlowfrontend-reviewer
deploymentChangeci-cd-reviewer
  • Only truthy keys are evaluated; unknown keys are ignored.
  • changesPublicApi / changesCliInterface / changesInstallation correspond to the devex Lens and deliberately map to no role, because no dedicated role exists for it.
  • Signals only add roles. They never remove anything from the existing selection, including the always-on bug-hunter.
  • For the Lens correspondence, see Reviewer Lens Taxonomy.

Example:

{
"reviewSignals": {
"stage": "exec",
"touchesAuth": true,
"changesUi": true
}
}

design​

An artifact that supplies the design document. A Flow's declared design input resolves to this same-named artifact ID.

  • How to supply it: Always supply it explicitly, with --artifact design=<path> or artifacts.design in the config file. It has no well-known filename for current-directory detection.
  • Why it has no default filename: design is a required input of design-review / technical-review, and a default binding on a required input would let a file that merely sits in the working tree declare the input satisfied (see Runner CLI Reference).
  • Format: UTF-8 Markdown. Describes architecture, design decisions, and technical premises.
  • Size guideline: 100 KB or less per file recommended.
  • Flows that require it: design-review / technical-review
  • Flows that treat it as optional: plan-review / requirements-review / research-review
  • When absent (Flows that require it): The input is reported as unbound.
  • When absent (Flows that treat it as optional): The related observation is skipped.
  • Distinct from the stage vocabulary: The design listed in the stage vocabulary above is a value of reviewSignals.stage and does not share a vocabulary space with artifact IDs. The names match, but the two are unrelated.

review-self / review-external​

  • Format: UTF-8 Markdown. Existing AI reviewer (including River Review itself) or human review output may be stored verbatim.
  • When absent: Double-check (W-check) skills are skipped.
  • Compatibility: Content may follow the issue definition in schemas/output.schema.json, but this is not required.

See also: pages/guides/w-check.md — W-check Practical Guide

findings-pool​

  • Format: UTF-8 JSON. An aggregation of findings[] collected from multiple Review Artifacts (execution history of river review exec / river review verify).

  • Size guideline: 5 MB or less recommended (typically hundreds of findings). When exceeded, apply rotation or time-window filtering on the CLI side.

  • Schema (provisional):

    {
    "version": "1",
    "entries": [
    {
    "timestamp": "2026-04-17T00:00:00Z",
    "phase": "exec",
    "skillId": "plangate-plan-integrity",
    "severity": "major",
    "file": "path/to/file.ts",
    "line": 42,
    "message": "description",
    "source": "path/to/review-artifact.json"
    }
    ]
    }
    • version: Fixed string "1" (bumped on incompatible changes).
    • entries[]: One entry per finding.
    • entries[].phase: exec or verify.
    • entries[].skillId: ID of the skill that produced the finding.
    • entries[].severity: External vocabulary (critical / major / minor / info).
    • entries[].file / entries[].line: Target location. Omittable for findings that reference outside the diff.
    • entries[].message: Human-readable description of the finding.
    • entries[].source (optional): Path of the originating Review Artifact. Recommended to preserve provenance.
  • Construction: CLI consumers are expected to build this artifact by reading multiple review-artifact.json files and concatenating their findings[] into entries[] (implementation tracked in follow-up issue).

  • When absent: Skills that require this artifact, such as plangate-rule-promotion, return NO_REVIEW at the Pre-execution Gate and skip the promotion-judgement process.

tdd-ledger​

  • Format: UTF-8 JSON. A ledger recording each TDD (test-driven development) phase execution. Expected to be produced during exec by upstream workflows such as PlanGate.

  • Role: Records the command and result (exitCode) of the RED / GREEN / REFACTOR VERIFY phases, providing evidence that TDD was performed in the declared, correct order.

  • Schema (provisional):

    {
    "version": "1",
    "task": "TASK-1234",
    "phases": [
    {
    "phase": "tdd_red",
    "command": "npm test -- discount.test.ts",
    "exitCode": 1,
    "conclusion": "Fails as expected because applyDiscount is unimplemented",
    "testCaseRefs": ["TC2"]
    },
    {
    "phase": "tdd_green",
    "command": "npm test -- discount.test.ts",
    "exitCode": 0,
    "conclusion": "Minimal implementation makes TC2 pass",
    "testCaseRefs": ["TC2"]
    }
    ]
    }
    • version: Fixed string "1" (bumped on future incompatible changes).
    • task (optional): Identifier of the corresponding task.
    • phases[].phase: One of tdd_red / tdd_green / refactor_verify / verification.
    • phases[].command: The test/verification command executed.
    • phases[].exitCode: Exit code of the command (tdd_red expects != 0; tdd_green / refactor_verify / verification expect 0).
    • phases[].conclusion (optional): Explanation of the phase outcome or failure reason.
    • phases[].testCaseRefs (optional): Array of corresponding test-cases IDs.
  • When absent: Skills that require this artifact, such as plangate-tdd-evidence, return NO_REVIEW at the Pre-execution Gate and skip the TDD evidence review.

diff​

  • Format: unified diff (git diff compatible). Binary diffs are ignored when the diff is supplied as an artifact. (When review plan|exec --base <ref> obtains the diff from git, the changed-file set comes from git diff --name-only, so binary changes and 100% renames are included.)
  • Requirement: A diff must be supplied by some channel. When no artifact is specified, River Review internally runs git diff <mergeBase>..HEAD and uses the result as the diff.
  • Precedence against --base (#2046): an explicitly specified artifact (tier 1 CLI argument / tier 2 config file) wins over review plan|exec --base <ref> — provided the file exists at that path; when it does not, the --base range is used and a warning says so. --base wins over tier 3 directory auto-detection (diff.patch). Either way, the discarded input is announced as a warning on stderr.
  • When the resulting diff is empty: If the supplied diff (explicit or fallback) is empty, status is set to no-changes and review skills are not executed.

Diff supply routes (full enumeration against the implementation)​

"Input Channels" below is the resolution order for artifact files, not a list of every route by which a diff reaches River Review. The implementation has 8 entry points through which a diff enters the system (as of 2026-09-17; the fixture-evaluation-only paths review-fixtures-eval.mjs / repo-wide-fixtures-eval.mjs are excluded as non-production). This section specifies, per route, who produces the diff, the context width, and whether a combined diff (diff --cc / @@@) can enter.

#Route (implementation site)SurfaceDiff producerContext widthCombined diff
1src/cli/commands/review.mjs:56 → collectRepoDiffriver review plan / river review execRiver Review (git)3cannot enter
2src/cli/commands/skills.mjs:133 → collectRepoDiffriver skillsRiver Review (git)3cannot enter
3src/lib/local-runner.mjs:269 planLocalReviewriver runRiver Review (git)3 (10 with --debug)cannot enter
4src/lib/local-runner.mjs:767 doctorLocalReviewriver doctorRiver Review (git)0 (10 with --debug)cannot enter
5artifact file read at src/lib/review-plan.mjs:484 / :841the diff artifact via tier 1 / 2 / 3Host (may be real git output)unspecifiedsupported
6src/lib/review-plan.mjs:481 / :838 diffOverride.diffText--base <ref> on review plan / execRiver Review (git)3cannot enter
7src/lib/local-runner.mjs:533 runLocalReview({ context })programmatic embeddingHostunspecifiedsupported
8the diffText option at runners/node-api/src/index.ts:342 / :389Node API (buildExecutionPlan() / review())Hostunspecifiedsupported
  • git-produced routes (1 / 2 / 3 / 4 / 6): all go through git diff --unified=<N> --no-color <baseRef> at src/lib/git.mjs:520. Because an explicit base ref makes this a two-tree diff, no combined diff is emitted. Even in a working tree with an unresolved merge conflict the output stays two-tree, with conflict markers appearing as ordinary added lines (measured in a throwaway repository on 2026-09-17).
  • Context width: the default is 3. Only river doctor (route 4) uses 0, and routes 3 / 4 use 10 when --debug is set. The width is an implementation choice inside River Review, not a value this contract promises externally. For diffs the host supplies through routes 5 / 7 / 8 the context width is unspecified.
  • Combined diff: diff --cc / @@@ output is supported (#2294). git show --cc and git log -p --cc are real git output and arrive legitimately through routes 5 / 7 / 8. The parse layer accepts a hunk header whose marker widens by one @ per parent (@@@ for two parents, @@@@ for a three-parent octopus merge) and counts each body line by its per-parent prefix COLUMNS. A line is absent from the merge result, and consumes no line number, when any column is -; it is recorded in addedLines when any column is +. A conflict-resolution line (++ for two parents) belongs to neither parent and therefore reaches review, which is the point.
  • Binary files inside a combined section: a combined section for a binary file emits only Binary files differ and carries no --- / +++ triple, so that file is not registered in files[] and is not reviewed. This matches the behaviour for ordinary (non-combined) binary diffs and is identical before and after #2294 (measured in a throwaway repository).
  • \ No newline at end of file: the marker is metadata, not a line of the merge result, and it consumes no line number on either the combined or the ordinary path (#2309). Real git always emits it for a file with no trailing newline, so host-supplied diffs on routes 5 / 7 / 8 are treated the same way.
  • Migration (#2309): before the fix the ordinary path counted the marker as a context line, so every addition below it was recorded in addedLines one line further down the file than it really is. A line number that is now smaller by one for the same diff is that correction, not a regression.
  • Measured blast radius (#2309): replaying the 400 most recent commits of this repository through the parser before and after the fix changed the output of 96 of them (24%), and every one of those 96 contains this marker. No commit without the marker changed. Whether you are affected therefore comes down to whether your diff contains a file with no trailing newline.
  • Effect on v2 suppressions (#2309): the v2 suppressions in src/lib/suppression-apply.mjs are line-anchored, so one placed below the marker can stop matching once the line numbers are corrected. A suppression that stops matching shows up as the finding reappearing, so re-anchor it if you still want it suppressed. v1 fingerprints carry no line number and are unaffected.
  • Migration: before #2294 a combined-diff input returned zero findings. The same input now returns findings. When comparing against a result recorded while those files read as empty, the difference is not a regression — it is previously invisible change becoming visible.

Ownership of diff supply​

  • Routes 1 / 2 / 3 / 4 / 6: producing the diff is River Review's responsibility. Format, context width, and base resolution are all decided by the implementation.
  • Routes 5 / 7 / 8: supplying the diff is the host's responsibility. As with reviewSignals, no producer exists in this repository. River Review acts purely as a consumer and does not verify that what it receives came from real git, nor that it is a valid unified diff. Host-supplied does not mean non-git-produced: route 5 includes the legitimate use case of passing real git output — such as git show --cc — as a file. Hosts should pass a two-tree unified diff equivalent to git diff --unified=3. Behavior for non-git-produced diffs and hand-written patches is unspecified.
  • Beware fail-silent behavior: "unspecified" does not mean "you will notice when it breaks". An invalid diff does not raise; it can come back as a normal result with zero findings. Confirm on the host side — by cross-checking output such as changedFiles — that the diff you supplied was interpreted as intended.

junit​

  • Format: JUnit XML compatible. Nested <testsuite> is permitted.
  • When absent: Test-pass/fail skills are skipped.

coverage​

  • Format: One of Cobertura XML, LCOV, or Istanbul JSON.
  • When absent: Coverage skills are skipped.
  • Note: Threshold evaluation is the skill's responsibility; this contract only fixes schema passthrough.

lint / typecheck​

  • Format: Prefer JSON (ESLint / stylelint / tsc JSON), fall back to plain text. Skills perform a tool-specific light parse on plain input.
  • When absent: Static-analysis skills are skipped.

Input Channels​

River Review resolves artifacts in this order:

  1. CLI / GitHub Action arguments (defined in river review plan / river review exec CLI spec). Example: --artifact pbi-input=./path/to/pbi-input.md
  2. Configuration file (defined in river review plan / river review exec CLI spec). artifacts section in river.config.*.
  3. Current directory auto-detection (fallback). Searches the workspace root for the default filenames above.

Artifacts not resolved by any channel are treated as "absent" and follow the per-artifact absence behavior above.

These three tiers apply only to the river review plan and river review exec surfaces. river run, river skills, and river doctor perform no artifact resolution and always obtain the diff from git themselves (routes 3 / 2 / 4 in "Diff supply routes" above).

Downstream Integration​

CLI​

  • river run records the resolved artifact set in the context / debug sections of the Review Artifact.
  • Failure to resolve required artifacts exits with code 1. See Stable Interfaces.

Skills​

  • Individual skills declare the artifact IDs they require (implemented as part of the skill-pack design).
  • Skills requiring an unresolved artifact are auto-skipped and recorded in plan.skippedSkills.

CI​

⚠️ GitHub Action limitation (not yet implemented)

The --artifact and --ensemble flags are not yet available as GitHub Action inputs. As a workaround, invoke the dist/index.mjs CLI directly. See the W-check Practical Guide for a concrete example. A dedicated artifact input is planned (see runners/github-action/action.yml).

  • CI should decide failure from the Review Artifact status and the severity mix of findings.

PlanGate Independence​

This contract treats PlanGate as one of several possible producers and deliberately avoids:

  • Hard-coding PlanGate-specific directory layouts (e.g. plangate/<phase>/) as default paths.
  • Adopting artifact names tied to PlanGate-internal commands or execution models.
  • Assuming PlanGate versions and River Review skill versions are co-released.
  • Adopting a PlanGate-specific signal format as the reviewSignals contract. The stage vocabulary and signal keys are defined by River Review; PlanGate is treated as one possible supplier.

This keeps River Review usable for workflows other than PlanGate or for artifacts generated manually.

Versioning​

  • This contract is managed as document version 1 (when later formalized as JSON Schema, a version field will be added).
  • Adding artifacts or extending formats is a minor bump (backward compatible); removal is a major bump.

See Also​