Repository navigation
docs: the limits page catches up, and a Linux reader installs without Homebrew (#857, #843) - #878
Merged
Conversation
…alse (#857) `mise run limits:check` had flagged eleven sections whose cited issues closed after anyone last looked. The rule attached to that signal is that a closed issue is not a lifted limit, so each one is read and then either corrected or re-dated — and `tools/docs/limits-acks.py refresh`, which re-dates every section at once, is exactly what #857 exists to prevent. Eleven read. **Three were false**, and the three are worth naming because they are the failure this page is supposed to catch rather than commit. ## "The Exoscale Terraform provider is refused, and why" The heading and its first paragraph said the provider does not work and that the reason is not something this emulator can fix. Terraform and OpenTofu have driven the Exoscale pack since 2026-09-05, from the published v0.71.0, with no fork and no `dev_overrides`. The body already recorded the lifting, eighty lines down. That is the defect: a reader who skims headings got the opposite of the truth, and a measurement buried under a false title is not a measurement anybody finds. Retitled to the floor it actually is, with the refusal kept — a floor is meaningless without what a provider below it does, or a version check reads as friction. ## "Identifiers are not checked against anything" False since #126. `--strict-catalog <file>` refuses a create naming an image, a template or a machine type outside a declared catalogue, in all three packs (`internal/providers/*/strict.go`), and `feint status` prints the declaration so the mode is never silent. A declaration naming a kind no pack checks is itself refused, so a line in that file cannot read as enforced while checking nothing. The default is unchanged and the cost paragraph now says so explicitly: a typo in an image id is still not caught by default, and the reason it is not is still the right one. ## "A run presented as local can still reach the real cloud" Understated rather than wrong, on its most load-bearing row. The Scaleway Object Storage escape was listed as live with a warning, and since #849 it can be closed instead: `feint run` terminates that host itself and refuses any host it was not told about rather than tunnelling it. Measured on provider 2.82.0, host network, no sudo, no namespace: 139,264 identical bytes by sha256, an empty second plan. The section now names two boundaries that do not depend on the client cooperating instead of one, and says plainly what has not changed: it is opt-in, so a client the run was not told about is exactly as free to leave. The default did not become safe; there is now a way to be sure. ## The other eight Read and re-dated, nothing changed. Four had simply never been acknowledged — the two snapshot-import sections (#850, #807), Elastic Metal (#631) and the reply-door measurement (#672) — and they are contemporaneous with the work they describe. Three absorb their cited issues inline already: the route-out section names #660, #684, #694, #696 and #697 in its own text, the DHCP section names #395, and the lifecycle section gained a line for the second opt-out it had not mentioned (the Outscale volume `creating` chain, which is what makes the 409 on a snapshot of a still-creating volume reachable at all). ## What this is not It is not the adoption item. "Is my stack in scope" over a 4,850-line page with no index is #873, opened today and deliberately separate: letting #857 stand in for it is how the reader-facing work disappears. `limits:check` now answers green — 60 sections, 116 issues cited, every one confirmed after it closed. Both READMEs are unchanged: the safety banner counts sections, and the count did not move. Assisted-by: Claude Code (claude-opus-5)
Renaming a heading in `docs/limits.md` breaks every anchor pointing at it, and internal/cli's TestEveryConfidenceRowCarriesItsProof caught the first one before the push: the confidence page linked `limits.md#identifiers-are-not-checked-against-anything`, which no heading produces any more. It also confirmed which of the two documents was stale. That row already read "with \`serve --strict-catalog\`, against the catalogue you declared" — so the confidence page had been right since #126 and `limits.md` was the one denying it, which is the opposite of the direction anybody would check first. Five more references followed, in tools/conformance, examples/stacks, docs/environment.md and both roadmaps. The one under docs/history/ is updated too: that snapshot must not read as the present, and a pointer that no longer resolves is a defect rather than a period detail. Assisted-by: Claude Code (claude-opus-5)
…e replays it (#843) The README's Quick Start opened with `brew install stephrobert/feint/feint`. This project's audience is Linux engineers, and most of them do not run Homebrew: their route was `docs/install.md`, which is correct, forty lines long, needs `cosign`, and sat behind a link. The first wall a stranger met was the install, not the emulator. ## The short route, generated rather than typed Six lines under the Homebrew block, in both locales, pinned to the same version the install page is pinned to — so the two cannot drift, which is why it goes in `renderQuickstart` and not in the README. It still verifies. The bytes are checked against the published `checksums.txt` before anything is installed, because what people reach for when a verified path is long is curl-to-shell, and offering that here would teach it. What the checksum does NOT prove is said rather than implied: it proves the bytes match the list, not who wrote the list. The signature over the list is one step further and stays in the install page. Two details that are not decoration. The architecture is a `case` with a refusal rather than a default, for the reason the install page gives at length: the wrong binary fails at exec with a message naming neither the file nor the machine. And the whole thing is wrapped in `( set -e … )`, because the two ordinary ways to stop a chain are both wrong where this block is read — a bare `return` outside a function is an error in an interactive shell, and a bare `exit` closes the terminal somebody just pasted into. ## The gate, and what it measures that nothing else did `tools/conformance/quickstart.sh` already drives the four commands the README prints, with the binary this repository just built. That proves the code and says nothing about whether a stranger can obtain it. `tools/conformance/released-linux.sh` takes the install commands **out of README.md**, runs them in a throwaway HOME, checks the installed binary reports the version the README pins, and then hands that binary to the quickstart gate. Extraction rather than a copy, for the reason quickstart.sh reads its expected `Apply complete!` line out of the README: a copy is a second source that drifts the day somebody improves the first, and then the gate proves the copy works. It refuses to start if any provider credential is visible. An acceptance that could have reached a real account proves nothing about locality, and asserting that is cheaper than arguing it. Measured here on 2026-11-11 against the published v0.15.0: the block installs, the binary reports 0.15.0, both quickstart stacks apply, both second plans are empty, both come down and the port is silent afterwards. ## Why the workflow is not on pull requests `released-linux.yml` replays a PUBLISHED release. A pull request's README can legitimately pin a version that is not published yet — that is exactly what `feint docs --check` enforces when the CHANGELOG moves — so gating a pull request on it would make every release-preparation branch red by construction. It runs when a release is published, nightly so the route cannot rot between releases, and on demand. It adopts `night-report.yml`, and that was not foresight: `TestEveryScheduledWorkflowReportsOrSaysWhyNot` reddened on this file before the job existed. falsify.yml was killed by its own timeout for twenty-four consecutive nights with nobody told, and that test exists so a new scheduled workflow cannot repeat it. ## What it must never be read as proving The example declares `runtime: mode: off` and nothing overrides it. This proves a control plane, an address and a server the API describes. It proves nothing about Incus or OVN networking, and both the script's last line and the job summary say so rather than letting a green tick imply it. ## The acceptance record #843 asks for the run on a clean, disposable Linux host. That is the workflow's first dispatch, which can only happen once the file is on the default branch — so this change carries the gate and the local measurement, and the clean-host record follows the merge rather than preceding it. mise run prepush green. Assisted-by: Claude Code (claude-opus-5)
5 tasks
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.
Summary
This pull request carries two subjects, and that is worth saying first. #857 (the limits page catching up) and #843 (a Linux reader installing without Homebrew) were committed to the same branch by mistake, and separating them afterwards needs a
reset --hardplus a force-push that this repository's hooks refuse — correctly. They are reviewable apart: the first two commits are #857, the last is #843.They do belong to one goal, which is the next release being consistent: one is the page that states what feint does not do, the other is the first wall a stranger meets.
Part one — #857: eleven flagged sections read, three false
mise run limits:checkhad flagged eleven sections ofdocs/limits.mdwhose cited issues closed after anyone last looked. Eleven were read. Three were false.The rule attached to that signal is that a closed issue is not a lifted limit, so each section is read and then either corrected or re-dated — and
tools/docs/limits-acks.py refresh, which re-dates every section at once, is exactly what #857 exists to prevent.The testplan's own caveat for a documentation diff is the subject of this pull request, word for word: "a document can be wrong in ways no gate reads; three of fifty limits had gone false on 2026-08-27." Three of eleven today.
The three that were false
"The Exoscale Terraform provider is refused, and why" — Terraform and OpenTofu have driven that pack since 2026-09-05, from the published v0.71.0, with no fork and no
dev_overrides. The body already recorded the lifting, eighty lines down, and that is the defect: a reader who skims headings got the opposite of the truth, and a measurement under a false title is not one anybody finds. Retitled to the floor it actually is, with the refusal kept — a floor is meaningless without what a provider below it does, or a version check reads as friction."Identifiers are not checked against anything" — false since #126.
--strict-catalog <file>refuses a create naming an image, a template or a machine type outside a declared catalogue, in all three packs (internal/providers/*/strict.go), and a declaration naming a kind no pack checks is itself refused. The default is unchanged and the cost paragraph now says so explicitly."A run presented as local can still reach the real cloud" — understated on its most load-bearing row. The Scaleway Object Storage escape was listed as live with a warning; since #849 it can be closed instead, and the section now names two boundaries that do not depend on the client cooperating rather than one. It also says plainly what has not changed: the interception is opt-in, so a client the run was not told about is exactly as free to leave. The default did not become safe; there is now a way to be sure.
Which document was stale, and how that was found
internal/cli'sTestEveryConfidenceRowCarriesItsProofreddened on the renamed anchor before the push — and it settled the direction nobody would have checked first. That row indocs/confidence.mdalready read "withserve --strict-catalog, against the catalogue you declared". The confidence page had been right since #126 andlimits.mdwas the one denying it.Six anchors follow the two renamed headings, including the one under
docs/history/: that snapshot must not read as the present, and a pointer that no longer resolves is a defect rather than a period detail.The other eight
Read and re-dated, nothing changed. Four had simply never been acknowledged — the two snapshot-import sections (#850, #807), Elastic Metal (#631) and the reply-door measurement (#672) — and each is contemporaneous with the work it describes. Three absorb their cited issues inline already: the route-out section names #660, #684, #694, #696 and #697 in its own text, and the DHCP section names #395. The lifecycle section gained one line for the second opt-out it had not mentioned, the Outscale volume
creatingchain, which is what makes the 409 on a snapshot of a still-creating volume reachable at all.What this is NOT
It is not the adoption item. "Is my stack in scope" over a 4,850-line page with no index is #873, opened separately and deliberately so: letting #857 stand in for it is how the reader-facing work disappears.
Type of change
Checklist
Always
mise run checkpassesinternal/corestill knows no provider — untouchedmise run testplanwas run, and what it printed was run — it prescribesdocs:checkandlimits:checkfor this diff, both greenWhen a model wrote a substantive part of this
Assisted-by:trailer names the tool and the model versionWhen a route is added or changed
N/A.
When behaviour a client can observe changes
docs/limits.mdupdated — it is the subjectfeint docs --checkpassesWhen
.github/workflows/is touchedN/A.
When a machine runtime is involved
N/A.
Part two — #843: a first Linux apply from the published artefacts
The Quick Start opened with
brew install stephrobert/feint/feint, and this project's audience is Linux engineers who mostly do not run Homebrew. Their route wasdocs/install.md: correct, forty lines, needscosign, behind a link.Six lines now sit under the Homebrew block, generated in both locales from the same version the install page is pinned to, so the two cannot drift. They still verify — the bytes are checked against the published
checksums.txtbefore anything is installed, because what people reach for when a verified path is long is curl-to-shell. What the checksum does not prove is said rather than implied: it proves the bytes match the list, not who wrote the list, and the signature over the list stays in the install page.Two details that are not decoration: the architecture is a
casewith a refusal rather than a default, and the block is wrapped in( set -e … )because a barereturnoutside a function is an error in an interactive shell and a bareexitcloses the terminal somebody just pasted into.tools/conformance/released-linux.shtakes those commands out of README.md and runs them, in a throwaway HOME, then hands the installed binary to the existing quickstart gate. Extraction rather than a copy, for the reasonquickstart.shreads its expectedApply complete!line out of the README. It refuses to start if any provider credential is visible.Measured on 2026-11-11 against the published v0.15.0: the block installs, the binary reports 0.15.0, both quickstart stacks apply, both second plans are empty, both come down, the port is silent.
released-linux.ymlruns on release, nightly and on demand — not on pull requests, because a pull request's README can legitimately pin a version that is not published yet, so gating one on it would make every release-preparation branch red by construction. It adoptsnight-report.yml, and that was not foresight:TestEveryScheduledWorkflowReportsOrSaysWhyNotreddened on the file before the job existed.What it must never be read as proving: the example declares
runtime: mode: off. This is a control plane, an address and a server the API describes. It is not Incus and not OVN, and the script's last line and the job summary both say so.The acceptance record follows the merge. #843 asks for a clean, disposable Linux host; that is the workflow's first dispatch, which cannot happen until the file is on the default branch.
Related issues
Closes #857. Closes #843 once the first clean-host dispatch is recorded on it.
limits:checknow answers green: 60 sections, 116 issues cited, every one confirmed after it closed. It also prints6 issue(s) could not be askedon this run — a network refusal while reading GitHub, and the checker says so rather than treating silence as freshness, which is the third-branch discipline this repository asks of every measurement.🤖 Generated with Claude Code