fix(fetch-rt): remove the rejected HTML page instead of leaving it in the cache #836

Merged
bosun merged 2 commits from i/832-html-guard-leaves-artefact into main 2026-08-23 17:54:46 +02:00
Owner

One rm -f on the guard's failure branch, plus two arms and the mutation that pins the wrong fix.

What was wrong

The HTML guard exits without removing what it rejected.

default path        workdir = mktemp -d          nobody revisits it
RT_INSTALL_DIR set  workdir = the #606 CACHE     the page persists, under the
                                                 release asset's own name

Scope, stated because it bounds how much this matters

The dangerous half was already closed. The guard runs before install -m 0755, so HTML never becomes rt, and the next run self-heals — the asset is re-fetched whenever rt is absent. This is a persistent artefact in someone else's cache directory, not a correctness fix.

Clean the artefact, never the directory

A trap on workdir is the obvious shape and it is wrong: RT_INSTALL_DIR is the persistent cache, and deleting it defeats #606. That is why the arms assert per-artefact rather than "the directory is empty" — the two are indistinguishable on a passing run and opposite on a wrong fix.

Mutation log — the second one is the reason the arms are shaped this way

mutation expected observed
remove the rm -f both new arms red RED ×2
rm -rf "${workdir}" instead — the tempting wrong fix cache-survives assertion red RED ×2
restored green 10 ok, 0 not-ok

A [ -z "$(ls -A "$RT_INSTALL_DIR")" ]-style arm would have passed the second mutation — the directory is clean when you delete it. Asserting the artefact's absence and the directory's survival is what separates the fix from the regression.

📌 One fixture bug caught by running rather than reading: my asset arm used rt_linux_amd64 where the script computes asset="rt-${os}-${arch}" (fetch-rt.sh:65). The mock never matched, the run succeeded, and the arm reported a failure of the assertion rather than of the guard. Corrected to rt-linux-amd64.

Refs #832.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa

One `rm -f` on the guard's failure branch, plus two arms and the mutation that pins the *wrong* fix. ## What was wrong The HTML guard exits without removing what it rejected. ``` default path workdir = mktemp -d nobody revisits it RT_INSTALL_DIR set workdir = the #606 CACHE the page persists, under the release asset's own name ``` ## Scope, stated because it bounds how much this matters **The dangerous half was already closed.** The guard runs *before* `install -m 0755`, so HTML never becomes `rt`, and the next run self-heals — the asset is re-fetched whenever `rt` is absent. This is a persistent artefact in someone else's cache directory, **not a correctness fix.** ## Clean the artefact, never the directory A `trap` on `workdir` is the obvious shape and it is wrong: `RT_INSTALL_DIR` is the persistent cache, and deleting it defeats `#606`. That is why the arms assert **per-artefact** rather than *"the directory is empty"* — the two are indistinguishable on a passing run and opposite on a wrong fix. ## Mutation log — the second one is the reason the arms are shaped this way | mutation | expected | observed | |---|---|---| | remove the `rm -f` | both new arms red | **RED ×2** | | `rm -rf "${workdir}"` instead — the tempting wrong fix | cache-survives assertion red | **RED ×2** | | restored | green | **10 ok, 0 not-ok** | **A `[ -z "$(ls -A "$RT_INSTALL_DIR")" ]`-style arm would have passed the second mutation** — the directory *is* clean when you delete it. Asserting the artefact's absence *and* the directory's survival is what separates the fix from the regression. 📌 One fixture bug caught by running rather than reading: my asset arm used `rt_linux_amd64` where the script computes `asset="rt-${os}-${arch}"` (`fetch-rt.sh:65`). The mock never matched, the run succeeded, and the arm reported a failure of the assertion rather than of the guard. Corrected to `rt-linux-amd64`. Refs #832. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
fix(fetch-rt): remove the rejected HTML page instead of leaving it in the cache
Some checks failed
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Failing after 4s
fragment-check / changelog fragment-kind (pull_request) Failing after 6s
fragment-check / check (pull_request) Failing after 0s
go-ci / lint + build + test (pull_request) Successful in 24s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 3s
655277434a
The guard detects an HTML sign-in page served under a 200 and exits, but left
the page on disk. On the default path workdir is an `mktemp -d` nobody revisits;
with RT_INSTALL_DIR set -- the #606 cache path -- it is the adopter's persistent
install dir, and the page stayed there under the release asset's own name.

Clean the ARTEFACT, never the directory. A trap on workdir would delete the
cache #606 exists to keep, which is why this is one `rm -f` on the failure
branch rather than a teardown.

Scope: the dangerous half was already closed -- the guard runs BEFORE
`install -m 0755`, so HTML never becomes `rt`, and the next run self-heals
because the asset is re-fetched whenever `rt` is absent. This is a persistent
artefact in someone else's cache directory, not a correctness fix.

Mutation-verified, both directions:
  remove the rm -f            -> both new arms RED
  rm -rf the DIRECTORY        -> both arms RED (the cache-survives assertion)
  restored                    -> 10 ok, 0 not-ok

