Skip to content

Completion is gated

Completion is gated

majordomus://rule/majordomus.completion-gates@1active tasksevidencecompletionci

it references

referenced by

Rationale

majordomus.obligation-closure made a task owe what its requires declares, and it made that evidence expire. What it left untouched is everything the validation pipeline knows. A repository's gates — the suites, the linters, the projection checks, the probes — were a property of a pull request and not of a task, so a task could be finished with the crate's own check red, or with the behavioural suite never having been run at all, and the record would say completed.

Two measurements decide the shape of this rule rather than the shape a first draft would take.

A verdict that never arrived reads exactly like one that passed. On 2026-09-10, in the Majordomus repository, where this rule was written, four runs on its trunk had every Linux job finished — five of them red — while three macOS jobs had been queued for between three and seven hours, so the verdict those failures were supposed to reach had not run. The trunk carried the defects overnight with nothing showing red anywhere. majordomus.never-reported-is-not-green states the principle; this rule is where it becomes a status a machine holds, distinct from both pass and unknown.

A gate's own output can be flattered. A coverage gate that counts its test code in its own denominator reports a higher percentage every time tests are added, whether or not anything is better covered. So nothing here reads what a gate printed: it reads the gate's exit status and the hash of the files the gate was run over. That is a claim a worker cannot improve by writing more code.

Required behaviour

Applicability is derived. Which gates a task must pass is computed from the repository's CI model — the gates it declares and the path classes that select them — applied to the task's own change set, which is every path between the commit the task started at and the working tree, uncommitted files included. No list of "source implies tests" is written anywhere: the classes already say which paths select which gates, and a class edited today changes the answer today. A gate the change cannot affect is exempt, which is a different finding from one that cannot be judged.

A gate run is evidence, and it expires. A run is recorded against the task as a ledger line naming the gate, its exit status and the hash of the files that select it — the union of the paths of the classes that name the gate, and everything for a gate every plan selects. The run discharges the gate only while that hash still equals the recomputed one. Evidence that cannot expire is a claim about the past presented as a claim about the present, which is the argument majordomus.obligation-closure already makes about obligations, applied to gates for the same reason.

Only a verdict that was read can back completed. With the outcome completed, a required gate that reported a non-zero exit, one whose run no longer describes the tree, and one that cannot run because something it depends on is in either state, each refuse. So does a checkout that cannot read the verdict at all — a CI model that is declared and does not parse, a reader that is not built, that errors or answers nothing, no jq: that is unknown, and an unknown that let completed through would be a check that passes whenever it cannot look. A repository that declares no CI model has no gate to be unknown about and refuses nothing. A gate that has never reported does not refuse either — the executable did reach that verdict, queued — it is reported as unverified, by name, with the rule that says why silence is not green. An outcome other than completed refuses nothing at all — a task reporting itself blocked is being honest, and refusing that teaches a worker to claim completed instead.

One judgement. The status of every gate is computed once, by the executable, and read by every surface: the command line through check and finish, the HTTP API, MCP, and any dashboard. A surface that recomputes it is how two surfaces come to disagree about whether the same work is finished.

Failure behaviour

A violation is a FAIL finding under the category gate, naming the gate, its status, the reason in the vocabulary above — the exit status it reported, or both hashes when the evidence has gone stale — and the command that would settle it. finish exits 10 and writes nothing. A checkout that cannot reach the judgement at all (an unreadable model, no built reader, a reader that fails) reports unknown by name and refuses completed with that finding; check and every other outcome report it without refusing.

Verification

mj_validate_completion_gates decides it, dispatched from check, finish, reading the gates.completion capability rather than judging for itself. The behavioural case test/cases/131_completion_gates.sh proves the verdicts, and test/cases/578_an_unknown_gate_refuses_completed.sh proves that an unreadable verdict refuses completed and nothing else; CI runs both.

Where this comes from

canonical file
.ai/repo/rules/vendor/majordomus/rules/completion-gates.v1.md
identity
majordomus.completion-gates@1
also served as
MCP resource majordomus://rule/majordomus.completion-gates@1 · majordomus entity show rule/majordomus-completion-gates-1 · GET /api/v1/entity?uri=majordomus://rule/majordomus.completion-gates@1
in the Cockpit
/cockpit/objects/rule/majordomus-completion-gates-1

This page is generated from the file above by scripts/generate-site-data; editing the page changes nothing, editing the file changes every surface. The relations above are edges of docs/generated/graph.json, which the executable writes from the same index.

Searches the titles and descriptions of every page this site publishes.