Skip to content

[security] fix(podcast): cap remote media file downloads#237

Open
Hinotoi-agent wants to merge 4 commits into
steipete:mainfrom
Hinotoi-agent:fix/cap-remote-media-file-download
Open

[security] fix(podcast): cap remote media file downloads#237
Hinotoi-agent wants to merge 4 commits into
steipete:mainfrom
Hinotoi-agent:fix/cap-remote-media-file-download

Conversation

@Hinotoi-agent
Copy link
Copy Markdown
Contributor

@Hinotoi-agent Hinotoi-agent commented Jun 4, 2026

Summary

This PR hardens remote podcast/media transcription downloads so the remote media size limit is enforced during the actual GET stream, not only during the optional HEAD preflight.

The default remains fail-closed at 512 MB. For operators who need larger legitimate remote podcast/media files and accept the disk/DoS tradeoff, this update also adds an explicit finite opt-in byte limit via SUMMARIZE_REMOTE_MEDIA_MAX_BYTES. Override values must be positive integer byte counts; fractional, sub-byte, or otherwise unsafe values are ignored so the built-in cap remains active.

  • Enforces the selected remote media byte cap while writing large remote media to a temp file.
  • Rejects responses that omit, fail, or under-report Content-Length once the streamed bytes exceed the cap.
  • Applies the same selected cap to HEAD Content-Length checks and streaming temp-file enforcement.
  • Covers default, explicit opt-in, invalid config, streaming, and non-streaming regression cases.

Security issues covered

Issue Impact Severity
Remote media temp-file downloads trusted HEAD metadata but did not enforce a byte cap during GET streaming A malicious podcast/feed media URL could cause the CLI to keep writing an oversized response to local temp storage, leading to disk/resource exhaustion Medium

Before this PR

  • transcribeMediaUrl() rejected media only when a successful HEAD response reported content-length > MAX_REMOTE_MEDIA_BYTES.
  • If HEAD failed, omitted Content-Length, or reported a smaller value than the GET body, the ffmpeg temp-file path streamed the full response to /tmp/summarize-podcast-*.bin.
  • The temp-file downloader had no byte ceiling of its own.
  • There was no documented bounded opt-in path for operators who intentionally needed a larger remote podcast/media limit.

After this PR

  • The default remote podcast/media transcription cap remains 512 MB.
  • transcribeMediaUrl() resolves an effective cap from SUMMARIZE_REMOTE_MEDIA_MAX_BYTES only when the value is a finite positive integer byte count.
  • Invalid values such as non-numeric strings, negative numbers, zero, empty values, Infinity, fractional values, or sub-byte values are treated as unset and fall back to the built-in cap.
  • The effective cap is used for both HEAD Content-Length preflight rejection and the GET temp-file write path.
  • downloadToFile() checks the next byte count before every file write and throws Remote media too large instead of writing beyond the configured cap.
  • The non-streaming arrayBuffer() fallback also rejects oversized responses before writing a file.
  • Documentation describes the default cap, the explicit opt-in environment variable, and the invalid-value fallback.

Why this matters

Remote media URLs can be controlled by a feed publisher or by whoever supplies a media URL to the CLI. A size check that only trusts HEAD metadata is not enough because servers can omit HEAD support, omit Content-Length, use chunked transfer, or advertise a smaller size than the body returned by GET.

Silently allowing unknown-size or under-reported responses to stream without a hard byte ceiling would keep the original host-disk exhaustion risk. The explicit finite opt-in gives operators a compatibility path for larger files without returning to unbounded temp-file writes by default.

Attack flow

malicious podcast/feed media URL
    -> podcast/media transcription temp-file path
        -> HEAD missing/under-reports size
            -> GET stream writes without a hard byte cap
                -> local temp disk/resource exhaustion

Affected code

Issue Files
Remote media temp-file download cap packages/core/src/content/transcript/providers/podcast/media.ts, packages/core/src/content/transcript/transcription-config.ts, tests/security.remote-media-file-download-cap.test.ts, docs/media.md

Root cause

Remote media temp-file download cap:

  • The preflight size check was metadata-only and did not enforce the same limit at the streaming sink.
  • The trusted boundary was the actual bytes written to local temp storage, but the guard lived only before the GET response body was consumed.
  • Compatibility for larger files needed an explicit bounded operator choice rather than an implicit unbounded fallback.

CVSS assessment

Issue CVSS v3.1 Vector
Remote media temp-file download cap 5.3 Medium CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L

Rationale:

  • The attacker can host or supply a remote media URL, but a user/agent still has to summarize or transcribe that URL.
  • The demonstrated impact is local availability/resource exhaustion, not code execution or data disclosure.

Safe reproduction steps

  1. Use a fetch stub whose HEAD metadata reports a bounded size, but whose GET stream returns one extra byte beyond the configured download cap.
  2. Call downloadToFile() with a small test maxBytes value.
  3. Before this PR, the promise resolves and writes all bytes returned by GET.
  4. After this PR, the promise rejects with Remote media too large before writing past the cap.
  5. Configure a larger finite cap and repeat with a response just above the default test cap but within the opt-in cap.
  6. The opt-in case succeeds only because the configured finite limit is explicit and still enforced.

The regression tests use this pattern safely with local in-memory streams and temporary files.

Real behavior proof

I also ran real HTTP download proofs against local loopback servers. The URLs/ports are redacted because the servers were local and ephemeral.

Original fail-closed proof with omitted Content-Length and production default cap:

pnpm -s tsx /tmp/summarize-remote-media-cap-proof.ts

Redacted terminal output:

proof: real HTTP oversized remote media download
url: http://127.0.0.1:<redacted-port>/redacted-oversized-episode.mp3
content-length: omitted
configured_cap_bytes: 536870912
server_stream_bytes: 537919488
result: Remote media too large (512MB). Limit is 512MB.
get_requests: 1
bytes_sent_before_rejection: 537919488

Follow-up proof for the explicit finite opt-in path:

pnpm -s tsx /tmp/summarize-remote-media-cap-optin-proof.ts

Redacted terminal output:

proof: explicit opt-in remote media cap
url: http://127.0.0.1:<redacted-port>/redacted-episode.mp3
content-length: omitted
default_config_remote_media_max_bytes: built-in 512MB
invalid_env_value_result: ignored
opt_in_env: SUMMARIZE_REMOTE_MEDIA_MAX_BYTES=66560
server_stream_bytes: 65537
downloaded_bytes: 65537
file_bytes: 65537
get_requests: 1
bytes_sent: 65537
result: larger finite opt-in cap honored

Together, these proofs exercise the actual HTTP GET streaming path and show both the secure default and the explicit bounded compatibility override.

Expected vulnerable behavior

  • Pre-patch streaming download result: downloadToFile() resolved after writing maxBytes + 1 bytes.
  • Pre-patch non-streaming fallback result: downloadToFile() resolved after writing maxBytes + 1 bytes.
  • Post-patch default behavior: both paths reject with Remote media too large before writing beyond the selected cap.
  • Post-patch opt-in behavior: a larger file can succeed only when an operator configures a larger finite integer byte limit.

Changes in this PR

  • Adds an optional maxBytes guard to downloadToFile().
  • Adds SUMMARIZE_REMOTE_MEDIA_MAX_BYTES parsing through transcription config.
  • Normalizes the remote media override to a finite positive byte count and ignores invalid/unsafe values.
  • Uses the effective cap for HEAD Content-Length checks and GET stream enforcement.
  • Rejects oversized non-streaming responses before writing them to disk.
  • Reuses a single remote-media-too-large error helper for HEAD and GET enforcement.
  • Adds regression tests for streaming and non-streaming oversized downloads, default cap behavior, explicit opt-in, and invalid config.
  • Updates docs/media.md with the 512 MB default, explicit opt-in variable, and invalid-value fallback.

Files changed

Category Files What changed
Runtime guard packages/core/src/content/transcript/providers/podcast/media.ts Enforces the effective remote media byte limit at HEAD preflight and temp-file write sink
Config packages/core/src/content/transcript/transcription-config.ts Adds SUMMARIZE_REMOTE_MEDIA_MAX_BYTES and finite positive byte normalization
Tests tests/security.remote-media-file-download-cap.test.ts Adds regression coverage for oversized streaming/non-streaming downloads plus default/opt-in/invalid config behavior
Docs docs/media.md Documents the 512 MB default cap, explicit larger finite opt-in, and invalid-value fallback

Maintainer impact

  • Scope is limited to remote podcast/media transcription download handling.
  • Existing small-media and capped in-memory transcription paths are unchanged.
  • The default behavior remains secure and fail-closed at 512 MB.
  • Operators who need larger legitimate media can raise the cap explicitly with a finite byte value.
  • Invalid or unsafe override values do not weaken the default guard.
  • Oversized remote media now fails earlier and more predictably instead of depending on HEAD support or metadata honesty.

Fix rationale

  • Enforcing the cap during GET streaming handles missing, failed, chunked, or dishonest HEAD responses.
  • Checking nextDownloadedBytes before each write prevents the temp file from growing past the configured limit.
  • Keeping the default cap fail-closed preserves the security boundary for untrusted remote media.
  • Adding an explicit finite opt-in resolves the compatibility concern without restoring unbounded unknown-size downloads.

Type of change

  • Security fix
  • Tests
  • Documentation update
  • Refactor with no behavior change

Test plan

Current head validation (b99d5bc7):

  • pnpm -s vitest run tests/security.remote-media-file-download-cap.test.ts — 1 file passed, 4 tests passed, including fractional/sub-byte override regression coverage.
  • pnpm -s tsx /tmp/summarize-remote-media-cap-optin-proof.ts — explicit opt-in proof passed.
  • git diff --check — passed.
  • pnpm -s format:check — all 969 matched files formatted.
  • pnpm -s lint — 0 warnings and 0 errors across 903 files.
  • pnpm -s typecheck — passed.

Earlier validation on this branch also passed:

  • pnpm exec vitest run tests/security.remote-media-file-download-cap.test.ts
  • pnpm -s tsx /tmp/summarize-remote-media-cap-proof.ts
  • pnpm format:check docs/media.md
  • pnpm exec vitest run tests/transcript.podcast-provider.transcribe-media-url-branches.test.ts tests/security.remote-media-file-download-cap.test.ts
  • pnpm typecheck
  • pnpm lint
  • pnpm test

Local pnpm previously emitted the repository engine warning because this machine was on Node v22.22.2 while package.json declares node >=24; the listed commands completed successfully locally.

Disclosure notes

  • This PR is bounded to local availability/resource exhaustion through remote media transcription downloads.
  • It does not claim remote code execution or credential disclosure.
  • I did not find a SECURITY.md in the repository, so I am submitting this as a regular hardening PR with safe regression tests.
  • No unrelated files are changed.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 4, 2026

Codex review: needs maintainer review before merge. Reviewed June 4, 2026, 11:08 PM ET / 03:08 UTC.

Summary
Adds streamed byte-limit enforcement for remote podcast/media temp-file downloads, a SUMMARIZE_REMOTE_MEDIA_MAX_BYTES override, documentation, and focused security regression tests.

Reproducibility: yes. from source inspection and the PR tests: current main checks only HEAD metadata before the temp-file GET stream, while the PR exercises under-reported and oversized streams. I did not execute tests because the review contract required a read-only checkout.

Review metrics: 3 noteworthy metrics.

  • Files affected: 4 files changed. The PR touches runtime download handling, config parsing, docs, and one focused security test file.
  • Regression coverage: 4 tests added. The new test file covers config parsing and both streaming and non-streaming oversized download behavior.
  • New operator knob: 1 environment variable added. The finite override is the compatibility path maintainers need to accept before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Get explicit maintainer acceptance that the 512 MB fail-closed default plus SUMMARIZE_REMOTE_MEDIA_MAX_BYTES opt-in is the desired upgrade behavior.

Risk before merge

  • [P1] Existing workflows that relied on remote podcast/media temp-file downloads above 512 MB will now fail with Remote media too large unless operators configure SUMMARIZE_REMOTE_MEDIA_MAX_BYTES.
  • [P1] I did not run the tests because this review was required to keep the checkout read-only; the PR body reports the focused vitest, typecheck, lint, format, and loopback proof commands passing locally.

Maintainer options:

  1. Accept the fail-closed default (recommended)
    Approve the PR once a maintainer confirms that the 512 MB default plus SUMMARIZE_REMOTE_MEDIA_MAX_BYTES opt-in is the intended upgrade behavior.
  2. Revise the upgrade policy before merge
    If maintainers do not want existing oversized remote podcast/media workflows to fail by default, ask for a different compatibility path before landing the security change.

Next step before merge

  • [P2] The remaining action is maintainer acceptance of the upgrade/compatibility behavior, not an automatable code repair.

Security
Cleared: The diff is security-sensitive but narrows an existing remote media disk-exhaustion path and does not add dependency, workflow, secret, or supply-chain risk.

Review details

Best possible solution:

Land the hard cap after a maintainer explicitly accepts the documented 512 MB fail-closed upgrade behavior and the finite opt-in path for larger legitimate media.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection and the PR tests: current main checks only HEAD metadata before the temp-file GET stream, while the PR exercises under-reported and oversized streams. I did not execute tests because the review contract required a read-only checkout.

Is this the best way to solve the issue?

Yes, with a maintainer decision on compatibility: enforcing the cap at the write sink is the right security boundary, and the finite opt-in is a narrow way to support larger legitimate files without restoring unbounded downloads.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 821e76613ded.

Label changes

