guard: a window binary with no window in it says so, fails, and stays off stdout - #53
Merged
Conversation
Somebody reports a bug, the fix lands on a branch, and they want to try it before there is a release. Clicking Run workflow builds that branch and leaves the binaries on the run page for fourteen days. Three owner decisions shape it. A choice input, defaulting to the command line binaries only: those cross compile to five platforms on one runner in about two minutes, while the window needs three real runners and CGO. No test gate, because the whole point is speed and the branch has its own CI on its own pull request. And fourteen days rather than the default ninety, because an unsigned binary should not sit for a quarter of a year behind a link somebody can pass on as if it were official. It is deliberately not shaped like a release, so an archive from here cannot be mistaken for one. The name carries the COMMIT rather than the version, and that is not a style choice: internal/version is a const and cannot be stamped at link time, so a build from a fix branch reports whatever version that branch inherited. The file name is the only place that can tell the truth about which code this is. Every archive also carries UNOFFICIAL-BUILD.txt saying the same in words, for whoever unpacks it a month later with no memory of where it came from - not signed, no attestation, and what the version string inside does and does not mean. The note is a script rather than a heredoc because two jobs on four runners write it, and a note that says one thing in one archive and something else in the other is worse than no note. Three guards, five mutations, all caught. The platform list is the one fact this shares with the release, so it is read out of both workflows and compared. A workflow that quietly built four of five platforms would leave somebody's machine unserved, and nothing would say so, because a missing platform looks like a build that did not run. The other two are about the failure mode that matters here, which is a person trusting a file they should not: nothing in this workflow may be granted write, no step may mention a way to publish, and both packaging jobs must write the note - counted rather than found, because one job losing its call would leave the other one proving nothing about it. Measured rather than assumed: the command line loop was run locally against this tree and packaged all five targets in 26 seconds, and the archive holds the binary, the licence, the notices, the readme and the note. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… off stdout internal/gui/gui.go was the only production file in the tree that no guard executed - measured with a coverage map, after subtracting the blocks init() lights up on its own. The gap was not in gui.go: run_nocgo.go carries a four part D6 message and an exit code, and nothing checked that a binary ever produced either. The catalogue guard knows the sentence exists as a text entry, which is a different fact. It cannot be an ordinary test. The guard binary is compiled with cgo, so run resolves to run_cgo.go and calling gui.Run here would try to open a real window. So it builds the binary the way somebody without a C compiler builds it, with CGO_ENABLED=0, and runs it. Measured at 1.7 s, because disabling cgo excludes the toolkit rather than compiling it. Three contracts, and the third had no guard anywhere: the message reaches standard error out of internal/gui/text, the exit code is 1, and standard output stays empty. That last one is on the regression surface for the command line and the window binary is its other half. Two mutations, both caught. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
internal/gui/gui.gowas the only production file in the tree that no guard executed at all - measured with a coverage map, after subtracting the blocksinit()lights up on its own.The gap was not in
gui.go. It was next door:internal/gui/run_nocgo.gocarries a four part D6 message and an exit code, and nothing checked that a binary ever produced either. The catalogue guard knows that sentence exists as a text entry, which is a different fact.Why it cannot be an ordinary test. The guard binary is compiled with cgo, so
runresolves torun_cgo.go, and callinggui.Runfrom a test would try to open a real window. So the guard builds the binary the way somebody without a C compiler builds it -CGO_ENABLED=0- and runs it. Measured at 1.7 s, because disabling cgo excludes the whole toolkit instead of compiling it.Three contracts, and the third had no guard anywhere:
internal/gui/textrather than written twice,Proof. Two mutations, both caught:
return 1becomesreturn 0, and the message goes toio.Discard.gui.gostill reads as unexecuted in the map. That is a limit of the map, not a gap in the guard, and it is written down.Full suite and
preflight --quickgreen locally, all 12 checks.🤖 Generated with Claude Code