Commit Graph
10 Commits
Author SHA1 Message Date
4grayandClaude Opus 5.5 33e4fc9c9a fix(electron): keep the backend specs on the base compile target
The ES2022 target moves from apps/electron-backend/tsconfig.json to
tsconfig.app.json, so it applies to the main-process and preload build
only. Compiling the Jest specs for ES2022 dropped the downleveled helpers
from Istanbul's statement counts (downloads.events.ts: 126 -> 111
statements, 79 -> 71 covered, 62.69% -> 63.96%) and tripped the absolute
minimumCovered ratchet in tools/coverage/coverage-policy.json without any
coverage being lost. The shipped bundles are byte-identical either way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:28:08 +02:00
4grayandClaude Opus 5.5 9b0b9b6944 perf(electron): compile the main process and preload for ES2022
apps/electron-backend/tsconfig.json now sets target ES2022, so the
main-process bundles, the preloads and the backend's Jest specs no longer
downlevel async/await, optional chaining and nullish coalescing for ES2015.
Electron 43 runs them natively in the main process and in the sandboxed
preload. tsconfig.base.json keeps es2015 because other projects inherit it.
useDefineForClassFields stays false, so class fields keep their constructor
assignment semantics and only syntax changes.

main.js + main.app.js + deferred-events.js + main.preload.js shrink from
2,008,115 to 1,853,599 bytes (-7.7%); every inlined __awaiter helper is gone.
Startup did not move measurably: main-process CPU to did-finish-load and the
J1 launch journey were flat in interleaved A/B runs, with identical counters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:20:09 +02:00
cd0a50dbec fix(playback): stop random black frames on software GL in frame-copy (#1748)
* test(e2e): explain black canvases in the packaged frame-copy smoke

When the smoke's canvas stays black, print and attach the session
snapshot (with mpv's drop counter), every slot of the helper's
shared-memory frame rings read from /dev/shm, and the session's verbose
mpv log (log-file). Together they separate these cases: the helper never
published a frame, mpv rendered black, or the preload pump did not draw
a real frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(playback): stop random black frames on software GL in frame-copy

mpv's LUT scalers (the default lanczos/spline family) build their weight
texture from an uninitialized talloc_array: mp_compute_lut fills only
kernel->size of every stride floats, so each row's padding is heap
garbage (reinit_scaler in video/out/gpu/video.c, mpv 0.41 and master).
The LUT is an rgba16f texture sampled with linear filtering. When the
padding holds NaN, or a value large enough to become Inf as half-float,
Mesa's llvmpipe carries it through the zero-weight neighbour texel, the
weights become NaN and the frame clamps to pure black. Whether it happens
depends on heap contents, so the packaged smoke's paused frame was black
in most attempts on the CI runner.

Evidence from CI (8 repeats each, no retries): baseline 2/8 passed;
LUT-free bilinear scalers 8/8; gpu-dumb-mode 8/8; LP_NUM_THREADS=1 6/8.
A synchronous glReadPixels right after mpv_render_context_render()
showed the black frame already in the helper's FBO. The readback, the
shared-memory ring and the preload pump were correct.

On a CPU rasterizer the helper now selects mpv's LUT-free bilinear
scalers and disables sigmoid upscaling. Software GL cannot afford the
LUT scalers anyway. A session option for the same key still wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(playback): report software scaler results and scope smoke ring diagnostics

The software-renderer fallback now reports which scaler options mpv
accepted and which it rejected (with mpv's error), instead of always
printing success. The smoke's black-canvas diagnostics read only the
failed session's rings (<sessionId>-g<N>), not every impv-fc ring in
/dev/shm.

Addresses Greptile review feedback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:37:21 +02:00
1d9a563d1a test(performance): count startup phases and SQL statements for the J1 launch journey (#1715)
* test(performance): count startup phases and SQL statements for the J1 launch journey

Implements plan item A2. With IPTVNATOR_PERF_CAPTURE=1 the main process
keeps named counters and registers a main-only performance:read-counters
IPC handler; without the flag nothing is counted and the handler does not
exist.

- debug-trace.ts owns the registry; traceStartupPhase replaces the
  trace('startup', ...) sites and counts main.startupPhases.
- The database worker counts executed statements through better-sqlite3's
  Statement prototype (the verbose callback expands every statement and
  made bulk inserts 2-4x slower) and posts the count over its message
  port, flushed before every other worker message. The main-thread shared
  connection is counted through a new connection observer in the shared
  database library.
- The first main window freezes main.modulesRegisteredBeforeWindow at
  creation and main.sqlStatementsBeforeReadyToShow at ready-to-show.
- The journey gate drops the ready-to-show that Electron emits for the
  about:blank detour, so the app sees the real document's first paint,
  and taps the counters handler; the J1 record reads both counters after
  the renderer probe completes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(database): require one SQL statement per exec during initialization

The performance capture counts one exec call as one statement, because
SQL cannot be split reliably in the counter (trigger bodies contain
semicolons). The historical-upgrade driver now wraps exec on every
connection initDatabase opens and fails on a batch, so that counting
assumption holds for the fresh profile and all historical schemas.
Documents the definition in the counter and the architecture docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(performance): count SQL statements only for the launch journey

Codex review: the M3U import, refresh-cancellation and Xtream benchmarks
also run with IPTVNATOR_PERF_CAPTURE=1, so the statement hook wrapped
every row of their bulk inserts and changed what they measure.

SQL counting now also needs IPTVNATOR_PERF_COUNT_SQL=1, which only the
launch journey sets; a harness test fails if another source sets it.
Startup phases, the window snapshot and the read handler stay on the
capture flag. Without SQL counting no ready-to-show listener is attached,
so a zero is never reported for statements nobody counted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:01:26 +02:00
4gray f166ff4d47 ci(packaging): time-box the Snap and Flatpak embedded MPV runtime probes (#1704) 2026-09-27 07:54:20 +02:00
4grayandClaude Fable 5.1 e39c854a41 perf(electron): load the main-process startup wiring after the window starts loading (#1702)
Registering IPC handlers costs 0.4 ms; evaluating the modules behind them (axios, drizzle-orm, better-sqlite3, electron-updater, fix-path) before the window could load was the real cost. main.ts now keeps only the pre-paint wiring and loads the rest as the deferred-events.js chunk inside the main window's did-start-loading listener, where the import and its registrations complete before any renderer invoke can arrive.

Interleaved A/B on the performance build: app.whenReady 323 -> 265 ms, did-finish-load 499 -> 447 ms; J1 journey spawnToDidFinishLoad ~405 -> ~365 ms with identical counters. Packaging ships the chunk explicitly, verify:package-layout requires it, and the benchmark build identity hashes it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-26 21:51:19 +02:00
4grayandClaude Fable 5.1 587e19541f perf(electron): compile the main-process bundle from a V8 code cache (#1696)
main.js is now a small entry that enables Node's on-disk V8 compile cache under userData/v8-compile-cache and then requires the application bundle main.app.js. Warm launches reach app.whenReady about 13 ms sooner at the median; IPTVNATOR_DISABLE_COMPILE_CACHE=1 turns it off and IPTVNATOR_COMPILE_CACHE_DIR relocates it.

Packaging now ships main.app.js explicitly and verify:package-layout requires the main-process entry files in app.asar, because nx-electron copies the backend through an allowlist. The Xtream benchmark build identity hashes both the launcher and the bundle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-26 19:19:30 +02:00
4gray 0ecfc06494 test(electron): fix Windows cleanup and retain packaged smoke diagnostics (#1665)
* test(electron): reap Windows process trees and retain smoke diagnostics

* test(electron): require confirmed process exit before relaunch

* test(electron): retain process handle after application exit

* test(electron): bind captured processes to application instances
2026-09-23 22:55:48 +02:00
4gray dc4b33991d chore(release): prepare v0.24.0 (#1659)
* chore(release): prepare v0.24.0

* docs(release): select sculptural v0.24 cover

* docs(release): preserve announcement cover prompt
2026-09-22 08:43:42 +02:00
4gray faad8fd8fd docs(agents): compact root guidance and preserve task-specific knowledge (#1645)
* docs(agents): compact root guidance and preserve task-specific knowledge

* fix(agents): parse guidance navigation with Markdown tokens

* fix(agents): validate generic literal repository paths

* fix(agents): distinguish code symbols and shortcut images

* fix(agents): recognize SCSS filename literals

* fix(agents): handle fenced imports and encoded paths

* fix(agents): parse prose and rendered HTML anchors

* fix(agents): validate rendered HTML navigation

* fix(agents): use GitHub-compatible heading slugs

* fix(agents): require standalone top-level Claude import

* fix(agents): exclude HTML-contained guidance imports

* fix(agents): handle image fragments and quoted imports

* fix(agents): validate visible HTML and image source sets

* fix(agents): recognize package scopes and route source work

* fix(agents): parse JSONC and constrain package exemptions

* fix(agents): decode link entities and allow package subpaths

* fix(agents): route source work and check extensionless files

* fix(agents): support package versions and source fragments

* fix(agents): accept qualified package prose

* fix(agents): retain rendered context for Markdown references

* fix(agents): validate visible headings and spaced paths

* fix(agents): validate media and hyphenated literal paths

* fix(agents): decode full HTML entities and media assets

* fix(agents): recognize possessive package mentions

* fix(agents): validate extensionless imports and version comparators

* fix(agents): retain visible backticks and explicit path punctuation

* fix(agents): validate image-map navigation targets

* fix(agents): count all Markdown line endings in budgets

* fix(agents): delimit package prose at Unicode punctuation

* fix(agents): normalize punctuation for extensionless imports

* fix(agents): preserve filenames across prose punctuation

* fix(agents): validate iframe document references

* fix(agents): inspect document suffix before URL fragments

* fix(agents): unify Markdown suffix and encoded import guards

* fix(agents): handle wildcard versions and alternate documents

* fix(agents): validate document formats and trim HTML URLs

* fix(agents): cover document families and guidance basenames

* fix(agents): require files for media references

* fix(agents): preserve block boundaries and validate embeds

* fix(agents): normalize internal HTML URL whitespace

* fix(agents): reject empty media and ignore URL at-signs

* fix(agents): validate srcdoc references and empty srcset

* fix(agents): honor HTML bases and preserve adjacent imports

* fix(agents): convert base file URLs to native paths

* fix(agents): preserve imports after bare URL punctuation

* fix(agents): exclude opaque URI prose from import scans

* fix(agents): keep import tokens outside URI scheme matches

* fix(agents): restrict opaque URI exemptions to parsed links

* fix(agents): handle opening prose delimiters

* fix(agents): scan nested imports and share document suffixes

* fix(agents): reject pathless media and direct file URLs

* fix(agents): reject file bases and preserve quoted URL boundaries

* fix(agents): distinguish URL quotes and cover guidance variants

* fix(agents): validate SVG images and conventional guides

* fix(agents): handle declared package names handles and SVG use

* fix(agents): normalize closing punctuation on federated handles

* fix(agents): normalize Unicode punctuation on handles

* fix(agents): normalize possessive federated handles

* fix(agents): separate parenthetical prose from handles

* fix(agents): exclude www autolinks from import scanning

* ci: allow manual CodeQL validation of PR branches

* fix(agents): reject nonportable Windows drive links
2026-09-21 18:07:14 +02:00