Skip to content

fix(media): report unavailable MediaSource playback as unsupported - #1588

Draft
lanyue-llk wants to merge 4 commits into
mainfrom
codex/webfetch-media-source
Draft

lanyue-llk wants to merge 4 commits into
mainfrom
codex/webfetch-media-source

Conversation

@lanyue-llk

@lanyue-llk lanyue-llk commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
PR #1588 at a glance

Problem

Moli reported Media Source Extensions (MSE) as supported for some codecs even though it does not implement the SourceBuffer playback lifecycle. The two public probes could also disagree: MediaSource.isTypeSupported() and MediaCapabilities.decodingInfo({ type: "media-source" }) did not share the complete capability decision.

That sends feature-detecting players toward a playback path that cannot run instead of allowing an ordinary media fallback.

Change

Both public APIs now use one shared MSE type predicate. It combines the MIME decision with the actual MSE pipeline availability, which remains false until Moli implements the SourceBuffer lifecycle. This also keeps the APIs coherent if that availability changes later.

The observable Chrome-UA fingerprint is explicit: MediaSource.isTypeSupported() and media-source decodingInfo() return unsupported, including VP9 and AV1 configurations. HTMLMediaElement.canPlayType() is unchanged. The MediaSource, SourceBuffer, and SourceBufferList globals remain exposed, so pages that check only for a global still see the partial surface.

The maintainer concern that this probe contributes to fingerprinting is valid. Reporting an unusable playback path as supported would break ordinary feature detection, so this PR keeps the default API answer tied to the implemented capability rather than adding a site-specific fingerprint exception.

Reproduce and verify

For the same H.264 content type, compare:

MediaSource.isTypeSupported(contentType)
await navigator.mediaCapabilities.decodingInfo({
  type: "media-source",
  video: { contentType, width: 1920, height: 1080, bitrate: 5_000_000, framerate: 30 }
})
await navigator.mediaCapabilities.decodingInfo({
  type: "file",
  video: { contentType, width: 1920, height: 1080, bitrate: 5_000_000, framerate: 30 }
})

The two MSE probes return unsupported while the file control remains supported. The codec-color matrix now expects unsupported for every media-source row and continues to validate file decoding across VP9/AV1 color configurations.

cargo nextest run --locked -p moli-renderer-v8 --lib \
  -E 'test(media_source_) | test(media_capabilities_) | test(zhihu_capability_probe_) | test(zhihu_bot_detection_harness_) | test(zhihu_probe_window_)' \
  --no-fail-fast

cargo nextest run --locked -p moli-web-mime --lib --no-fail-fast

Local execution on macOS is blocked before compilation because Apple Command Line Tools are unavailable. cargo fmt --all -- --check and git diff --check pass. CI runs the Rust suites.

The current 430-task Web Fetch cohort does not score MSE playback, so this PR makes no benchmark-score claim.

Dependencies

Independent change targeting main; no other open PR is required.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Sequential Navigation Soak A/B

✅ HEAD completed the 200-navigation resilience and memory observation.

One browser process, one target, and one CDP session navigate CSDN → SegmentFault → Huaban → example.com repeatedly. This run issued 200 Page.navigate commands per binary.

Common ancestor bd8e0b27a9 → HEAD 70465dbdea; benchmark order: head-first; workflow: success.

Session resilience

Metric Base HEAD
Attempted / planned 200 / 200 200 / 200
Direct observable pass 198 / 200 197 / 200
Failures / recovered 2 / 2 3 / 3
Recovery failures 0 0
Lifecycle order violations 0 0
Network order violations 0 0
Wall time 512.5 s 621.0 s

A public-page failure is reported separately from an unrecoverable session. The soak requires all navigation attempts, zero failed recovery, zero lifecycle/network ordering violations, and complete resource evidence.

Process-tree memory

