[PR #7361] [MERGED] fix(browser): save from gzip, deflate and cached responses within a bound #7832

Closed
opened 2026-11-05 01:48:00 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/7361
Author: @earakely-scale
Created: 10/27/2026
Status: ✅ Merged
Merged: 10/27/2026
Merged by: @morluto

Base: main ← Head: fix/saved-compressed-responses


📝 Commits (3)

  • bf75e61 fix(browser): save from gzip, deflate and cached responses within a bound
  • 2bb245d Merge remote-tracking branch 'origin/main' into fix/saved-compressed-responses
  • 4660989 merge: update main for browser response tests

📊 Changes

4 files changed (+131 additions, -18 deletions)

View changed files

📝 docs/browser-scenario-contract.md (+5 -4)
📝 src/browser/BrowserScenarioResponseValues.ts (+35 -7)
📝 src/browser/PlaywrightScenarioRequest.test.ts (+58 -4)
📝 src/browser/network/PlaywrightScenarioNetwork.test.ts (+33 -3)

📄 Description

Summary

Since #7267, a scenario step that saves values from a response refuses any response whose Content-Encoding is not absent or identity, and any whose received size is unknown or zero, as from the browser's cache. Grafana answers POST /api/folders gzipped, so a UI step that saves a new folder's uid fails, and recordings that create Grafana folders through the UI cannot carry its id to later steps. #7162, which #7267 builds on, read such responses within a bound; that bound did not carry over (noted when closing #7162).

This PR bounds a saved response's decoded size before reading it: its received size, or the declared Content-Length of one served from cache, times 1032 for each gzip, x-gzip or deflate coding, the most DEFLATE (zlib) expands. A response whose bound fits the 12,000,000-byte limit is read; one whose bound passes it is refused before the body is read, as are other codings (br, zstd) and unknown or zero sizes. The same reader protects marked response content in network evidence, so a marked gzip body within the bound is now read and redacted rather than withheld.

Problem and expected behavior

  • A UI step saving from a gzip or deflate JSON answer should save when the received size bounds the decoded text within the limit.
  • A cached answer with a declared length should be bounded by that length.
  • A response no bound covers, or one that could decode past the limit, should stay unread and refused, as now.

Change and scope

  • src/browser/BrowserScenarioResponseValues.ts: decodedBodyBound, used by readBoundedResponseBody for UI saves and for marked network content.
  • docs/browser-scenario-contract.md: the UI-step reading rule.
  • Tests in src/browser/PlaywrightScenarioRequest.test.ts and src/browser/network/PlaywrightScenarioNetwork.test.ts.

Contract and boundary impact

  • Semantic owner and earliest changed stage: the browser scenario's saved-response reader.
  • Contribution scope fit and linked maintainer decision: follows the comparison of #7162 against #7267.
  • CLI and MCP/tool-catalog contract: unchanged; more responses can be saved from.
  • Provider, bridge, target-format, or platform compatibility: unchanged.
  • Evidence, artifact, provenance, or reconstruction contract: marked gzip or deflate response content within the bound is retained redacted instead of withheld.
  • Target selection, authority, upstream behavior, and cleanup details: not applicable.
  • Generated metadata, package, or installation impact: none.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Real Chrome, a loopback fixture whose create answer is gzip-compressed JSON: a scenario clicks Save with save_response on POST /api/items, then opens /items/{saved:item_1}. On main the save step fails with "the decoded response size cannot be bounded before reading it; this response body was not read."; on this branch every step completes and the destination opens with the saved id (/items/item-43).
  • Grafana: both saved-values recordings that created folders through the UI saved each folder's uid from POST /api/folders, whose answers were gzip-encoded.
  • Tests added or updated: UI saves from gzip, deflate and x-gzip answers, from a cached answer by its declared length, and from a cached gzip answer; a gzip answer whose bound passes the limit is refused unread; br, gzip, zstd, zero and unknown sizes stay refused unread; marked gzip network content within the bound is read and redacted; br and unknown cache sizes stay withheld.
  • Base reproduction: the seven new behaviour tests fail on main 83bbad2b.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run -s check:fast, format:check, scan:todos, docs:check, verify:test-discovery, mcp-catalog:check and
    jscpd: passed, merged with main 27ac1b67.
  • npx knip: staticFileUrlPath and ObjcClassImportBindingCoverage only, which main reports too.
  • npx vitest run --project domain --project services: 11,538 passed, 6 skipped. --project adapters: 7,661 passed,
    19 skipped, 1 failed ("stops Inspector target authorization after the current stat settles"), which fails the same
    way on main in this environment.
  • npm run -s test:focused -- the environment and analysis-view CLI and MCP boundaries: 7 files, 79 passed.
  • The real-Chrome run above, against main 83bbad2b and this branch.
  • CI run 40434949397: the failing tests, providerBinding.test.ts (bundle-root identity for artifact inventory),
    artifactInspectionCoverageMcp.test.ts (both FIFO cases) and ghidraJavaDoctor.test.ts (empty PATH component),
    are outside the browser. The first three fail the same way on main 27ac1b67 locally, and main's CI run 40436425782
    at bfdde7ee fails the bundle-root test too; the Ghidra doctor test passes locally on both. Other shards show no
    failing test.
  • Greptile: 5/5, no findings. Codex could not review this head (repository usage limit).

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: Google Chrome on macOS with a loopback fixture.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: the body is read only when its decoded size is bounded within the existing limit before reading; marked content keeps the existing redaction.

Maintainer validation

Merged main at ef11f778 into 4660989fa. build:cached, check:fast, and focused browser response, provider binding, artifact MCP coverage, and Ghidra doctor tests passed (167 tests). GitHub CI is rerunning. No new real-browser run was performed for this merge.

Author readiness

Human owner: @earakely-scale

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/7361 **Author:** [@earakely-scale](https://github.com/earakely-scale) **Created:** 10/27/2026 **Status:** ✅ Merged **Merged:** 10/27/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/saved-compressed-responses` --- ### 📝 Commits (3) - [`bf75e61`](https://github.com/morluto/rea/commit/bf75e611c87d21047e538cc17026328fefce9615) fix(browser): save from gzip, deflate and cached responses within a bound - [`2bb245d`](https://github.com/morluto/rea/commit/2bb245d7b7e207668ac9af4e8852578c5b4542ec) Merge remote-tracking branch 'origin/main' into fix/saved-compressed-responses - [`4660989`](https://github.com/morluto/rea/commit/4660989fae0c9a08b52a1d207124b087b047d048) merge: update main for browser response tests ### 📊 Changes **4 files changed** (+131 additions, -18 deletions) <details> <summary>View changed files</summary> 📝 `docs/browser-scenario-contract.md` (+5 -4) 📝 `src/browser/BrowserScenarioResponseValues.ts` (+35 -7) 📝 `src/browser/PlaywrightScenarioRequest.test.ts` (+58 -4) 📝 `src/browser/network/PlaywrightScenarioNetwork.test.ts` (+33 -3) </details> ### 📄 Description ## Summary Since #7267, a scenario step that saves values from a response refuses any response whose `Content-Encoding` is not absent or `identity`, and any whose received size is unknown or zero, as from the browser's cache. Grafana answers `POST /api/folders` gzipped, so a UI step that saves a new folder's `uid` fails, and recordings that create Grafana folders through the UI cannot carry its id to later steps. #7162, which #7267 builds on, read such responses within a bound; that bound did not carry over (noted when closing #7162). This PR bounds a saved response's decoded size before reading it: its received size, or the declared `Content-Length` of one served from cache, times 1032 for each `gzip`, `x-gzip` or `deflate` coding, the most DEFLATE (zlib) expands. A response whose bound fits the 12,000,000-byte limit is read; one whose bound passes it is refused before the body is read, as are other codings (`br`, `zstd`) and unknown or zero sizes. The same reader protects marked response content in network evidence, so a marked gzip body within the bound is now read and redacted rather than withheld. ## Problem and expected behavior - A UI step saving from a gzip or deflate JSON answer should save when the received size bounds the decoded text within the limit. - A cached answer with a declared length should be bounded by that length. - A response no bound covers, or one that could decode past the limit, should stay unread and refused, as now. ## Change and scope - `src/browser/BrowserScenarioResponseValues.ts`: `decodedBodyBound`, used by `readBoundedResponseBody` for UI saves and for marked network content. - `docs/browser-scenario-contract.md`: the UI-step reading rule. - Tests in `src/browser/PlaywrightScenarioRequest.test.ts` and `src/browser/network/PlaywrightScenarioNetwork.test.ts`. ## Contract and boundary impact - **Semantic owner and earliest changed stage:** the browser scenario's saved-response reader. - **Contribution scope fit and linked maintainer decision:** follows the comparison of #7162 against #7267. - **CLI and MCP/tool-catalog contract:** unchanged; more responses can be saved from. - **Provider, bridge, target-format, or platform compatibility:** unchanged. - **Evidence, artifact, provenance, or reconstruction contract:** marked gzip or deflate response content within the bound is retained redacted instead of withheld. - **Target selection, authority, upstream behavior, and cleanup details:** not applicable. - **Generated metadata, package, or installation impact:** none. Expected effects: - [ ] Read existing files or captured data. - [x] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [x] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Real Chrome, a loopback fixture whose create answer is gzip-compressed JSON: a scenario clicks Save with `save_response` on `POST /api/items`, then opens `/items/{saved:item_1}`. On main the save step fails with "the decoded response size cannot be bounded before reading it; this response body was not read."; on this branch every step completes and the destination opens with the saved id (`/items/item-43`). - Grafana: both saved-values recordings that created folders through the UI saved each folder's `uid` from `POST /api/folders`, whose answers were gzip-encoded. - Tests added or updated: UI saves from `gzip`, `deflate` and `x-gzip` answers, from a cached answer by its declared length, and from a cached gzip answer; a gzip answer whose bound passes the limit is refused unread; `br`, `gzip, zstd`, zero and unknown sizes stay refused unread; marked gzip network content within the bound is read and redacted; `br` and unknown cache sizes stay withheld. - Base reproduction: the seven new behaviour tests fail on main `83bbad2b`. For evidence-bearing changes: - [ ] Observed, derived, and inferred claims remain distinguishable. - [ ] Artifact identity, source provenance, and failed attempts remain preserved. - [ ] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run -s check:fast`, `format:check`, `scan:todos`, `docs:check`, `verify:test-discovery`, `mcp-catalog:check` and `jscpd`: passed, merged with main `27ac1b67`. - `npx knip`: `staticFileUrlPath` and `ObjcClassImportBindingCoverage` only, which main reports too. - `npx vitest run --project domain --project services`: 11,538 passed, 6 skipped. `--project adapters`: 7,661 passed, 19 skipped, 1 failed ("stops Inspector target authorization after the current stat settles"), which fails the same way on main in this environment. - `npm run -s test:focused --` the environment and analysis-view CLI and MCP boundaries: 7 files, 79 passed. - The real-Chrome run above, against main `83bbad2b` and this branch. - CI run 40434949397: the failing tests, `providerBinding.test.ts` (bundle-root identity for artifact inventory), `artifactInspectionCoverageMcp.test.ts` (both FIFO cases) and `ghidraJavaDoctor.test.ts` (empty PATH component), are outside the browser. The first three fail the same way on main `27ac1b67` locally, and main's CI run 40436425782 at `bfdde7ee` fails the bundle-root test too; the Ghidra doctor test passes locally on both. Other shards show no failing test. - Greptile: 5/5, no findings. Codex could not review this head (repository usage limit). ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: Google Chrome on macOS with a loopback fixture. - Package or release metadata impact: none. - Security, privacy, process, or containment review: the body is read only when its decoded size is bounded within the existing limit before reading; marked content keeps the existing redaction. ### Maintainer validation Merged main at ef11f778 into 4660989fa. `build:cached`, `check:fast`, and focused browser response, provider binding, artifact MCP coverage, and Ghidra doctor tests passed (167 tests). GitHub CI is rerunning. No new real-browser run was performed for this merge. ## Author readiness Human owner: @earakely-scale - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-05 01:48:00 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7832
No description provided.