Files
iptvnator/docs/architecture/validation-map.md
T
4grayandClaude Fable 5 e14b8ae8d9 feat(ci): enforce lint, guard coverage policy, add max-lines rule (#1117)
* fix(lint): resolve module-boundary and prefer-inject errors

Retag workspace-shell-util as type:data-access to match its injectable
services that depend on @iptvnator/services, and convert
RemoteControlService to inject(HttpClient).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(lint): enforce max-lines 400 with generated baseline

Add a max-lines ESLint error (hard cap 400 raw lines per TypeScript
file) per the repo file-size rule. The 134 pre-existing offenders are
baselined in tools/eslint/max-lines-baseline.mjs, regenerable via
generate-max-lines-baseline.mjs; the list should only shrink.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(ci): enforce lint on PRs and guard coverage policy drift

- Add a Lint job to ci.yml running nx run-many -t lint --all, so
  module-boundary tags, legacy-alias bans, and max-lines gate merges.
- Fix the root lint script (was linting only electron-backend).
- Add tools/coverage/check-coverage-policy.mjs: fails CI when a project
  with a test target is missing from coverage-policy.json; wired into
  coverage:ci as coverage:policy:check.
- Run Tier B/C unit tests in CI without coverage (list derived from the
  policy), so website/packaging/remote-control tests run on PRs.
- Replace the hand-picked 16-project test:unit:ci list with --all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: document CI lint enforcement and coverage policy guard

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): address bot review feedback on policy guard and baseline generator

- Drive Tier B/C validation from each policy entry's validationCommand
  (falling back to nx test), skipping projects with an e2e target since
  the E2E workflow already runs them (Codex).
- Fail when a Tier A entry has no test target (Greptile, adapted:
  checking all entries against test targets would false-positive on the
  intentionally spec-less e2e/mock-server tiers).
- Guard against missing JSON array in nx show projects output (Greptile).
- Scan .tsx files in the max-lines baseline generator to match the
  ESLint rule's file patterns (Greptile).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 10:06:45 +02:00

5.0 KiB

Validation Map

This map records the lowest-cost validation commands agents should reach for before broad CI-sized runs.

Discovery

pnpm nx show projects --withTarget test
pnpm nx show projects --withTarget lint
pnpm nx show projects --withTarget e2e

Unit And Type Checks

Area Command
Angular renderer entry points pnpm run typecheck:web
Electron main process entry points pnpm run typecheck:backend
Full unit suite (all projects) pnpm run test:unit:ci
EPG data access pnpm nx test epg-data-access
Workspace shell utilities pnpm nx test workspace-shell-util
Shared SQLite schema/connection pnpm nx test database
Packaging metadata pnpm nx test packaging

Lint

pnpm run lint                 # nx run-many --target=lint --all
pnpm nx lint <project>        # single project

The CI workflow (.github/workflows/ci.yml) runs lint for every project on each PR. This enforces @nx/enforce-module-boundaries (scope/domain/type tag constraints), the legacy bare-alias ban, and the max-lines file-size rule (hard maximum 400 lines per TypeScript file). Files that predate the max-lines rule are baselined in tools/eslint/max-lines-baseline.mjs; after splitting a baselined file below the limit, regenerate the list with node tools/eslint/generate-max-lines-baseline.mjs. Never add new files to the baseline.

Coverage Tiers

Use tools/coverage/coverage-policy.json as the source of truth for coverage ownership. Every project with a test target must be classified in a tier; pnpm run coverage:policy:check (part of coverage:ci) fails CI when a new project is missing from the policy, a listed project no longer exists, or a Tier A entry has no test target. CI runs Tier A with coverage (uploaded to Codecov) and each Tier B/C project's validationCommand (falling back to nx test) without coverage; projects with an e2e target are skipped there because the E2E workflow already runs them on every PR.

Tier Rule Validation
A Product/runtime Angular, Electron, backend, data-access, portal, playlist, workspace, playback, EPG, and shared UI code collects source coverage. pnpm run coverage:ci
B Validate behavior without percentage coverage, such as website, packaging, and Playwright E2E projects. pnpm nx test website, pnpm nx test packaging, or the closest E2E target
C Excluded from the source coverage baseline, such as mock servers, test helper libraries, and untested feature shells. Validate through dependent flows, or add focused tests when changing behavior directly

apps/website is an Astro marketing site. Its useful signal is a successful static build plus targeted output checks, not a merged code coverage percentage. Projects with a test target but no specs, such as remote-control-web and remote-control today, should not be in Tier A until focused specs exist.

For local coverage inspection:

pnpm run coverage:unit:ci
pnpm run coverage:merge
pnpm run coverage:health

The merged report is written to coverage/merged/ as HTML, LCOV, Cobertura, and JSON summary output. CI uploads the merged Tier A report to Codecov with the unit flag and keeps the HTML report as a GitHub artifact.

E2E

Area Command
Web app browser flows pnpm nx run web-e2e:e2e -- --project=chromium
Electron flows pnpm nx run electron-backend-e2e:e2e

Use atomized E2E targets when available, for example pnpm nx run web-e2e:e2e-ci--src/xtream.e2e.ts.

Playwright coverage is measured semantically by tags and critical journeys, not by a source-line percentage. E2E reports should use tags such as @critical, @electron, @web, @xtream, @stalker, @m3u, @search, @epg, @persistence, @settings, @pwa, and @self-hosted.

After an E2E run, generate the semantic summary with:

pnpm run coverage:e2e:summary

For local investigation only, Chromium browser V8 coverage can be explored with:

pnpm run coverage:e2e:v8:web

I18n

pnpm run i18n:check

The i18n check is non-mutating. It compares every locale file in apps/web/src/assets/i18n/ against en.json and fails on missing or extra keys. Identical English fallback values are reported as warnings by default; use node tools/i18n/check-drift.mjs --fail-on-identical for a stricter translation audit.

Logging

Runtime playback and EPG debug logs should use the existing logger or trace helpers instead of unconditional console.log. Electron external-player traces are gated by:

IPTVNATOR_TRACE_PLAYER=1 pnpm run serve:backend