ci, web: enumerate the account, reap leaked previews, and fix three 301s onto a 404 - #375
Merged
Merged
Conversation
…rving the ?ref= hole §5.3 closed with a *look* rather than a step: the Cloudflare dashboard's Workers ▸ Routes for both zones, "since nothing in either repo enumerates what is actually deployed". Taking it turned up two things. It never needed the dashboard. The wrangler OAuth token already on the machine carries account:read and workers_scripts, so two REST calls list every Worker and every zone route — a check something can run rather than a thing to remember. And the sheet wasn't clean. Four PR-preview Workers leaked from PRs closed 2026-08-11/12, all of them workers_dev=true and publicly reachable. Two predate the 301 map, so they are copies of the old site Worker: /init.sh answers 200, and ?ref=<a real 40-hex sha> answers 200 with the bootstrap from that ref — the fork-network hole §5.3 recorded as closed. Deleting nebelhaus-init closed the path it was on, not the code; the code lives on in every preview upload of that era, each with its own hostname. preview-web.yml's cleanup job is not at fault — both leaks are its trigger failing to fire, which no pull_request-triggered job can fix. The paths filter is evaluated against the PR's whole diff, so a PR that touched web/** early and not finally deploys a preview and never fires `closed` (nebelhaus-pr-321). And a PR closed in the same operation that deletes its head branch gets no `closed` run at all (nebelhaus-pr-341). So ask the other question, from state: preview-sweep.yml lists the account's Workers daily, asks GitHub whether each <prefix>-pr-<n>'s PR is still open, and deletes the ones that aren't. Anchored name match, so neither production Worker can match; workflow_dispatch takes a dry_run. Verified by driving the extracted job body against the live account in dry-run — it named those four and nothing else — and shellcheck-clean. One thing no merge can fix, left 👤 in §5.3: an api.hausfold.co route pointing at the nebelhaus.com 301 map, declared in no config in either repo, dormant only because that subdomain has no DNS record. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkTBtapKcZTCeTqfhRZEJ7
JulienMartel
temporarily deployed
to
nebelhaus.com / PR #375
August 15, 2026 11:05 — with
GitHub Actions
Inactive
… the code Three published nebelhaus.com URLs have been redirecting onto a 404 since #372 deployed at 10:06Z: /start/what-is-nebelhaus, /start/first-run and /reference/keybindings all pointed at hausfold.co/desktops/hacker/, which is the desktop's old path with its new name substituted in. hausfold.co had retired that tree into the docs hours earlier (hausfold.co#47) — /desktops/ hacker/ is a 404, /desktops/nebelhaus/ is itself a 301 into /docs/haus/desktops/hacker/, and the #keys fragment the keybindings row carried does not exist on any page any more (the ids are what-it-turns-on, first-moves, making-it-yours, where-to-go-next). So: the two desktop rows land on /docs/haus/desktops/hacker/, keeping the #first-moves fragment which is real there. Keybindings follows the ruling hausfold.co already made for the same URL — the keys were a shortened reprint of the windows room and the port deliberately didn't copy them, so it lands on the page that has them rather than on a fragment of the desktop's sheet. The suite stayed green throughout, which is the part worth keeping: it proves the map is complete and points at hausfold.co, and nothing in it fetches, so a destination that 404s is invisible to it. Two tests now pin the renamed rows by hand, and one fails any future row pointing under hausfold.co/desktops/ — that prefix is either a 404 or the second hop this file exists to avoid. Separately, README.md and AGENTS.md picked up "new installs scaffold `haus`" in #372. They don't — haus's bootstrap.sh:567 writes inputs.nebelhaus.url for a fresh install, so a new machine spells it exactly as this one does. That claim is the §11.2 trap dressed as progress: believing the input has half-moved is what leads to finishing it by editing bench's OVERRIDABLE alone, which is the edit that makes every --override-input silently no-op while reporting success. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkTBtapKcZTCeTqfhRZEJ7
JulienMartel
force-pushed
the
worktree-peppy-meandering-dragonfly
branch
from
August 15, 2026 11:06
68605e9 to
af1b43b
Compare
JulienMartel
added a commit
that referenced
this pull request
Aug 15, 2026
…377) Both preview-sweep copies merged and ran 2026-08-15 11:16 UTC, dry-run first then for real. All four leaked Workers deleted; re-enumerating the account leaves nebelhaus, hausfold and one open PR's preview, and the two hostnames that were serving /init.sh?ref=<sha> now 404 — checked against the account and the URLs, not read off the job log. Three things the live run settled that construction alone could not. The keep arm is real: hausfold.co's run had hausfold-pr-49 (an open PR) in front of it and left it alone in both passes, which is the safety property that most needed demonstrating before anyone trusts this on a cron. The CI token can list — the header called Workers Scripts:Read "inference until the first run", and it isn't any more. And preview-web.yml's fast path is fine when it fires: #375's own preview was already gone before the sweep looked, which is the difference between a backstop and a replacement. Production was untouched: hausfold.co 200, nebelhaus.com/guides/pounce still 301s onto the launcher room. Claude-Session: https://claude.ai/code/session_01PkTBtapKcZTCeTqfhRZEJ7 Co-authored-by: Claude Opus 5 (1M context) <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.
What
Two things, both found by taking the one open item §5.3 left — "a look at the Cloudflare dashboard's Workers ▸ Routes for both zones".
.github/workflows/preview-sweep.yml— a daily (+workflow_dispatch, withdry_run) sweep that lists the account's Workers, asks GitHub whether eachnebelhaus-pr-<n>'s PR is still open, and deletes the ones that aren't. hausfold.co gets the same file in its own repo.web/worker.js— three published nebelhaus.com URLs have been 301'ing onto a 404 since rename: dropnebelhaus— decision 10, §11, and the workshop half #372 deployed at 10:06Z today. Fixed, plus two tests that would have caught it.Also:
README.mdandAGENTS.mdpicked up "new installs scaffoldhaus" in #372. They don't —haus'sbootstrap.sh:567writesinputs.nebelhaus.urlfor a fresh install.Why
The look didn't need the dashboard, and it wasn't clean. The wrangler OAuth token on the machine carries
account (read)+workers_scripts, so two REST calls enumerate everything — a check something can run, not a thing to remember. It found:nebelhaus-initnebelhaus.com/*→nebelhausapi.hausfold.co→nebelhausnebelhaus-pr-321/341,hausfold-pr-16/22— all public🚨 The two
nebelhaus-pr-*re-opened the hole §5.3 closed. They predate the 301 map, so they are copies of the old site Worker:…/init.sh→ 200 withbootstrap.sh, and?ref=<a real 40-hex sha>→ 200 with the bootstrap from that ref. Deletingnebelhaus-initclosed the path it sat on, not the code — the code lives on in every preview upload of that era, each with its own hostname.preview-web.yml's cleanup job isn't at fault; all three leak modes are its trigger failing, which nopull_requestjob can fix: thepaths:filter is judged on the PR's whole diff (321 touchedweb/**early, merged onenotes/file); a PR closed in the same operation that deletes its head branch gets no run at all (341); and a closed PR never re-fires, so one transient delete failure leaks forever.The 404s are a narrower lesson: when a rename moves a page, curl the destination — don't derive it by substituting the new name into the old path.
/desktops/hacker/looked right and never existed.Verify
Watch out
nebelhaus,hausfold) nor the sibling's previews can be caught. Clearing all four is therefore two dispatches.api.hausfold.cois account-side and in no config — see §5.3's box for the delete.result_info.total_countagainst what it got and refuses to run on a truncated page, rather than paging speculatively — a silently truncated list is the same "reports clean forever" failure this whole section is about.🤖 Generated with Claude Code
https://claude.ai/code/session_01PkTBtapKcZTCeTqfhRZEJ7