Read a root file a document links, which the paths leg could not see - #165
Merged
iderex merged 1 commit intoAug 22, 2026
Merged
Conversation
Closes #162. The invariants leg holds this repository's own documents to the paths they name, and it could not see a file at the root. pathInProse requires a leading segment naming a directory of this tree, so LICENSE, README.md, NOTICE.md, DCO, go.mod and the dotfiles were never read as paths at all, wherever a document wrote them. The leg says at itself that it holds documents to the paths they name and said nothing about the paths it could not see, so a green run over README.md read as every pointer in it resolving, and it was not that. That is the shape of a removal already on this branch's history. README.md linked LICENSE, both left the default branch in one commit, and had only the link survived nothing here would have said so. What separates a path from a word at the root is the parentheses. A name inside a link is somebody saying they expect a file to be there; the same name in a sentence is a word, and a pattern general enough to read A-FILE.md as a path also reads a capitalised word, a version string and the last segment of a URL as one. So the leg gains a second reading rather than a widened pattern: a link target with no directory in it is joined to the directory its own document sits in and resolved, and a bare word is left to the reading that was already there. Joining to the document's own directory rather than to the root is what the tree requires: docs/privacy.md links supply-chain.md and means docs/supply-chain.md. Both readings feed one refusal site, so a document that writes a path in a sentence and links it as well is one dead pointer and is refused once. Proved by deleting it. With the link reading removed and everything else in place: go test ./internal/invariants -count=1 --- FAIL: TestCases/a-document-linking-a-root-file-that-is-not-there invariants_test.go:159: expected refusal not produced: document-names-a-path-that-does-not-resolve Its near neighbour is the same tree with the file added, and the third case is the same names in a sentence rather than in a link. Putting the parentheses around one of those names is what turns that case red, so the two differ by the link alone. One fixture had to change to keep proving what it proves. no-intended-use-notice is a tree with no NOTICE.md whose readme pointed at it, and that readme now names the notice without linking it. The tree it described trips two rules once this one can see it, which is correct behaviour and not something a single-property fixture can carry. The readme half of the notice leg asks that the readme names the notice rather than links it, so the case is unchanged in what it exercises. What this does not do. A link target carrying a directory is left to the pattern that was already there, which reads such a path wherever a document writes it out rather than resolving it against the document's own directory. A target with a scheme in it is somebody else's server and nothing here can say whether a file on one exists. Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
iderex
deleted the
invariants/a-root-file-a-document-links-and-the-tree-does-not-hold
branch
August 22, 2026 04:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #162.
What this changes
The invariants paths leg gains a second reading, and the pattern it already had
is untouched.
pathInProserequires a leading segment naming a directory of this tree, so afile at the root was never read as a path at all, wherever a document wrote it.
The repair is not a wider pattern. What separates a path from a word at the root
is the parentheses: a name inside a link is somebody saying they expect a file to
be there, and the same name in a sentence is a word.
So
check.LinkTargetsWithoutADirectoryreads the markdown link targets that namea file beside the document, the leg joins each one to the directory its own
document sits in, and both readings feed the one refusal site that was already
there. A document that writes a path in a sentence and links it as well is one
dead pointer and is refused once.
Joining to the document's own directory rather than to the root is what this tree
requires rather than a nicety.
docs/privacy.mdlinkssupply-chain.mdand meansdocs/supply-chain.md; resolving that against the root would refuse the file thatis there and pass the one that is not.
What failure it prevents
A green run over
README.mdread as every pointer in that file resolving, and itwas not that. The leg was exact on a path one directory deep and blind on a path
at the root, and the difference was invisible in its output.
That is a removal this branch's own history carries.
README.mdlinkedLICENSE,both went in one commit, and had only the link survived nothing here would have
said so.
The measurement from the issue, run on this branch with one line appended to
README.mdand taken off again afterwards:The proof that it bites
Deleted and watched go red. With the link reading taken out of the leg and
everything else in place:
Three cases, which are the three the issue asks for.
a-document-linking-a-root-file-that-is-not-thererefuses exactlydocument-names-a-path-that-does-not-resolveand no other property.a-document-linking-a-root-file-that-is-thereis its near neighbour, the sametree with the file added, and refuses nothing.
a-root-file-name-in-a-sentence-rather-than-a-linknames the same two files in asentence, neither of them in the tree, and refuses nothing.
The third case earns its place by being one character pair away from a refusal.
Putting parentheses around one of those names turns it red:
internal/check/paths_test.gocovers the arms no fixture reaches: a fragment, ascheme, an address, a target under a directory, a backslash, an empty target and
a parenthetical following a bracketed phrase. Each of those arms fails silently
if it stops working, which is the same outcome as an arm that never existed.
One fixture changed and why
no-intended-use-noticeis a tree with noNOTICE.mdwhose readme pointed at itwith a link. Once the leg can see that link, that tree trips two rules, which is
correct behaviour and is not something a case declaring exactly one property can
carry. Its readme now names the notice without linking it. The readme half of the
notice leg asks that the readme names the notice rather than links it, so the case
still exercises what it always exercised.
What was run
Everything CONTRIBUTING.md names, at
2639376a04a9771cf4d7fe0d99c08db676cd5b9f,with the working tree clean.
The suite was also run with
-v. The integration-hardware harness reports thatit was not asked for and nothing in it ran, which is unchanged by this and is the
ordinary state of a run on this machine.
Read by one pair of eyes
This board has no second reader for this change tonight. The two runs above, the
deletion that reddens the suite and the one-character near miss stand in place of
one.
What this does not do
A link target carrying a directory is left to the pattern that was already there.
That pattern reads such a path wherever a document writes it out and never
resolves it against the document's own directory, so a link from inside
docs/whose target starts with
docs/is read as the path it spells rather than as theplace a reader lands. That is the state this leg was already in and this change
neither widens nor repairs it.
A target with a scheme in it is somebody else's server. Nothing here can say
whether a file on one exists, and a refusal for a document on somebody else's
machine is the annoyance that gets a check switched off.
Nothing about the licence declaration moves.
DeclaredLicenceininternal/invariants/invariants.gois still the empty string and the licence legstill reports that it was not asked, which is #47.