timothy ae4bf8b662 fix(786,789): guard against env shadowing, and close the weaker proof shapes
Second cold re-review (Claude, cold brief, isolated worktree) of the tree at 0944877bf. Its
BLOCKER (the retracted rule surviving in four sites) and its duplicate-row finding were already
fixed in d8a507a3b, which it did not see. Six further findings remain and are fixed here.

JOB-LEVEL env COULD SHADOW A MEMORY-CRITICAL WORKFLOW-LEVEL ONE. Raised as an unmeasured
assumption, and it is the one worth acting on: before this branch NO job in docker-build.yml
declared `env:` at all, and that workflow's workflow-level `env:` carries UseSharedCompilation,
DOTNET_CLI_USE_MSBUILD_SERVER and MSBUILDDISABLENODEREUSE — what keeps a 7.8 GB VBCSCompiler off a
RAM-oversubscribed runner (#406). Actions merges the scopes with the more specific winning, so a
same-named job-level key replaces the workflow value and the loss is INVISIBLE: the job still runs,
just with the shared compiler back on.

Rather than measure the merge once and write the answer in prose, the reliance is removed:
test_no_job_env_key_SHADOWS_a_workflow_level_one asserts no job-level key collides with a
workflow-level one, in any tracked workflow. Measured clean today across all six. Witnessed red by
planting `UseSharedCompilation: true` on `test`:

  docker-build.yml::test declares job-level ['UseSharedCompilation'], which also exists at
  workflow level. The job value WINS and the workflow value is silently lost.

TWO PROOFS WERE WEAKER THAN THEIR TWINS.
  * test_MUTATION_a_guard_job_with_its_row_DELETED_is_reported had no negative control, so a
    PRE-EXISTING missing row satisfied every iteration. Its phantom twin got one in c00126b82 and
    this one did not — the same asymmetry, one commit apart. It now pins `declared - listed` to
    empty first and asserts the deletion is reported as EXACTLY that job.
  * test_a_commented_out_marker_does_NOT_count asserted that PyYAML ignores comments — a fact this
    suite does not own and that no change here could break. It now writes a workflow to tmp_path,
    drives the real `role_faults`, and asserts the commented text IS present in the file, which is
    the actual guard: a reader that ever became a text scan would find it.

A PROSE COUNT SHIPPED FIVE LINES ABOVE THE ONE 0944877bf DELETED. "Only three jobs are `none` —"
enumerated the workflow by hand, unasserted, in the same file where the previous commit replaced a
count with an invariant for exactly that reason. Removed: which jobs are `none` is read off the
markers, and the table is the only enumeration a check keeps honest.

Three accuracy fixes, each measured:
  * docs-reminder: "all three check steps carry continue-on-error" is off by one — there are TWO
    check steps plus a `Set up Python` between them, all three with the flag. The substantive
    claim (no finding can fail the job) was right.
  * The two REQUIRED-context strings dropped the ` (pull_request)` suffix that
    .gitea/required-status-contexts.json carries, so a reader copying one into branch protection
    would get a context that never reports. Both now match the file exactly, verified against it.
  * The `_FULL_LINE_COMMENT` comment read as though stripping cured a live red. It did not:
    measured, ZERO toolchain tokens appear in the raw `run:` bodies of all three bare-runner jobs,
    comment lines included. It is preventive, and now says so — along with why it cannot manufacture
    a match (`.sub` on a `^…$` match leaves the newline, so no lines are joined).

The re-review independently re-derived the verdict/artifact classification across all 17 jobs and
would not reclassify any, and confirmed the three earlier de-vacuuming fixes hold under execution.

Suite: 1179 passed, 2 skipped. ruff 0.12.11 clean; decisions-validate OK.

Refs #786
Refs #789
2026-08-28 22:14:44 +02:00
2022-04-28 06:56:01 -05:00
2025-11-11 06:12:46 -06:00
2021-02-08 21:13:53 -06:00
2023-08-13 09:33:33 -05:00
2025-11-26 10:49:01 -06:00
2026-02-24 15:27:51 -06:00

ErsatzTV

ErsatzTV lets you transform your media library into a personalized, live TV experience - complete with EPG, channel scheduling, and seamless streaming to all your devices. Rediscover your content, your way.

contact features community

epg-example

How It Works

  1. Install ErsatzTV: Download and set up the server on your system.
  2. Add Your Media: Connect your media libraries and collections.
  3. Create Channels: Design and schedule your own live channels.
  4. Stream Anywhere: Watch on any device with IPTV and EPG support.

Key Features

  • Custom channels: Create and schedule your own live TV channels.
  • IPTV & EPG: Stream with IPTV and Electronic Program Guide support.
  • Hardware Transcoding: High-performance streaming with hardware acceleration (NVENC, QSV, VAAPI, AMF, VideoToolbox)
  • Media Server Integration: Connect Plex, Jellyfin, Emby and more.
  • Music & Subtitles: Mix music videos and enjoy subtitle support.
  • Open Source: Free, open, and community-driven project.

Documentation

Documentation is available at ersatztv.org.

License

This project is inspired by pseudotv-plex and the dizquetv fork and is released under the zlib license.

S
Description
Fork of ErsatzTV - custom IPTV channel server (upstream archived Feb 2026)
Readme Zlib
79 MiB
v26.11.0
Latest
2026-07-20 22:22:04 +02:00
Languages
C# 64.6%
TypeScript 15.7%
Python 10.1%
JavaScript 5.8%
Shell 2.6%
Other 1.1%