Skip to content

fix(core): tell an opaque document how to actually get its Web Audio back - #3940

Merged
jrusso1020 merged 1 commit into
mainfrom
fix/web-audio-opaque-origin-reason
Sep 14, 2026
Merged

jrusso1020 merged 1 commit into
mainfrom
fix/web-audio-opaque-origin-reason

Conversation

@jrusso1020

Copy link
Copy Markdown
Collaborator

What

Follow-up to #3937. Splits the Web Audio bypass verdict into two reasons, cross_origin_no_cors and a new opaque_document_origin, and gives each its own diagnostic note and remediation text.

Why

#3937 fixed the real bug correctly: a composition inside a sandboxed iframe no longer loses its sound. But the fix added a new path into a diagnostic, and the diagnostic gives dead-end advice on that path.

This module exists so something gets said. Its own docstring says the complaint in #3458 was that nothing was. On the new opaque path it now says, at webAudioRoute.ts:279:

Native playback cannot reproduce: fx-chain, automation — proxy or download the asset to a same-origin URL to keep it.

In an opaque document that is a guaranteed no-op. The asset is usually already same-origin by URL, which is exactly why the bug existed, and nothing is same-origin with an opaque origin, so there is no URL that satisfies the instruction. The two remediations that do work, allow-same-origin on the sandbox or crossorigin with a matching Access-Control-Allow-Origin, were never mentioned.

The reason token had the same problem one level down. An opaque document reached the identical cross_origin_no_cors verdict a genuinely foreign asset gets, so the two cases were indistinguishable at the classifier's output and on the bridge message. That is defensible in the narrow sense, since from an opaque document every http(s) origin genuinely is foreign, but it is what forced the message to be wrong for one of the two cases it covers.

Credit to Somu for the shape: a second reason is cleaner than branching the prose, because it fixes the conflation rather than papering over it.

How

  • isCorsSilenced becomes corsSilenceReason, returning which reason applies or null. Module-private, one call site.
  • Opacity wins when both conditions hold. It is the blocking condition and the only one an author cannot fix by moving the asset. A test pins this case explicitly.
  • NOTE_BY_REASON and REMEDY_BY_REASON carry the per-reason text, so the console line and the details on the bridge message stay in sync.
  • The URL parse plus scheme filter moved into httpMediaUrl, and the window.origin read into documentSecurityOrigin. That was not cosmetic: fallow blocked the first commit at cyclomatic 10 / CRAP 31.6 on the merged function, and it reads better split.

No behaviour change to the routing. A crossorigin opt-in still rescues the opaque case, file: still exits at the scheme guard, and a normal document is untouched. Only the reason value and the words change.

The scraper contract is safe. packages/cli/src/utils/checkBrowser.ts:309 matches text.startsWith("[hyperframes] runtime_web_audio_bypass"), the code prefix only, never the reason. checkBrowser.test.ts:447-453 exercises the whole console line as a fixture with a genuinely cross-origin asset, so it keeps the old reason and is unaffected. I checked this before choosing the approach, not after.

Test plan

  • Unit tests added/updated. Four new or rewritten tests in webAudioRoute.test.ts: the opaque classification, opaque-plus-remote (opacity wins), a crossorigin opt-in still rescuing an opaque document, the opaque remediation line, and the reason and note crossing the bridge.
  • Failing-first, proven not assumed. Reverted webAudioRoute.ts to origin/main and re-ran: 4 failed, 25 passed. With the fix: 29 passed. The opaque test previously asserted the misleading token, so it was pinning the defect as expected.
  • packages/core suite: 576 passing. 18 test files fail to collect on @hyperframes/parsers/* imports, which is an unbuilt workspace in my worktree, not this change. Confirmed by stashing the diff and re-running on a pristine tree: the same 18 fail there, with 571 passing.
  • oxfmt --check clean, and all lefthook hooks pass including fallow and typecheck. Commit is signed.
  • Manual testing performed. Not done. The behaviour under test is a console line and a bridge message, both asserted directly.

— Rames

…back

The opaque-origin fix in #3937 routed correctly but sent the diagnostic down
a dead end. An opaque document reached the same `cross_origin_no_cors` verdict
a genuinely foreign asset gets, so the message told the author to "proxy or
download the asset to a same-origin URL". That is impossible advice, because
nothing is same-origin with an opaque origin and the asset is usually
same-origin by URL already.

Split the verdict into two reasons and give each its own note and remedy. The
opaque case now names the two fixes that work: `allow-same-origin` on the
sandbox, or `crossorigin` plus an `Access-Control-Allow-Origin` of `null` or
`*`. Opacity wins when both conditions hold, since it is the blocking one and
the one an author cannot fix by moving the asset.

The CLI scraper matches on the code prefix only (checkBrowser.ts:309), so the
new reason value does not touch that contract.

- Rames

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 68e1f970202f4c46136599115fb921fc5e4b4c57. The predicate retains the same HTTP/non-HTTP, same-origin, and CORS-opt-in decisions; the behavioral change is the reason/remediation chosen for an opaque document. The opaque reason takes precedence and is exercised for same-host and remote assets, with console and bridge assertions. No other runtime consumer compares the old reason literal. Current CI is green; reviewed the complete diff and tests, without a new browser/audio experiment. No database changes.

Verdict: APPROVE
Reasoning: The diagnostic now names the correct origin problem without changing the media-routing decision. No blocking finding.

— Magi

@jrusso1020
jrusso1020 merged commit 8886743 into main Sep 14, 2026
60 checks passed
@jrusso1020
jrusso1020 deleted the fix/web-audio-opaque-origin-reason branch September 14, 2026 18:56
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.

2 participants