Close the holes the committee found, and stop testing the file's prose - #74
Merged
Conversation
Three reviewers, three lenses, and between them the first version promised more than it delivered. Copilot measured the scope in a real browser: five files were still a single request each, and a 503 on any of them showed no panel at all. One of those was new — with autostart="false" set and the retry living in boot.js, a 503 on boot.js itself meant nothing ever started. That was a regression this PR introduced, so it is fixed here rather than filed. The panel and a watchdog now live inline in index.html. Inline because the one failure an external file can never explain is its own. The watchdog fires when nothing has advanced for 45 s, not on a deadline, so a cheap phone on a bad connection is still allowed to be slow; it covers the runtime's ES modules, which must be handed back as a URL and so can never be retried, and a connection that accepts and then hangs. Each fetch now has its own 25 s abort, because a hung request consumed no attempt and reached no panel. The failure state is per download. Kept per module, a file that failed once and then recovered was named as the cause of a later, unrelated startup error — found by executing it, not by reading. DeepSeek read the copy and found the panel saying more than it knows. "Almost always a passing server fault" is not a frequency we failed to measure, it is one we can never measure: the panel exists precisely when the app never started, and this project does not phone home. Gone, along with exonerating a browser that a school VPN has already disproved once, and a privacy assurance answering a question nobody asked — the reader has not typed anything yet. The panel now offers the desktop app by absolute URL, because every route on this site is served by the page that just failed, and it says to copy the technical detail when reporting. It also honours the language the reader chose, which persists in localStorage and outlives the failed startup. The tests are behaviour now. The old ones searched this file's text, and every one of them could be satisfied by a comment or by dead code — `void undefined;` passed the test guarding the ES-module exclusion while breaking every module load. tests/boot/boot.test.mjs runs the real boot.js against a fake network, and each guarantee was checked by reintroducing the bug it guards: dropping the integrity handoff, fetching the ES modules, and the original misattribution are all detected. What stays in C# is the wiring those cannot see, asserted against source with comments stripped. Verified in a browser for all five scenarios: a healthy load, a 503 on boot.js, on the Blazor script, on a runtime module, and on an assembly. All five now explain themselves; four of them previously did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF
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.
Follow-up to #73, which merged while this was being written — so what is deployed right now is the first version, and it carries a regression this PR removes.
Three reviewers, three lenses. Between them, #73 promised more than it delivered.
The regression first, because it is live
With
autostart="false"set and the retry living inboot.js, a 503 onboot.jsitself means nothing ever starts. Before #73 that file did not exist and Blazor started itself. That is one case where the deployed build is worse than what preceded it, and it is the reason this should not wait.What the committee found
Copilot measured the scope in a real browser rather than arguing about it. Five files were still a single request each, and a 503 on any of them produced no panel at all:
It also executed the misattribution: failure state kept per module meant a file that failed once and recovered was named as the cause of a later, unrelated startup error.
Fable verified the security stance holds — a returned Promise short-circuits the runtime before it sets integrity of its own, so handing the manifest hash to
fetchis not hygiene, it is the entire check — and killed the service-worker alternative on grounds specific to this project: a pinned app keeps serving yesterday's published false-positive rate, when publishing today's is the whole claim.DeepSeek read the copy and found the panel saying more than it knows.
What changed
The panel and a watchdog now live inline in
index.html. Inline because the one failure an external file can never explain is its own. The watchdog fires when nothing has advanced for 45 s rather than on a deadline, so a cheap phone on a bad connection is still allowed to be slow. It covers the runtime's ES modules — which must be handed back as a URL and so can never be retried — and a connection that accepts and then hangs. Each fetch also gets its own 25 s abort, since a hung request consumed no attempt and reached no panel.Failure state is per download, which is the misattribution fixed.
The copy no longer claims what it cannot know. "Almost always a passing server fault" is not a frequency we failed to measure — it is one we can never measure: the panel exists precisely when the app never started, and this project does not phone home. Gone too: exonerating a browser that a school VPN has already disproved once, and a privacy assurance answering a question nobody asked, since the reader has not typed anything yet. The panel now offers the desktop app by absolute URL — every route on this site is served by the page that just failed — tells the reader to copy the technical detail when reporting, and honours the language they chose, which persists in
localStorageand outlives the failed startup.The tests are behaviour now
The old ones searched the file's text, and every one could be satisfied by a comment or by dead code:
void undefined;passed the test guarding the ES-module exclusion while breaking every module load.tests/boot/boot.test.mjsruns the realboot.jsagainst a fake network, in CI. Each guarantee was checked by reintroducing the bug it guards — dropping the integrity handoff, fetching the ES modules, and the original misattribution are all detected. What stays in C# is the wiring those cannot see, asserted against source with comments stripped.Verified in a browser, all five scenarios
js/boot.jsblazor.webassembly.jsAlso verified: browser in
en-USwith the app set to Spanish now gets a Spanish panel.332 C# tests + 11 boot tests.
🤖 Generated with Claude Code
https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF