Skip to content

Fix the runner's exit codes and record the contract #52

Description

@iderex

Four places in this plan already depend on what the runner returns, and nothing
fixes the set. The first verb exits zero on a clean tree. The refusals exit
non-zero. The hardware harness owes a distinct non-zero result when it was asked
to run and executed nothing. The operator guide has to explain every exit code the
runner can return, which it cannot do while no issue produces the list.

That is the shape of a Done-when pointing at something no issue creates, and it is
cheapest to close before the first workflow reads a status.

Fix a small set and record it.

Zero means the run completed and refused nothing. It does not mean the tree is
good, only that nothing this runner judges was found wrong, and the guide should
say it in those words.

One means the run completed and refused something. This is the ordinary red that a
contributor sees, and it is the only code that carries refusals.

Two means the runner could not do its job. A path that is not a directory, a
record it cannot read at all, an argument it does not understand. Separating this
from one is the whole reason for having more than one non-zero code: a gate that
treats them alike reports a broken invocation as either a clean tree or a
violation, and both readings are wrong in a way nobody investigates.

Three means the run was asked for something and delivered nothing. This is what
the hardware harness needs when it was asked to run and every test skipped. Being
asked for coverage and producing none is a failure of the request even though no
assertion broke.

What was considered and rejected. One non-zero code for everything, rejected
because it collapses a broken invocation into a refusal and the collapse is
invisible: both look like a red check. A larger space modelled on a well-known
tool, rejected because a code nothing returns is a promise, and the operator guide
would then explain outcomes that cannot happen.

Two properties belong in the same change. Every code the runner can return is
reached by a test, so a code that exists only in the document is caught here
rather than by an operator. And no code is added later without superseding this
record, because a workflow keyed on a number is a reader of this contract whether
or not anybody told it so.

The limit belongs at the code. An exit code is a summary and the output is the
evidence. A caller that reads only the number learns that something was refused
and never what, which is why the run says what it examined whatever it returns.

Done when docs/decisions/0011-the-exit-codes.md exists on the default branch
naming each code and what it means, the runner returns exactly those codes, a test
in the default suite reaches every one of them, and the operator guide explains
the codes by pointing at that record rather than restating it.

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationenhancementNew feature or request

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions