fix(browser): the console channel sees CSP violations and resource failures - #751
Open
vaibhav8a wants to merge 1 commit into
Open
Conversation
Contributor
Author
|
The Every lost cell is a Worth noting the console cell in the same run went the right way: Happy to re-run if you'd like, but I don't think another attempt tells us anything new. |
…ilures
`reticle_assert({ kind: "console", level: "error", absent: true })`
returned a confident pass on pages visibly full of errors, because two
whole classes of failure never reached this channel at all (reticlehq#666). A
negative check where a dead channel and a clean page read alike is a
false green in the one place the product's claim rests.
**CSP violations are not console calls.** The browser never routes them
through console, so DevTools printed dozens of `font-src` failures while
this channel reported nothing. `securitypolicyviolation` exists precisely
so a page can observe what the browser refused, and it is now listened
for.
**A resource failure fires on the ELEMENT and does not bubble.** The
`error` listener was registered without `capture`, so a broken `<img>`,
`<script>` or `<link>` could not be observed from `window` under any
circumstances -- only uncaught exceptions, which reach `window` directly.
Capture phase is the only way to see an event that never travels upward.
A resource failure is an `Event`, not an `ErrorEvent`: no message, no
filename, and the thing that failed is the target. Reporting it as an
empty-message uncaught error would be worse than not reporting it, so it
is named from the element -- tag plus the URL, read from `src` or `href`
depending on which the element carries. An element error with no URL to
name falls through to the existing path rather than being invented into a
resource event it structurally is not.
The teardown removes each listener with the SAME options it added,
because a capture listener removed without `capture` is not the listener
being removed and would survive teardown.
Not fixed here: the startup blind window, the issue's other half. Grading
an `absent: true` console predicate as undecidable over a window that
starts before the channel was installed needs the install timestamp
carried on the session and read by the grader, which crosses from this
package into the server's honesty engine. It is the larger half and worth
its own review.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Vaibhav Srivastava <vaibhavsri1712@gmail.com>
vaibhav8a
force-pushed
the
fix/console-sees-violations-and-resource-errors
branch
from
September 5, 2026 07:47
4d24acc to
e675d76
Compare
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.
#666 — half 2, the capture gaps. Half 1 is the larger one and I've left it; see the end.
Why this is the worst class of bug we ship
reticle_assert({ kind: "console", level: "error", absent: true })is a negative. A dead channel and a clean page are the same reading, and we graded the dead channel as proof.Two whole classes of failure could never reach this channel:
CSP violations are not console calls. The browser never routes them through
console, so DevTools printed dozens offont-srcfailures while this channel reported nothing.securitypolicyviolationexists precisely so a page can observe what the browser refused.A resource failure fires on the element and does not bubble. The
errorlistener was registered withoutcapture, so a broken<img>,<script>or<link>could not be observed fromwindowunder any circumstances — only uncaught exceptions, which reachwindowdirectly. Capture phase is the only way to see an event that never travels upward.The care that took
Event, not anErrorEvent: no message, no filename, and the thing that failed is the target. Reporting it as an empty-message uncaught error would be worse than not reporting it, so it is named from the element — tag plus URL, read fromsrcorhrefdepending on which the element carries.ErrorEventonwindowstill reports as an uncaught exception, with its message, filename and stack — pinned by a test, because rewritingkaboomintofailed to load windowis the regression this could most easily cause.captureis not the listener being removed, and would survive teardown.Tests
7 new cases in
console.test.ts. 4 of them fail onmain— I checked by stashing the source and re-running:They cover: a
font-srcviolation, a violation with an emptyblockedURI(inline content), an<img>failure, a<link>failure read offhref, an uncaught exception staying an uncaught exception, an element error with no URL, and full teardown.Not in this PR: the startup blind window
Grading an
absent: trueconsole predicate as undecidable over a window that starts before the channel was installed needs the install timestamp carried on the session and read by the grader — it crosses frompackages/browserinto the server's honesty engine, and it changes what a verdict says. It is the larger half and worth its own review. This PR closes the half where the channel was blind by construction.🤖 Generated with Claude Code