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. The unquoted colon-space advisory is excluded and never gates (see below) | — |
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 unquoted colon-space advisory never gates either. When lint reports a
frontmatter key whose unquoted plain-scalar value contains a colon-space
(#93) it names the key to quote
in the prose report and in --json under result.colon_space_scalars, but
keeps it out of the findings count, so --strict does not escalate it. The
reason is not squeamishness about a new rule, and it is not a claim about YAML’s
quoting rules: a colon-space can appear in plenty of documents that parse
perfectly well, for instance inside a block scalar, where it is ordinary text and
not a key at all. The guarantee comes from the wiring instead. The advisory is
derived only for a file the codec could not parse — convert computes it from
the same recovered flag that produces the invalid frontmatter schema
violation, so the file carrying an advisory is always already reported by that
violation, and that violation does gate under --strict. Counting the
advisory too would gate twice on one defect. Nothing goes unreported; the
advisory only says which key to quote in a file already flagged. Removing that
gate would not be a simplification: it is the whole of the never-gates
guarantee, and without it the rule can name a “key” in a cleanly-parsing file
with no violation to subsume it. result.colon_space_scalars is additive
to binder.report/v1 (the schema string is unbumped).
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