Label changes:

  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes redacted terminal output from real loopback HTTP GET streaming proofs showing default oversized rejection and the finite opt-in path after the fix.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P2: This is bounded security hardening for remote podcast/media downloads with focused tests and proof, but it still needs maintainer acceptance of the compatibility behavior.
  • merge-risk: 🚨 compatibility: Merging changes oversized remote podcast/media temp-file downloads from potentially unbounded streaming to fail-closed rejection unless an operator opts into a larger finite cap.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes redacted terminal output from real loopback HTTP GET streaming proofs showing default oversized rejection and the finite opt-in path after the fix.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted terminal output from real loopback HTTP GET streaming proofs showing default oversized rejection and the finite opt-in path after the fix.
Evidence reviewed

What I checked:

Likely related people:

  • Peter Steinberger: Current-main blame for the podcast media transcription path, downloadToFile, transcription config, and docs points to Peter Steinberger, and git log -S traces the downloader and remote media cap symbols through the same area history. (role: introduced behavior and recent area contributor; confidence: high; commits: fcf8c8e5e98d, 6b05434fef63, 9caff8aab292; files: packages/core/src/content/transcript/providers/podcast/media.ts, packages/core/src/content/transcript/transcription-config.ts, docs/media.md)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jun 4, 2026
@Hinotoi-agent
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

I pushed follow-up commit 9819a5e8 addressing the P1 rank-up items:

  • Added docs/media.md alignment for the enforced 512 MB remote podcast/media transcription cap and the deliberate fail-closed behavior when Content-Length is missing or dishonest.
  • Added real behavior proof to the PR body from an actual HTTP GET streaming path, not a fetch stub. The proof uses a loopback HTTP server with redacted ephemeral port, omitted Content-Length, and streams beyond MAX_REMOTE_MEDIA_BYTES; the observed result is Remote media too large (512MB). Limit is 512MB.
  • Re-ran validation:
    • pnpm exec vitest run tests/security.remote-media-file-download-cap.test.ts
    • pnpm -s tsx /tmp/summarize-remote-media-cap-proof.ts
    • pnpm typecheck
    • pnpm lint
    • pnpm format:check docs/media.md

All completed successfully locally; only the repo's existing Node engine warning appeared because this machine is on Node v22.22.2 while package.json declares node >=24.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 5, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 5, 2026
Keep the default remote podcast/media download cap fail-closed while allowing operators to configure a larger finite byte limit explicitly.

Invalid or unsafe override values are ignored so the built-in cap remains active, and the selected cap is used for both content-length preflight checks and streaming enforcement.
@Hinotoi-agent
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

I pushed follow-up commit d927de03 for the compatibility concern while preserving the security boundary:

  • Default remote podcast/media downloads still fail closed at the built-in 512 MB cap.
  • Added explicit finite opt-in via SUMMARIZE_REMOTE_MEDIA_MAX_BYTES=<positive byte limit> for operators who accept the disk/DoS tradeoff for larger files.
  • Invalid/unsafe override values are ignored, so the default 512 MB cap remains active.
  • The effective cap is now applied consistently to both HEAD Content-Length checks and GET streaming temp-file enforcement.
  • Updated docs/media.md and the PR body with the opt-in behavior and proof.
  • Added regression coverage for default cap behavior, explicit larger finite opt-in, invalid/unsafe config, and the existing oversized streaming/non-streaming protections.

Current local validation passed:

  • pnpm -s vitest run tests/security.remote-media-file-download-cap.test.ts — 4 tests passed.
  • pnpm -s tsx /tmp/summarize-remote-media-cap-optin-proof.ts — explicit opt-in proof passed.
  • git diff --check — passed.
  • pnpm -s format:check — all 969 matched files formatted.
  • pnpm -s lint — 0 warnings and 0 errors across 903 files.
  • pnpm -s typecheck — passed.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 5, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 5, 2026
@Hinotoi-agent
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

I pushed follow-up commit b99d5bc7 addressing the parser issue from the latest re-review:

  • SUMMARIZE_REMOTE_MEDIA_MAX_BYTES now accepts only finite positive integer byte counts via Number.isSafeInteger(parsed) && parsed > 0.
  • Fractional/sub-byte values such as 0.5 and 1.5 are treated as invalid and fall back to the built-in 512 MB cap instead of normalizing to 0.
  • Updated docs to call out the positive-integer requirement and fractional/sub-byte invalid-value fallback.
  • Added focused regression coverage for fractional and sub-byte override values.

Current local validation passed:

  • pnpm -s vitest run tests/security.remote-media-file-download-cap.test.ts — 4 tests passed, including fractional/sub-byte override coverage.
  • pnpm -s tsx /tmp/summarize-remote-media-cap-optin-proof.ts — explicit opt-in proof passed.
  • git diff --check — passed.
  • pnpm -s format:check — all 969 matched files formatted.
  • pnpm -s lint — 0 warnings and 0 errors across 903 files.
  • pnpm -s typecheck — passed.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 5, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant