Skip to content

Point a downloaded binary at the file that is beside it - #239

Merged
iderex merged 1 commit into
mainfrom
documents/point-a-download-at-the-file-beside-it
Sep 6, 2026
Merged

Point a downloaded binary at the file that is beside it#239
iderex merged 1 commit into
mainfrom
documents/point-a-download-at-the-file-beside-it

Conversation

@iderex

@iderex iderex commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Closes #235

What this changes

The paragraph the runner prints at the end of lab help, lab version and the
unknown-verb branch named docs/privacy.md and nothing else. Each of the three
documents now carries the two spellings it actually has - the path a checkout
holds and the name a download holds - and the paragraph names both:

NOTICE.md says what this program is for, LICENSE carries the terms it is under,
and privacy.md says what stays on the host. Those are the names beside a
downloaded binary; in a checkout the third one is docs/privacy.md. Reading them
is on you; this text only says where they are.

It is still one string, printed by all three routes, rather than one per layout.
Two spellings that drift apart is the same failure the paragraph itself is
written against, one level up.

No path is removed from the tree. The two files this touches are
cmd/lab/main.go and cmd/lab/main_test.go, and the release workflow is
unchanged: a release asset name cannot carry a directory separator, so the
repair is in the paragraph rather than in the asset name, and renaming the tree
file would move a pointer four other documents here use.

What failure it prevents

An operator holding a downloaded binary is told to read a file in a directory
that is not in front of them. The release publishes the three documents flat, as
separate assets beside the binaries, which is deliberate and is why the fix is
not the obvious one-word edit. Read off the published release rather than off
this tree:

gh api repos/Flowfin/lab/releases --jq '.[0].assets[].name' | grep -v '^lab_'
LICENSE
NOTICE.md
privacy.md
SHA256SUMS
SHA256SUMS.sig
THIRD-PARTY-NOTICES.md

Why this shipped green, which is the part worth reading. The two output
tests asked strings.Contains for each document, and docs/privacy.md contains
privacy.md, so the defective paragraph satisfied both of them for all three
files. A test that cannot tell a paragraph naming both spellings from one naming
only the checkout spelling asserts nothing about the download route.
namesOnItsOwn splits the output into the maximal runs of path bytes and
compares whole tokens instead, so the download spelling has to appear as a path
in its own right.

Two further guards hold that spelling to what is published rather than to an
assumption. One asks that the name beside a binary is the base of the path in
the tree. The other reads the release workflow, because that base is only true
while the workflow copies the documents into the assets directory itself, and it
compares the operands of that copy against the documents this package declares.

What was run

All of it at e02958c0f50bd15e3567d1f92065d374e9bff6e8, the head being pushed,
on Windows.

The guards, proved by breaking each one rather than by reading the code for it.
The old paragraph put back:

go test -count=1 -run NamesTheDocumentsAnOperatorIsOwed ./cmd/lab/
--- FAIL: TestHelpNamesTheDocumentsAnOperatorIsOwed (0.00s)
    main_test.go:273: the help output does not name privacy.md as a path in its own right:
--- FAIL: TestVersionNamesTheDocumentsAnOperatorIsOwed (0.00s)
    main_test.go:301: the version output does not name privacy.md as a path in its own right:

The download spelling mistyped in the declaration:

go test -count=1 -run TestTheDownloadSpellingIsTheNameTheReleasePublishes ./cmd/lab/
--- FAIL: TestTheDownloadSpellingIsTheNameTheReleasePublishes (0.00s)
    main_test.go:322: docs/privacy.md is published beside a binary as privacy.md, and this declaration calls it docs-privacy.md

A document dropped from the release copy, and the same copy sent into a
subdirectory of the assets - both against the workflow, restored afterwards:

go test -count=1 -run TestTheReleaseCopiesTheDocumentsInFlat ./cmd/lab/
--- FAIL: TestTheReleaseCopiesTheDocumentsInFlat (0.01s)
    main_test.go:368: the release copies [LICENSE NOTICE.md] into the assets directory and this package declares [LICENSE NOTICE.md docs/privacy.md]

--- FAIL: TestTheReleaseCopiesTheDocumentsInFlat (0.01s)
    main_test.go:361: no line of the release workflow copies NOTICE.md into "${assets}/", so nothing here publishes the documents beside the binaries

Then the gate, on the restored tree:

go build ./cmd/... ./internal/...
go vet ./cmd/... ./internal/...
gofmt -l cmd internal
(no output)
go test -count=1 -v ./cmd/... ./internal/...
ok  	github.com/Flowfin/lab/cmd/bom	64.796s
ok  	github.com/Flowfin/lab/cmd/contexts	4.339s
ok  	github.com/Flowfin/lab/cmd/lab	15.655s
ok  	github.com/Flowfin/lab/cmd/notices	73.381s
ok  	github.com/Flowfin/lab/cmd/pullrequest	2.877s
ok  	github.com/Flowfin/lab/internal/bom	2.882s
ok  	github.com/Flowfin/lab/internal/check	3.768s
ok  	github.com/Flowfin/lab/internal/contexts	2.998s
ok  	github.com/Flowfin/lab/internal/hardware	2.881s
ok  	github.com/Flowfin/lab/internal/invariants	3.433s
ok  	github.com/Flowfin/lab/internal/notices	3.000s
ok  	github.com/Flowfin/lab/internal/prose	2.947s
ok  	github.com/Flowfin/lab/internal/pullrequest	2.891s