Metric Base HEAD Δ
Boundary samples 200 200 0
Boundary RSS samples 200 200 0
Boundary PSS samples 200 200 0
Periodic peak RSS 258.5 MiB 263.1 MiB +4.6 MiB
Periodic peak PSS 254.5 MiB 259.0 MiB +4.5 MiB
RSS · first 10 avg 187.8 MiB 171.0 MiB -16.8 MiB
RSS · last 10 avg 194.9 MiB 199.7 MiB +4.8 MiB
RSS · last − first window +7.1 MiB +28.7 MiB +21.6 MiB
RSS · warm slope / 100 nav +4.2 MiB +7.8 MiB +3.6 MiB
PSS · first 10 avg 184.4 MiB 167.4 MiB -17.0 MiB
PSS · last 10 avg 191.8 MiB 196.3 MiB +4.5 MiB
PSS · last − first window +7.4 MiB +28.9 MiB +21.5 MiB
PSS · warm slope / 100 nav +4.3 MiB +8.1 MiB +3.7 MiB
Peak file descriptors 58 58 0
Peak threads 29 30 1

HEAD memory by 50-navigation quarter

HEAD range Avg RSS Final RSS Peak RSS Avg PSS Final PSS Peak FD
1–50 178.9 MiB 160.2 MiB 220.3 MiB 175.2 MiB 156.5 MiB 53
51–100 190.2 MiB 204.2 MiB 225.2 MiB 186.3 MiB 200.3 MiB 53
101–150 193.3 MiB 169.4 MiB 232.9 MiB 189.7 MiB 165.9 MiB 53
151–200 192.3 MiB 137.2 MiB 229.0 MiB 188.9 MiB 133.7 MiB 53

Raw reports and per-navigation boundary samples: workflow run and full sequential-navigation-soak-results artifact.

Public-site timing and memory are observational. Use the A/B deltas and trend shape as evidence, not as a deterministic performance threshold.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Spider Bench A/B

⚠️ Benchmark observation recorded non-blocking run issues: real48/head: service-run-failed.

Public HEAD: 169 / 240 rows; 35 / 48 sites produced rows; 13 unexpected empty sites.

✅ Deterministic fixture contract is clean.

Common ancestor bd8e0b27a955 → HEAD 70465dbdea11; benchmark order: head-first; workflow: success.

Public 48-site run · informational

Metric Base HEAD Δ
Run status success failed —
Extracted rows / contract 184 / 240 169 / 240 -15 (-8.15%)
Contract fill 76.67% 70.42% -6.25 pp (-8.15%)
Sites with rows 38 / 48 35 / 48 -3 (-7.89%)
Sites meeting row contract 36 / 48 33 / 48 -3 (-8.33%)
Unexpected empty sites 10 13 +3 (+30.00%)
Partial-row sites 2 2 0 (0.00%)
Site outcomes extracted: 37; HTTP error + rows: 1; empty: 7; HTTP error + empty: 1; snapshot error + empty: 2 extracted: 33; HTTP error + rows: 2; empty: 7; navigation error + empty: 4; snapshot error + empty: 2 —
Observed duration 49.04 s 41.57 s -7.47 s (-15.23%)
Estimated CPU 43.39 s 38.66 s -4.72 s (-10.88%)
Peak PSS 265.32 MiB 237.50 MiB -27.83 MiB (-10.49%)
Peak RSS 268.57 MiB 240.68 MiB -27.89 MiB (-10.39%)
Peak threads 26 26 0 (0.00%)
Mismatched sites 0 0 0
Timeout with items 0 0 0
Category rows Base HEAD Δ
news 35 / 40 35 / 40 0
stocks 20 / 40 20 / 40 0
tech 35 / 40 35 / 40 0
sports 27 / 40 27 / 40 0
games 37 / 40 37 / 40 0
life 30 / 40 15 / 40 -15

Public-site content, timing, and memory are noisy. This single A/B run reports evidence only; site outcome counts explain missing rows without treating them as a deterministic regression.

CPU and memory timelines

These are bounded 40-point views of the same complete process-tree samples used by the HTML report. CPU uses 100% per occupied logical core; memory lines are RSS first and PSS second when complete PSS samples are available.

Base

