Verdicts and exit codes: wiring name checks into a publish pipeline
A gate that blocks a build has to be unambiguous about when it blocks. name-collision gate answers with one of four named verdicts and, in the mode meant to sit in front of a publish step, exactly two exit codes: 0 to proceed, 2 to stop. Nothing about "maybe" ships as a pass.
Four verdicts, two exit codes
Every check resolves to one named verdict, and check mode maps it to a binary outcome a pipeline can act on.
| Verdict | Meaning | check mode |
|---|---|---|
| PASS | no relevant registered or filed mark | exit 0 |
| FLAG | relevant mark, different or unknown Nice class, or dead marks only | exit 0, human reviews |
| FAIL | relevant live mark in an overlapping Nice class | exit 2, blocked |
| INCONCLUSIVE | CIPO unreachable or throttled after a retry | exit 2, blocked |
Check mode: one name, blocking
Check mode gates exactly one proposed name. Run it before that name goes public, and a non-zero exit means stop: `node cli.mjs --name "Harbourline Cafe" --classes 43`. A real-brand name adds one more blocking condition on top of the CIPO verdict: without recorded evidence of the paid OBR search, the gate blocks even on an otherwise clean result, because the required leg was never performed.
Every check, pass or block, writes a JSON evidence bundle to a directory you choose (`collision-evidence/` by default): every expanded query fired, every mark matched, the verdict, the manual checklist lines, and a timestamp. The audit trail exists whether the name passed or not.
Sweep mode: many names, never blocking
Sweep mode is a different job: a batch pass over a manifest of names, meant for reviewing a backlog rather than gating a single ship decision. It reports a verdict for every name and prints a summary tally, and it never exits non-zero on a collision. A human reviews whatever it flags. The only way sweep mode fails the run is a runner error, a manifest that will not parse or has no checks in it, which fails closed by design rather than silently reporting an empty, all-clear sweep.
Why INCONCLUSIVE blocks instead of guessing
An unreachable registry is not evidence of anything. If CIPO cannot be reached after a retry, or returns the throttle-symptom empty body twice in a row, the check comes back INCONCLUSIVE and check mode blocks on it exactly like a FAIL. The alternative, treating a failed lookup as a pass because nothing bad was found, would make network flakiness a way to smuggle an unchecked name through, which defeats the entire point of gating in the first place.
Keep reading, then see the rest of the tooling.
- name-collision gate: what it is
- Why a literal search misses the obvious collision
- The three legs, honestly
- The same pattern for style: de-AI gate in CI
name-collision gate runs today as an internal check in our own publish pipeline. It is not currently published as a standalone open source project.
See the rest of our honesty toolingFAQ
Will it block my pipeline?
In check mode, yes, on a FAIL or an INCONCLUSIVE result (exit 2), and also on a real-brand name missing its required OBR evidence. Sweep mode never blocks; it reports and exits 0 so a human reviews the batch.
What is written to disk on every check?
A JSON evidence bundle: every expanded query fired, every mark matched, the verdict, the manual OBR and MRAS checklist lines, and a timestamp, written to the output directory whether the check passed or blocked.
Why does sweep mode exist if it never blocks?
It is built for reviewing many names at once, a backlog or an existing fleet, where a human needs to see every verdict and decide what to act on rather than having the run halt at the first collision.
Is INCONCLUSIVE treated as risky as a real collision?
For blocking purposes, yes. It shares FAIL's exit code 2 in check mode, because an unreachable registry proves nothing and treating it as a pass would let network trouble quietly wave an unchecked name through.