Changed-line coverage and binary windows
Use a clean build of the commit you want to review. Bind and ingest coverage for each binary that ran. Keep every cover directory until its labels and evidence have been checked.
reflow coverage ingest --cover-dir /tmp/server-cov --processes launched \ --window abc123-W1-a1 --member server --batch <batch-key>reflow coverage ingest --cover-dir /tmp/gateway-cov --processes 2 \ --window abc123-W1-a1 --member gateway --batch <batch-key>reflow coverage documents --window abc123-W1-a1 --jsonreflow coverage status --window abc123-W1-a1 --expect-members server,gateway --jsonreflow coverage diff --window abc123-W1-a1 --base <base-commit> --jsonWindows select documents; they do not sum their metrics. Each member is one binary at the same
repository, commit, tree and dirty state. A duplicate member label or a binary repeated under another
label is refused. Window and member labels are part of the canonical document hash, so correcting
one means ingesting again from the retained cover directory. A suggested label is
<INTEGRATION-short>-W<n>-a<attempt>. Window labels allow letters, digits, ., _, :, -
(up to 128 characters; . and .. are refused); member labels allow letters, digits, ., _, -
(up to 32). Pass both labels on ingest, including LLVM ingest.
status --window returns the binding, members, instrumented packages, overlapping packages and
batch keys. --expect-members requires an exact member set and refuses window_incomplete if it
is missing or has extras. An older server that ignores the list filter is refused. Windows can hold
Go and LLVM members. A changed-line review may select both: each changed file is judged by the
documents of the format that measures it (lists the file or holds its package), and a file no
format measures is a gap over every document. formats maps each format to its labels, and the
batch check counts each format’s documents separately.
A window can contain at most 64 members. Collection retention still keeps only the latest 50 clean
and, separately, 20 dirty documents; windows do not pin their members against retention. Ingesting
more documents can therefore retire a member even while the window is below its 64-member cap.
Use --expect-members on every status check to detect missing members before citing the window.
The exit-only Go document stores the checked process expectation as
producer.processes: {source: "count" | "launched", n}. The command checks exactly n distinct
counter-producing processes before ingest. This preserves the launch-count claim; it is not proof
that a process could not have started and crashed without producing counters. Older and verified Go
documents may not store a process count: cite the ingest receipt when the report warns that this
evidence is absent. LLVM documents expose the number of ingested profiles.
Two diff forms
Section titled “Two diff forms”The existing document comparison stays available:
reflow coverage diff --document <after-document-id> --base <before-document-id> --jsonA UUID base selects that form. It compares documents and reports like-for-like gain or a descriptive comparison. See reading coverage.
Any other base must resolve locally to a commit. This form returns kind: "changed-lines"; without
--json it prints a text summary (warnings first, totals, one line per changed file with its
changed, hit and missed lines), and --json gives the full per-hunk report:
mkdir -p oraclecat > oracle/pathspecs.txt <<'EOF'server/**tunnel/**EOFreflow coverage diff --document A=<server-document-id> --document B=<gateway-document-id> \ --base <base-commit-or-ref> --head <head-commit> \ --paths oracle/pathspecs.txt --exclude '**/*_test.go' \ --report-only 'client/**' --json--head defaults to the documents’ bound commit. All selected documents must have clean, matching
repository, commit, tree and object format, and the checkout must contain those Git objects. At most
16 documents contribute to one report. Each CLI --paths <file> reads a regular UTF-8 file of Git
pathspecs, one per line, and restricts measured paths. Repeat it to combine files. The files may total
at most 1 MiB and contain 1-256 pathspecs altogether, each at most 4096 bytes. LF and CRLF are accepted,
with an optional final newline; blank lines, control characters and symlinks are refused. Spaces and
Git magic such as :!*_test.go are preserved literally: omit shell quotes and comments inside the file.
Missing or malformed files refuse usage; raw inline CLI pathspecs are not accepted. MCP keeps its
inline paths array and never reads these files. With no matching measured changes, the command refuses
no_changes, even when report-only paths changed. A base whose tree equals the head tree (the head
commit itself, or only empty commits between them) instead returns an empty changed-lines report,
exit 0, zero changed lines, and the warning base and head trees are identical; there are no changed lines.
--report-only gets a separate diff, so browser paths can appear even when outside --paths.
Symlinks and submodules are listed as excluded. Hunk selection uses the Myers diff algorithm,
the indent heuristic and zero inter-hunk context regardless of local Git configuration.
Each added or changed head line has one verdict. A line is hit if any covering block in any selected
document has a positive count. It is missed if it has covering blocks and all have zero counts.
A measured file’s comments, declarations and other lines without blocks are notInstrumentable.
A file absent from every document is an explicit gap, never a non-instrumentable line: the report
separates fileNotInDocument from notInBinary (no document contains its package). The latter can
also mean the binary linked the package but the build omitted it from -coverpkg. A file Go
coverage never measures (a _test.go file, or a non-Go file such as CHANGELOG.md, a .sql file
or package.json) is notInBinary for a Go document even beside an instrumented package.
Stored documents do not record GOOS/GOARCH. A file omitted by an OS build constraint is therefore
reported conservatively as fileNotInDocument with reason not_compiled_or_no_statements;
the command does not guess from the local host platform.
The lines totals count changed source lines. The separate statements totals sum canonical block
numStmt values for blocks intersecting changed lines; they are not renamed line counts. They are
null when no Go document is selected or a changed file was judged by LLVM documents; a Go file’s
own statements stay set when Go and LLVM documents are selected together. Per-hunk
arrays and document labels show the hit/miss evidence. Absent files have unknown statement weights,
so statements.notInBinary and statements.fileNotInDocument remain zero; their line gap counts
retain the known evidence. Deleted lines are top-level only, because
head blame cannot attribute removed lines. Batch keys and process evidence accompany each document.
This is process-wide evidence over the selected window; it does not isolate individual flow steps.
A missed line is only “not hit in the selected documents”. When any changed line is missed, the
report adds batchCoverage: for each batch key the selected documents name, the server’s count of
executed runs, the batch’s runs (id, flow, status), the selected labels that name it and any
unselected documents at the same commit, format and producer that name it. state is incomplete
when a batch executed more runs than selected documents name it, or when unselected documents name
it; unknown when the runs cannot be read or a document names no batch; otherwise complete. The
check assumes one document per run (a cover directory bound per flow), so one document holding
several runs’ processes reports a short batch. A warning then leads the report and names the runs
that did not succeed: a failed flow whose processes quit normally still wrote coverage, and it is
often the only one that reached the change. Ingest its cover directory with the same --batch and
select it before treating a missed line as unreached. The check is advisory; read failures become
warnings and never change per-line verdicts.
When any changed instrumentable line is hit in no selected document, the report leads with
untestedChange (the first key after kind) and a first warning that starts untested change:,
naming the count, the files and their line ranges. state is untested when none of the changed
instrumentable lines ran and partly_untested when some did; missed and instrumentable give the
numbers, and files lists every missed run. It is computed over all selected documents, never a PR
row’s document subset. scope is batch only when batchCoverage.state is complete: then no run
of the batch executed those lines, executedRuns counts the runs, and no flow in the review reaches
the change, so a regression there would pass every flow. Otherwise scope is selected_documents
and the claim covers only the selected documents until the batch check is resolved. It is null
when every changed instrumentable line ran. Lines in files absent from every document are reported
as gaps, not counted here.
A changed line in a file no selected document measures (notInBinary) is neither hit nor missed,
so it never produces untestedChange. When any exist, the report adds unmeasuredChange (lines,
the selected document formats and files with each file’s [start, end] runs) and a warning that
starts unmeasured change:, naming the files and saying which languages the selected documents
measure. Coverage cannot say whether any flow ran those lines: a TypeScript dashboard change under Go
documents, for example, is unmeasured, not neutral. Check it with a flow that asserts its visible
result, or reflow evidence diff. fileNotInDocument lines keep their own gapReason and are not
counted here; use --exclude for changed files, such as documentation, that no flow should run.
A hit line only proves that a flow executed it, not that any checkpoint saw what it produced. When
changed lines that ran sit in code that writes state (a call such as Insert..., Emit, Publish,
Audit, log or Exec, an sqlc Insert...Params literal or SQL INSERT/UPDATE/DELETE, in
the enclosing Go, Swift or Objective-C function or one same-file function those lines call), the
report adds unobservedChange and a warning that starts unobserved change (hint, not a verdict):.
functions lists each path, function, changed hit line runs and the write-shaped signals found.
Each function’s source: {side: "head", commit} identifies the exact committed head source;
signalLocations lists each signal and its lines as [start, end] runs in that source.
Signal locations are lexical context: they can be elsewhere in the enclosing function or a same-file
callee, and need not be changed or hit. The text names changed hit lines separately from write-signal
locations, all on the head side;
evidence lists what the batch’s runs retained: runs listed, checkpoint steps by kind (query,
mcp, command, screenshot, accessibility, other) and the runs (named by flow) that retained no checkpoint at all. A wrong
value written there (a row, an event, an audit entry) passes every flow unless a checkpoint reads
it, so name the checkpoint that does and compare it between base and head with
reflow evidence diff, or add one. When runs of the batches failed, timed out or were cancelled,
evidence.failedRuns lists them and the warning names them first, with the step each one ended at
and that step’s error (or the run’s summary when every recorded step passed): a failed assert there
may be the checkpoint that read the written value. Coverage is process-wide, so the report never
says which run executed the changed lines. Detection is lexical and checkpoint contents are not read, so
the lead never claims the output is unobserved; it is null when no changed line that ran writes.
Attribute a review
Section titled “Attribute a review”--attribution <manifest.json> maps PRs to commits and optionally to document labels.
For example:
{ "integration": "<bound-head-commit>", "base": "<recorded-base-commit>", "prs": [{"pr": 7363, "tier": "T3", "commits": ["<pr-commit>"], "documents": ["A"]}]}A PR can instead supply base and head to select its commit range. Commits can belong to only one
PR. Changed lines whose head blame belongs to no listed PR appear in the integration row.
--pr <number> selects emitted PR rows and can be repeated. To support a claim about a flow’s own
window, use one invocation per window, or set each PR’s documents in the manifest. Only those
members can produce that PR’s hit verdicts. --dispositions <file.json> attaches missed-hunk
explanations: a planned flow, unit-tests-only:<test name>, or unreachable-locally:<reason>.
Attribution and disposition inputs must be regular JSON files at most 1 MiB each; symlinks are refused.
A disposition file is an array such as
[{"pr":7363,"path":"server/a.go","start":17,"end":19,"disposition":"unit-tests-only:TestGuard"}].
An omitted disposition remains null in the report and must be resolved before making a tier claim.
Report-only browser hunks need their own assertion evidence.
The local MCP query_code_coverage diff operation accepts the same changed-line inputs as inline
arrays and objects. It does not read manifest or disposition filenames. A hosted connection without
a checkout refuses no_checkout. The changed-line form requires the additive server batch-lines
API: an older server returns server_unsupported; the client does not substitute per-file reads.