mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 04:26:16 -08:00
* docs(performance): plan Xtream benchmark * feat(xtream-mock-server): add deterministic 100k fixture * style(xtream-mock-server): apply repository formatting * fix(xtream-mock-server): harden performance fixture data * feat(xtream-mock-server): add performance control plane * docs(performance): correct Xtream capture plan * fix(xtream-mock-server): harden performance controls * fix(xtream-mock-server): harden control lifecycle * feat(performance): add Xtream preload markers * feat(performance): trace Xtream main phases * feat(performance): mark Xtream store publications * feat(performance): trace Xtream database phases * feat(performance): trace Xtream delete cancellation * feat(performance): capture Xtream phase attribution * feat(performance): mark Sources Xtream refresh * test(performance): define Xtream benchmark evidence contracts * test(performance): add Xtream benchmark runner * test(performance): surface failure evidence writes * test(performance): align database read clock * test(performance): preserve capture failure contracts
1043 lines
43 KiB
Markdown
1043 lines
43 KiB
Markdown
# Xtream Performance Benchmark 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:** Add a reproducible, fail-closed Electron benchmark for large Xtream initial import, refresh, deletion, cancellation, and concurrent UI interaction, with process-separated profiles and count-only phase attribution, without changing normal production behavior.
|
|
|
|
**Architecture:** A performance-only 100,000-item Xtream mock fixture is materialized and hashed before capture. An opt-in, fail-neutral instrumentation layer emits sanitized renderer, preload, Electron-main, and database-worker markers. A Playwright orchestrator runs five scenarios in fresh Electron processes with exactly one warm-up, five measured iterations, and one diagnostic iteration per scenario, writes only to the ignored `dist/performance/<timestamp>` tree, and rejects incomplete or contaminated measurements. The existing M3U capture implementation remains behaviorally unchanged and supplies stable process/worker primitives through small, tested extensions rather than a broad rewrite.
|
|
|
|
**Tech Stack:** Angular 21 signals and router, Electron 41 IPC/preload, Chrome DevTools Protocol, Node `inspector`/`perf_hooks`/Worker APIs, Axios, better-sqlite3, Express, Jest, Playwright, TypeScript, Nx.
|
|
|
|
---
|
|
|
|
## Non-Negotiable Measurement Contract
|
|
|
|
- Formal runs use only a clean tracked worktree and exact CDP endpoint
|
|
`127.0.0.1:9222`. An alternate loopback CDP port is smoke-only and makes the
|
|
run ineligible for before/after claims.
|
|
- The mock binds to `127.0.0.1`, uses only the committed
|
|
`performance-100k` fixture, and rejects arbitrary provider URLs,
|
|
credentials, payloads, and cardinalities. No response field used by the
|
|
benchmark may reference a non-loopback URL.
|
|
- Every formal scenario has exactly:
|
|
`warmup-01`, `run-01` through `run-05`, and `diagnostic`.
|
|
Warm-up and diagnostic values never enter headline distributions.
|
|
- Each iteration gets a fresh Electron process and data directory. Stateful
|
|
refresh/delete/UI iterations seed the portal before capture in that same
|
|
process, verify database idleness, and atomically roll capture into the
|
|
measured operation.
|
|
- Renderer, Electron main, and `database.worker` metrics remain separate.
|
|
Main RSS is labelled process-wide and includes worker/native/SQLite memory;
|
|
worker RSS is unavailable because a Node Worker is a thread. Native/SQLite
|
|
memory is never inferred by subtracting JS heaps.
|
|
- Xtream does not instantiate `playlist-refresh.worker`. Report it as
|
|
`N/A: not-instantiated-by-xtream-flow` only after observing zero matching
|
|
workers and artifacts. Any instance invalidates the iteration.
|
|
- IPC boundary deltas are named structured-clone proxies because they include
|
|
queueing/scheduling. SQLite transaction spans include commit. Index creation
|
|
is `N/A: schema-indexes-pre-exist; operation-creates-none`.
|
|
- Cancellation acknowledgement is the terminal database `cancelled` event.
|
|
Also retain click-to-preload return, main HTTP abort, DB cancel dispatch, and
|
|
dev-only worker-receipt timestamps as separate diagnostics.
|
|
- Instrumentation is active only when `IPTVNATOR_PERF_CAPTURE=1` and/or
|
|
`IPTVNATOR_PERF_WORKER_PROFILING=1`, is count/identifier-only, never logs
|
|
credentials/URLs/titles/search text/payloads, and is fail-neutral.
|
|
- No production bottleneck fix belongs in this branch. This branch establishes
|
|
the benchmark and instrumentation required to prove a later fix.
|
|
|
|
## Scenario Matrix
|
|
|
|
| Scenario ID | Seed state | Measured trigger | Authoritative terminal |
|
|
| ----------------------------- | ----------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
|
| `xtream-initial-import-large` | Empty DB, prepared mock | Final Add button | All three import states completed, overlay absent, expected DB counts, two painted frames |
|
|
| `xtream-refresh-large` | Complete 100k import | Refresh-confirm button | Delete/reimport/empty restore complete, exact counts, no duplicate or stale rows |
|
|
| `xtream-delete-large` | Complete 100k import | Delete-confirm button | `DB_DELETE_PLAYLIST` completed, source row absent, playlist/category/content counts zero |
|
|
| `xtream-cancel-import` | Empty DB, prepared mock | Final Add; cancel at first real live save progress threshold | Worker receipt plus authoritative DB `cancelled`, visible cancelled state painted, no later VOD/series request |
|
|
| `xtream-background-ui` | Complete 100k import | Refresh-confirm button | Fixed navigation/search/action sequence paints while DB operation is active, then normal refresh terminal |
|
|
|
|
The fixture contains 60 live categories/items groups, 20 VOD groups, and 20
|
|
series groups with 1,000 items each: exactly 60,000 live + 20,000 VOD +
|
|
20,000 series = 100,000 imported catalog rows and 100 categories.
|
|
|
|
## Task 0: Reconfirm Branch, Baseline, And Safety Preconditions
|
|
|
|
**Files:**
|
|
|
|
- Verify only: `AGENTS.md`
|
|
- Verify only: `package.json`
|
|
- Verify only: `pnpm-lock.yaml`
|
|
- Verify only: `apps/electron-backend-e2e/project.json`
|
|
|
|
- [ ] **Step 1: Confirm the linked worktree and branch**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git status --short --branch
|
|
git rev-parse --show-toplevel
|
|
git rev-parse --git-common-dir
|
|
git log -1 --oneline
|
|
```
|
|
|
|
Expected: branch `agent/perf-xtream-harness`, clean tracked tree, repository root
|
|
`/Users/4gray/.codex/worktrees/05cf/iptvnator`, and base commit
|
|
`24f0dee6f033613148aeab4b699e9db667041927`.
|
|
|
|
- [ ] **Step 2: Verify dependencies and Nx discovery**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
pnpm install --frozen-lockfile
|
|
pnpm nx show projects
|
|
pnpm nx show projects --withTarget test
|
|
pnpm nx show projects --withTarget e2e
|
|
```
|
|
|
|
Expected: all commands exit 0 and the project list includes
|
|
`electron-backend`, `electron-backend-e2e`, `portal-xtream-data-access`,
|
|
`portal-xtream-feature`, and `xtream-mock-server`.
|
|
|
|
- [ ] **Step 3: Record the pre-change regression baseline**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
pnpm nx test portal-xtream-data-access --skip-nx-cache
|
|
pnpm nx test portal-xtream-feature --skip-nx-cache
|
|
```
|
|
|
|
Expected baseline: performance harness 156/156, Xtream data-access 162 tests,
|
|
Xtream feature 144 tests. Stop and use `systematic-debugging` if the baseline
|
|
changes before editing code.
|
|
|
|
- [ ] **Step 4: Preserve the CDP blocker as an external precondition**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
lsof -nP -iTCP:9222 -sTCP:LISTEN || true
|
|
```
|
|
|
|
Do not terminate an unrelated listener without explicit user authorization.
|
|
Harness implementation and unit tests may continue; no formal M3U or Xtream
|
|
run may start while `9222` is occupied.
|
|
|
|
## Task 1: Add A Deterministic, Local-Only 100k Xtream Fixture
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/xtream-mock-server/jest.config.ts`
|
|
- Create: `apps/xtream-mock-server/tsconfig.spec.json`
|
|
- Create: `apps/xtream-mock-server/src/app/generators/performance.generator.ts`
|
|
- Create: `apps/xtream-mock-server/src/app/generators/performance.generator.spec.ts`
|
|
- Modify: `apps/xtream-mock-server/project.json`
|
|
- Modify: `apps/xtream-mock-server/src/app/scenarios.ts`
|
|
- Modify: `apps/xtream-mock-server/src/app/data-store.ts`
|
|
|
|
- [ ] **Step 1: Add the mock-server Jest target**
|
|
|
|
Mirror the established `stalker-mock-server` Node/Jest configuration:
|
|
|
|
```ts
|
|
export default {
|
|
displayName: 'xtream-mock-server',
|
|
preset: '../../jest.preset.js',
|
|
testEnvironment: 'node',
|
|
transform: {
|
|
'^.+\\.[tj]s$': [
|
|
'ts-jest',
|
|
{ tsconfig: '<rootDir>/tsconfig.spec.json' },
|
|
],
|
|
},
|
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
coverageDirectory: '../../coverage/apps/xtream-mock-server',
|
|
};
|
|
```
|
|
|
|
Add an `@nx/jest:jest` `test` target with `jestConfig` and `tsConfig` paths.
|
|
|
|
- [ ] **Step 2: Write failing fixture identity tests**
|
|
|
|
The tests must require:
|
|
|
|
- scenario key `performance:performance`, name `performance-100k`, seed
|
|
`91001`;
|
|
- exactly 100 categories and 100,000 catalog items with the 60k/20k/20k split;
|
|
- unique stream/series IDs and valid category references;
|
|
- two full resets/rebuilds serialize to identical byte counts and SHA-256;
|
|
- every artwork/backdrop/stream URL field is empty or begins with the exact
|
|
supplied `http://127.0.0.1:<port>` origin;
|
|
- the account-info call does not eagerly materialize 20,000 series-detail
|
|
objects; a detail is built lazily on `getSeriesInfo`;
|
|
- VOD/series detail caches are keyed by portal plus item ID, not global ID.
|
|
|
|
Run and preserve the red result:
|
|
|
|
```bash
|
|
pnpm nx test xtream-mock-server --skip-nx-cache
|
|
```
|
|
|
|
Expected: failure because the fixture and test target do not yet exist.
|
|
|
|
- [ ] **Step 3: Implement the dedicated deterministic generator**
|
|
|
|
Add this scenario shape without changing `large`, `stress`, or other existing
|
|
fixtures:
|
|
|
|
```ts
|
|
'performance:performance': {
|
|
name: 'performance-100k',
|
|
description: 'Deterministic local-only 100k performance catalog',
|
|
seed: 91001,
|
|
categoryCount: { live: 60, vod: 20, series: 20 },
|
|
itemsPerCategory: 1000,
|
|
seasonsPerSeries: 1,
|
|
episodesPerSeason: 1,
|
|
accountStatus: 'Active',
|
|
expiryDate: '2099-12-31',
|
|
performanceFixture: 'catalog-100k',
|
|
deferSeriesDetails: true,
|
|
},
|
|
```
|
|
|
|
`performance.generator.ts` must use no Faker date clock, `Math.random`, or
|
|
`Date.now`. Derive names, ratings, timestamps, extensions, IDs, and ordering
|
|
from stable integer indices plus fixed epoch `1_767_225_600` (2026-01-01 UTC).
|
|
Use empty artwork/backdrop fields for the list payloads. Do not create stream
|
|
URLs in catalog objects.
|
|
|
|
- [ ] **Step 4: Make performance series details lazy and cache-safe**
|
|
|
|
Branch only the performance fixture in `data-store.ts`; leave every other
|
|
scenario's output unchanged. Use `${username}:${password}:${id}` cache keys for
|
|
VOD/series details, and skip prepopulation when `deferSeriesDetails` is true.
|
|
|
|
- [ ] **Step 5: Run the green mock tests and lint**
|
|
|
|
```bash
|
|
pnpm nx test xtream-mock-server --skip-nx-cache
|
|
pnpm nx lint xtream-mock-server --skip-nx-cache
|
|
```
|
|
|
|
Expected: all fixture identity, local-only, lazy-detail, existing mock tests,
|
|
and lint checks pass.
|
|
|
|
## Task 2: Add A Locked-Down Mock Performance Control Plane
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/xtream-mock-server/src/app/performance-control.ts`
|
|
- Create: `apps/xtream-mock-server/src/app/performance-control.spec.ts`
|
|
- Create: `apps/xtream-mock-server/src/app/server.ts`
|
|
- Create: `apps/xtream-mock-server/src/app/server.spec.ts`
|
|
- Modify: `apps/xtream-mock-server/src/main.ts`
|
|
- Modify: `apps/xtream-mock-server/src/app/data-store.ts`
|
|
- Modify: `apps/xtream-mock-server/README.md`
|
|
- Modify: `docs/architecture/xtream-mock-server.md`
|
|
|
|
- [ ] **Step 1: Write failing control-plane tests**
|
|
|
|
Use a real loopback HTTP server on port `0`; do not add `supertest`.
|
|
Cover:
|
|
|
|
- controls are absent unless `IPTVNATOR_XTREAM_MOCK_CONTROL=1`;
|
|
- performance mode rejects non-loopback bind hosts;
|
|
- every `/__control/*` request requires the exact per-process token header;
|
|
- JSON bodies reject unknown fields, arbitrary scenarios/cardinalities/URLs,
|
|
duplicate rules, past occurrences, and delays outside integer `0..5000`;
|
|
- `prepare` materializes `performance-100k` and returns only
|
|
`{epoch, scenario, seed, counts, bytes, catalogSha256}`;
|
|
- `reset observations` clears ledger/rules but preserves the prepared fixture;
|
|
`reset all` also clears fixture caches and increments epoch;
|
|
- request identity is
|
|
`(epoch,scenario,transport,canonicalAction,categoryId|'all',occurrence)`,
|
|
so parallel category arrival order does not affect matching;
|
|
- barrier release and request-abort both settle and remove held responses;
|
|
- ledger entries contain only safe action/scenario/count/status/timestamps and
|
|
never password, username, raw URL, query, or response payload;
|
|
- performance stream and `/playlist.m3u` endpoints return `410`, while no
|
|
non-loopback request is made.
|
|
|
|
Run and preserve the red result:
|
|
|
|
```bash
|
|
pnpm nx test xtream-mock-server --skip-nx-cache
|
|
```
|
|
|
|
- [ ] **Step 2: Extract an Express app factory**
|
|
|
|
Move route wiring, without behavior changes, into:
|
|
|
|
```ts
|
|
export interface XtreamMockServerOptions {
|
|
readonly control?: {
|
|
readonly enabled: boolean;
|
|
readonly token: string;
|
|
};
|
|
readonly host: string;
|
|
readonly port: number;
|
|
}
|
|
|
|
export function createXtreamMockApp(
|
|
options: XtreamMockServerOptions
|
|
): express.Express;
|
|
```
|
|
|
|
Keep `main.ts` responsible only for validated environment parsing, HTTP
|
|
startup, logging, and signal/error shutdown. Normal `serve` behavior remains
|
|
port 3211 and existing routes remain compatible.
|
|
|
|
- [ ] **Step 3: Implement bounded observations, barriers, and delays**
|
|
|
|
Use an exact allowlist for canonical Xtream actions. Cap ledger and rule counts.
|
|
A barrier matches before dispatch/serialization, is one-shot, and records
|
|
`arrived -> blocked -> responded|aborted`. A delay is abort-aware and exists
|
|
only for deterministic smoke/control tests; formal scenario manifests require
|
|
zero delay rules.
|
|
|
|
- [ ] **Step 4: Add fixture preparation and manifest hashing**
|
|
|
|
Hash stable UTF-8 JSON for the three category arrays and three catalog arrays
|
|
in a documented fixed order. The hash input contains no credentials or server
|
|
origin. Materialization happens before capture, so mock generation is excluded
|
|
from application acquisition time.
|
|
|
|
- [ ] **Step 5: Run focused tests and docs checks**
|
|
|
|
```bash
|
|
pnpm nx test xtream-mock-server --skip-nx-cache
|
|
pnpm nx lint xtream-mock-server --skip-nx-cache
|
|
pnpm exec prettier --check apps/xtream-mock-server/README.md docs/architecture/xtream-mock-server.md
|
|
```
|
|
|
|
Expected: green. Docs explain the opt-in control flag, loopback/token
|
|
requirements, fixed scenario, prepare/reset/ledger semantics, and that delays
|
|
are forbidden in formal timing.
|
|
|
|
## Task 3: Add Sanitized Xtream IPC And Main-Process Phase Markers
|
|
|
|
**Files:**
|
|
|
|
- Create: `libs/shared/interfaces/src/lib/xtream-performance-marker.interface.ts`
|
|
- Create: `apps/electron-backend/src/app/api/xtream-preload-performance-capture.ts`
|
|
- Create: `apps/electron-backend/src/app/api/xtream-preload-performance-capture.spec.ts`
|
|
- Create: `apps/electron-backend/src/app/events/xtream-performance.ts`
|
|
- Create: `apps/electron-backend/src/app/events/xtream-performance.spec.ts`
|
|
- Modify: `libs/shared/interfaces/src/index.ts`
|
|
- Modify: `apps/electron-backend/src/app/api/main.preload.ts`
|
|
- Modify: `apps/electron-backend/src/app/api/main.preload.performance.contract.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/api/main.preload.performance.gates.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/events/xtream.events.ts`
|
|
- Modify: `apps/electron-backend/src/app/events/xtream.events.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing schema, gating, redaction, and lifecycle tests**
|
|
|
|
Target only these bridge methods:
|
|
|
|
```text
|
|
xtreamRequest
|
|
xtreamCancelSession
|
|
dbGetCategories
|
|
dbSaveCategories
|
|
dbGetContent
|
|
dbSaveContent
|
|
dbDeleteXtreamContent
|
|
dbDeletePlaylist
|
|
dbRestoreXtreamUserData
|
|
dbSearchContent
|
|
dbGlobalSearch
|
|
dbCancelOperation
|
|
```
|
|
|
|
Markers may include only schema version, IPC call ID, method, boundary/outcome,
|
|
epoch, playlist/operation/session identifiers, Xtream action, content/category
|
|
type, and item count. Tests must reject or prove absence of URL, username,
|
|
password, params, titles, search term, arrays, and result bodies. Prove exact
|
|
pass-through result identity, error propagation, no marker work when disabled,
|
|
and fail-neutral behavior when the marker sink throws.
|
|
|
|
Run the red tests:
|
|
|
|
```bash
|
|
pnpm nx test electron-backend --skip-nx-cache --testPathPatterns='xtream-preload-performance-capture|main.preload.performance|xtream.events|xtream-performance'
|
|
```
|
|
|
|
- [ ] **Step 2: Implement a separate Xtream preload marker protocol**
|
|
|
|
Do not overload `preload-performance-correlation.ts`, whose state machine is
|
|
M3U refresh-specific. Add a separate channel and schema. Extract safe identity
|
|
from arguments without cloning/traversing payload arrays. Emit start and
|
|
success/error around the existing proxied call only when
|
|
`IPTVNATOR_PERF_CAPTURE=1`.
|
|
|
|
- [ ] **Step 3: Instrument main HTTP phases without changing normal Axios behavior**
|
|
|
|
Emit count-only main phases:
|
|
|
|
```text
|
|
xtream.network.total
|
|
xtream.json.transform
|
|
xtream.response.ready
|
|
xtream.cancel-session
|
|
```
|
|
|
|
Under capture only, wrap Axios's existing default `transformResponse` chain and
|
|
invoke the same functions with the same context. Do not switch response type or
|
|
introduce a separate manual `JSON.parse`. `network.total` contains the nested
|
|
transform; the report derives acquisition as total minus JSON transform.
|
|
Every success, error, and abort path must close its phase exactly once.
|
|
|
|
- [ ] **Step 4: Keep debug-copy overhead explicit**
|
|
|
|
Electron imports always create a portal-debug request ID, but performance
|
|
builds use the production environment and disable portal-debug sanitize/send
|
|
before the payload is copied. Record that work as
|
|
`N/A: production-debug-send-disabled`; do not infer that the request ID is
|
|
absent. If a future diagnostic build enables the send path, instrument
|
|
redaction/send separately and never fold that development-only copy into
|
|
production acquisition.
|
|
|
|
`ElectronService.forwardXtreamRequest()` also posts the full returned payload
|
|
through `window.postMessage()` after the preload call completes. Keep that
|
|
second renderer clone unchanged until a baseline proves it is the selected
|
|
bottleneck; attribute it through the preload-end to store-marker gap and the
|
|
renderer CPU profile.
|
|
|
|
- [ ] **Step 5: Run focused backend tests and lint**
|
|
|
|
```bash
|
|
pnpm nx test electron-backend --skip-nx-cache --testPathPatterns='xtream-preload-performance-capture|main.preload.performance|xtream.events|xtream-performance'
|
|
pnpm nx lint electron-backend --skip-nx-cache
|
|
```
|
|
|
|
Expected: green with no changes to normal IPC payloads or Axios results.
|
|
|
|
## Task 4: Add Database-Worker Phase And Cancellation-Receipt Markers
|
|
|
|
**Files:**
|
|
|
|
- Modify: `libs/shared/interfaces/src/lib/performance-phase.interface.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-capture.model.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-phase.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/database.worker.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/category.operations.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/content.operations.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/xtream.operations.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/playlist.operations.ts`
|
|
- Modify: `apps/electron-backend/src/app/events/database/worker-ipc-contract.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/services/database-worker-client.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-phase.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-capture.concurrency.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-cancellation.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/workers/worker-performance-integration.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/category.operations.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/content.operations.spec.ts`
|
|
- Create: `apps/electron-backend/src/app/database/operations/xtream.operations.spec.ts`
|
|
- Modify: `apps/electron-backend/src/app/database/operations/playlist.operations.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing phase-placement and cancellation tests**
|
|
|
|
Require one ordered pair per aggregate phase, count-only metadata, closure on
|
|
success/error/cancel, and no calls when worker profiling is off. Required phase
|
|
names:
|
|
|
|
```text
|
|
sqlite.categories.read
|
|
normalize.categories
|
|
sqlite.categories.write-transactions
|
|
sqlite.content.read
|
|
sqlite.content.category-map-read
|
|
normalize.content
|
|
sqlite.content.write-transactions
|
|
sqlite.xtream-cache-clear.write-transactions
|
|
sqlite.xtream-delete.collect-user-data
|
|
sqlite.xtream-delete.write-transactions
|
|
sqlite.playlist-delete.collect-ids
|
|
sqlite.playlist-delete.write-transactions
|
|
sqlite.search.query
|
|
normalize.search-rank
|
|
```
|
|
|
|
Wrap the complete batch loop in one aggregate `write-transactions` span;
|
|
metadata reports total items. This avoids ambiguous repeated phase pairs.
|
|
Tests must state that the span includes all transaction commits.
|
|
|
|
Cancellation cleanup runs `DB_CLEAR_XTREAM_IMPORT_CACHE` after an aborted
|
|
import. Measure its complete delete loops with the dedicated cache-clear phase
|
|
instead of hiding that work in the request envelope or mislabelling it as a
|
|
content-save phase. Synthetic benchmark fixtures keep favorites/recent data
|
|
empty, so restore-user-data remains explicitly `N/A: no-user-data`.
|
|
|
|
Require a dev-only `performance-cancel-received` worker message containing only
|
|
operation/request IDs and epoch. It must not change
|
|
`DatabaseWorkerClient.cancel()` into a wait or alter normal cancellation order.
|
|
|
|
- [ ] **Step 2: Extend the worker phase union generically**
|
|
|
|
Change the capture helper/model to accept the union of existing app-playlist
|
|
phases and new Xtream database phases. Preserve existing M3U phase strings and
|
|
tests exactly.
|
|
|
|
- [ ] **Step 3: Add operation adapters without changing SQL or concurrency**
|
|
|
|
Pass the optional capture adapter from `database.worker.ts` into the existing
|
|
operations. Measure around existing normalization, query, and transaction-loop
|
|
blocks. Do not reorder statements, change batch size, add indexes, serialize
|
|
parallel requests, or alter transaction boundaries.
|
|
|
|
- [ ] **Step 4: Preserve overlap invalidation**
|
|
|
|
`registerDatabaseWorkerPerformanceCapture()` must continue marking overlapping
|
|
request CPU/ELU/event-loop-delay data invalid. Tests must prove no hidden
|
|
serialization is introduced. Whole-worker profiles remain valid diagnostics;
|
|
request-scoped overlapping metrics remain explicitly invalid.
|
|
|
|
- [ ] **Step 5: Run focused and full backend tests**
|
|
|
|
```bash
|
|
pnpm nx test electron-backend --skip-nx-cache --testPathPatterns='worker-performance|worker-ipc-contract|database-worker-client|category.operations|content.operations|xtream.operations|playlist.operations'
|
|
pnpm nx test electron-backend --skip-nx-cache
|
|
pnpm nx lint electron-backend --skip-nx-cache
|
|
```
|
|
|
|
Expected: green and no SQL/business-result changes.
|
|
|
|
## Task 5: Add Renderer Store Markers Without Equating Them To Paint
|
|
|
|
**Files:**
|
|
|
|
- Modify: `libs/shared/logging/src/lib/renderer-performance-phase.ts`
|
|
- Modify: `libs/shared/logging/src/lib/renderer-performance-phase.spec.ts`
|
|
- Modify: `libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.ts`
|
|
- Modify: `libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.spec.ts`
|
|
- Modify: `libs/portal/xtream/data-access/src/lib/stores/features/with-search.feature.ts`
|
|
- Modify: `libs/portal/xtream/data-access/src/lib/stores/features/with-search.feature.spec.ts`
|
|
- Modify: `libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.ts`
|
|
- Modify: `libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts`
|
|
- Modify: `libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.ts`
|
|
- Modify: `libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing opt-in/fail-neutral store-marker tests**
|
|
|
|
Add count-only phase names:
|
|
|
|
```text
|
|
store.xtream-publish-categories
|
|
store.xtream-publish-live
|
|
store.xtream-publish-vod
|
|
store.xtream-publish-series
|
|
store.xtream-import-terminal
|
|
store.xtream-search-results
|
|
store.xtream-refresh-meta
|
|
store.xtream-delete-row
|
|
```
|
|
|
|
Tests must prove the marker wraps only the synchronous `patchState` or NgRx
|
|
dispatch, emits one start/end pair, preserves thrown errors/results, performs
|
|
no metadata work without a hook, and ignores hook failures.
|
|
|
|
- [ ] **Step 2: Wrap the exact existing publication sites**
|
|
|
|
Use `measureRendererPerformancePhase` around the category publication at
|
|
`with-content.feature.ts:965`, live/VOD/series publications at
|
|
`:1047/:1083/:1119`, import-terminal publication, search result publication,
|
|
refresh metadata dispatch, and delete-row dispatch. Do not change fetch order,
|
|
signals, routes, or visible behavior.
|
|
|
|
- [ ] **Step 3: Keep Angular paint external to store timing**
|
|
|
|
Document in code comments and benchmark contracts that a synchronous store
|
|
span is not render time. The Playwright renderer probe will observe a
|
|
scenario-specific DOM sentinel and two `requestAnimationFrame` callbacks after
|
|
the marker end.
|
|
|
|
- [ ] **Step 4: Run affected project tests**
|
|
|
|
```bash
|
|
pnpm nx test shared-logging --skip-nx-cache
|
|
pnpm nx test portal-xtream-data-access --skip-nx-cache
|
|
pnpm nx test playlist-shared-ui --skip-nx-cache
|
|
```
|
|
|
|
If the exact project names differ, discover them with:
|
|
|
|
```bash
|
|
pnpm nx show projects --withTarget test
|
|
```
|
|
|
|
Then run the owning targets; do not guess a project name.
|
|
|
|
## Task 6: Extend The Existing Process Capture For Xtream Attribution
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-ipc-marker-events.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-ipc-marker-events.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-worker-phase-events.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-worker-phase-events.spec.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/m3u-refresh-main-capture.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/worker-performance-phase-events.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/worker-request-performance.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/worker-request-performance-envelope.spec.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/performance-phase-events.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/performance-phase-events.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing parsing/correlation tests**
|
|
|
|
Require:
|
|
|
|
- exact schema validation and count-only fields;
|
|
- ordered start/end pairs and no unclosed/duplicate boundaries;
|
|
- FIFO correlation by safe method/playlist/type/action/operation key;
|
|
- quarantine rather than guessing when the same key overlaps;
|
|
- handler/preload/worker timestamps remain monotonic;
|
|
- acquisition = `network.total - json.transform`, never negative;
|
|
- main-to-worker and worker-to-main deltas are named IPC proxies;
|
|
- worker cancel receipt and terminal cancel are separate;
|
|
- existing M3U parsers produce byte-equivalent normalized output.
|
|
|
|
- [ ] **Step 2: Parameterize main capture phase subscriptions**
|
|
|
|
Extend `installMainCapture()` to subscribe to both existing M3U and new Xtream
|
|
diagnostics channels. Keep the old state key and exported API for compatibility;
|
|
do not rename or copy the 1,500-line injected protocol in this task. Add only
|
|
the minimum channel allowlists and timeline record shapes.
|
|
|
|
- [ ] **Step 3: Capture Xtream preload and main-handler boundaries**
|
|
|
|
Listen for sanitized preload markers in main and record handler receive/ready
|
|
phases. Match DB worker requests using safe operation ID where supplied and
|
|
FIFO/quarantine otherwise. Never attach raw IPC payloads to the timeline.
|
|
|
|
- [ ] **Step 4: Record true worker cancellation receipt**
|
|
|
|
Recognize `performance-cancel-received` without counting it as a normal
|
|
response. Store the epoch/IDs in the current capture generation. Late or
|
|
cross-generation markers invalidate cancellation attribution.
|
|
|
|
- [ ] **Step 5: Run the complete performance-harness unit suite**
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
```
|
|
|
|
Expected: all old M3U tests and new Xtream contracts pass.
|
|
|
|
## Task 7: Build Xtream Scenario, Summary, And Validity Contracts
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-contract.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-contract.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-control-client.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-control-client.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-summary-contract.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-phase-attribution.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-phase-attribution.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-report.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-report.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-diagnostic-artifacts.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-diagnostic-artifacts.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing schedule and safety tests**
|
|
|
|
Require the five exact scenario IDs and formal iteration schedule:
|
|
|
|
```ts
|
|
[
|
|
{ runId: 'warmup-01', kind: 'warmup' },
|
|
{ runId: 'run-01', kind: 'measured' },
|
|
{ runId: 'run-02', kind: 'measured' },
|
|
{ runId: 'run-03', kind: 'measured' },
|
|
{ runId: 'run-04', kind: 'measured' },
|
|
{ runId: 'run-05', kind: 'measured' },
|
|
{ runId: 'diagnostic', kind: 'diagnostic' },
|
|
];
|
|
```
|
|
|
|
Smoke may reduce measured runs to one but must set `eligibleForComparison=false`.
|
|
Reject non-loopback origin, unexpected fixture name/hash/counts, any credential
|
|
field in serialized artifacts, nonzero formal delay/barrier residue, and any
|
|
unexpected mock action.
|
|
|
|
- [ ] **Step 2: Define the request and phase contract**
|
|
|
|
After observations reset, initial/reimport expects exactly seven application
|
|
actions:
|
|
|
|
```text
|
|
get_account_info
|
|
get_live_categories
|
|
get_vod_categories
|
|
get_series_categories
|
|
get_live_streams
|
|
get_vod_streams
|
|
get_series
|
|
```
|
|
|
|
Category order is irrelevant; content order is live -> VOD -> series. Cancel
|
|
requires account + categories + live only, with no VOD/series request after the
|
|
authoritative cancellation point.
|
|
|
|
- [ ] **Step 3: Define process-separated result types**
|
|
|
|
Each result stores:
|
|
|
|
- total and named phase durations;
|
|
- renderer peak/post-GC heap, long-task count/max, frame-gap p95/max,
|
|
heartbeat p95/max, store-to-paint, navigation/search/action latency;
|
|
- main CPU, peak/post-GC heap, process-wide peak/post-GC RSS, ELD
|
|
p95/p99/max, ELU/unavailable reason, BrowserWindow
|
|
unresponsive/responsive events;
|
|
- database-worker CPU, peak/post-GC heap, external memory, ELD p95/p99/max,
|
|
ELU, request validity, profile paths, and RSS `N/A` reason;
|
|
- playlist-refresh worker `N/A` reason;
|
|
- cancel dispatch/receipt/terminal/paint latencies;
|
|
- explicit index, exact-commit, native-memory, and debug-copy N/A/proxy labels.
|
|
|
|
- [ ] **Step 4: Fail closed on comparison validity**
|
|
|
|
Formal summaries require five valid measured values for every required metric;
|
|
never silently filter nulls. Require one renderer identity, one current database
|
|
worker, zero playlist-refresh workers, no late DB request after capture cutoff,
|
|
complete action/DB phase contracts, exact catalog invariants, no console errors,
|
|
and valid regular contained diagnostic artifacts.
|
|
|
|
- [ ] **Step 5: Run the harness unit suite**
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
```
|
|
|
|
## Task 8: Build The Renderer Probe And Initial/Cancel Drivers
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-renderer-probe.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-renderer-probe.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-renderer-capture.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-scenario-driver.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-scenario-driver.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing probe lifecycle tests**
|
|
|
|
Mirror the proven M3U capture lifecycle and require:
|
|
|
|
- Long Tasks clipped to operation boundaries;
|
|
- continuous rAF gaps and a 50 ms deadline-based UI heartbeat;
|
|
- 20 ms renderer heap sampling plus explicit GC/post-GC heap;
|
|
- route, store marker, DOM sentinel, and two-rAF paint timestamps;
|
|
- idempotent stop/dispose after partial startup failure;
|
|
- CPU/trace/heap snapshot only in diagnostic;
|
|
- no profile path in measured/warm-up runs.
|
|
|
|
- [ ] **Step 2: Implement initial-import trigger and terminal**
|
|
|
|
Prepare the Xtream dialog with only the fixed synthetic name, loopback origin,
|
|
and committed synthetic credential pair. Start clocks immediately before the
|
|
final Add button activation. Terminal requires overlay absent, all three
|
|
import-status values completed, exact 100k content/100 category DB counts, and
|
|
two rendered frames after the final store marker.
|
|
|
|
- [ ] **Step 3: Implement cancellation at real DB progress**
|
|
|
|
Install the DB-event listener before triggering import. On the first live
|
|
`save-content` progress event at or above
|
|
`max(100, floor(total * 0.10))`, synchronously record the click epoch and
|
|
activate the visible cancel button. Use no timeout/delay as the trigger.
|
|
Require worker receipt, terminal DB `cancelled`, painted cancelled state, no
|
|
later success, no automatic retry, and no VOD/series mock requests.
|
|
|
|
- [ ] **Step 4: Add interaction-free smoke driver tests**
|
|
|
|
Use deterministic mocked Page/CDP/main-capture adapters to prove trigger order,
|
|
terminal checks, cleanup, and that credential strings never enter result,
|
|
manifest, console label, or artifact filenames.
|
|
|
|
- [ ] **Step 5: Run the complete harness tests**
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
```
|
|
|
|
## Task 9: Build Refresh, Delete, And Background-UI Drivers
|
|
|
|
**Files:**
|
|
|
|
- Modify: `apps/electron-backend-e2e/src/performance/xtream-scenario-driver.ts`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/xtream-scenario-driver.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-ui-action-probe.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-ui-action-probe.spec.ts`
|
|
|
|
- [ ] **Step 1: Write failing seed/rollover tests**
|
|
|
|
Require a complete seed import outside measured capture, an idle DB worker,
|
|
zero pending requests, and atomic main-capture rollover before trigger. Store
|
|
seed metrics separately as `seed-main-capture.json`; never include them in
|
|
measured summaries.
|
|
|
|
- [ ] **Step 2: Implement refresh**
|
|
|
|
Start at the refresh confirmation button. Include
|
|
`DB_DELETE_XTREAM_CONTENT`, playback/meta parallel work, navigation, the seven
|
|
mock actions, three category writes, three content writes, empty user-data
|
|
restore, final store publication, and paint. Assert exact counts and no
|
|
duplicate/stale rows.
|
|
|
|
- [ ] **Step 3: Implement full source deletion**
|
|
|
|
Start at the delete confirmation button. Require started/progress/completed DB
|
|
events, source row removal, zero playlist/category/content rows, and no stale
|
|
active-store route. Capture all delete transaction phases and final dispatch
|
|
to paint.
|
|
|
|
- [ ] **Step 4: Implement the fixed background UI sequence**
|
|
|
|
Start a natural delay-zero refresh. Only after proving the DB delete operation
|
|
active, perform:
|
|
|
|
1. Sources filter input and result paint;
|
|
2. navigation to Dashboard and two-rAF route paint;
|
|
3. navigation back to Sources;
|
|
4. source search input and result paint;
|
|
5. one stable, non-destructive UI action.
|
|
|
|
Record input/click to paint latency for every action and require the background
|
|
operation to be active both before and after each action. If it finishes too
|
|
early, invalidate the iteration and increase the fixed fixture cardinality in
|
|
a separately reviewed change; never add sleeps or mock delay to formal timing.
|
|
|
|
- [ ] **Step 5: Run harness and existing responsiveness tests**
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
pnpm nx run electron-backend-e2e:e2e-ci--src/xtream-responsiveness.e2e.ts --skip-nx-cache
|
|
```
|
|
|
|
The existing E2E may keep its deliberate worker batch delay because it is a
|
|
functional regression test. The benchmark must always set
|
|
`IPTVNATOR_DB_WORKER_BATCH_DELAY_MS=0`.
|
|
|
|
## Task 10: Add The Orchestrator, Nx Target, And Artifact Validation
|
|
|
|
**Files:**
|
|
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-orchestrator.ts`
|
|
- Create: `apps/electron-backend-e2e/src/performance/xtream-benchmark-lifecycle.spec.ts`
|
|
- Create: `apps/electron-backend-e2e/src/xtream.performance.ts`
|
|
- Create: `apps/electron-backend-e2e/playwright.xtream-performance.config.ts`
|
|
- Modify: `apps/electron-backend-e2e/project.json`
|
|
- Modify: `apps/electron-backend-e2e/src/performance/initial-import-diagnostic-artifacts.ts`
|
|
|
|
- [ ] **Step 1: Write failing lifecycle and artifact tests**
|
|
|
|
Require:
|
|
|
|
- preflight before directory creation;
|
|
- mock prepare before capture and observations reset immediately before trigger;
|
|
- fresh app/data dir per iteration and guaranteed cleanup;
|
|
- raw iteration JSON written before summary validity throws;
|
|
- diagnostic regular/non-symlink/nonempty JSON trace, CPU profile, and heap
|
|
snapshot for renderer/main/database worker;
|
|
- no playlist-refresh worker artifacts;
|
|
- source-map/build hash manifest sufficient to map profiles after a rebuild;
|
|
- output contained by a fresh absolute
|
|
`dist/performance/<timestamp>/<variant>` path;
|
|
- no `.cpuprofile`, `.heapsnapshot`, trace, or generated summary staged by Git.
|
|
|
|
- [ ] **Step 2: Implement the serial orchestrator**
|
|
|
|
For each scenario, run all seven definitions serially. Launch Electron with:
|
|
|
|
```text
|
|
--js-flags=--expose-gc
|
|
--remote-debugging-address=127.0.0.1
|
|
--remote-debugging-port=9222
|
|
--user-data-dir=<fresh temp path>
|
|
```
|
|
|
|
Set:
|
|
|
|
```text
|
|
IPTVNATOR_DB_WORKER_BATCH_DELAY_MS=0
|
|
IPTVNATOR_PERF_CAPTURE=1
|
|
IPTVNATOR_PERF_WORKER_PROFILING=1
|
|
IPTVNATOR_TRACE_RENDERER_CONSOLE=0
|
|
```
|
|
|
|
Start renderer/main capture before trigger, wait for authoritative terminal and
|
|
DB settlement, stop capture, write raw capture/result JSON, validate artifacts,
|
|
then build the scenario summary.
|
|
|
|
- [ ] **Step 3: Add the isolated mock web server**
|
|
|
|
`playwright.xtream-performance.config.ts` starts exactly one control-enabled
|
|
mock on a dedicated loopback port with a per-process token, `reuseExistingServer:
|
|
false`, one Playwright worker, no retries, and a 30-minute test timeout. The
|
|
token is passed to the control client but never serialized.
|
|
|
|
- [ ] **Step 4: Add the Nx target**
|
|
|
|
Add `benchmark-xtream` with:
|
|
|
|
```json
|
|
{
|
|
"dependsOn": ["electron-backend:build-performance"],
|
|
"executor": "nx:run-commands",
|
|
"cache": false,
|
|
"parallelism": false,
|
|
"options": {
|
|
"cwd": "apps/electron-backend-e2e",
|
|
"command": "pnpm exec playwright test --config=playwright.xtream-performance.config.ts src/xtream.performance.ts"
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 5: Run all harness tests**
|
|
|
|
```bash
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
```
|
|
|
|
Expected: old M3U and new Xtream lifecycle/contract tests pass.
|
|
|
|
## Task 11: Run A Non-Claim Smoke And Close The Harness PR
|
|
|
|
**Files:**
|
|
|
|
- Modify: `docs/architecture/xtream-mock-server.md`
|
|
- Modify: `docs/architecture/sqlite-db-worker.md`
|
|
- Modify if command/environment text changed: `AGENTS.md`
|
|
- Modify if command/environment text changed: `CLAUDE.md`
|
|
- Verify only: `.gitignore`
|
|
- Verify only: `.changes/README.md`
|
|
|
|
- [ ] **Step 1: Run the full validation ladder**
|
|
|
|
```bash
|
|
pnpm nx test xtream-mock-server --skip-nx-cache
|
|
pnpm nx test electron-backend --skip-nx-cache
|
|
pnpm nx test portal-xtream-data-access --skip-nx-cache
|
|
pnpm nx test portal-xtream-feature --skip-nx-cache
|
|
pnpm nx run electron-backend-e2e:test-performance-harness --skip-nx-cache
|
|
pnpm nx run electron-backend-e2e:e2e-ci--src/xtream-responsiveness.e2e.ts --skip-nx-cache
|
|
pnpm nx run electron-backend-e2e:e2e-ci--src/sources.e2e.ts --skip-nx-cache
|
|
pnpm nx run electron-backend-e2e:e2e-ci--src/search.e2e.ts --skip-nx-cache
|
|
pnpm nx affected -t lint --base=24f0dee6f033613148aeab4b699e9db667041927 --head=HEAD --skip-nx-cache
|
|
pnpm run release:notes:validate
|
|
```
|
|
|
|
- [ ] **Step 2: Run a smoke benchmark only when a CDP port is available**
|
|
|
|
If `9222` remains occupied, use an unused alternate loopback port only for
|
|
smoke:
|
|
|
|
```bash
|
|
perf_output="$PWD/dist/performance/$(date -u +%Y%m%dT%H%M%SZ)-xtream-smoke"
|
|
IPTVNATOR_PERF_OUTPUT_DIR="$perf_output" \
|
|
IPTVNATOR_PERF_VARIANT=smoke \
|
|
IPTVNATOR_PERF_SMOKE=1 \
|
|
IPTVNATOR_PERF_CDP_PORT=9322 \
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT=false \
|
|
pnpm nx run electron-backend-e2e:benchmark-xtream --skip-nx-cache
|
|
```
|
|
|
|
Validate that every smoke summary says `eligibleForComparison=false`. Never
|
|
quote smoke values as baseline or improvement evidence.
|
|
|
|
- [ ] **Step 3: Update canonical docs**
|
|
|
|
Document the future formal command, fixture identity, exact run schedule,
|
|
process/RSS/heap distinctions, Xtream worker topology, control-plane safety,
|
|
artifact layout, validity gates, and before/after rules. Keep `AGENTS.md` and
|
|
`CLAUDE.md` mirrored if their tracing/benchmark environment section changes.
|
|
|
|
- [ ] **Step 4: Test-impact and release-note decision**
|
|
|
|
This PR changes only opt-in development/test instrumentation and synthetic mock
|
|
tooling; normal user-visible behavior is unchanged. Do not add a `.changes`
|
|
note. Apply `no-release-note` when opening the PR because runtime paths under
|
|
`apps/**` and `libs/**` are touched.
|
|
|
|
- [ ] **Step 5: Verify tracked scope and ignored raw artifacts**
|
|
|
|
```bash
|
|
git status --short
|
|
git check-ignore -v dist/performance
|
|
git diff --check
|
|
git diff --stat 24f0dee6f033613148aeab4b699e9db667041927
|
|
git ls-files 'dist/performance/**'
|
|
```
|
|
|
|
Expected: tracked source/tests/docs only; `git ls-files` prints nothing.
|
|
|
|
- [ ] **Step 6: Commit, push, open the PR, and run the review loop**
|
|
|
|
Use focused conventional commits, push `agent/perf-xtream-harness`, open a
|
|
ready PR with validation and smoke caveats, apply `no-release-note`, trigger
|
|
`@codex review`, and inspect all CI/review threads. Do not merge until every
|
|
actionable item is fixed, re-tested, independently reviewed, and current-head
|
|
CI is green.
|
|
|
|
## Task 12: Run The Formal Xtream Baseline After Harness Merge
|
|
|
|
**Files:**
|
|
|
|
- Generated only, ignored: `dist/performance/<timestamp>-xtream/baseline/**`
|
|
|
|
- [ ] **Step 1: Start from the exact clean merged commit**
|
|
|
|
```bash
|
|
git switch master
|
|
git pull --ff-only
|
|
git status --short
|
|
lsof -nP -iTCP:9222 -sTCP:LISTEN
|
|
```
|
|
|
|
Expected: clean tree and port 9222 free. If an unrelated listener remains, stop
|
|
and request authorization rather than killing it.
|
|
|
|
- [ ] **Step 2: Run the formal benchmark**
|
|
|
|
```bash
|
|
perf_output="$PWD/dist/performance/$(date -u +%Y%m%dT%H%M%SZ)-xtream"
|
|
IPTVNATOR_PERF_OUTPUT_DIR="$perf_output" \
|
|
IPTVNATOR_PERF_VARIANT=baseline \
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT=false \
|
|
pnpm nx run electron-backend-e2e:benchmark-xtream --skip-nx-cache
|
|
```
|
|
|
|
Do not set smoke or alternate-port flags.
|
|
|
|
- [ ] **Step 3: Validate and analyze raw profiles**
|
|
|
|
Verify every scenario has one warm-up, five measured, one diagnostic, valid
|
|
process identities, exact fixture/action hashes, zero external requests, and
|
|
all required artifacts. Run the ignored CPU/heap analyzers sequentially,
|
|
preserve source-mapped hotspot and retaining-path JSON beside the raw profiles,
|
|
and hash the analyzer/source-map inputs.
|
|
|
|
- [ ] **Step 4: Name and prove three bottlenecks**
|
|
|
|
For each candidate, cite:
|
|
|
|
- scenario and measured phase distribution;
|
|
- renderer/main/database-worker CPU stack;
|
|
- retaining path and retained/self sizes with process scope;
|
|
- corroborating event-loop/long-task/frame/heartbeat evidence;
|
|
- explicit confounders and attribution gaps.
|
|
|
|
Choose only the strongest candidate. Add a regression test that fails at the
|
|
merged baseline, implement the smallest production change, rerun all affected
|
|
tests, and repeat the identical formal benchmark into a fresh `after`
|
|
directory.
|
|
|
|
- [ ] **Step 5: Claim improvement only after matched five-run evidence**
|
|
|
|
Report before/after medians and p95 where appropriate, percentage change,
|
|
memory/process separation, variance, unchanged/counter-regressed metrics, and
|
|
tradeoffs. If the matched results do not improve, revert or describe the change
|
|
as unconfirmed; never call it an optimization.
|