Files
iptvnator/docs/superpowers/plans/2026-08-01-structured-mpegts-diagnostics.md
T
4gray 0c59aace71 fix(playback): structure MPEG-TS diagnostics (#1327)
* docs(playback): design structured mpegts diagnostics

* docs(playback): plan structured mpegts diagnostics

* fix(playback): structure mpegts error evidence

* fix(playback): structure HTML5 mpegts errors

* fix(playback): share mpegts evidence across players

* fix(playback): render structured mpegts evidence

* docs(playback): document structured mpegts diagnostics

* chore(playback): keep diagnostics lint clean

* docs(playback): complete mpegts diagnostics plan
2026-08-01 17:13:16 +02:00

25 KiB
Raw Blame History

Structured mpegts.js Diagnostics Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Replace mpegts.js message heuristics with a version-locked, allowlisted evidence boundary shared by HTML5, Video.js, and ArtPlayer.

Architecture: Normalize only mpegts.js 1.8.0 public error type/detail constants and the exact HTTP-status slot into MpegTsPlaybackEvidence. The shared classifier maps internally consistent evidence to existing diagnostic codes, and the existing viewport renders only structured evidence while the three engine owners keep their current source and lifecycle behavior.

Tech Stack: Angular 21, TypeScript 5.9, mpegts.js 1.8.0, Jest through Nx, Markdown architecture and release-note documentation.


Task 0: Confirm The Isolated Baseline And Public Runtime

Files:

  • Verify: package.json

  • Verify: pnpm-lock.yaml

  • Verify: node_modules/mpegts.js/src/player/player-errors.js

  • Verify: node_modules/mpegts.js/src/io/loader.js

  • Verify: node_modules/mpegts.js/src/core/transmuxing-controller.js

  • Verify: node_modules/mpegts.js/d.ts/mpegts.d.ts

  • Step 1: Create the isolated feature branch from current master

Run:

git switch -c agent/structure-mpegts-diagnostics origin/master

Expected: branch starts at 9f4e11d6d, the merge of PR #1318.

  • Step 2: Verify dependency and Nx availability

Run:

test -d node_modules
pnpm nx show projects --withTarget test

Expected: exit 0 and output containing ui-playback.

  • Step 3: Run the affected-project baseline

Run:

pnpm nx test ui-playback

Expected: 87 suites and 849 tests pass before implementation.

  • Step 4: Audit the installed public contract

Confirm:

mpegts.js version = 1.8.0
ErrorTypes = NetworkError, MediaError, OtherError
ErrorDetails = Exception, HttpStatusCodeInvalid, ConnectingTimeout,
               UnrecoverableEarlyEof, MediaMSEError, FormatError,
               FormatUnsupported, CodecUnsupported
HttpStatusCodeInvalid info = { code: HTTP status, msg: status text }
recoverable EarlyEof is handled internally before the public player error

Task 1: Drive The Public Evidence Boundary From Failing Tests

Files:

  • Create: libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.model.ts

  • Create: libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.ts

  • Create: libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.spec.ts

  • Step 1: Write the failing installed-runtime contract test

Create mpegts-playback-evidence.util.spec.ts and assert the real installed runtime before using any mocks:

import mpegts from 'mpegts.js';
import {
    MpegTsPlaybackEngineDetails,
    MpegTsPlaybackEngineType,
} from './mpegts-playback-evidence.model';
import {
    MPEGTS_DIAGNOSTIC_VERSION,
    createMpegTsPlaybackEvidence,
} from './mpegts-playback-evidence.util';

describe('mpegts.js playback evidence', () => {
    it('locks the accepted public contract to mpegts.js 1.8.0', () => {
        expect(mpegts.version).toBe(MPEGTS_DIAGNOSTIC_VERSION);
        expect(mpegts.ErrorTypes).toEqual({
            NETWORK_ERROR: MpegTsPlaybackEngineType.Network,
            MEDIA_ERROR: MpegTsPlaybackEngineType.Media,
            OTHER_ERROR: MpegTsPlaybackEngineType.Other,
        });
        expect(mpegts.ErrorDetails).toEqual({
            NETWORK_EXCEPTION:
                MpegTsPlaybackEngineDetails.NetworkException,
            NETWORK_STATUS_CODE_INVALID:
                MpegTsPlaybackEngineDetails.HttpStatusCodeInvalid,
            NETWORK_TIMEOUT:
                MpegTsPlaybackEngineDetails.ConnectingTimeout,
            NETWORK_UNRECOVERABLE_EARLY_EOF:
                MpegTsPlaybackEngineDetails.UnrecoverableEarlyEof,
            MEDIA_MSE_ERROR: MpegTsPlaybackEngineDetails.MediaMseError,
            MEDIA_FORMAT_ERROR: MpegTsPlaybackEngineDetails.FormatError,
            MEDIA_FORMAT_UNSUPPORTED:
                MpegTsPlaybackEngineDetails.FormatUnsupported,
            MEDIA_CODEC_UNSUPPORTED:
                MpegTsPlaybackEngineDetails.CodecUnsupported,
        });
    });
});

Run:

NODE_OPTIONS=--experimental-vm-modules node node_modules/jest/bin/jest.js \
  --config jest.web-esm.workspace.ts --runTestsByPath \
  libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.spec.ts \
  --runInBand

Expected: FAIL because the model and evidence modules do not exist.

  • Step 2: Add the focused evidence model

Create mpegts-playback-evidence.model.ts with const-derived unions:

export const MpegTsPlaybackEngineType = {
    Network: 'NetworkError',
    Media: 'MediaError',
    Other: 'OtherError',
    Unknown: 'unknown',
} as const;

export type MpegTsPlaybackEngineType =
    (typeof MpegTsPlaybackEngineType)[keyof typeof MpegTsPlaybackEngineType];

export const MpegTsPlaybackEngineDetails = {
    NetworkException: 'Exception',
    HttpStatusCodeInvalid: 'HttpStatusCodeInvalid',
    ConnectingTimeout: 'ConnectingTimeout',
    UnrecoverableEarlyEof: 'UnrecoverableEarlyEof',
    MediaMseError: 'MediaMSEError',
    FormatError: 'FormatError',
    FormatUnsupported: 'FormatUnsupported',
    CodecUnsupported: 'CodecUnsupported',
    Unknown: 'unknown',
} as const;

export type MpegTsPlaybackEngineDetails =
    (typeof MpegTsPlaybackEngineDetails)[keyof typeof MpegTsPlaybackEngineDetails];

export const MpegTsPlaybackDisposition = { Terminal: 'terminal' } as const;
export type MpegTsPlaybackDisposition =
    (typeof MpegTsPlaybackDisposition)[keyof typeof MpegTsPlaybackDisposition];
export const MpegTsPlaybackStage = {
    Loader: 'loader',
    Demux: 'demux',
    MediaSource: 'media-source',
    Unknown: 'unknown',
} as const;
export type MpegTsPlaybackStage =
    (typeof MpegTsPlaybackStage)[keyof typeof MpegTsPlaybackStage];
export const MpegTsPlaybackFailure = {
    Http: 'http',
    Timeout: 'timeout',
    Network: 'network',
    TruncatedStream: 'truncated-stream',
    Format: 'format',
    Codec: 'codec',
    MediaSource: 'media-source',
    Unknown: 'unknown',
} as const;
export type MpegTsPlaybackFailure =
    (typeof MpegTsPlaybackFailure)[keyof typeof MpegTsPlaybackFailure];

export interface MpegTsPlaybackEvidence {
    readonly engineType: MpegTsPlaybackEngineType;
    readonly engineDetails: MpegTsPlaybackEngineDetails;
    readonly disposition: MpegTsPlaybackDisposition;
    readonly stage: MpegTsPlaybackStage;
    readonly failure: MpegTsPlaybackFailure;
    readonly httpStatus?: number;
}

Use const-derived aliases for disposition, stage, and failure rather than duplicating string unions if TypeScript reports drift.

  • Step 3: Add failing sanitization and mapping cases

Extend the spec with a table covering every consistent pair and expected stage/failure. Add explicit cases proving:

expect(
    createMpegTsPlaybackEvidence('NetworkError', 'HttpStatusCodeInvalid', {
        code: 404,
        msg: 'Not Found secret',
        url: 'https://provider.example/live.ts?token=secret',
    })
).toEqual({
    engineType: 'NetworkError',
    engineDetails: 'HttpStatusCodeInvalid',
    disposition: 'terminal',
    stage: 'loader',
    failure: 'http',
    httpStatus: 404,
});

expect(
    createMpegTsPlaybackEvidence('OtherError', 'CodecUnsupported', {
        code: 503,
    })
).toEqual({
    engineType: 'OtherError',
    engineDetails: 'CodecUnsupported',
    disposition: 'terminal',
    stage: 'unknown',
    failure: 'unknown',
});

Also assert status strings, 399, 600, nested code, lowercase constants, unknown objects, and circular payloads do not add httpStatus or throw.

Run the focused spec. Expected: FAIL because the factory is missing.

  • Step 4: Implement the minimal sanitizer

Create mpegts-playback-evidence.util.ts with:

export const MPEGTS_DIAGNOSTIC_VERSION = '1.8.0';

export function createMpegTsPlaybackEvidence(
    type: unknown,
    details: unknown,
    info: unknown
): MpegTsPlaybackEvidence {
    const engineType = normalizeEngineType(type);
    const engineDetails = normalizeEngineDetails(details);
    const { stage, failure } = deriveMpegTsStageAndFailure(
        engineType,
        engineDetails
    );
    const httpStatus =
        engineType === MpegTsPlaybackEngineType.Network &&
        engineDetails ===
            MpegTsPlaybackEngineDetails.HttpStatusCodeInvalid
            ? readHttpStatus(info)
            : undefined;

    return {
        engineType,
        engineDetails,
        disposition: MpegTsPlaybackDisposition.Terminal,
        stage,
        failure,
        ...(httpStatus === undefined ? {} : { httpStatus }),
    };
}

Implement exact switch statements for type/detail normalization and the eight accepted pairs. readHttpStatus reads only top-level code and accepts integers 400–599. Do not stringify, clone, enumerate, or inspect any message or unknown property.

  • Step 5: Run the evidence spec green

Run the focused Jest command from Step 1.

Expected: PASS with the runtime contract and sanitizer cases green.

  • Step 6: Commit the evidence boundary
git add -- \
  libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.model.ts \
  libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.ts \
  libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.spec.ts
git commit -m "fix(playback): sanitize mpegts error evidence"

Task 2: Replace Heuristic Classification With Structured Evidence

Files:

  • Modify: libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.model.ts

  • Modify: libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts

  • Modify: libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts

  • Modify: libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts

  • Test: libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.spec.ts

  • Step 1: Write failing classifier tests

Add table-driven expectations that pass evidence, not raw errors:

const issue = classifyMpegTsPlaybackIssue(
    createMpegTsPlaybackEvidence(
        'NetworkError',
        'HttpStatusCodeInvalid',
        { code: 404, msg: 'secret' }
    ),
    createPlaybackSourceMetadata({
        url: 'https://example.test/missing.ts',
        mimeType: 'video/mp2t',
        player: InlinePlaybackPlayer.VideoJs,
    })
);

expect(issue).toEqual(
    expect.objectContaining({
        code: PlaybackDiagnosticCode.NetworkError,
        source: PlaybackDiagnosticSource.MpegTs,
        httpStatus: 404,
        mpegTs: expect.objectContaining({ failure: 'http' }),
        externalFallbackRecommended: false,
    })
);
expect(issue.details).toBeUndefined();

Cover timeout/exception → network, early EOF/format/MSE → media decode, unsupported format → container, codec → codec, and inconsistent/other/unknown → unknown. Verify only decode/container/codec outcomes recommend fallback.

Run the evidence and diagnostics specs. Expected: FAIL because the classifier still accepts raw MpegTsPlaybackErrorInput and emits details.

  • Step 2: Wire evidence into the shared diagnostic model

In playback-diagnostics.model.ts:

import type { MpegTsPlaybackEvidence } from './mpegts-playback-evidence.model';
export * from './mpegts-playback-evidence.model';

Remove MpegTsPlaybackErrorInput and add:

readonly mpegTs?: MpegTsPlaybackEvidence;

to PlaybackDiagnostic.

  • Step 3: Implement evidence-only classification

Change the signature to:

export function classifyMpegTsPlaybackIssue(
    evidence: MpegTsPlaybackEvidence,
    metadata: PlaybackSourceMetadata
): PlaybackDiagnostic

Map the exact failures from the approved design, pass httpStatus: evidence.httpStatus and mpegTs: evidence to createPlaybackDiagnostic, and add mpegTs to that factory's options, destructuring, and result. Export createMpegTsPlaybackEvidence from the diagnostics facade.

  • Step 4: Remove obsolete mpegts text helpers

Delete normalizeErrorDetails, isNetworkFailure, isEarlyEofFailure, and their serialization helpers from playback-error-patterns.util.ts. Keep isBrowserAccessFailure for native browser errors. Remove other now-unused text helpers only when rg proves they have no callers.

Run:

rg -n "normalizeErrorDetails|isNetworkFailure|isEarlyEofFailure|MpegTsPlaybackErrorInput" \
  libs/ui/playback/src/lib

Expected: no matches.

  • Step 5: Run classifier tests green

Run both focused specs by path.

Expected: PASS with no raw message or arbitrary payload retained.

  • Step 6: Commit structured classification
git add -- \
  libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.model.ts \
  libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts \
  libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts \
  libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts \
  libs/ui/playback/src/lib/playback-diagnostics/mpegts-playback-evidence.util.spec.ts
git commit -m "fix(playback): classify exact mpegts failures"

Task 3: Route HTML5 Through The Shared Boundary

Files:

  • Modify: libs/ui/playback/src/lib/html-video-player/html-video-player-diagnostics.ts

  • Modify: libs/ui/playback/src/lib/html-video-player/html-video-player.component.shared-controls.spec-fixtures.ts

  • Modify: libs/ui/playback/src/lib/html-video-player/html-video-player.component.shared-controls.sources.spec.ts

  • Step 1: Make the mpegts fixture emit registered events

Give MockMpegTsPlayer a listener map and emit(event, ...args) helper, matching the existing VJS and ArtPlayer test doubles. Preserve lifecycle logging for on, off, attachment, and load.

  • Step 2: Write the failing HTML5 HTTP regression

Start a .ts source, emit:

engine.emit('error', 'NetworkError', 'HttpStatusCodeInvalid', {
    code: 404,
    msg: 'Not Found html-secret',
    url: 'https://provider.example/error?token=html-secret',
});

Assert the component emits HTML5 source metadata, network-error, HTTP 404, structured mpegTs evidence, no raw details, and no external fallback.

Run the focused sources spec. Expected: FAIL because the HTML5 helper still passes a raw error object to the classifier.

  • Step 3: Normalize before classification

Import createMpegTsPlaybackEvidence in html-video-player-diagnostics.ts and change:

classifyMpegTsPlaybackIssue(
    createMpegTsPlaybackEvidence(error.type, error.details, error.info),
    createHtml5SourceMetadata(url, 'video/mp2t')
)

Accept unknown callback values so normalization owns validation.

  • Step 4: Run the HTML5 regression green and commit

Run the focused sources spec, then:

git add -- \
  libs/ui/playback/src/lib/html-video-player/html-video-player-diagnostics.ts \
  libs/ui/playback/src/lib/html-video-player/html-video-player.component.shared-controls.spec-fixtures.ts \
  libs/ui/playback/src/lib/html-video-player/html-video-player.component.shared-controls.sources.spec.ts
git commit -m "fix(playback): structure HTML5 mpegts errors"

Task 4: Route Video.js And ArtPlayer Through The Same Boundary

Files:

  • Modify: libs/ui/playback/src/lib/vjs-player/vjs-mpegts-session.ts

  • Modify: libs/ui/playback/src/lib/vjs-player/vjs-mpegts-session.spec.ts

  • Modify: libs/ui/playback/src/lib/art-player/art-player-source-session.ts

  • Modify: libs/ui/playback/src/lib/art-player/art-player-source-session.spec.ts

  • Modify: libs/ui/playback/src/lib/art-player/art-player.component.spec.ts

  • Step 1: Replace the misleading VJS CORS regression

Change the existing synthetic FetchError/CORS case to the real public event:

mpegTsPlayer.emit(
    'error',
    'NetworkError',
    'HttpStatusCodeInvalid',
    { code: 503, msg: 'provider secret', headers: { Authorization: 'secret' } }
);

Expect network-error, HTTP 503, player=videojs, exact mpegts evidence, no fallback, and serialized output without either secret. Add a generic NetworkError + Exception case proving message text that says CORS remains a generic network diagnostic.

Run the VJS session spec. Expected: FAIL under the raw classifier contract.

  • Step 2: Normalize in VjsMpegTsSession

Import the factory and call:

classifyMpegTsPlaybackIssue(
    createMpegTsPlaybackEvidence(type, details, info),
    createPlaybackSourceMetadata({
        url,
        mimeType: 'video/mp2t',
        player: InlinePlaybackPlayer.VideoJs,
    })
)

Keep duration sync, listener cleanup, play, and teardown unchanged.

  • Step 3: Add the failing ArtPlayer structured regression

Emit MediaError + CodecUnsupported with a secret-bearing info object. Assert unsupported-codec, player=artplayer, structured evidence, fallback enabled, and no secret in the emitted issue. Update old lowercase/message-based fixtures to exact public constants.

Run the ArtPlayer source-session and component specs. Expected: FAIL until the session uses the factory.

  • Step 4: Normalize in ArtPlayerSourceSession

Import createMpegTsPlaybackEvidence and pass the callback arguments through it before the shared classifier. Change the stored listener parameter types to unknown so the sanitizer, not the adapter, owns validation. Preserve the destroyed/current-engine guard.

  • Step 5: Run all three engine-owner specs green and commit

Run HTML5 sources, VJS session, ArtPlayer source-session, and ArtPlayer component specs by path. Then:

git add -- \
  libs/ui/playback/src/lib/vjs-player/vjs-mpegts-session.ts \
  libs/ui/playback/src/lib/vjs-player/vjs-mpegts-session.spec.ts \
  libs/ui/playback/src/lib/art-player/art-player-source-session.ts \
  libs/ui/playback/src/lib/art-player/art-player-source-session.spec.ts \
  libs/ui/playback/src/lib/art-player/art-player.component.spec.ts
git commit -m "fix(playback): share mpegts evidence across players"

Task 5: Render Only Structured mpegts.js Details

Files:

  • Modify: libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts

  • Modify: libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts

  • Step 1: Write the failing rendering and privacy regression

Add createStructuredMpegTsDiagnostic() with structured HTTP 404 evidence plus legacy details and native message fields containing sentinels. Assert:

expect(component.getDiagnosticDetails(issue)).toEqual(
    expect.arrayContaining([
        {
            labelKey: 'PLAYBACK_DIAGNOSTICS.DETAIL_ERROR_DETAILS',
            value:
                'stage=loader · failure=http · type=NetworkError · ' +
                'details=HttpStatusCodeInvalid · disposition=terminal · HTTP 404',
        },
    ])
);
expect(renderedDetails).not.toContain('mpegts-render-secret');
expect(component.getDiagnosticMeta(issue)).toBe('HTTP 404');

Run the component spec. Expected: FAIL because mpegts evidence is not formatted.

  • Step 2: Add the structured formatter branch

Before VHS/HLS legacy formatting, add:

if (issue.mpegTs) {
    return [
        `stage=${issue.mpegTs.stage}`,
        `failure=${issue.mpegTs.failure}`,
        `type=${issue.mpegTs.engineType}`,
        `details=${issue.mpegTs.engineDetails}`,
        `disposition=${issue.mpegTs.disposition}`,
        issue.mpegTs.httpStatus === undefined
            ? ''
            : `HTTP ${issue.mpegTs.httpStatus}`,
    ]
        .filter((value) => value.length > 0)
        .join(' · ');
}

Also suppress the native-message row when issue.mpegTs exists, matching the HLS/VHS/Shaka structured boundaries.

  • Step 3: Run the view regression green and commit
git add -- \
  libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts \
  libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts
git commit -m "fix(playback): render structured mpegts evidence"

Task 6: Update Canonical Documentation And Release Note

Files:

  • Modify: docs/architecture/embedded-inline-playback.md

  • Modify: AGENTS.md

  • Modify: CLAUDE.md

  • Create: .changes/playback-structured-mpegts-diagnostics.md

  • Step 1: Update the canonical diagnostic contract

Replace the current early-EOF-only mpegts paragraph with the 1.8.0 public boundary: exact type/detail pairs, terminal player events, validated HTTP status, classification mapping, rejected raw fields, all three owners, and the absence of message-based browser-access guesses.

  • Step 2: Keep repository guidance current

Add the same concise contract to the mpegts ownership summaries in AGENTS.md and CLAUDE.md: all three owners use the shared version-locked evidence boundary; raw payloads do not cross it; shared controls remain unchanged.

  • Step 3: Add the user-facing release note

Create:

---
type: fix
area: playback
issues: [1159]
---

MPEG-TS playback errors now show exact engine evidence, including HTTP status,
without exposing provider response details. Format, codec, truncated-stream,
and MediaSource failures now produce more accurate fallback guidance.

Keep the body below 400 characters.

  • Step 4: Validate docs and note, then commit

Run:

git diff --check
pnpm run release:notes:validate

Expected: exit 0. Then:

git add -- \
  docs/architecture/embedded-inline-playback.md \
  AGENTS.md CLAUDE.md \
  .changes/playback-structured-mpegts-diagnostics.md
git commit -m "docs(playback): document structured mpegts diagnostics"

Task 7: Complete Validation And Local P1/P2 Review

Files:

  • Verify all files changed since origin/master

  • Step 1: Run focused regression tests

Run all new and changed spec files by path with the web ESM Jest config.

Expected: every focused suite passes.

  • Step 2: Run the affected validation ladder
pnpm nx test ui-playback
pnpm nx lint ui-playback
pnpm run typecheck:web
pnpm run i18n:check
pnpm run release:notes:validate

Expected: all commands exit 0. No new E2E is required because source routing, player lifecycle, actions, and UI layout do not change; engine events, all three adapters, classification, privacy, and rendered output have deterministic unit/integration coverage.

  • Step 3: Inspect size, scope, and accidental raw-data retention
git diff --check origin/master...HEAD
git diff --stat origin/master...HEAD
rg -n "JSON\.stringify|info\.msg|error\.message|normalizeErrorDetails|isNetworkFailure|isEarlyEofFailure" \
  libs/ui/playback/src/lib/playback-diagnostics \
  libs/ui/playback/src/lib/html-video-player/html-video-player-diagnostics.ts \
  libs/ui/playback/src/lib/vjs-player/vjs-mpegts-session.ts \
  libs/ui/playback/src/lib/art-player/art-player-source-session.ts

Expected: no mpegts error serialization/message inference; any unrelated matches are inspected and justified.

  • Step 4: Perform the requested local Codex review

Review origin/master...HEAD specifically for P1/P2 defects:

  • false classification from mismatched type/detail pairs;
  • unvalidated or duplicated HTTP status;
  • raw provider data escaping through top-level or rendered fields;
  • different behavior among HTML5, Video.js, and ArtPlayer;
  • missing stale-listener/teardown guards;
  • incorrect fallback behavior;
  • version-lock drift;
  • missing tests or stale canonical docs.

Fix every confirmed P1/P2 finding through a new failing regression first, rerun the focused and affected validation ladders, and commit the fixes. Repeat until the review is clean.

  • Step 5: Verify the final branch state
git status --short --branch
git log --oneline origin/master..HEAD
git diff --check origin/master...HEAD

Expected: clean worktree, focused commits only, and no whitespace errors.

Task 8: Publish The Pull Request After Explicit Authorization

Files:

  • Inspect: all changes in origin/master...HEAD

  • Step 1: Confirm final staged and branch scope

Do not stage unrelated files. Verify the exact branch and commits before push.

  • Step 2: Push only after user authorization
git push -u origin agent/structure-mpegts-diagnostics
  • Step 3: Create one ready PR only after user authorization

Use base master, head agent/structure-mpegts-diagnostics, and summarize:

  • version-locked public mpegts.js evidence;
  • exact HTTP/format/codec/EOF/MSE classification;
  • shared HTML5, Video.js, and ArtPlayer integration;
  • privacy boundary and future recommendation-layer compatibility;
  • tests and validation run.

Link issue #1159 and include the release note. Do not create multiple or draft PRs unless the user requests that state.