Skip to content

Nothing this repository commits names a path of the machine it was written on

Nothing this repository commits names a path of the machine it was written on

majordomus://rule/project.no-machine-paths@1active derivedgenerationportabilityreproducibility

Rationale

A repository that names the machine it was written on is a repository that does not read the same anywhere else. This one paid for that twice in a single afternoon, in two different ways, and the second is the instructive one.

The first was an authored document. The reasoning of I0908 — an issue whose own stated purpose is that "no absolute developer path exists anywhere in the image" — named a home directory in prose. It reached plan.json, reached the site, and turned master's deploy red at the moment of publication, billing whoever was deploying rather than whoever wrote it.

The second was a generated artifact. share/allow/*.txt and share/sections/*.txt were committed naming their source schema by the absolute path of the worktree the generator last ran in. The cause was a path helper whose fallback was to emit the absolute path:

path.strip_prefix(root).unwrap_or_else(|_| path.display().to_string())

Share::open canonicalises the share directory; the repository root arrives as it was discovered. When the two spellings differ — one symlinked or firmlinked component is enough, and the macOS temporary directory is exactly that — strip_prefix fails and the fallback writes the generator's own location into a file that is then committed.

Two things let it survive. The helper existed twice, as generate::relative_to and as metadata::rel_or_abs, so fixing one left the other writing the same leak — a repeated semantic definition across projections, which this repository already calls a design defect (ADR 0004). And derive-check is structurally blind to this class: it regenerates in the same checkout and gets the same answer back, so the tree looks current. The banner disagrees only for the next person, in another worktree, where it appears as unexplained drift in a file nobody edited.

Required behaviour

  • No tracked file contains an absolute path naming a home directory or a developer's checkout. Write what the path means — "a developer's working directory" — not an example of one.
  • The rule is one check over the whole tracked tree, not a list of directories. Two pathspec allowlists were tried first and left site/content/ — generated, committed, published — covered by neither.
  • A path a generated artifact records is repository-relative whenever the file it names is inside the repository. A share directory genuinely outside the repository, supplied by --share or MAJORDOMUS_SHARE, keeps its absolute path: that is the only honest answer when no relative one exists.
  • The function that computes a repository-relative path is defined once in the crate. A second copy is a second fallback, and the second fallback is what leaked after the first was fixed.

Two exceptions, both narrow and both necessary. The fixtures under test/ name such a path deliberately, because a gate that cannot be shown to fail is decoration. And the pattern itself is written down once, because something has to: apps/majordomus-cli/src/quality/leak-patterns.tsv, which scripts/ci/no-machine-paths, scripts/site-check and majordomus quality rustdoc all read, so no gate keeps a copy of it that can drift from the others.

Failure behaviour

scripts/ci/no-machine-paths exits 1 and prints every match as file:line:text, under a message that names both faults and their different fixes: an authored document is a wording problem, a generated artifact is a generator problem, and the second is never fixed by editing the file. scripts/ci/core-check runs it as a blocking step, so it fails a commit, a push and CI alike.

scripts/site-check keeps its own private check over the built site. That one stays: it is the last line, it catches whatever reaches publication by a route nobody anticipated, and it costs one grep.

Verification

test/cases/58_home_path_gate.sh runs scripts/ci/no-machine-paths itself rather than re-implementing its grep, and proves each half over a fixture repository: an authored document carrying a home directory fails and its reworded form passes; a generated banner naming its schema by an absolute path fails and its repository-relative form passes; and a file under site/content/ fails, which is the case the two pathspec allowlists missed. It also asserts the gate is wired into scripts/ci/core-check.

apps/majordomus-cli/src/generate.rs holds the single helper and its two unit tests: one resolves a share inside the repository reached by a differently-spelled root, and fails on the previous implementation with an absolute temporary path where a repository-relative one was expected; the other holds the external-share case, so the fix cannot quietly turn an honest absolute path relative.

Where this comes from

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