xychart-beta
    title "Base CPU"
    x-axis "Elapsed seconds" [1.536, 2.537, 4.039, 5.041, 5.542, 6.541, 7.042, 8.044, 9.547, 11.049, 12.551, 13.553, 15.056, 16.559, 17.559, 19.061, 20.564, 22.066, 23.068, 24.57, 25.07, 26.07, 27.072, 28.572, 30.074, 31.577, 32.579, 34.08, 35.581, 37.084, 38.085, 39.588, 41.088, 42.09, 43.594, 45.096, 46.598, 47.6]
    y-axis "CPU percent" 0 --> 200
    line [119.86, 127.86, 139.74, 121.74, 133.96, 110.05, 145.86, 85.83, 49.9, 109.95, 25.95, 0, 77.85, 107.95, 42.01, 5.99, 37.92, 70.03, 115.71, 100.01, 114.04, 101.86, 105.93, 115.93, 117.95, 101.92, 115.89, 43.98, 113.94, 97.77, 9.99, 105.93, 101.88, 99.84, 99.23, 105.85, 13.98, 131.65]
Loading
xychart-beta
    title "Base memory: RSS then PSS"
    x-axis "Elapsed seconds" [0.035, 1.536, 2.537, 4.039, 5.041, 5.542, 6.541, 7.042, 8.044, 9.547, 11.049, 12.551, 13.553, 15.056, 16.559, 17.559, 19.061, 20.564, 22.066, 23.068, 24.57, 25.07, 26.07, 27.072, 28.572, 30.074, 31.577, 32.579, 34.08, 35.581, 37.084, 38.085, 39.588, 41.088, 42.09, 43.594, 45.096, 46.598, 47.6, 49.037]
    y-axis "Memory MiB" 0 --> 500
    line [13.05, 97.93, 109.6, 137.5, 154.31, 144.66, 132.29, 145.82, 130.31, 148.52, 131.78, 138.15, 122.49, 125.71, 153.11, 123.59, 120.39, 129.7, 118.42, 135.41, 232.69, 268.57, 184.93, 207.49, 137.5, 144.29, 145.71, 146.05, 141.16, 234.34, 156.41, 147.09, 148.74, 172.79, 172.92, 173.05, 162.75, 127.22, 151.49, 0]
    line [9.81, 94.87, 106.59, 134.54, 151.38, 141.67, 129.54, 142.97, 127.44, 145.31, 129.08, 135.28, 119.65, 122.82, 150.37, 120.9, 117.51, 126.79, 115.79, 132.46, 229.51, 265.32, 181.67, 204.43, 134.31, 141.14, 143.05, 142.93, 138.12, 231.1, 153.27, 143.93, 146.05, 169.51, 169.63, 169.76, 159.78, 123.94, 148.37, 0]
Loading

HEAD

xychart-beta
    title "HEAD CPU"
    x-axis "Elapsed seconds" [1.036, 2.037, 2.538, 3.538, 4.54, 6.041, 7.042, 8.043, 9.043, 10.546, 11.546, 12.547, 14.05, 15.051, 16.051, 16.551, 17.553, 18.554, 19.555, 21.056, 22.059, 23.06, 24.061, 25.562, 26.565, 27.567, 29.068, 30.071, 31.073, 32.574, 33.575, 34.076, 34.577, 35.579, 37.08, 38.082, 39.083, 40.584]
    y-axis "CPU percent" 0 --> 200
    line [31.97, 79.91, 133.87, 111.98, 147.71, 124.03, 75.94, 147.8, 44, 49.9, 130.01, 58.01, 35.91, 2, 40.01, 157.95, 67.84, 107.96, 99.84, 101.98, 109.82, 73.96, 119.97, 99.86, 105.79, 109.74, 12, 139.6, 103.77, 51.97, 15.98, 0, 13.97, 123.74, 99.93, 99.75, 99.89, 99.89]
