Skip to content

Stop replays serving truncated answers as empty, and check the recordings - #326

Merged
adamjohnwright merged 3 commits into
mainfrom
har-check
Sep 28, 2026
Merged

adamjohnwright merged 3 commits into
mainfrom
har-check

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Second guard from #321.

The problem. A response still streaming when a test's page closed is recorded as a 200 with no body. Replayed, that was a successful empty answer the server never gave, and the page quietly showed nothing. There were 24 such answers in 15 recordings. The audit found a test that had been skipping itself for weeks because of one.

Changes

  • The harness (e2e/support/backend.ts) treats a truncated answer (2xx, headers promise a body, none kept) as the cut-off request it was, and aborts it, as it already did for requests that never got a response.
  • Recording keeps each test's context open until its backend requests have finished, with a 15 s ceiling. The HAR is written when the context closes, and that's what caught these mid-stream. Re-recording brought truncated answers from 18 to 0, and requests still open at a test's end from 243 to 193.
  • One test (publication authors link to their person pages) left its page while it was still loading; it now waits first.
  • npm run check:har (scripts/check-har.mjs) refuses any recording with a truncated answer and no complete copy, and reports the cut-off count. It runs in CI (unit job) and after every e2e:record. The rules it shares with the harness, meaning what the backend is and what counts as truncated, live in e2e/support/har-entry.mjs, so the two can't disagree. There are unit tests in tools/har-check/.
  • record-e2e.mjs still exits with the recording's status first, and a killed recording (null status) still fails.

Verification

  • Seven spec files re-recorded: 103 passed while recording, and the check is clean.
  • With the stricter replay, before re-recording: the full suite passed, so no test currently depends on an empty answer.
  • After: full suite 269 passed, 0 failed.
  • The contributors test gained the API-probe sidecar it lacked, the order-dependent skip in the audit.
  • Unit tests 562; types, lint (651), dead code (145) and format unchanged; check:har clean.

🤖 Generated with Claude Code

adamjohnwright and others added 3 commits September 27, 2026 22:42
…ings

A response cut off after its headers -- still streaming when a test's page
closed -- is recorded as a 200 with no body. Replayed, it was a successful
*empty* answer the server never gave, and the page quietly showed nothing;
24 such answers sat in 15 recordings, and the audit (#321) found a test that
skipped itself for weeks on one.

- The harness treats them as the cut-off requests they were and aborts
  them, as it already did for requests that never got a response.
- Recording keeps each test's context open until its backend requests have
  finished (15s ceiling). The HAR is written when the context closes, which
  is what caught them mid-stream: truncated answers 18 -> 0 on re-recording,
  and requests still open at a test's end 243 -> 193.
- One test left its page while it was still loading; it waits for the page
  first.
- scripts/check-har.mjs refuses any recording with a truncated answer and no
  complete copy, and reports the cut-off count. It runs in CI and after
  every recording. The rules it shares with the harness -- what the backend
  is, what counts as truncated -- live in e2e/support/har-entry.mjs, so the
  two cannot disagree.

Seven spec files re-recorded. Full suite 269 passed, none failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A response cut off mid-stream now counts as truncated when it had no
  length to declare, not only when its Content-Length promised a body: with
  no length, a chunked or JSON response that kept no body was cut off. Eight
  such answers, in six recordings the re-recording had not touched, were
  still replayed as successful empty ones; five of the six are re-recorded.
- The three left are answers the app itself abandons mid-load, so a
  recording always catches them cut off. The check names them, each with
  why, rather than refusing them; anything else is a test ending too soon.
- While recording, the test's time limit grows by the settle ceiling, which
  runs in teardown and counted against it.
- The harness comment says a truncated answer falls to the pooled
  recordings and is aborted only if none has a complete copy; stray doc
  comments moved to their functions; the check's main guard survives an
  import with no argv.

Re-recorded specs and the release suite: 62 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned answer

- A test limit of 0 means none; adding the settle ceiling turned it into 15s.
- Each abandoned answer is pinned to its own recording, so a new cut-off in a
  neighbouring one is not let through; and the wording no longer promises an
  abort where another test's complete copy may answer instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 5355242 into main Sep 28, 2026
6 checks passed
@adamjohnwright
adamjohnwright deleted the har-check branch September 28, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant