Skip to content

fix(runway-video): bound JSON response reads#96899

Closed
mushuiyu886 wants to merge 2 commits into
openclaw:mainfrom
mushuiyu886:fix/followup-96604
Closed

fix(runway-video): bound JSON response reads#96899
mushuiyu886 wants to merge 2 commits into
openclaw:mainfrom
mushuiyu886:fix/followup-96604

Conversation

@mushuiyu886

@mushuiyu886 mushuiyu886 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Bound Runway video create/status JSON response parsing through the provider JSON reader instead of direct response.json().
  • Added a regression test with an oversized streamed Response that verifies the stream is cancelled on overflow.
  • Updated the shared provider-http test mock to expose readProviderJsonResponse for provider tests that import it from the SDK facade.
  • Fixed the follow-up test helper typing so check:test-types accepts the intentional partial Response used by the overflow regression test.

What Problem This Solves

Runway video generation parsed external create and poll responses with a local helper that called response.json() directly. A successful provider response with an unbounded body could be buffered before JSON parsing, unlike the already-bounded video download path.

User Impact

  • Why it matters / User impact: Users configuring Runway video generation get the same 16 MiB JSON response cap used by other provider response readers. Oversized create/status responses now fail early with a provider-owned error instead of being materialized through the native JSON reader.
  • What did NOT change: The patch only changes Runway's JSON response helper, its regression test, and the shared provider-http test mock needed for SDK facade imports. It does not change request construction, polling state transitions, generated video downloads, model capabilities, auth, or provider configuration.
  • Architecture / source-of-truth check: Runway's readRunwayJsonResponse remains the provider-local owner for object-shape validation, while the canonical readProviderJsonResponse contract remains the source-of-truth for provider JSON byte limits and malformed JSON wrapping.

Origin / follow-up

Follows #96604.

  • Follows / completes: fix(qwen): bound video description success response reads #96604 established the same bounded response-body pattern for video description success responses.
  • Gap this fills: Runway video generation still had a sibling local JSON helper reading create/status success responses through direct response.json().
  • Consistency: This patch reuses the existing readProviderJsonResponse SDK facade and keeps Runway's existing object-shape validation and provider-owned malformed JSON errors.

Competition / linked PR analysis

No linked issue. Related open PR scan before implementation found no open PR touching extensions/runway/video-generation-provider.ts or matching Runway bounded JSON response reads. This PR is limited to the uncovered Runway video sibling path.

Real behavior proof

  • Behavior or issue addressed: Runway video create/status success responses are read through a bounded provider JSON reader and oversized streams are cancelled.
  • Real environment tested: Local OpenClaw provider runtime path in /media/vdb/code/ai/aispace/openclaw-worktrees/pr-96899, using buildRunwayVideoGenerationProvider().generateVideo() with a real streamed Response body.
  • Exact steps or command run after this patch: pnpm check:test-types, node scripts/run-vitest.mjs extensions/runway/video-generation-provider.test.ts, and a local loopback HTTP proof that streams a >16 MiB provider JSON response into the production readProviderJsonResponse path.
  • Evidence after fix: /media/vdb/code/ai/aispace/openclaw-pr-96899-evidence/runway-video-test-types-after-response-cast.txt, /media/vdb/code/ai/aispace/openclaw-pr-96899-evidence/runway-video-vitest-after-response-cast.txt, and /media/vdb/code/ai/aispace/openclaw-pr-96899-evidence/runway-provider-json-loopback-overflow.txt
  • Observed result after fix: pnpm check:test-types completed successfully. The Runway Vitest shard reported Test Files 1 passed (1) and Tests 10 passed (10). The local loopback proof observed Runway video generation failed: JSON response exceeds 16777216 bytes, cancel_observed=true, and server close after 16,908,288 streamed bytes.
  • What was not tested: Runway credential-backed network call: out of scope for this follow-up because the changed contract is the response-body reader boundary, which is exercised through the provider function with a real streamed Response.
  • Fix classification: Root cause fix

Review findings addressed

  • RF-001: Fixed. The oversized response fixture now uses an unknown intermediate cast for the intentional partial Response, and pnpm check:test-types passes at current head.
  • RF-002: Fixed with non-mock after-fix proof. The local loopback HTTP proof streams a >16 MiB provider JSON response through the production readProviderJsonResponse path and observes overflow plus server close/cancel.
  • RF-003: Fixed with the same loopback proof file: /media/vdb/code/ai/aispace/openclaw-pr-96899-evidence/runway-provider-json-loopback-overflow.txt.
  • RF-004: Maintainer compatibility decision, not a repair item. Create/status metadata responses larger than the shared 16 MiB provider JSON cap now fail closed by design, and this body documents that choice.
  • RF-005: Fixed. The current head passes pnpm check:test-types after making the oversized response fixture type-correct.
  • RF-006: Fixed with non-mock proof beyond mocked-provider Vitest output: the loopback proof uses a real HTTP stream and the production provider JSON reader.
  • RF-007: Fixed for contributor-owned actions: the type-check failure is repaired and the non-mock proof has been added; any remaining compatibility approval is a maintainer decision.
  • RF-008: Fixed. The fixture now uses the narrow intentional partial Response cast accepted by TypeScript while preserving the guard that direct response.json() would fail the test.

Regression Test Plan

  • Target test file: extensions/runway/video-generation-provider.test.ts
  • Scenario locked in: The regression test feeds Runway's create response path an oversized streamed JSON body and asserts the provider reports Runway video generation failed: JSON response exceeds 16777216 bytes.
  • Why this is the smallest reliable guardrail: The test uses the public buildRunwayVideoGenerationProvider().generateVideo() path and a real ReadableStream body with a cancel hook, so it fails if the helper regresses to direct response.json() or stops cancelling oversized streams.
  • pnpm check:test-types
  • node scripts/run-vitest.mjs extensions/runway/video-generation-provider.test.ts

Risk / Compatibility

Low. Successful Runway JSON responses still parse into the same typed payloads and still require top-level objects. Responses larger than 16 MiB now fail with a bounded-reader error, matching existing provider JSON response limits.

Merge risk

  • Risk labels considered: merge-risk: compatibility, provider/auth surface, shared test-helper surface.
  • Risk explanation: This touches a provider implementation and a shared provider-http test mock, but production behavior is limited to replacing direct JSON materialization with the existing provider JSON reader. The shared test mock change mirrors the already exported SDK facade function so provider tests can exercise the same import shape.
  • Why acceptable: The runtime contract is stricter only for oversized JSON bodies. Normal JSON success payloads continue through the same Runway object validation, and malformed JSON still reports the same provider-owned malformed JSON error.
  • Maintainer-ready confidence: High: the diff is small, the source-of-truth helper is reused rather than reimplemented in production code, and the regression test covers the overflow/cancel behavior at the provider function boundary. The current-head type check also passes after the partial Response cast fix.
  • Patch quality notes: The broad catches are confined to the test mock's JSON reader shim to preserve the same malformed/overflow error semantics as the real provider JSON reader. No production broad catch was added. The repair commit only changes the TypeScript cast for an intentional partial test Response.

What was not changed

  • Did not change Runway request construction, polling state handling, download size limits, or model capability declarations.
  • Did not change any live Runway credentials or provider configuration behavior.

Root Cause

  • Root cause: The source of the unbounded read was Runway's local JSON helper: it used direct response.json() for HTTP success responses instead of the shared bounded reader contract.
  • Why this is root-cause fix: The helper now reads through the shared provider JSON reader contract, so every Runway create/status JSON response consumed through that helper is capped before JSON parsing while preserving existing validation semantics.

@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

This PR should close in favor of the newer canonical Runway bounded-reader PR, which targets the same create/poll JSON helper, is open and mergeable, has sufficient real behavior proof, and avoids this branch's duplicated test-mock JSON reader implementation.

Root-cause cluster
Relationship: superseded
Canonical: #96907
Summary: The current PR and #96907 target the same Runway create/poll bounded JSON root cause; the newer PR is the viable canonical path because it has sufficient proof and keeps the shared JSON reader real in tests.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Use #96907 as the canonical landing path, and port a real-reader overflow regression there only if maintainers want that extra committed coverage.

So I’m closing this here and keeping the remaining discussion on #96907.

Review details

Best possible solution:

Use #96907 as the canonical landing path, and port a real-reader overflow regression there only if maintainers want that extra committed coverage.

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

Yes. Current main reaches direct response.json() for Runway create and poll success responses, so the unbounded read is source-reproducible even though I did not run an OOM harness in this read-only review.

Is this the best way to solve the issue?

No for this branch as the landing path. The production fix shape is right, but the newer canonical PR solves the same issue with a cleaner test-helper boundary and stronger proof.

Security review:

Security review cleared: The diff introduces no dependency, workflow, secret, permission, package-resolution, or supply-chain change; it narrows an external provider response-body path.

AGENTS.md: found and applied where relevant.

What I checked:

  • Current main has the unbounded Runway success JSON helper: Current main's readRunwayJsonResponse still accepts Pick<Response, "json"> and calls response.json(), and that helper is used by the create and poll paths. (extensions/runway/video-generation-provider.ts:68, 6830aa39eaa1)
  • This branch fixes the production helper but duplicates the shared JSON reader in tests: At PR head, production Runway code delegates to readProviderJsonResponse, but the provider HTTP test mock reimplements a local bounded JSON reader instead of keeping the source-of-truth helper real. (src/plugin-sdk/test-helpers/provider-http-mocks.ts:242, 69f13d10300e)
  • Canonical replacement keeps the real shared reader in the test mock: The newer Runway PR uses importActual so readProviderJsonResponse remains the real SDK helper under tests, while still applying the same production helper change. (src/plugin-sdk/test-helpers/provider-http-mocks.ts:211, 2f684dfccc13)
  • Canonical replacement is a viable open landing path: The newer PR is open, mergeable, maintainer-editable, labeled proof: sufficient, and its CI rollup includes green type, lint, dependency, guard, and broad check lanes. (2f684dfccc13)
  • Related search identifies the duplicate pair: A live GitHub search for readRunwayJsonResponse found this PR and the newer Runway PR as the only direct matches.
  • Shared reader provenance: The shared readProviderJsonResponse bounded-reader contract was merged in the earlier provider JSON response PR and is the source-of-truth helper both Runway PRs reuse. (src/agents/provider-http-errors.ts:312, 2592f8a51a4e)

Likely related people:

  • Alix-007: Authored the open canonical Runway replacement PR and several recently merged bounded-response PRs, including the shared provider JSON reader and Qwen sibling pattern. (role: canonical replacement and shared-reader contributor; confidence: high; commits: 2592f8a51a4e, cc124d2921b8, 2f684dfccc13; files: src/agents/provider-http-errors.ts, src/agents/provider-http-errors.test.ts, extensions/qwen/media-understanding-provider.ts)
  • obviyus: GitHub commit metadata for the current-main grafted repair commit shows obviyus as committer on the code state that includes the Runway helper and shared reader paths. (role: recent current-main committer; confidence: medium; commits: ace22feb3fe2; files: extensions/runway/video-generation-provider.ts, src/agents/provider-http-errors.ts, src/plugin-sdk/test-helpers/provider-http-mocks.ts)
  • mushuiyu886: Beyond this PR, authored a merged OpenRouter video catalog bounded JSON response change, so they have recent adjacent history in the same response-limit campaign. (role: adjacent bounded-response contributor; confidence: medium; commits: 5715b5500067; files: extensions/openrouter/video-model-catalog.ts, extensions/openrouter/video-generation-provider.test.ts)

Codex review notes: model internal, reasoning high; reviewed against 6830aa39eaa1.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. 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. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. 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. labels Jun 26, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 26, 2026
@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

  • Action: closed this PR.
  • Close reason: duplicate or superseded.
  • Evidence: durable ClawSweeper review.
  • Coverage proof: PR B clearly carries PR A's core production fix and review concerns for the same Runway create/poll bounded JSON reader work. PR A's extra oversized-create regression is optional coverage rather than separate material behavior that requires keeping PR A open. Covering PR: fix(runway): bound video create/poll response reads #96907.

@clawsweeper clawsweeper Bot closed this Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: S 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