Loading
xychart-beta
    title "HEAD memory: RSS then PSS"
    x-axis "Elapsed seconds" [0.036, 1.036, 2.037, 2.538, 3.538, 4.54, 6.041, 7.042, 8.043, 9.043, 10.546, 11.546, 12.547, 14.05, 15.051, 16.051, 16.551, 17.553, 18.554, 19.555, 21.056, 22.059, 23.06, 24.061, 25.562, 26.565, 27.567, 29.068, 30.071, 31.073, 32.574, 33.575, 34.076, 34.577, 35.579, 37.08, 38.082, 39.083, 40.584, 41.57]
    y-axis "Memory MiB" 0 --> 500
    line [13.07, 83.2, 103.01, 111.66, 123.45, 129.42, 145.1, 153.12, 144.92, 130.46, 135.27, 135.36, 125.83, 143.73, 114.58, 128.52, 142.41, 123.64, 119.71, 168.45, 177.61, 161.7, 143.25, 173.47, 131.07, 138.65, 130.09, 138.11, 192.13, 240.68, 136.86, 125.88, 125.72, 125.74, 156.11, 162.7, 162.73, 162.73, 164.64, 0]
    line [9.78, 79.72, 99.56, 108.23, 119.94, 125.98, 141.58, 149.61, 141.4, 126.94, 131.63, 131.84, 122.38, 140.31, 111.06, 125, 138.96, 120.13, 116.19, 165.39, 174.09, 158.98, 139.74, 169.97, 127.5, 135.13, 126.58, 134.67, 188.74, 237.5, 133.38, 122.39, 122.24, 122.34, 152.7, 159.08, 159.12, 159.3, 161.92, 0]
Loading

Deterministic fixture · required contract

The fixture exercises 15 routes: 8 are expected to emit rows and 7 intentionally exercise empty, loading, or timeout behavior.

Metric Base HEAD Δ
Run status success success —
Extracted rows / contract 40 / 40 40 / 40 0 (0.00%)
Contract fill 100.00% 100.00% 0.00 pp (0.00%)
Sites with rows 8 / 15 8 / 15 0 (0.00%)
Sites meeting row contract 15 / 15 15 / 15 0 (0.00%)
Unexpected empty sites 0 0 0
Partial-row sites 0 0 0
Site outcomes extracted: 7; HTTP error + rows: 1; empty: 3; timeout + empty: 4 extracted: 7; HTTP error + rows: 1; empty: 3; timeout + empty: 4 —
Observed duration 19.86 s 19.87 s +0.01 s (+0.06%)
Estimated CPU 0.41 s 0.42 s +0.01 s (+2.42%)
Peak PSS 66.06 MiB 66.07 MiB +0.01 MiB (+0.02%)
Peak RSS 69.65 MiB 69.80 MiB +0.14 MiB (+0.21%)
Peak threads 18 18 0 (0.00%)
Mismatched sites 0 0 0
Timeout with items 0 0 0

Full HTML, JSON, CSV, logs, and page snapshots: workflow run and full spider-bench-results artifact.

The public-web A/B is informational. The exact HEAD fixture contract runs as a separate required CI check; timing and public-site content deltas remain non-blocking.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

CI Regression Report

Source CI run · source state at render: in_progress · artifacts: 6/6

Check Status Signal
Release regression ✅ HEAD/base failures 0/0; raw binary −0.000066%
Frontend differential ✅ 1,020/1,020 cases matched; 0 issues
Agent episodes ✅ 8/8 Moli episodes passed; 0 failures
Runtime/CDP contracts ✅ 26 contract cases; 0 failures
CDP smoke ✅ 52/52 groups passed; 622 scenarios
WebMainBench ✅ 545/545 completed; 0 unexpected failures
Release regression — ✅ HEAD/base failures 0/0; raw binary −0.000066%

Package and image size

Metric Base HEAD Delta Delta %
Raw binary 150.19 MiB 150.19 MiB −104 B −0.000066%
Stripped binary 103.27 MiB 103.27 MiB 0 B 0.00%
gzip binary 51.58 MiB 51.58 MiB −209 B −0.000386%
Rootfs 157.10 MiB 157.10 MiB 0 B 0.00%
gzip rootfs 60.49 MiB 60.49 MiB +125 B +0.000197%

Startup latency and PSS

Case Base p50 HEAD p50 Delta Base PSS HEAD PSS Delta
Serve ready 26.81 ms 26.78 ms −0.03 ms 4.77 MiB 4.83 MiB +58.00 KiB
CDP first page 47.36 ms 48.37 ms +1.01 ms 4.13 MiB 4.43 MiB +308.00 KiB
CDP warm page 11.57 ms 12.76 ms +1.19 ms 50.49 MiB 50.45 MiB −47.50 KiB
CLI about:blank 14.77 ms 15.22 ms +0.45 ms 4.14 MiB 4.09 MiB −49.00 KiB
CLI local JS 18.84 ms 19.37 ms +0.53 ms 4.36 MiB 5.13 MiB +794.00 KiB

Concurrency matrix

Concurrency Base p50 HEAD p50 Delta Base PSS HEAD PSS Delta HEAD failures Unstable B/H
1 18.08 ms 18.33 ms +0.25 ms 898.00 KiB 768.00 KiB −130.00 KiB 0 0/0
5 20.85 ms 20.39 ms −0.46 ms 28.27 MiB 13.53 MiB −14.74 MiB 0 0/0
10 20.65 ms 21.92 ms +1.27 ms 27.81 MiB 28.30 MiB +500.00 KiB 0 0/0
25 21.30 ms 21.02 ms −0.28 ms 13.50 MiB 13.74 MiB +241.00 KiB 0 0/0
100 21.71 ms 20.27 ms −1.44 ms 18.87 MiB 13.64 MiB −5.24 MiB 0 0/0
Frontend differential — ✅ 1,020/1,020 cases matched; 0 issues
Match DOM mismatch Diagnostic mismatch Moli error Reference error Infrastructure error Mismatched frames Duration
1,020 0 0 0 0 0 0 6m 25.31s
Agent episodes · Moli vs Chromium — ✅ 8/8 Moli episodes passed; 0 failures
Fast contract Episodes Passed Assertions Ready p50 Episode p50
Moli 8 8 47/47 3.05 ms 24.78 ms
Chromium 8 8 47/47 265.64 ms 84.08 ms
Operation p50 Chromium Moli Delta Delta %
navigate 40.35 ms 5.96 ms −34.39 ms −85.22%
observe 1.76 ms 1.01 ms −0.76 ms −43.04%
fill 3.34 ms 3.29 ms −0.05 ms −1.49%
click 5.74 ms 4.53 ms −1.21 ms −21.05%
Idle-resource episode Peak RSS Peak PSS Average CPU Peak CPU Peak processes Sampler
Moli 65.97 MiB 62.96 MiB 0.76% 8.04% 1 ✅
Chromium 1277.04 MiB 403.01 MiB 0.56% 6.03% 13 ⚠️ PSS partial
Runtime and CDP session contracts — ✅ 26 contract cases; 0 failures
Suite Cases Failures Median case p50 Median case p95 Median peak PSS p50
Synthetic fetch 13 0 17.19 ms 18.02 ms 598.00 KiB
Long-lived CDP session 13 0 17.57 ms 17.97 ms —
CDP smoke — ✅ 52/52 groups passed; 622 scenarios

Workers: 4 · cumulative group time: 156.67 s · failed groups: 0

Slowest group Scenarios Duration Status
scrollbar-visibility 22 15.87 s ✅
target-lifecycle 24 14.54 s ✅
dom-input 27 10.51 s ✅
chromium-cdp 56 10.04 s ✅
multi-page 45 9.01 s ✅
WebMainBench · 545 pages — ✅ 545/545 completed; 0 unexpected failures
Completed Successful Expected DNS failure Unexpected failures Panics Crashes Timeouts Empty output
545/545 544 1 0 0 0 0 0

Frozen HTML · Linux · --wait done · 45 seconds per page · no retries. Content quality is evaluated separately.

Diagnostics: webmainbench-results — every page's Markdown, stderr, and exit status. Source run and artifacts

All artifact fields are parsed by the trusted default-branch renderer; missing or invalid inputs remain visible as unavailable.

@lanyue-llk lanyue-llk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

复核提交 d7d79015443c,未发现本次改动新增的明确阻断问题。

当前 MediaSource 只有构造和能力查询表面,没有可用的 SourceBuffer/addSourceBuffer 流程;继续返回 true 会让页面选择无法执行的播放路径。MSE 的能力查询应反映实现实际支持的类型。现阶段统一返回 false 比伪造一份支持列表合适,也无需为此实现整个 MSE。

参数仍先经过 WebIDL 转换,缺参、Symbol 和用户转换异常没有被提前返回吞掉;改动也没有修改普通媒体的 MIME 判断。已核对相关代码和转换测试;本机缺少原生开发工具,未运行该提交的 V8 测试。

@ldm0

ldm0 commented Oct 16, 2026

Copy link
Copy Markdown
Member

It's part of fingerprint, I think it's by design.