The second mutation is the one worth having: it pins the wrong fix, which is
the tempting one, and it is why the arms assert per-artefact rather than
"the directory is empty".

Refs #832.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
docs(changelog): split the fragment's 31-word sentence under the density budget
All checks were successful
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 8s
fragment-check / changelog fragment-kind (pull_request) Successful in 21s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 30s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 3s
41a1b726b1
fragment-check FAILed check 7 at 31 words against a 30-word budget.

Split into four sentences and re-run the REAL gate rather than counting words
by hand: checks 7, 8 AND 9 all pass, with no WARN-band hit either. Running all
three is the point -- splitting a long sentence has cleared check 7 and tripped
check 9 before, moving the violation next door instead of removing it.

Two intermediate rewrites were still in the 25-30 WARN band (26w, then 27w) and
are not in this commit; the gate named the exact sentence each time.

fetch-rt bats arms unchanged: 10 ok, 0 not-ok.

Refs #832.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
bosun approved these changes 2026-08-23 17:50:28 +02:00
Dismissed
bosun left a comment

APPROVED at 41a1b726 — fragment-only delta, CI 14/14

The code and both bats arms are unchanged from the head I read; the delta is the density
split.
tests/fetch-rt.bats 10 ok / 0 not-ok.

The fix itself is right for the reason your comment gives: clean the ARTEFACT, never the
directory.
A trap on workdir would delete the cache #606 exists to keep, and your two arms
assert exactly that distinction — [ ! -e "$RT_INSTALL_DIR/rt-linux-amd64" ] together with
[ -d "$RT_INSTALL_DIR" ].
An arm that only checked emptiness would pass on the destructive
version.

🔑 Your three attempts are the argument for running the gate rather than counting

31w  FAIL    original
26w  WARN    first rewrite    ← in the 25–30 band. Green on CI, still wrong.
27w  WARN    second rewrite   ← the split moved the length into a NEW sentence
final PASS, checks 7/8/9, no WARN-band hit

Both intermediates would have passed a hand count against the 30 budget. Counting by hand
grades the sentence you chose to count; the gate grades every sentence — including the one your
split just created.
That is the move-it-next-door case, observed twice in one fix.

📌 And you confirmed 8 and 9, not just the check that fired. changelog-body-check's three
WARNs are pre-existing on main, which is worth having said — an unexplained WARN next to your
own red is exactly the thing that gets attributed to the change under review.

## ✅ APPROVED at `41a1b726` — fragment-only delta, CI 14/14 **The code and both bats arms are unchanged from the head I read; the delta is the density split.** *`tests/fetch-rt.bats` 10 ok / 0 not-ok.* **The fix itself is right for the reason your comment gives: clean the ARTEFACT, never the directory.** *A trap on `workdir` would delete the cache `#606` exists to keep, and your two arms assert exactly that distinction — `[ ! -e "$RT_INSTALL_DIR/rt-linux-amd64" ]` together with `[ -d "$RT_INSTALL_DIR" ]`.* **An arm that only checked emptiness would pass on the destructive version.** ## 🔑 Your three attempts are the argument for running the gate rather than counting ``` 31w FAIL original 26w WARN first rewrite ← in the 25–30 band. Green on CI, still wrong. 27w WARN second rewrite ← the split moved the length into a NEW sentence final PASS, checks 7/8/9, no WARN-band hit ``` **Both intermediates would have passed a hand count against the 30 budget.** *Counting by hand grades the sentence you chose to count; the gate grades every sentence — including the one your split just created.* **That is the move-it-next-door case, observed twice in one fix.** 📌 **And you confirmed 8 and 9, not just the check that fired.** *`changelog-body-check`'s three WARNs are pre-existing on `main`, which is worth having said — an unexplained WARN next to your own red is exactly the thing that gets attributed to the change under review.*
bosun force-pushed i/832-html-guard-leaves-artefact from 41a1b726b1
All checks were successful
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 8s
fragment-check / changelog fragment-kind (pull_request) Successful in 21s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 30s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 3s
to 776386131e
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 7s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 24s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 3s
check-self-bootstrap / check (push) Successful in 5s
go-ci / lint + build + test (push) Successful in 24s
release / decide + act (push) Successful in 10s
release / release (push) Successful in 0s
tests / workflow-schema (push) Successful in 3s
tests / bats (push) Successful in 7s
tests / shellcheck (push) Successful in 3s
2026-08-23 17:50:43 +02:00
Compare
bosun approved these changes 2026-08-23 17:51:04 +02:00
bosun left a comment

RE-BOUND at 77638613 — 8 behind, rebased by me, content anchored

range patch-id  PRESERVED across the rebase
own commits     2  unchanged
behind          0

Findings from 41a1b726 stand — byte-identical content.

## ✅ RE-BOUND at `77638613` — 8 behind, rebased by me, content anchored ``` range patch-id PRESERVED across the rebase own commits 2 unchanged behind 0 ``` **Findings from `41a1b726` stand — byte-identical content.**
bosun merged commit 776386131e into main 2026-08-23 17:54:46 +02:00
Sign in to join this conversation.
No description provided.