ae4bf8b662ce595e70267c3b66a5135bdb77dfca
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
fix(787): derive the dropped-step guard's scope, and reconcile its snapshot against the server (#861)
fix(754,757): declare graphicsElementIds + padToNearestMinute, and pin every MCP tool to its OpenAPI contract (#760)
fix(754,757): declare graphicsElementIds + padToNearestMinute, and pin every MCP tool to its OpenAPI contract (#760)
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.
How It Works
- Install ErsatzTV: Download and set up the server on your system.
- Add Your Media: Connect your media libraries and collections.
- Create Channels: Design and schedule your own live channels.
- 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.
