Living Websites

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.

VerdictMeaningcheck mode
PASSno relevant registered or filed markexit 0
FLAGrelevant mark, different or unknown Nice class, or dead marks onlyexit 0, human reviews
FAILrelevant live mark in an overlapping Nice classexit 2, blocked
INCONCLUSIVECIPO unreachable or throttled after a retryexit 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 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 tooling

FAQ

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.