In tests/e2e/network.js the guard reporting unrecognised POST bodies ended in batch.every(...). Array.prototype.every is vacuously true on an empty array,
so a POST with body [] was fulfilled with 200 [] instead of being reported.
That is a hole in the one mechanism whose entire job is to make unrecognised
outbound traffic fail the suite rather than pass silently.
The fix is one clause: batch.length === 0 is now rejected alongside the
existing checks. No real JSON-RPC batch is empty, so nothing legitimate is
caught by it. The guard got stricter; nothing was loosened, and ALLOWED_ERRORS
is still []. TRAILING_WATCH_MS and the interception canary were not touched.
Demonstrated by execution
A throwaway probe (four tests, each firing one POST the harness does not stub,
asserting nothing — the run itself is the assertion) was added, both runs
captured, then the probe removed.
GREEN BEFORE — [] sails through:
ok 27 - ConfirmTx reports a failed ERC-20 estimate as unknown, not as a fee problem (#238)
# probe [] -> fulfilled
ok 28 - PROBE empty-array batch []
# probe bodyless -> rejected: Failed to fetch
not ok 29 - PROBE bodyless POST
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe scalar -> rejected: Failed to fetch
not ok 30 - PROBE scalar JSON body
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe [null] -> rejected: Failed to fetch
not ok 31 - PROBE [null] batch
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# 28/31 tests passed
# FAILED
RED AFTER — same probe, same run, with the fix:
ok 27 - ConfirmTx reports a failed ERC-20 estimate as unknown, not as a fee problem (#238)
# probe [] -> rejected: Failed to fetch
not ok 28 - PROBE empty-array batch []
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe bodyless -> rejected: Failed to fetch
not ok 29 - PROBE bodyless POST
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe scalar -> rejected: Failed to fetch
not ok 30 - PROBE scalar JSON body
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe [null] -> rejected: Failed to fetch
not ok 31 - PROBE [null] batch
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# 27/31 tests passed
# FAILED
# probe [] -> fulfilled becoming rejected: Failed to fetch, and ok 28
becoming not ok 28 with network: unstubbed request: POST, is the whole
change.
Siblings still report
Visible in both captures above: bodyless POST, scalar JSON body and [null] batch are reported and fail in the before run and in the after run
alike. No regression.
Legitimate stubbed calls unaffected
Tests 1-27 stayed green throughout, including the ConfirmTx section whose
fixtures widened the RPC stub (eth_getBlockByNumber for any block parameter, eth_getCode). Nothing legitimate started being reported as unstubbed.
The corrected comment
The old comment claimed postData() returns null for a body Playwright cannot
decode as UTF-8, citing sendBeacon with a Blob. That is wrong. playwright-core@1.56.0 (lib/client/network.js:89) does buffer.toString("utf-8") || null, so a binary body is decoded lossily into
mojibake rather than yielding null. The guard was load-bearing either way, but
for a different reason than stated. It now reads:
// Anything that is not a JSON-RPC object, or a NON-EMPTY batch of
// them, is not RPC at all and must be reported like any other
// unrecognised outbound traffic rather than dereferenced.
//
// The length check is not decoration: every() is vacuously true on an
// empty array, so without it a POST with body [] was answered 200 []
// and escaped the guard entirely (issue #187). No real batch is empty,
// so nothing legitimate is caught by it.
//
// Two distinct paths land a non-RPC body here, and neither is an
// empty-string special case. playwright-core's postData() is
// `buffer.toString("utf-8") || null`, so an absent or empty body
// decodes to null, JSON.parse("null") yields null, and the type guard
// below reports it. A binary body is instead decoded LOSSILY into
// mojibake — not null — which is not valid JSON, so the catch above
// reports that one. Both end up reported; only the route differs.
Verification
make check: green. 25 test suites, 576 tests passed; test-verify-build
18 cases passed; prettier --check . clean.
make test-e2e: green, # 27/27 tests passed, run after the probe was
removed and after the rebase onto next.
make fmt run; git status clean before committing. Rebased onto origin/next at 5af89a1 immediately before pushing.
Change is confined to tests/e2e/network.js (plus the TODO.md entry).
Closes [#187](https://git.eeqj.de/sneak/AutistMask/issues/187).
## The hole
In `tests/e2e/network.js` the guard reporting unrecognised POST bodies ended in
`batch.every(...)`. `Array.prototype.every` is vacuously true on an empty array,
so a POST with body `[]` was fulfilled with `200 []` instead of being reported.
That is a hole in the one mechanism whose entire job is to make unrecognised
outbound traffic fail the suite rather than pass silently.
The fix is one clause: `batch.length === 0` is now rejected alongside the
existing checks. No real JSON-RPC batch is empty, so nothing legitimate is
caught by it. The guard got stricter; nothing was loosened, and `ALLOWED_ERRORS`
is still `[]`. `TRAILING_WATCH_MS` and the interception canary were not touched.
## Demonstrated by execution
A throwaway probe (four tests, each firing one POST the harness does not stub,
asserting nothing — the run itself is the assertion) was added, both runs
captured, then the probe removed.
**GREEN BEFORE** — `[]` sails through:
```
ok 27 - ConfirmTx reports a failed ERC-20 estimate as unknown, not as a fee problem (#238)
# probe [] -> fulfilled
ok 28 - PROBE empty-array batch []
# probe bodyless -> rejected: Failed to fetch
not ok 29 - PROBE bodyless POST
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe scalar -> rejected: Failed to fetch
not ok 30 - PROBE scalar JSON body
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe [null] -> rejected: Failed to fetch
not ok 31 - PROBE [null] batch
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# 28/31 tests passed
# FAILED
```
**RED AFTER** — same probe, same run, with the fix:
```
ok 27 - ConfirmTx reports a failed ERC-20 estimate as unknown, not as a fee problem (#238)
# probe [] -> rejected: Failed to fetch
not ok 28 - PROBE empty-array batch []
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe bodyless -> rejected: Failed to fetch
not ok 29 - PROBE bodyless POST
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe scalar -> rejected: Failed to fetch
not ok 30 - PROBE scalar JSON body
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# probe [null] -> rejected: Failed to fetch
not ok 31 - PROBE [null] batch
uncaught browser errors during this test
network: unstubbed request: POST https://e2e-probe.invalid/rpc
console.error: Failed to load resource: net::ERR_FAILED
# 27/31 tests passed
# FAILED
```
`# probe [] -> fulfilled` becoming `rejected: Failed to fetch`, and `ok 28`
becoming `not ok 28` with `network: unstubbed request: POST`, is the whole
change.
### Siblings still report
Visible in both captures above: **bodyless POST**, **scalar JSON body** and
**`[null]` batch** are reported and fail in the before run and in the after run
alike. No regression.
### Legitimate stubbed calls unaffected
Tests 1-27 stayed green throughout, including the ConfirmTx section whose
fixtures widened the RPC stub (`eth_getBlockByNumber` for any block parameter,
`eth_getCode`). Nothing legitimate started being reported as unstubbed.
## The corrected comment
The old comment claimed `postData()` returns `null` for a body Playwright cannot
decode as UTF-8, citing `sendBeacon` with a Blob. That is wrong.
`playwright-core@1.56.0` (`lib/client/network.js:89`) does
`buffer.toString("utf-8") || null`, so a binary body is decoded **lossily** into
mojibake rather than yielding `null`. The guard was load-bearing either way, but
for a different reason than stated. It now reads:
```
// Anything that is not a JSON-RPC object, or a NON-EMPTY batch of
// them, is not RPC at all and must be reported like any other
// unrecognised outbound traffic rather than dereferenced.
//
// The length check is not decoration: every() is vacuously true on an
// empty array, so without it a POST with body [] was answered 200 []
// and escaped the guard entirely (issue #187). No real batch is empty,
// so nothing legitimate is caught by it.
//
// Two distinct paths land a non-RPC body here, and neither is an
// empty-string special case. playwright-core's postData() is
// `buffer.toString("utf-8") || null`, so an absent or empty body
// decodes to null, JSON.parse("null") yields null, and the type guard
// below reports it. A binary body is instead decoded LOSSILY into
// mojibake — not null — which is not valid JSON, so the catch above
// reports that one. Both end up reported; only the route differs.
```
## Verification
- `make check`: green. 25 test suites, 576 tests passed; `test-verify-build`
18 cases passed; `prettier --check .` clean.
- `make test-e2e`: green, `# 27/27 tests passed`, run after the probe was
removed and after the rebase onto `next`.
- `make fmt` run; `git status` clean before committing. Rebased onto
`origin/next` at `5af89a1` immediately before pushing.
Change is confined to `tests/e2e/network.js` (plus the `TODO.md` entry).
batch.every() is vacuously true on an empty array, so a POST with body []
was fulfilled with 200 [] instead of being reported as an unstubbed
request. The one mechanism whose job is to fail the suite on unrecognised
outbound traffic let it through. Reject an empty batch explicitly; no real
JSON-RPC batch is empty, so nothing legitimate is caught by it.
Demonstrated by execution with a throwaway probe firing four POSTs the
harness does not stub. Before: [] fulfilled and its probe passed, while
the bodyless, scalar-JSON and [null] probes were reported and failed.
After: all four reported and failed, with tests 1-27 still green.
Also corrects the comment above the guard. postData() is
buffer.toString("utf-8") || null in playwright-core, so a binary body is
decoded lossily into invalid JSON and reported by the catch, not returned
as null; only an absent or empty body yields null and reaches the type
guard. Both paths report, but the stated reason was wrong.
PASS — independently reproduced both directions in my own clone ([] fulfilled 200 [] on origin/next, reported as unstubbed request: POST at 2048e76), and both comment paths by execution including a binary body the PR did not fire, which decoded lossily to mojibake and was reported by the catch as unstubbed RPC: unparseable body while bodyless and empty-string bodies reported via the type guard; the change is strictly narrowing (an added disjunct in an || chain of pure predicates, reachable only for []), all four sibling cases report identically before and after, make check green (25 suites / 576 tests, test-verify-build 18 cases, prettier clean) and make test-e2e 27/27 executed not cached, single commit fast-forwardable onto origin/next at 5af89a1, scope confined to tests/e2e/network.js and TODO.md with ALLOWED_ERRORS still [] and TRAILING_WATCH_MS and the canary untouched.
PASS — independently reproduced both directions in my own clone (`[]` fulfilled `200 []` on `origin/next`, reported as `unstubbed request: POST` at `2048e76`), and both comment paths by execution including a binary body the PR did not fire, which decoded lossily to mojibake and was reported by the `catch` as `unstubbed RPC: unparseable body` while bodyless and empty-string bodies reported via the type guard; the change is strictly narrowing (an added disjunct in an `||` chain of pure predicates, reachable only for `[]`), all four sibling cases report identically before and after, `make check` green (25 suites / 576 tests, `test-verify-build` 18 cases, prettier clean) and `make test-e2e` 27/27 executed not cached, single commit fast-forwardable onto `origin/next` at `5af89a1`, scope confined to `tests/e2e/network.js` and `TODO.md` with `ALLOWED_ERRORS` still `[]` and `TRAILING_WATCH_MS` and the canary untouched.
clawbot
merged commit 18b47cd579 into next2026-08-12 11:50:39 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #187.
The hole
In
tests/e2e/network.jsthe guard reporting unrecognised POST bodies ended inbatch.every(...).Array.prototype.everyis vacuously true on an empty array,so a POST with body
[]was fulfilled with200 []instead of being reported.That is a hole in the one mechanism whose entire job is to make unrecognised
outbound traffic fail the suite rather than pass silently.
The fix is one clause:
batch.length === 0is now rejected alongside theexisting checks. No real JSON-RPC batch is empty, so nothing legitimate is
caught by it. The guard got stricter; nothing was loosened, and
ALLOWED_ERRORSis still
[].TRAILING_WATCH_MSand the interception canary were not touched.Demonstrated by execution
A throwaway probe (four tests, each firing one POST the harness does not stub,
asserting nothing — the run itself is the assertion) was added, both runs
captured, then the probe removed.
GREEN BEFORE —
[]sails through:RED AFTER — same probe, same run, with the fix:
# probe [] -> fulfilledbecomingrejected: Failed to fetch, andok 28becoming
not ok 28withnetwork: unstubbed request: POST, is the wholechange.
Siblings still report
Visible in both captures above: bodyless POST, scalar JSON body and
[null]batch are reported and fail in the before run and in the after runalike. No regression.
Legitimate stubbed calls unaffected
Tests 1-27 stayed green throughout, including the ConfirmTx section whose
fixtures widened the RPC stub (
eth_getBlockByNumberfor any block parameter,eth_getCode). Nothing legitimate started being reported as unstubbed.The corrected comment
The old comment claimed
postData()returnsnullfor a body Playwright cannotdecode as UTF-8, citing
sendBeaconwith a Blob. That is wrong.playwright-core@1.56.0(lib/client/network.js:89) doesbuffer.toString("utf-8") || null, so a binary body is decoded lossily intomojibake rather than yielding
null. The guard was load-bearing either way, butfor a different reason than stated. It now reads:
Verification
make check: green. 25 test suites, 576 tests passed;test-verify-build18 cases passed;
prettier --check .clean.make test-e2e: green,# 27/27 tests passed, run after the probe wasremoved and after the rebase onto
next.make fmtrun;git statusclean before committing. Rebased ontoorigin/nextat5af89a1immediately before pushing.Change is confined to
tests/e2e/network.js(plus theTODO.mdentry).batch.every() is vacuously true on an empty array, so a POST with body [] was fulfilled with 200 [] instead of being reported as an unstubbed request. The one mechanism whose job is to fail the suite on unrecognised outbound traffic let it through. Reject an empty batch explicitly; no real JSON-RPC batch is empty, so nothing legitimate is caught by it. Demonstrated by execution with a throwaway probe firing four POSTs the harness does not stub. Before: [] fulfilled and its probe passed, while the bodyless, scalar-JSON and [null] probes were reported and failed. After: all four reported and failed, with tests 1-27 still green. Also corrects the comment above the guard. postData() is buffer.toString("utf-8") || null in playwright-core, so a binary body is decoded lossily into invalid JSON and reported by the catch, not returned as null; only an absent or empty body yields null and reaches the type guard. Both paths report, but the stated reason was wrong.clawbot referenced this pull request2026-08-12 11:43:42 +02:00
PASS — independently reproduced both directions in my own clone (
[]fulfilled200 []onorigin/next, reported asunstubbed request: POSTat2048e76), and both comment paths by execution including a binary body the PR did not fire, which decoded lossily to mojibake and was reported by thecatchasunstubbed RPC: unparseable bodywhile bodyless and empty-string bodies reported via the type guard; the change is strictly narrowing (an added disjunct in an||chain of pure predicates, reachable only for[]), all four sibling cases report identically before and after,make checkgreen (25 suites / 576 tests,test-verify-build18 cases, prettier clean) andmake test-e2e27/27 executed not cached, single commit fast-forwardable ontoorigin/nextat5af89a1, scope confined totests/e2e/network.jsandTODO.mdwithALLOWED_ERRORSstill[]andTRAILING_WATCH_MSand the canary untouched.