Skip to content

A session does not finish behind its own published site

A session does not finish behind its own published site

majordomus://rule/majordomus.publication-currency@1active taskscompletiondeploymentevidence

it references

referenced by

Nothing in the layer names it. Backlinks are derived, so an empty list is an answer rather than an omission.

Rationale

majordomus.completion-gates made the validation pipeline's verdict a property of the task rather than of a pull request. It derives which gates apply from the change set's own paths, which is the right derivation for every gate that measures a tree — and it is structurally incapable of reaching the ones that do not.

A repository that publishes has two trees. There is the one in the checkout, which every gate in the model examines, and there is the one the public is actually being served, which none of them can see. The second is not a function of the first: it is a function of whether a deployment ran, whether it ran to completion, whether the hosting provider's own build of what was pushed succeeded, and whether anything has landed since. No edit to any file can make that question come out differently, so a path class can never select the gate that asks it, and a gate in no class is asked only by a full plan — which, in a repository that plans its full run on a push to its trunk, runs before the publication it would judge.

The result is a question nobody owns. Three instances measured in the Majordomus repository, where this rule was written, each of which left every commit-level check green:

  • an unmerged ref served as the public site for about half an hour, noticed by a person's eye;
  • twenty pull requests landed in one afternoon and the site sat hours behind the trunk;
  • the hosting provider's own build of a correctly pushed commit errored, and the previous commit was served for 27 minutes.

The moment this question is worth asking is not when a file changes. It is when a worker says the work is done, because "done" and "the public cannot see it" is the contradiction the finish contract exists to refuse.

Why this is measured and not recorded. majordomus.completion-gates discharges a gate with a ledger line carrying the hash of the files the gate was run over, and the run stops counting when that hash changes. That mechanism cannot hold this verdict, because its subject is not in the tree: a publication check run ten minutes ago describes a site that may have been superseded since, with every file in the repository untouched. Evidence whose subject can change without the tree changing has no hash to expire against, so it is not stored. The gate is run, live, at the moment of the claim.

Required behaviour

The CI model declares which gates measure a deployment. A gate with at-finish: true is one of them. Nothing is hardcoded here: a repository that publishes nothing marks no gate, and the requirement then has nothing to run and says so.

The policy selects the requirement. publication_current in verification.finish_requires is what turns it on, like every other line of the contract.

finish asks it, and check does not. check is run often and cheaply, and this gate reaches the network and waits for a CDN; making it part of every check would be a slow, flaky check, which is a check people stop running. The session-end hook writes a handover rather than a finish, so a session that hands over is never asked either — for the same reason an honest blocked is not: handed_over is a claim about unfinished work, and this requirement is about a claim that the work is done.

Only the outcome completed is refused. A task reporting itself partial, blocked, failed or no_match is being honest about unfinished work, and refusing that teaches a worker to claim completed instead — the argument majordomus.completion-gates already makes, applied here unchanged.

A verdict that could not be reached is reported, never inferred. The gate distinguishes "the publication is not current" from "I could not find out" — no network, no published branch, no hosting API. The first refuses. The second is reported by name, with its exit and reason, and refuses completed too: a session on a train is not evidence that the site is stale, but completed claims it is current, and a requirement that passes whenever it cannot measure is decoration. It is never reported as the first, and an honest partial or blocked is never refused over it. Silence is not green; it is named — the argument the Majordomus repository states as project.never-reported-is-not-green, which the package cannot depend on because a vendored rule must resolve inside the package it ships in.

Failure behaviour

A violation is a FAIL finding under the category gate, naming the gate, the command that was run and the reason the gate gave — which commit is published, which commit is on the trunk, how long the publication has been owed. finish exits 10 and writes nothing, so the task stays active and the record never says completed. The remediation is the deployment, not a flag.

Verification

mj_validate_publication_currency decides it, dispatched from finish, reading the gates the CI model marks at-finish and running each one. test/cases/275_publication_is_current.sh proves it against fixture repositories whose gate scripts are written by the case: one that exits 0, one that exits 10, one that exits 12 (refused, and named as unreachable), one that declares no such gate, and one finishing with an outcome other than completed; test/cases/578_an_unknown_gate_refuses_completed.sh proves the unreachable refusal beside the completion-gates reader's.

Where this comes from

canonical file
.ai/repo/rules/vendor/majordomus/rules/publication-currency.v1.md
identity
majordomus.publication-currency@1
also served as
MCP resource majordomus://rule/majordomus.publication-currency@1 · majordomus entity show rule/majordomus-publication-currency-1 · GET /api/v1/entity?uri=majordomus://rule/majordomus.publication-currency@1
in the Cockpit
/cockpit/objects/rule/majordomus-publication-currency-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.