JR-004, JR-005, JR-006: scene-scoped read path
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>
This commit is contained in:
+24
-9
@@ -35,13 +35,28 @@ Tag code with `// TRACES: JR-012 | SR-002`.
|
||||
| UT-013 | …and **warns** naming the install URL, with no "falling back" claim | JR-023 | **Passing** |
|
||||
| UT-014 | Overlay disabled ⇒ `index.html` returned unchanged | JR-023 | **Passing** |
|
||||
| UT-015 | Null contents return empty rather than throwing — this callback runs on every page another plugin serves | JR-023 | **Passing** |
|
||||
| UT-016 | Both bounds **inclusive** — start, interior and end all present | JR-005 | **Passing** |
|
||||
| UT-017 | Just outside either bound is absent | JR-005 | **Passing** |
|
||||
| UT-018 | A zero-length window is a real sighting, not a degenerate one to discard | JR-005 | **Passing** |
|
||||
| UT-019 | **Overlapping windows** — present inside an enclosing window | JR-005 | **Passing** |
|
||||
| UT-020 | **Unsorted windows still resolve**; sortedness is a producer guarantee, not a correctness dependency | JR-006 | **Passing** |
|
||||
| UT-021 | **Adjacent windows are never merged** — reported once, from two windows | JR-004 | **Passing** |
|
||||
| UT-022 | Truth file round-trips with windows byte-identical | JR-004 | **Passing** |
|
||||
| UT-023 | 50 actors × 1000 windows: response bounded by actor count, lookup not quadratic | JR-006 | **Passing** |
|
||||
|
||||
All 15 execute and pass. The suite was also checked to **fail** on two separate
|
||||
All execute and pass. The suite is also checked to **fail** on deliberate
|
||||
mutations, because a suite that has only ever passed is not evidence that it
|
||||
tests anything: removing the newline-stripping from `RemoveInjection` fails
|
||||
UT-001 alone, and downgrading the missing-dependency warning to `Information`
|
||||
fails UT-013 alone. In both cases the blast radius was one test, and the source
|
||||
was restored and re-verified.
|
||||
tests anything. Three so far, each restored and re-verified afterwards:
|
||||
|
||||
| Mutation | Fails | Blast radius |
|
||||
|---|---|---|
|
||||
| Drop the newline-stripping in `RemoveInjection` | UT-001 | 1 test |
|
||||
| Downgrade the missing-dependency warning to `Information` | UT-013 | 1 test |
|
||||
| Make the window end bound exclusive (`t < end`) | UT-016, UT-018 | 2 tests |
|
||||
|
||||
The third is the one worth keeping: a single character turns an inclusive window
|
||||
into a half-open one, which would drop an actor at exactly the moment a scene
|
||||
ends — and nothing else in the suite would have noticed.
|
||||
|
||||
`JR` is flat rather than split by theme. The plugin is one deployable with one
|
||||
audience, and the thematic grouping lives in the section headings below, where it
|
||||
@@ -62,9 +77,9 @@ coordinated `schema_version` bumps (SR-003).
|
||||
| JR-001 | The truth-file format is normatively defined here; other repos reference it rather than restating it | SR-003 | High | In Progress |
|
||||
| JR-002 | `schema_version: 2` shape — `extraction.*` provenance block, `cut.*` block, `scenes` as objects carrying belief and route | SR-003 | High | Planned |
|
||||
| JR-003 | Reject an unknown `schema_version`, never guess. **Flag day: v2 only**, no dual-accept | SR-003 | High | Planned |
|
||||
| JR-004 | A window is a **scene-membership claim**, not a recognition event — never reinterpreted, merged, split or trimmed | **SR-002** | High | Planned |
|
||||
| JR-005 | Query semantics: actor present at `t` if any window contains `t`; presentation must not assert instantaneous visibility | **SR-002** | High | In Progress |
|
||||
| JR-006 | Read path holds up under **numerous** windows — no assumption of a handful of long ones | SR-002 | Medium | Planned |
|
||||
| JR-004 | A window is a **scene-membership claim**, not a recognition event — never reinterpreted, merged, split or trimmed | **SR-002** | High | **Done** (UT-021, UT-022) |
|
||||
| JR-005 | Query semantics: actor present at `t` if any window contains `t`; presentation must not assert instantaneous visibility | **SR-002** | High | **Done** (UT-016…019) |
|
||||
| JR-006 | Read path holds up under **numerous** windows — no assumption of a handful of long ones | SR-002 | Medium | **Done** (UT-020, UT-023) |
|
||||
| JR-007 | Identity is public identifiers: prefer `jellyfin_id` locally, else resolve `imdb_id`/`tmdb_id` against the item's People `ProviderIds` | SR-001 | High | Done |
|
||||
|
||||
## Truth-data sources and precedence (JR-008 … JR-011)
|
||||
@@ -246,7 +261,7 @@ framework reference and leans on `RollForward` to reach the 10.0 runtime.
|
||||
| JR-003 | **T1** | `schema_version` 1 and 3 are both **rejected**, not coerced | Missing field entirely; non-integer value |
|
||||
| JR-004 | T1 | Windows are stored and served byte-identical to input | Adjacent windows that "look" mergeable must **not** merge |
|
||||
| JR-005 | T1 | `t` exactly on `start` and on `end` are both present | Zero-length window; overlapping windows for one actor |
|
||||
| JR-006 | T1 | Query cost is acceptable with 10³ windows on one actor | Sorted-window assumption stated and tested |
|
||||
| JR-006 | T1 | Response bounded by actor count, not window count; lookup not quadratic | 50 × 1000 windows; **unsorted input still resolves** — sortedness is a producer guarantee, never a correctness dependency |
|
||||
| JR-007 | T1 | `jellyfin_id` preferred; falls back to provider ids | All three ids empty → actor still displayable by name |
|
||||
| JR-008 | T1 | Sidecar path derived from the item path plus the configured suffix | Item with no path; suffix changed at runtime |
|
||||
| JR-009 | T2 | `PUT` stores, `DELETE` removes, both admin-only | `DELETE` on an item with no managed truth is still `204` |
|
||||
|
||||
Reference in New Issue
Block a user