docs(playback): design structured mpegts diagnostics

This commit is contained in:
4gray committed 2026-08-01 16:20:18 +02:00
1 parent 9bb1811984
commit ae4718d88b
1 file changed
+301
@@ -0,0 +1,301 @@
# Structured mpegts.js Diagnostics
## Context
PR #1314 stopped treating ambiguous native media errors as codec evidence and
retained explicit HTTP status. PR #1316 added an allowlisted hls.js boundary,
PR #1317 added one for Video.js/VHS, and PR #1318 added one for Shaka Player.
mpegts.js is now the remaining browser source engine whose diagnostic path
serializes arbitrary error payloads and classifies them with substring
heuristics.
The locked workspace installs mpegts.js `1.8.0`. Its public player error event
has three arguments: error type, error detail, and an information value. The
runtime exports exact `ErrorTypes` and `ErrorDetails` constants. The current
IPTVnator classifier instead lowercases the arguments, serializes arbitrary
`info`, and searches the resulting text for network, access, codec, format,
MSE, and early-EOF fragments. This can misdiagnose failures, retain provider
text, and miss reliable facts such as the HTTP status carried by
`HttpStatusCodeInvalid`.
All three built-in web players own a mpegts.js integration:
- `HtmlVideoPlayerComponent` for the built-in HTML5 player;
- `VjsMpegTsSession` for Video.js;
- `ArtPlayerSourceSession` for ArtPlayer.
They must cross the same evidence boundary so the selected player does not
change the diagnosis for an identical engine event.
## Goals
- Add one minimal, allowlisted `MpegTsPlaybackEvidence` boundary shared by all
three mpegts.js owners.
- Version-lock the accepted public constants to installed mpegts.js `1.8.0`.
- Classify only exact, internally consistent public type/detail pairs.
- Surface a validated HTTP 4xx/5xx status for
`NetworkError + HttpStatusCodeInvalid`.
- Preserve the existing useful distinction for unrecoverable early EOF while
replacing text inference with the exact public detail.
- Prevent arbitrary `info`, messages, URLs, headers, bodies, credentials, and
provider objects from reaching stored or rendered diagnostics.
- Shape the evidence so a later player-neutral recommendation layer can use it
without coupling diagnostics to `PlayerController`.
## Non-goals
- Building the cross-player recommendation matrix.
- Moving recommendations, diagnostics, or fallback policy into
`PlayerController`.
- Automatic failover, player preference changes, retries beyond those already
owned by mpegts.js, probes, persistence, correlation, or diagnostic history.
- Adding new top-level diagnostic codes or changing diagnostic layout and
translations.
- Inferring CORS, mixed content, Content Security Policy, private-network
access, codec, format, or pipeline stage from message text.
- Inspecting mpegts.js loaders, demuxers, workers, or MediaSource internals at
runtime.
- Changing source selection, live/VOD mode, playback controls, duration
correction, or engine cleanup.
## Approaches Considered
### Public allowlisted evidence boundary (selected)
Normalize the public error-event arguments immediately into a small evidence
object. Accept only exact mpegts.js `1.8.0` type/detail constants, derive stage
and failure from consistent pairs, and read only a validated numeric status
from the documented network error-info slot. Classification and rendering then
receive the sanitized evidence rather than the raw event.
This is the strongest stable contract available. It fixes HTTP diagnostics,
removes unsafe serialization, keeps all three players consistent, and gives a
future recommendation layer explicit facts instead of prose.
### Exact constants plus message heuristics
Keep the public constants but continue reading `info.msg` to infer browser
access or more specific causes. This could preserve a few synthetic CORS cases,
but browser fetch exceptions commonly expose only generic text such as
`Failed to fetch`. Message text is not a stable public taxonomy and may contain
provider data. This approach is rejected.
### Add HTTP status to the existing classifier
Special-case `HttpStatusCodeInvalid` while leaving the rest of the substring
classifier unchanged. This would address issue #1159 narrowly but retain the
privacy and accuracy problems for every other mpegts.js failure. It would also
leave no coherent evidence contract for later recommendations. This approach
is rejected.
## Version-Locked Public Contract
The production allowlist accepts the exact public constants exported by
mpegts.js `1.8.0`.
Error types:
- `NetworkError`;
- `MediaError`;
- `OtherError`.
Error details:
- `Exception`;
- `HttpStatusCodeInvalid`;
- `ConnectingTimeout`;
- `UnrecoverableEarlyEof`;
- `MediaMSEError`;
- `FormatError`;
- `FormatUnsupported`;
- `CodecUnsupported`.
The package also exports loader-only `EarlyEof`, but it is not a public player
`ErrorDetails` value. mpegts.js attempts its finite-source reconnect internally
and exposes only `UnrecoverableEarlyEof` through the player error event when
recovery cannot complete. IPTVnator must not create a terminal diagnostic for
the internal recoverable value.
A contract test compares the allowlist and package version with the real
installed runtime. A dependency upgrade must fail that test and trigger a new
audit before changed or additional constants are accepted.
## Evidence Contract
`MpegTsPlaybackEvidence` contains:
- `engineType`: exact `NetworkError`, `MediaError`, or `OtherError`, otherwise
`unknown`;
- `engineDetails`: one exact public mpegts.js detail, otherwise `unknown`;
- `disposition`: `terminal`;
- `stage`: `loader`, `demux`, `media-source`, or `unknown`;
- `failure`: `http`, `timeout`, `network`, `truncated-stream`, `format`,
`codec`, `media-source`, or `unknown`;
- optional `httpStatus`: an integer from 400 through 599.
Stage and failure names are app-owned and stable. Exact engine type and detail
remain available separately so technical output still identifies the public
mpegts.js condition.
The evidence object does not retain:
- `info.msg` or any other message;
- arbitrary or serialized `info` values;
- request, response, redirect, or source URLs;
- headers, response text, bodies, events, exceptions, or loader objects;
- provider metadata, tokens, cookies, credentials, or unknown properties.
The existing `PlaybackDiagnostic.sourceUrl` remains the active source metadata
used by Retry, Copy URL, and explicit external-player actions. No URL is copied
from an engine error.
## Sanitization And HTTP Status
`createMpegTsPlaybackEvidence(type, details, info)` validates exact,
case-sensitive public values. Unknown strings, differently cased variants,
numbers, objects, and missing values become `unknown`; message fragments never
upgrade them.
The boundary reads `info.code` only for the exact
`NetworkError + HttpStatusCodeInvalid` pair. It retains the value only when it
is an integer from 400 through 599. Status-like fields on any other pair,
inside nested objects, or supplied as strings are ignored. No other `info`
property is read or copied.
The validated status is mirrored to the top-level diagnostic so the existing
metadata badge shows `HTTP 404` or `HTTP 5xx` without a UI redesign.
## Stage And Failure Mapping
Only internally consistent public type/detail pairs receive a stage or failure:
| Public type | Public detail | Stage | Failure |
| --- | --- | --- | --- |
| `NetworkError` | `HttpStatusCodeInvalid` | `loader` | `http` |
| `NetworkError` | `ConnectingTimeout` | `loader` | `timeout` |
| `NetworkError` | `Exception` | `loader` | `network` |
| `NetworkError` | `UnrecoverableEarlyEof` | `loader` | `truncated-stream` |
| `MediaError` | `FormatError` | `demux` | `format` |
| `MediaError` | `FormatUnsupported` | `demux` | `format` |
| `MediaError` | `CodecUnsupported` | `demux` | `codec` |
| `MediaError` | `MediaMSEError` | `media-source` | `media-source` |
`OtherError`, unknown values, and mismatched pairs keep both fields unknown.
For example, `OtherError + CodecUnsupported` must not become codec evidence.
This fail-closed rule prevents a future engine change or malformed event from
borrowing meaning from only half of the public contract.
## Lifecycle And Disposition
The public player `ERROR` event is terminal for IPTVnator's diagnostic
boundary. The installed engine handles recoverable finite-source early EOF
inside `IOController`; only failed recovery becomes
`UnrecoverableEarlyEof` and reaches the player event. Network, demux, and MSE
error paths likewise reach the player event after the active engine operation
has failed.
IPTVnator does not subscribe to internal recovery events or duplicate engine
retry logic. All accepted evidence therefore records `disposition=terminal`.
## User-Facing Classification
`classifyMpegTsPlaybackIssue` consumes sanitized evidence with this mapping:
1. `failure=http`, `timeout`, or `network` → `network-error`.
2. `failure=truncated-stream` → `media-decode-error`.
3. Exact `MediaError + FormatUnsupported` → `unsupported-container`.
4. Exact `MediaError + CodecUnsupported` → `unsupported-codec`.
5. `failure=format` or `media-source` → `media-decode-error`.
6. Everything else → `unknown-playback-error`.
The existing code-derived fallback behavior remains intentional:
- HTTP, timeout, generic network, and unknown failures do not claim that a
different decoder will fix the provider response;
- truncated-stream, unsupported-container, unsupported-codec, format, and
MediaSource failures may offer configured MPV/VLC actions because another
demuxer or media pipeline can plausibly handle the same source.
No mpegts.js error becomes `browser-access-error`. The public constants do not
distinguish CORS, mixed content, CSP, or private-network access from a generic
fetch exception, and status zero is not sufficient evidence.
## Runtime Integration
The raw event must cross the boundary once in each owner:
- `emitMpegTsPlaybackError` creates evidence for
`HtmlVideoPlayerComponent`;
- `VjsMpegTsSession` creates evidence before emitting its issue;
- `ArtPlayerSourceSession` creates evidence before emitting its issue.
All three call the same classifier with source metadata that preserves their
existing `InlinePlaybackPlayer` identity. No owner keeps or forwards the raw
event after normalization. Listener binding, stale-engine guards, live/VOD
mode, duration correction, source routing, play calls, and teardown remain
unchanged.
## Relationship To Shared Controls And Recommendations
`PlayerController` remains the engine-neutral command/state/capability
contract. It does not own error taxonomy, fallback policy, or provider
evidence.
Playback diagnostics are a sibling player-neutral layer: engine adapters emit
sanitized evidence, the diagnostic classifier maps it to a user-facing issue,
and the existing viewport renders that issue. A later recommendation layer can
consume diagnostic code, source, engine evidence, source metadata, and runtime
capabilities to explain whether another player is likely to help. That later
work must not require parsing the technical-details string or changing the
controls contract.
## User Interface
The existing technical `Error details` row renders only structured mpegts.js
evidence, for example:
`stage=loader · failure=http · type=NetworkError · details=HttpStatusCodeInvalid · disposition=terminal · HTTP 404`
When `issue.mpegTs` exists, legacy raw `details` and native message fields are
ignored even if a caller accidentally supplies them. Existing titles,
descriptions, HTTP badge, Retry, Copy URL, external-player actions, layout, and
translations remain unchanged.
## Testing
Use test-driven development:
- Compare the accepted constants and version with the real installed
mpegts.js `1.8.0` runtime.
- Cover every consistent public type/detail mapping.
- Prove mismatched, unknown, differently cased, and malformed inputs remain
unknown.
- Prove only exact `HttpStatusCodeInvalid` can expose a validated HTTP 4xx/5xx
status.
- Prove `info.msg`, nested status, URLs, headers, bodies, exceptions, and
arbitrary provider objects never enter evidence or rendered details.
- Cover HTTP 404, timeout, exception, unrecoverable early EOF, format error,
unsupported format, unsupported codec, MSE error, other, and unknown
classification.
- Cover evidence creation and issue emission through HTML5, Video.js, and
ArtPlayer integrations.
- Prove the rendered detail row uses only structured mpegts.js evidence and
preserves the HTTP metadata badge.
Run the focused red/green tests, complete `ui-playback` unit and lint targets,
web typecheck, i18n validation, release-note validation, and the repository
test-impact pass. No new E2E case is required because source selection,
playback lifecycle, controls, actions, and diagnostic layout remain unchanged;
the engine event, three adapter boundaries, classifier, and rendered output are
covered directly and deterministically.
## Documentation And Release Note
Update `docs/architecture/embedded-inline-playback.md` as the canonical
browser diagnostic contract. Update the mpegts.js diagnostic summaries in
`AGENTS.md` and `CLAUDE.md` because they describe the affected player engines
and evidence boundaries. No `player-controls-contract.md` change is needed
because the controls contract does not change.
Add a `fix(playback)` note under `.changes/` because users receive accurate HTTP
status, safer technical details, and more precise mpegts.js diagnoses.