@ldm0
ldm0 marked this pull request as draft October 16, 2026 04:16
@lanyue-llk
lanyue-llk force-pushed the codex/webfetch-media-source branch from d7d7901 to b7e9d21 Compare October 20, 2026 10:42
@lanyue-llk

Copy link
Copy Markdown
Contributor Author

I checked this against the implemented surface and kept the change.

MediaSource.isTypeSupported() is a capability query, not only a fingerprint bit. Moli currently exposes neither an operational SourceBuffer lifecycle nor MediaSource.prototype.addSourceBuffer. Returning true for AVC therefore sends ordinary feature-detecting pages down an MSE path that cannot run. Returning false is the smallest coherent behavior until MSE is implemented; it preserves the constructor shape and WebIDL conversion behavior and does not add site-specific handling.

The fingerprint concern is real, but advertising an unusable capability is not a safe general fingerprint strategy. If Moli later adds an explicit fingerprint-emulation mode, that should be a separate policy decision rather than the default Web API contract.

The branch has also been rebased onto current main; the focused capability/coercion controls remain part of the PR CI.

@lanyue-llk lanyue-llk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This PR changes MediaSource.isTypeSupported() to always return false (after WebIDL argument conversion), because Moli exposes MediaSource without a SourceBuffer/addSourceBuffer lifecycle, so players should take a progressive or other fallback path instead of an MSE path that can never play. Returning false conforms to the MSE spec (a UA may report any type as unsupported) and keeps hls.js/dash.js/video.js-style isTypeSupported gates correct. However, the fix covers only one of the two MSE capability probes and leaves the old predicate as dead code, so I am requesting changes.

[major] navigator.mediaCapabilities.decodingInfo({type: 'media-source'}) still claims support, which now contradicts isTypeSupported. media_capabilities_decoding_info_callback (moli-renderer-v8/src/context_bootstrap/navigator_runtime/media_capabilities.rs:357) computes supported through configuration_supported() -> media_mime_support() and ignores configuration.decoding_type. So decodingInfo({type:'media-source', video:{contentType:'video/mp4; codecs=\"avc1.42E01E\"', ...}}) resolves {supported: true} while MediaSource.isTypeSupported on the same type now returns false. Media Capabilities defines media-source as a configuration for MSE playback, and players such as Shaka and YouTube's player filter variants with decodingInfo (Shaka even polyfills decodingInfo on top of isTypeSupported). Those players can still pick the unusable MSE path, and the two answers are now internally incoherent, which is also a fingerprinting signal. Suggested fix: put the MSE answer in one shared capability function (for example moli_web_mime::media_source_support() returning false until SourceBuffer exists) and call it from both isTypeSupported and the MediaDecodingType::MediaSource branch of decodingInfo. Add a test asserting that both APIs agree.

[minor] Dead code left behind. moli_web_mime::is_media_source_type_supported (moli-web-mime/src/media.rs:34, re-exported in lib.rs:32) no longer has any production caller; only moli-web-mime/src/tests.rs:334-347 uses it, and those tests still assert true for avc1 and so document behavior Moli no longer has. Under the repo's one-implementation rule, either remove the function and its tests, or keep it as the single owner and have it return the honest answer.

[minor] Anti-bot fingerprint impact is not addressed. The flipped expectations live in fixtures named zhihu_bot_detection_harness / zhihu_capability_probe ("stable moli baseline"). The UA is Chrome-like, and real Chrome returns true for avc1.42E01E. Open-source Chromium/headless builds without proprietary codecs return false, a known bot-detection heuristic. The PR rewrites these baselines without saying whether Zhihu (or similar) gates content on this probe. The CI A/B runs (Spider, WebMainBench, soak) show no regression, but they do not exercise Zhihu's anti-bot path specifically. Please state the tradeoff in the PR description, or show that the Zhihu fixtures do not gate on avc1.

[nit] Remaining partial-exposure limitation. window.MediaSource (constructible) and SourceBuffer/SourceBufferList (illegal-constructor globals) are still exposed, so players that feature-detect only by 'MediaSource' in window still take MSE. The PR deliberately accepts this; consider noting it in the PR description so it is not mistaken for full coverage.

