Artifacts & Schema
Public contract details for PatchPatrol output artifacts and JSON payload structure.
Artifacts & Schema Reference
Use this page when you want to integrate PatchPatrol output into automation, checkers, or any non-interactive workflow.
Source of truth: schema.json plus the current artifact writing behavior in patchpatrol/artifacts.py and patchpatrol/cli.py.
What PatchPatrol Writes
PatchPatrol writes files into AI_REVIEW_OUTPUT_DIR (default .ai-review).
| Artifact | Purpose | Stability posture |
|---|---|---|
ai-review.md | Human-readable Markdown Run Report for quick manual review and triage. | Stable, documented public artifact. |
ai-review.html | Static printable HTML Run Report for browser review or PDF export. | Default additive artifact; disabled with AI_REVIEW_HTML_REPORT=false or ai-review run --no-html-report. |
ai-review.json | Machine-readable Run Report and canonical FindingsReport payload for scripts and integrations. | Stable, documented public contract. |
gl-code-quality-report.json | Optional Code Quality format mirror of findings. | Optional output; enabled by default via AI_REVIEW_CODE_QUALITY_EXPORT, including early exits that have no findings and therefore render as []. |
ai-review.json, ai-review.md, and ai-review.html are Run Reports for one
PatchPatrol execution. The HTML and Markdown Run Reports are human-facing
renderings derived from the same validated payload. They can surface review
context, Review Outcome, findings, coverage, and token usage sections, but
ai-review.json remains the automation contract.
A Run Report does not own the merge request's cross-run Active Finding Set. When optional MR feedback is enabled, that lifecycle belongs to the persistent GitLab Review Summary.
Use the First review output page for quick interpretation.
Core JSON contract (stable)
ai-review.json validates against schema.json with three required top-level fields:
metasummaryfindings
The top-level object and finding objects reject unknown properties, so key names above and their nested fields should match what integrators send to downstream systems.
meta
meta is required and includes at least these stable keys:
modelbase_shahead_shagenerated_atdiff_basediff_statslimitsreview_coverage
meta.diff_stats requires:
filesinsertionsdeletions
meta.limits is a dictionary. It always exists and carries runtime-applied limit values and execution diagnostics.
meta.review_coverage is a deterministic execution manifest. It records what
PatchPatrol attempted and what it actually reviewed, including:
status:complete,partial,limited, orprovider_failedchunk_countandchunk_order_fingerprintchunks_attempted,chunks_succeeded,chunks_retried, andchunks_fallbackedreviewed_bytes,skipped_bytes, andfallbacked_bytesomitted_fileswith path, reason code, and diff-byte countomitted_reasonsgrouped by reason codevalidation.status:passed,fallback, orprovider_failedchunk_executionentries with per-chunk attempts, status, bytes, and reason codes
Use meta.review_coverage when you need to distinguish provider-runtime
failure from invalid-output fallback and from successfully reviewed chunks. The
older meta.limits counters remain for compatibility, but this manifest is the
clearer audit surface for reviewed, skipped, retried, and fallbacked scope.
For structured-output provider behavior, meta.limits may also include compact
diagnostics such as:
structured_output_review_call_countstructured_output_requested_modesstructured_output_effective_modesstructured_output_fallback_countstructured_output_reason_codes
These fields are optional and additive. They record output-mode decisions and fallback reason codes without persisting raw prompts or provider request payloads.
When repo-local .ai-review.yml review.rules are configured, meta.limits
may also include compact counters such as:
prompt_review_rule_total_countprompt_review_rule_matched_countprompt_review_rule_included_countprompt_review_rule_omitted_count
These counters make rule matching observable without persisting raw rule instructions in review artifacts.
Repository-aware runs also add meta.repository_context when repository context
metadata is available. Within one execution, ai-review.json is the per-run
source of truth for meta.repository_context; the Markdown and HTML Run Reports
and GitHub Actions job summary render compact views of that metadata.
Repository-context diagnostics stay in the current Run Reports, GitHub Actions
job summary, and console Operational Diagnostics; they are excluded from the
persistent GitLab Review Summary. That summary owns the merge request's separate
cross-run Active Finding Set.
meta.repository_context can include mode, policy_file,
policy_file_status, rule counts and matched rule identities, context_budget,
context_sources, reason_codes, and persisted_memory. Rule identities expose
id, severity, and scope; raw rule instructions are not stored in normal
artifacts by default. Source categories can include repo_rules,
preflight_hints, supporting_code, semantic_diagnostics, and
repository_overview. Current context-source statuses include disabled,
included, not_applicable, not_available, not_configured, not_enabled,
not_matched, not_run, omitted, omitted_max_bytes,
partially_included, truncated, unavailable, and unknown.
See Repository-aware rules for the customer-facing interpretation guide.
When deterministic preflight hints are generated, meta.limits may include
compact counters and reason codes such as:
prompt_preflight_hint_total_countprompt_preflight_hint_matched_countprompt_preflight_hint_included_countprompt_preflight_hint_omitted_countprompt_preflight_hint_reason_codes
These fields are optional and additive. They make hint matching observable without persisting raw hint evidence, raw prompt bodies, or provider chain-of-thought in artifacts. Preflight hints are prompt evidence only: they can point the provider at duplicate added code-like text, dependency additions, risky import additions, or missing test-counterpart signals, but they are not automatic findings or CI gates.
summary
summary is required and includes these stable fields:
overall_risktop_issues
overall_risk is one of low, medium, or high.
findings
findings is required and is an array of finding objects.
A finding currently requires:
severitycategoryfileline_startline_endtitledescriptionrecommendationconfidence
suggested_patch and provenance are optional.
When remediation output is enabled with AI_REVIEW_REMEDIATION_MODE=briefs or
AI_REVIEW_REMEDIATION_MODE=suggestions, PatchPatrol derives advisory fix
briefs under meta.remediation from validated, unsuppressed findings. This
keeps ai-review.json as the canonical artifact for remediation guidance while
making clear that all output is human-reviewed guidance. PatchPatrol does not
commit, push, or modify repository state.
meta.remediation.briefs[] preserves each finding's file, line range,
confidence, fingerprint, title, and recommended action. In suggestions mode,
briefs[].suggestion can contain a safe suggested replacement only for
high-confidence, narrow findings. GitLab suggestion blocks are emitted only
when that advisory suggestion is eligible and the finding also has a valid
GitLab inline anchor.
These fix briefs are advisory and human-reviewed; they are not automatic code changes.
line_start and line_end are normal new/right-side integer file line
numbers. Provider prompts may render prompt-only L<number>: labels on added
and context lines to help the model anchor findings, but those labels are not
persisted in ai-review.json, ai-review.md, ai-review.html, or GitLab
exports.
Published enums and controlled values
The following enum sets are the reliable values currently emitted and validated:
finding.severity:blocker,high,medium,low,infofinding.category:security,correctness,reliability,performance,maintainability,testing,stylesummary.overall_risk:low,medium,highfinding.provenance.origin:llm,semantic,security_tool,combinedfinding.provenance.sources:llm,semantic,security_toolmeta.security_precheck.status:pass,fail,unavailable,error,skippedmeta.license.status:valid,missing,invalid,expired,not_yet_valid,unsupported
Runtime fields in meta you may see today
The schema allows additional public metadata in meta. In the shipped runtime paths, these meta sections are currently present in supported cases:
meta.diff_basemeta.licensemeta.semantic_precheckmeta.security_precheckmeta.trust_gatemeta.provider_runtimemeta.feedbackmeta.incremental_reviewmeta.remediationmeta.repository_contextmeta.repository_overviewmeta.usage_ledgermeta.performance_diagnostics
These are additive and may grow as execution behavior evolves.
meta.license records non-sensitive Self-Hosted License evaluation state when a
real-provider review is blocked before provider-backed work. It includes
the following fields when available:
| Field | Meaning |
|---|---|
status | License Status: valid, missing, invalid, expired, not_yet_valid, or unsupported. |
mode | self_hosted for Self-Hosted License v1. |
reason_codes | Stable machine-readable LICENSE_* evaluation reasons. |
customer_slug | Trusted non-secret customer identifier; omitted when claims are not trusted. |
license_id | Trusted non-secret support handle; omitted when claims are not trusted. |
expires_at | Trusted license expiry; omitted when claims are not trusted. |
features | Trusted enabled feature names; omitted when claims are not trusted. |
Artifacts never include the raw Signed License payload, signature, or private
signing key. License-blocked artifacts mean provider review did not run. Empty
findings therefore do not mean the diff is clean, and for a blocked manual
source scan they do not mean the codebase is clean. A source scan blocked before
extraction records meta.source_coverage.status=not_run_license_blocked instead
of inventing source omissions.
meta.diff_base records the strategy used to choose the reviewed diff base.
Use it when a branch or merge request is behind its target branch and you need
to confirm PatchPatrol reviewed only the feature branch's net changes.
| Field | Meaning |
|---|---|
strategy | merge-base for branch/MR merge-base extraction, gitlab-diff-base-sha when GitLab MR diff refs were used, not-applicable for staged/working-tree modes, or error for early diff-context artifacts. |
reason_codes | Compact reason codes such as DIFF_BASE_MERGE_BASE, DIFF_BASE_GITLAB_DIFF_BASE_SHA, DIFF_BASE_NOT_APPLICABLE, or a diff-context error code. |
base_ref | The requested target/base ref when branch or MR mode selected one. |
head_ref | The requested head ref, usually HEAD or the CI commit SHA. |
diff_base_ref | The actual first ref passed to git diff; for merge-base, this is the resolved merge-base SHA. |
status | Present as error only on early diff-context artifacts. |
diagnostic | Present only on early diff-context artifacts, with the reason-coded ref-resolution diagnostic. |
meta.base_sha resolves from meta.diff_base.diff_base_ref when an actual diff
base was selected. That keeps base_sha aligned with the reviewed patch rather
than the current target-branch tip.
meta.incremental_review records the GitLab MR incremental-review decision
when ai-review run has resolved review scope. Use it to distinguish a full MR
provider review from a rerun where the provider only reviewed the delta since
the previous PatchPatrol-reviewed head SHA.
| Field | Meaning |
|---|---|
configured_mode | Effective AI_REVIEW_INCREMENTAL_MODE: auto, always, or never. |
status | incremental when provider scope was narrowed, full when PatchPatrol used full provider scope, or disabled when incremental review was not applicable. |
provider_scope | incremental or full, matching the scope sent to the provider. |
reason_codes | Stable reason codes such as INCREMENTAL_PRIOR_HEAD_REACHABLE, INCREMENTAL_PRIOR_HEAD_MISSING, INCREMENTAL_PRIOR_HEAD_UNAVAILABLE, INCREMENTAL_PRIOR_HEAD_NOT_ANCESTOR, or INCREMENTAL_DIFF_EXTRACTION_FAILED. |
prior_reviewed_head_sha | Prior PatchPatrol-reviewed MR head SHA when available. |
current_head_sha | Current reviewed MR head SHA when available. |
full_scope | The complete MR scope kept for line anchoring and Active Finding lifecycle comparison. |
provider_scope_details | The actual scope sent to the provider. When incremental, this uses diff_base_strategy=incremental-prior-head-sha. |
meta.usage_ledger, when present, is interpretive provider-call metadata used
for token usage tables. It has three levels: calls for all provider calls,
by_phase for phase totals, and records for individual calls. If the trust
gate blocks execution before provider review, no provider call is made;
fail-fast artifacts can therefore show meta.usage_ledger.calls.call_count as
0 and zero prompt/completion/total tokens. In that same blocked state,
findings: [] means the provider review did not run, not that the merge request
was clean.
Provider timing fields in meta.usage_ledger are additive. When the configured
provider exposes native timings, records and totals may include these fields:
| Field | Meaning |
|---|---|
prompt_tokens | Prompt/input tokens reported for the provider call. |
completion_tokens | Generated/completion tokens reported for the provider call. |
total_tokens | Prompt plus completion tokens when available. |
wall_elapsed_seconds | PatchPatrol-measured wall time for the provider call or total. |
provider_total_duration_seconds | Provider/server total runtime when exposed by the provider. |
provider_load_duration_seconds | Provider-reported model load time, useful for cold-start diagnosis. |
provider_prompt_eval_duration_seconds | Provider-reported prompt ingestion/evaluation time. |
provider_generation_duration_seconds | Provider-reported generation/decode time. |
total_tokens_per_second_wall | Total tokens divided by PatchPatrol wall time. Human reports label this Wall total tok/s. |
prompt_tokens_per_second_provider | Prompt tokens divided by provider prompt-eval time. Human reports label this Prompt tok/s. |
generation_tokens_per_second_provider | Completion tokens divided by provider generation time. Human reports label this Generation tok/s; this is the Ollama model decode-speed metric. |
total_tokens_per_second_provider | Total tokens divided by provider total runtime. Human reports label this Provider total tok/s. |
provider_wall_overhead_seconds | PatchPatrol wall time minus provider total runtime. Use this to spot Docker, network, wrapper, or orchestration overhead. |
For Ollama, provider-native durations come from nanosecond fields in the
/api/chat response and are converted to seconds:
prompt_tok_s = prompt_eval_count / (prompt_eval_duration / 1e9)
generation_tok_s = eval_count / (eval_duration / 1e9)
provider_total_tok_s = total_tokens / (total_duration / 1e9)
wall_total_tok_s = total_tokens / PatchPatrol_wall_elapsed_secondsBlended wall/provider total rates are not generation speed. A large prompt and
short completion can make Wall total tok/s or Provider total tok/s much
higher than Generation tok/s. Providers that expose only token counts leave
provider-native prompt/generation rates as unavailable, rendered as n/a in
human reports, while wall throughput may still be available.
meta.performance_diagnostics, when enabled with
AI_REVIEW_ENABLE_PERFORMANCE_DIAGNOSTICS=true, mirrors the same usage values
under observed.token_usage and duration values under
observed.elapsed_seconds. The markdown and optional HTML reports render the
same concepts in ## Token Usage and ## Performance Diagnostics.
Treat missing optional sections as normal and preserve unknown keys when forwarding or storing reports.
Minimal valid payload example
{
"meta": {
"model": "deepseek-coder-v2:16b",
"base_sha": "1111111",
"head_sha": "2222222",
"generated_at": "2026-02-26T12:00:00Z",
"diff_stats": {
"files": 0,
"insertions": 0,
"deletions": 0
},
"limits": {
"max_diff_bytes": 32768,
"max_files": 50
}
},
"summary": {
"overall_risk": "low",
"top_issues": []
},
"findings": []
}That structure is intentionally minimal, but valid for parser bootstrap checks and contract tests.
Stability posture
ai-review.jsonis the contract source of truth.ai-review.mdandai-review.htmlare human-facing renderings derived from that validated payload.schema.jsonis the contract source for those artifacts.- Integrators should validate required fields and enums from
schema.jsonand treat extra fields as optional forward-compatible extensions. - Any optional output sections should be handled defensively (null/absent checks first), because these sections are surfaced opportunistically.