* docs(playback): design structured HLS diagnostics * docs(playback): plan structured HLS diagnostics * fix(playback): structure HLS diagnostics * docs(playback): document structured HLS evidence * fix(playback): keep HLS startup logs private
9.1 KiB
Structured HLS Diagnostics
Context
PR #1314 made native media diagnostics evidence-based, but the HLS path still
normalizes type, details, message, and an arbitrary error payload into
one string. classifyHlsPlaybackIssue then searches that string for broad
fragments such as network, status, and codec. This can misclassify a
provider message, and serializing arbitrary values can retain URLs,
credentials, response content, loader context, or other provider data.
IPTVnator currently installs hls.js 1.6.16. Its public ErrorData supplies
structured type, details, fatal, and an optional response.code.
Specific ErrorDetails values also identify the manifest, level, segment, key,
or media stage. The same payload contains unsafe or unbounded fields, including
error, reason, networkDetails, context, loader, url, and response
URL/text/data, which are not needed for classification.
Both the HTML5 player and ArtPlayer subscribe to Hls.Events.ERROR. They
currently ignore fatal: false before calling the classifier, but each adapter
builds the broad string input independently.
Goals
- Create one structured HLS evidence boundary for the installed hls.js error shape.
- Retain only allowlisted engine type/detail identifiers, the final fatal/recoverable disposition, a stage derived from exact details, a structured failure kind, and a validated HTTP status when present.
- Classify HLS failures from exact engine values rather than substring heuristics.
- Keep insufficient evidence explicitly unknown.
- Ensure recoverable hls.js events never become terminal playback diagnostics.
- Use the same extraction and classification path in HTML5 and ArtPlayer.
- Show only the sanitized evidence in technical diagnostic details.
Non-goals
- Diagnostic history, persistence, correlation, or telemetry.
- Additional manifest or stream probes.
- Automatic player failover.
- A Shaka or mpegts.js diagnostic redesign.
- A cross-player confidence or likelihood matrix.
- Inferring browser access failures from status zero,
TypeError, or error message text. - Changing hls.js retry, level-switch, or recovery behavior.
Approaches Considered
Boundary sanitizer (selected)
Convert hls.js ErrorData into a small HlsPlaybackEvidence value at the
adapter boundary. The classifier accepts only that value. This centralizes the
allowlist, makes unsafe fields structurally unavailable to classification and
UI code, and gives HTML5 and ArtPlayer identical behavior.
Pass ErrorData directly
This would preserve the strongest TypeScript relationship with hls.js, but it would leave every consumer able to read or render URLs, loader state, headers, response payloads, and arbitrary errors. It also makes privacy depend on each future call site remembering the same exclusions.
Keep the broad input and tighten string tests
Exact comparisons could improve classification, but the adapters would still copy arbitrary messages and objects into diagnostics. This would not establish the requested safe evidence contract.
Evidence Contract
HlsPlaybackEvidence contains:
engineType: one of the installed hls.jsErrorTypesvalues, otherwiseunknown;engineDetails: one of the installed hls.jsErrorDetailsvalues, including its existingunknownvalue;disposition:fatalwhenErrorData.fatal === true, otherwiserecoverable;stage:manifest,level,segment,key,media, orunknown;failure:http,timeout,network,access, orunknown;- optional
httpStatus: an integer from 100 through 599 copied only fromErrorData.response.code.
The access value is part of the contract but hls.js 1.6.16 does not expose a
reliable structured CORS, mixed-content, CSP, or private-network-access code.
Status zero and generic fetch failures can also mean DNS, offline, connection,
or abort failures. The extractor therefore does not emit access for current
runtime shapes; it uses network or unknown and never inspects message text.
The extractor does not copy:
ErrorData.url;context, including request URLs and headers;networkDetailsor loader instances;response.url,response.text, orresponse.data;error, deprecatederr,reason, events, fragments, or arbitrary values.
The existing playback metadata still carries the active source URL for the pre-existing Retry, Copy URL, and explicit external-player workflows. No HLS error URL is copied into evidence or shown in technical details.
Stage Mapping
Stages are derived only from exact ErrorDetails values:
manifest: manifest load, timeout, parsing, and incompatible-codec details;level: level load, timeout, parsing, empty, and switch details, plus audio/subtitle track playlist load details;segment: fragment load, timeout, parsing, decrypt, and gap details;key: key load/timeout and key-system details;media: buffer, mux/remux, attach-media, and playback-stall details;unknown: internal, aborted, interstitial, unrecognized, or otherwise unmapped details.
This mapping describes the engine stage, not root-cause likelihood. For example, a segment-stage timeout is still classified as a network timeout.
Failure Mapping
Failure kind uses this precedence:
- Exact timeout details produce
timeout. - A validated 4xx or 5xx
response.codeproduceshttp. - Exact network load-error details, or the exact
networkErrorengine type, producenetwork. - No current hls.js 1.6.16 field independently proves
access. - Everything else is
unknown.
A 1xx, 2xx, or 3xx status remains retained as factual response metadata but does not by itself produce an HTTP-failure kind.
Classification
classifyHlsPlaybackIssue returns PlaybackDiagnostic | null:
recoverablereturnsnullbefore classification.- Exact incompatible/add-codec details produce
unsupported-codec. - Exact key-system or fragment-decrypt evidence produces
drm-or-encryption. - Exact network type, load/timeout details, or HTTP failure evidence produces
network-error. - Exact media or mux type produces
media-decode-error. - Everything else produces
unknown-playback-error.
The HLS path does not emit browser-access-error without structured access
evidence. It also does not classify keyLoadError as DRM: failure to fetch an
encryption key is network evidence, while fragDecryptError and key-system
details are encryption/DRM evidence.
The normalized PlaybackDiagnostic retains the sanitized HLS evidence and
copies its validated HTTP status into the existing top-level httpStatus
field. External fallback recommendations continue to derive from the final
diagnostic code.
Adapter Flow
HTML5 and ArtPlayer both use:
createHlsPlaybackEvidence(data);classifyHlsPlaybackIssue(evidence, sourceMetadata);- emit only when the classifier returns a diagnostic.
The fatal gate therefore lives in the shared classifier rather than being
duplicated in the two adapters. hls.js registers its final error-controller
listener during construction, before IPTVnator subscribes, so the application
observes the final fatal value after retry/alternate handling has had a
chance to update it.
User Interface
The existing technical “Error details” row renders a deterministic, safe HLS summary made only from the evidence fields, for example:
stage=manifest · failure=http · type=networkError · details=manifestLoadError · disposition=fatal · HTTP 404
No HLS error message, URL, header, body, response text, or arbitrary provider payload appears. HLS startup development logs are event-only and omit provider-supplied channel names and source URLs. Existing title/description and HTTP metadata rendering remain unchanged, so no new translation keys or layout changes are required.
Testing
Use test-driven development:
- Add extractor tests using hls.js 1.6.16-shaped manifest, level, segment, key, media, HTTP, timeout, and unknown payloads.
- Prove unrecognized runtime values become
unknown. - Prove response URLs/text/data, request context/headers, error messages, network details, and credential-shaped payloads do not appear in evidence or rendered details.
- Add classifier tests for exact codec, DRM, network, media, and unknown values.
- Prove misleading strings cannot override structured engine values.
- Prove recoverable events return
null. - Update HTML5 and ArtPlayer integration tests to cover fatal HTTP evidence and recoverable suppression through the shared path.
- Add a focused view test for the deterministic safe HLS summary.
Run the complete ui-playback unit target, its lint target, the web typecheck,
i18n drift validation, and release-note validation. No E2E is required because
the player workflow and diagnostic controls are unchanged; adapter, classifier,
and rendered-detail behavior are covered at their closest unit/component
boundaries.
Documentation And Release Note
Update docs/architecture/embedded-inline-playback.md, the canonical playback
diagnostic description, to replace raw HLS details with the structured
contract. Add a fix(playback) release note because users receive more accurate
HLS diagnoses and safer technical details.