Tests: the new test mostly re-asserts the hard-coded false. Its operational/route logic depends only on addSourceBuffer being absent (SourceBuffer is already a global function), and the 'video/mp4' and '' cases returned false before this PR too, so only the first two claims fail without the fix. Acceptable, but the cross-API agreement test above would be more valuable. CI: all checks pass (fmt, clippy, nextest, A/B benches).

Verdict: changes requested (posted as a comment because GitHub does not allow requesting changes on your own PR).

Automated review by Claude Code.

Comment thread moli-renderer-v8/src/context_bootstrap/media_source.rs Outdated
Comment thread moli-renderer-v8/src/context_bootstrap/media_source.rs Outdated
Comment thread moli-renderer-v8/src/script_vm/tests/browser_api/media.rs Outdated
@lanyue-llk
lanyue-llk force-pushed the codex/webfetch-media-source branch from ece5986 to f39415b Compare October 22, 2026 06:31

@lanyue-llk lanyue-llk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-review of the updated version (f39415bc5)

Round 2. The PR now reports MSE as unavailable from both MediaSource.isTypeSupported() and navigator.mediaCapabilities.decodingInfo({type:'media-source'}), gated through one shared moli_web_mime::media_source_available(). File, WebRTC and canPlayType answers are unchanged. The design is right, but the new gate breaks an existing test that still expects media-source support, and Nextest is red on the new head. Verdict: request changes.

Previous findings

# Finding Status Evidence
1 [major] decodingInfo({type:'media-source'}) disagreed with isTypeSupported FIXED media_capabilities.rs:522-528 returns false for Decoding(MediaSource) when !media_source_available(). media_source.rs:51 goes through is_media_source_type_supported, which is gated by the same function.
2 [nit] no-op drop(parsed.media_type) FIXED (moot) The callback now passes parsed.media_type to the shared predicate (media_source.rs:51).
3 [minor] test only re-asserted the hard-coded false FIXED media.rs:2150-2181 checks both APIs for two MP4 types. Without the decodingInfo gate it would produce [[false,true],...] and fail.
4 [minor] dead is_media_source_type_supported PARTIAL The function has a caller again, but its codec body is now unreachable behind a const false and has lost its test coverage. It also does not match decodingInfo's type rules. See new finding 2.
5 [minor] anti-bot fingerprint tradeoff undocumented PUSHBACK PARTLY ACCEPTED The author's argument holds: advertising an unusable capability is not a sound default. The PR body still does not state the visible change, though, and the scope grew: Chrome-UA pages now also see decodingInfo media-source false for VP9/AV1, and canPlayType still says probably. Maintainer @ldm0 commented "It's part of fingerprint, I think it's by design", and that thread has no resolution.
6 [nit] window.MediaSource/SourceBuffer still exposed NOT ADDRESSED (accepted limitation) The PR body still does not mention it. Fine to leave, but say it in one line.

New findings

  1. [blocker] An existing test now fails. navigator_devices.rs::media_capabilities_codec_colors_constrain_support_without_rejecting_the_dictionary runs media_capabilities_codec_color.js, which loops for (const type of ['file','media-source']) (line 261) and requires supported === expected. Its expected ignores type and is true for every well-formed VP9/AV1 case. With the new gate every media-source row returns false, so the test fails. This matches the Nextest failure (exit 100) on f39415b; full logs are not available yet because the run is still in progress. Fix: make expected include type === 'file', or keep the color matrix on file only and add one media-source row that asserts supported:false, smooth:false, powerEfficient:false. The PR's suggested -E filter misses this test, so run all of navigator_devices/media_capabilities_*.
  2. [minor] Only the availability gate is shared, not the type decision. Once media_source_available() becomes true, isTypeSupported would accept only video/mp4 + avc1.*, while decodingInfo accepts any video/mp4|webm|ogg through media_mime_support. For example, video/webm; codecs="vp09.00.10.08" would give false from one API and true from the other, which brings back the round-1 disagreement. Today the avc1 body is unreachable, and the tests that covered it (case-insensitive Video/MP4, hev1, notvideo/mp4) were deleted. Fix: have one media_source_type_supported(content_type) that both callers use (decodingInfo per audio/video member), or make is_media_source_type_supported just media_source_available() && media_mime_support(t) != Unsupported. Then delete the avc1-only branch rather than keep untested dead logic.
  3. [nit] The coherence test does not show the gate is scoped to media-source. Add the same content type with type:'file' and expect true, so a regression that disables all decodingInfo support fails here too.
  4. [nit] PR body and fingerprint. Add one sentence on the observable change for Chrome-UA probes (MSE isTypeSupported and decodingInfo media-source both false, canPlayType unchanged, MediaSource/SourceBuffer globals still present). Get an explicit maintainer OK on @ldm0's "by design" comment before marking ready. Author thread replies cite ece5986ef, which is not in the PR (head is f39415b).