and the walk over this tree:

go run ./cmd/lab check .
examined .
1 experiment directory walked, 1 record read
27 decision records read
the time this run read is 2026-09-06T11:34:17Z
0 refused

The integration-hardware harness was not asked for. That is the disclosure the
-v run prints from internal/hardware, and it is unchanged by this branch.

The means. Go, in the package that already declares the string. The rule is
a property of that declaration, the suite that judges it is beside it, and a
check written anywhere else would need a parallel apparatus to reach a constant
in a command package. No language, runtime or dependency is added.

What this does not do

It does not read a release. The workflow guard reads
.github/workflows/release.yml, so it says what the next run of that workflow
would publish and nothing about what any published release contains. The
evidence above about the existing v0.1.0 assets is a reading of the tracker,
made by hand, and no test here repeats it.

It finds that copy by shape. An assemble step rewritten as a loop, or split
across two commands, reddens TestTheReleaseCopiesTheDocumentsInFlat while the
documents still travel correctly. That is a red gate asking for the test to be
rewritten against the new shape rather than a defect in the release, and the
comment on the test says so where somebody meeting the failure will read it.

It does not judge whether any of the three documents says what it should. That
is a reading of prose and no test here makes one, which is the bound the
existing tests already carried.

It adds no changelog entry. CHANGELOG.md carries one entry per release and has
no unreleased section, and this is text a verb prints, which that file says is
not a contract and is announced there rather than anywhere else. The entry for
the release that carries this belongs to whoever cuts it; there is nothing in
this tree that will remind them, and that is a gap this branch does not close.

There is no second reader on this board tonight. Nothing here reached the
mainline that only its own author has read, in the sense the rule intends, and
this body carries the evidence in place of one rather than implying a review
that did not happen.

The paragraph the runner prints at the end of `lab help`, `lab version` and the
unknown-verb branch named docs/privacy.md. That is where the file sits in a
checkout, and it is not what a download holds: the release publishes the three
documents flat, as separate assets beside the binaries, so somebody who took the
artefact route was sent into a directory that is not in front of them. Read off
the published release rather than off this tree:

    gh api repos/Flowfin/lab/releases --jq '.[0].assets[].name' | grep -v '^lab_'
    LICENSE
    NOTICE.md
    privacy.md
    SHA256SUMS
    SHA256SUMS.sig
    THIRD-PARTY-NOTICES.md

One string still serves both routes rather than two strings drifting apart. Each
document now carries the two spellings it has - the path a checkout holds and the
name a download holds - and the paragraph names both. Two of the three are the
same word twice and only privacy.md is not, which is why a single spelling looked
right for as long as it did.

WHAT A CONTAINMENT TEST COULD NOT SEE IS THE REASON THIS DEFECT SHIPPED GREEN.
The two output tests asked strings.Contains for each document, and
"docs/privacy.md" contains "privacy.md", so the paragraph the issue was raised
against satisfied both of them for all three files. namesOnItsOwn splits the
output into the maximal runs of path bytes and compares whole tokens, so the
download spelling has to appear as a path of its own.

I proved that bites by putting the old paragraph back:

    go test -count=1 -run NamesTheDocumentsAnOperatorIsOwed ./cmd/lab/
    --- FAIL: TestHelpNamesTheDocumentsAnOperatorIsOwed
        the help output does not name privacy.md as a path in its own right
    --- FAIL: TestVersionNamesTheDocumentsAnOperatorIsOwed
        the version output does not name privacy.md as a path in its own right

Two more guards hold the download spelling to what is actually published rather
than to an assumption about it. One asks that the name beside a binary is the
base of the path in the tree, and reddens on a mistyped spelling in the
declaration:

    docs/privacy.md is published beside a binary as privacy.md, and this
    declaration calls it docs-privacy.md

The other reads the release workflow, because the base above is only true while
that workflow copies the documents into the assets directory itself. It compares
the operands of that copy against the documents this package declares, and it
reddens in both directions - a document dropped from the release:

    the release copies [LICENSE NOTICE.md] into the assets directory and this
    package declares [LICENSE NOTICE.md docs/privacy.md]

and a copy that stopped being flat, destination "${assets}/docs/":

    no line of the release workflow copies NOTICE.md into "${assets}/", so
    nothing here publishes the documents beside the binaries

WHAT THAT SECOND GUARD CANNOT SEE is written beside it rather than only here. It
reads a workflow file and not a release, so it says what the next run of that
workflow would publish and nothing about what any published release contains.
And it finds the copy by shape, so an assemble step rewritten as a loop or split
across two commands reddens it while the documents still travel correctly.

The means is the Go this package is already written in, in the file that declares
the string, which fits because the rule is a property of that declaration and the
suite that judges it already exists. A check written anywhere else would need a
parallel apparatus to reach a constant in a command package.

The release workflow is unchanged. The repair is in the paragraph rather than in
the asset name, because a release asset name cannot carry a directory separator
and renaming the tree file would move the pointer every other document here uses.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex iderex added the documentation Improvements or additions to documentation label Sep 6, 2026
@iderex iderex self-assigned this Sep 6, 2026
@iderex
iderex merged commit ae5d7f4 into main Sep 6, 2026
25 checks passed
@iderex
iderex deleted the documents/point-a-download-at-the-file-beside-it branch September 6, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The document pointer names docs/privacy.md, which is not what is beside a downloaded binary

1 participant