Presence was decided by a LINQ predicate inline in the controller, so the
semantics SR-002 sets were nowhere stated in code -- the read path complied by
accident rather than by requirement. PresenceLookup is now the unit that
decides, tagged, with the reasoning next to it.
JR-004: windows are served exactly as given. UT-021 pins that [0,10] and
[10,20] are not merged despite looking mergeable -- two windows mean a genuine
departure and return, and collapsing them answers a different question from the
one the truth file asked. UT-022 pins a byte-identical round trip.
JR-005: bounds inclusive at both ends, zero-length windows are real sightings
rather than degenerate ones to discard, overlaps resolve.
The wording was the larger half of JR-005. The overlay rendered a bare list: it
asserted nothing, but told the viewer nothing either, and the default reading of
a paused frame is "these people are on screen" -- exactly what SR-002 forbids.
It now carries an "In this scene" heading. ActorAtTime became ActorInScene, and
README no longer contains "on screen" anywhere; it stated the forbidden reading
outright in seven places, including the opening sentence.
JR-006: measured rather than assumed. UT-023 builds 50 actors x 1000 windows and
asserts the response is bounded by actor count, never window count. The lookup
is a full scan on purpose -- an early exit on `start > t` would exploit the
sortedness the format requires, but would silently under-report the moment one
producer emitted windows out of order. UT-020 pins that unsorted input still
resolves; WindowsAreSorted is a diagnostic, not a correctness dependency.
Third mutation check: making the end bound exclusive fails UT-016 and UT-018 and
nothing else. One character turns an inclusive window into a half-open one,
dropping an actor at exactly the moment a scene ends.
TRACES: UT-016, UT-017, UT-018, UT-019, UT-020, UT-021, UT-022, UT-023
TRACES: JR-004, JR-005, JR-006 | SR-002
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deletes the on-disk index.html injection rather than leaving it switched off.
Plugin.cs had already stopped calling it, but an unreachable write path with a
live signature is the one a later refactor re-enables by accident, and it was
still the behaviour the README and the release changelog advertised.
Patching index.html on disk is destructive in ways a plugin cannot clean up
after: the patch outlives an uninstall, a web-client upgrade discards it
silently, and it races any other plugin touching the same file. It is also a
second code path, and the one nobody runs is the one that rots.
WebClientPatchService is now removal-only. The strip is factored out as
RemoveInjection so it is testable without a filesystem. Removal is the one
write JR-021 permits -- an earlier JRay did patch the file, and those users
must not be left with a stale injection pointing at endpoints that have since
changed. It keys on JRay's own marker, so it touches nothing another plugin
added.
JR-021 is a requirement to *not do* something, which no unit test can
demonstrate, so scripts/checks/no-index-injection.sh verifies it by absence.
The check was confirmed to fail on a reintroduced Apply() and on reintroduced
ReplaceLast injection -- a check that has only ever passed is not evidence.
Jellyfin has no plugin dependency mechanism, so nothing installs File
Transformation for the user and a log warning alone is one nobody reads.
GET /Plugins/JRay/Status/Dependencies reports whether the dependency is
satisfied, and the configuration page renders it with the repository URL and
what to do with it. Absent the plugin only the overlay is disabled; every
other feature works.
JR-022 and JR-023 stay In Progress rather than Done: neither has a test that
executes, and this repo has no test project yet.
TRACES: JR-021, JR-022, JR-023 | PR-004
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The markdown codeblocks in the README were using `json`, which has no support for comments, making them highlighted in red. `jsonc` does have support, correctly rendering the codeblocks.
This commit describes how to setup an automation for Visual Studio Code.
The automation aims to build the plugin and then start the server and
optionally the web-client. This way, only one IDE project has to be
opened which starts all necessary dependencies.