CI / merge: On f39415b, Nextest and CDP smoke (Chromium) fail, and both release builds are queued. CDP smoke has also failed on a recent main run (45be4e3), so it may be unrelated, but I could not confirm that. All A/B bot reports are for the old head b7e9d21. git merge-tree --write-tree origin/main (14d3c08) merges cleanly. Commit stack: 2 commits, both on topic.

Verdict: changes requested (posted as a comment because GitHub does not allow requesting changes on your own PR).

Automated review by Claude Code.

Comment thread moli-renderer-v8/src/context_bootstrap/navigator_runtime/media_capabilities.rs Outdated
Comment thread moli-web-mime/src/media.rs
Comment thread moli-renderer-v8/src/script_vm/tests/browser_api/media.rs

@lanyue-llk lanyue-llk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Final re-review (P0/P1 only) (6cad52920)

Final round (head 6cad529). Verdict: approve, provided Nextest goes green. The round-2 blocker is fixed in the fixture. isTypeSupported and decodingInfo({type:'media-source'}) now share one complete type predicate.

# Previous finding Status Evidence
R1-1 [major] decodingInfo media-source disagreed with isTypeSupported FIXED media_capabilities.rs:522-532: every audio/video member goes through moli_web_mime::is_media_source_type_supported. media_source.rs:51 calls the same predicate.
R2-1 [blocker] navigator_devices.rs::media_capabilities_codec_colors_constrain_support_without_rejecting_the_dictionary broken, Nextest red FIXED (static) media_capabilities_codec_color.js:266: expected = type === 'file' && .... Media-source rows now expect supported:false. smooth and powerEfficient are always false (media_capabilities.rs:303-306), so the (supported || (!smooth && !powerEfficient)) guard passes too. I checked the other fixtures that query media-source (media_capabilities_mime.js:671, media_capabilities_video_options.js). They only assert supported===false or a rejection, so they still pass. window_surface.rs:620 and platform_compat.rs:186/419 already expect false.
R2-2 Type rules differ between the two APIs (latent regression of R1-1) FIXED moli-web-mime/src/media.rs:45-47: media_source_available() && media_mime_support(input) != Unsupported. The avc1-only branch is gone. Both APIs now use the same rule per member; decodingInfo additionally applies the codec color check, which is correct. Test added at tests.rs:341 (webm vp09 → false).
R2-3 [nit] no file control in the coherence test FIXED media.rs:2167-2183 expects [[false,false,true],[false,false,true]].

New P0/P1 findings: none. The delta from the previous round is 5 files and +21/-16 lines, all scoped to the MSE gate and its tests.

CI on 6cad529: Format, Clippy, Windows persistent storage, Node harness, Python harness and CDP smoke (Chromium) pass. CDP smoke failed last round and now passes. Nextest and both release builds are still queued. The Nextest log from the previous head is gone (BlobNotFound), so I could not confirm that the codec-color test was its only failure. Approve only after Nextest is green. The PR merges cleanly with origin/main (14d3c08). It is still a draft.

Verdict: approve (posted as a comment; self-approval is not allowed).

Automated review by Claude Code.

@lanyue-llk

Copy link
Copy Markdown
Contributor Author

Follow-up on the current-head Nextest failure: the capability implementation was correct; the new test observed a two-stage async/await chain after only the test VM checkpoint. Commit 70465db issues all four capability promises before one Promise.all, preserving the same cross-API assertion without depending on extra checkpoints. Validation: the focused moli-web-mime capability test passes, and cargo check --locked --tests -p moli-renderer-v8 passes. The monolithic renderer test binary exceeds this local 12 GiB linker budget, so the exact linked test is left to the PR Nextest job rather than weakening or splitting the test target.

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