Strict mode
By default binder is never-reject: advisories are reported but exit 0.
--strict opts a single run into promoting advisories to gating findings
(exit 1), so CI can fail the build on conditions that are informational
locally. Each command promotes its own advisory set, listed in the table below.
The read-boundary normalization advisory is carved out of those sets: it is
reported and does not gate, on enrich or on convert. On a run that reports,
the flag changes only the exit code — the report (prose or JSON) is
byte-identical with and without the flag — and in no case does it affect any
other run.
The per-command contract:
| Command | --strict gates (exit 1) on |
Always gates, regardless |
|---|---|---|
validate |
trust advisories (malformed trust, actor-convention, date-shape warnings) | spec §11 hard non-conformance (unparseable frontmatter, missing/empty type) |
review |
any review finding: orphans, stale concepts, unresolved links, unparsed-frontmatter recoveries | — |
lint |
any lint finding: broken links, missing titles, orphans, stale, schema violations | — |
convert |
unresolved links, recovery warnings, or non-conformant --status-map status values |
— (a clean run is exit 0 even under --strict) |
enrich |
skipped (unparseable-frontmatter) files, preserve-or-advise findings, or non-conformant --status-map status values. The read-boundary normalization advisory is excluded and never gates (see below) |
— (a clean run is exit 0 even under --strict) |
infer |
any warning or inference failure (in practice, Gemini-tier warnings — the deterministic tiers do not warn) | — |
The read-boundary normalization advisory never gates. When enrich strips a
leading UTF-8 BOM or translates a lone CR before recognising the frontmatter
(#124), it reports that on two
channels, neither of them optional: an advisory: line in the prose report, and
in --json a per-file normalized signal plus a top-level
result.normalizations entry. That entry discloses what binder did to the
input; it is not a finding about the corpus, so enrich keeps it out of the
findings count and --strict does not escalate it
(#154). A run whose only finding
is that advisory exits 0 with or without the flag. A skipped file or a
preserve-or-advise warning in the same run still exits 1 under --strict, and
the advisory contributes nothing to that count. result.normalizations is
additive to binder.report/v1 (the schema string is unbumped) and is omitted
when nothing was normalized. convert normalizes at the same read boundary and
reports its own read-boundary advisory, which does not gate either; see the
convert row above for what convert --strict does gate on. Bound 6 of
Residual bounds under enrich covers
what the normalization does to the bytes.
The --status-map vocabulary gate is the one that fires before anything is
written: convert --strict exits 1 without creating the output directory, and
enrich --strict exits 1 without touching a single source file. Adding
--canonicalize-status resolves a known alias and the run returns to exit 0.
See Status vocabulary and --canonicalize-status.
--strict is available on validate, review, lint, convert, enrich, and
infer. A clean run stays exit 0 even with --strict set, so the flag is safe
to leave on permanently in CI. index, graph, and config have no advisory
surface and do not take it.
# Fail CI on any unresolved link or recovered file, not just spec violationsSOURCE_DATE_EPOCH=1700000000 binder convert docs/ -o build/bundle --strictbinder validate build/bundle --strictbinder review build/bundle --strict# Fail CI on source-corpus health before conversionbinder lint docs/ --strict