Ship the SR-003 schema bump: jmanifest_version 2
CI / fmt, clippy, test (push) Failing after 1m22s
CI / static musl binary (push) Has been skipped
CI / advisories and licences (push) Successful in 26s

Moves the exchange envelope to version 2 in lockstep with the truth file's
schema_version, per SR-003's requirement that breaking changes be batched and
ship together rather than piecemeal. The plugin had already moved to
schema_version 2; the server declaring 1 while accepting the new fields
defeated the point of having a version at all.

Flag day, not dual-accept (JR-003): version 1 is now rejected outright. All
three components are pre-release, and a v1 read path would be the one nobody
exercises, so it is the one that would rot while being dragged through every
later change to the reader. A pipeline still emitting v1 is incompatible until
updated — stated plainly rather than papered over with a shim nobody tests.

scenes become objects carrying belief and route (extraction AR-017) instead of
float pairs. Belief is bounded to [0, 1] rather than merely stored: §5a's
Threat 1 argument rests on every accepted value being bounded, and an unbounded
float is a 64-bit channel however harmless it looks. route is a closed enum, so
an invented value cannot be stored.

UR-018 is the requirement with the trap in it, and the reason content_id.rs is
untouched by this commit: belief is a producer-side estimate that may
legitimately differ between pipeline versions for identical timings, so
including it in the canonical form would give two servers different ids for the
same content — the exact failure mode §9a quantises centiseconds to avoid,
reintroduced one field along. It replicates as an attribute, exactly as
audio_signature does. The golden vector still passes unchanged, which is the
evidence rather than the claim.

191 tests. UR-015..018 move from Planned to Done; coverage 24/32 (75%).

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

TRACES: UR-014, UR-015, UR-016, UR-017, UR-018 | SR-003
This commit is contained in:
2026-07-31 09:13:14 +02:00
co-authored by Claude Opus 5
parent c73f417d45
commit 88c7264094
12 changed files with 494 additions and 179 deletions
+25 -11
View File
@@ -107,7 +107,7 @@ and a cut fingerprint; the actor timeline payload is unchanged.
```json
{
"jmanifest_version": 1,
"jmanifest_version": 2,
"identity": {
"type": "movie",
"tmdb_id": "504172",
@@ -133,7 +133,10 @@ and a cut fingerprint; the actor timeline payload is unchanged.
"name": "Steve Buscemi",
"imdb_id": "nm0000114",
"tmdb_id": "884",
"scenes": [[191.6, 209.2], [438.2, 465.6]]
"scenes": [
{ "start": 191.6, "end": 209.2, "belief": 0.98, "route": "live" },
{ "start": 438.2, "end": 465.6, "belief": 0.81, "route": "deferred" }
]
}
]
}
@@ -154,8 +157,10 @@ For an episode, `identity` is:
Field notes:
- `jmanifest_version` — separate from the plugin's `schema_version`; this
versions the *exchange* envelope.
- `jmanifest_version` — **currently 2.** Separate from the plugin's
`schema_version`; this versions the *exchange* envelope, and the two remain
independent by design. They coincide at 2 only because the SR-003 bump touched
both. An unknown version is rejected outright (UR-014), never guessed at.
- `identity.tmdb_id` / `imdb_id` — at least one required. These are the
lookup keys.
- `cut.runtime_sec` — **required**, the decoded duration of the media the
@@ -173,7 +178,10 @@ Field notes:
- `actors[].jellyfin_id` — **must not appear.** The server rejects uploads
containing it (see §6).
- `movie` (absolute path) — **must not appear.** Rejected likewise.
- `actors[].scenes` — `[start_sec, end_sec]` inclusive, sorted. **A window is a
- `actors[].scenes` — objects, not float pairs. `start`/`end` in seconds,
inclusive, sorted. `belief` is the accumulated posterior that justified the
claim, in `[0, 1]`; `route` is `live`, `deferred` or `pooled` (extraction
AR-017). Both are optional and both are **excluded from `content_id`** (§9a). **A window is a
claim about scene membership, not a recognition event** (UR-013, system spec
SR-002): an actor who turns away or is off-camera during a reverse shot is
still present. The server therefore never reinterprets, merges, splits or
@@ -188,12 +196,13 @@ Field notes:
server-authoritative. Contributors should not expect a name they invented to
round-trip.
### Pending schema bump — SR-003
### Schema bump — SR-003, shipped at version 2
The truth file and the Jmanifest are consumed by components that ship
independently, so breaking changes are **batched into one `schema_version`
bump** coordinated across all three repos (system spec SR-003). One bump is
currently pending, and this server must accept the new shape when it lands:
bump** coordinated across all three repos (system spec SR-003). One bump has
shipped, moving `jmanifest_version` to **2** in lockstep with the truth file's
`schema_version`:
| Change | Effect here |
|---|---|
@@ -219,8 +228,13 @@ bump rather than after it:
as an attribute, exactly as `audio_signature` is (§9a).
- Quantisation is unchanged: integer centiseconds, for the reasons in §9a.
Until the bump ships, this server accepts `jmanifest_version: 1` and rejects
anything else outright (UR-014) rather than guessing at an unknown shape.
**Flag day, not dual-accept.** This server accepts `jmanifest_version: 2` and
rejects everything else outright (UR-014), including version 1. All three
components are pre-release, and a v1 read path would be the one nobody
exercises — so it is the one that would rot while being carried through every
later change to the reader. The consequence is that a pipeline still emitting v1
is incompatible until it is updated, which is stated plainly rather than papered
over with a compatibility shim nobody tests.
### Series bundles
@@ -232,7 +246,7 @@ A bundle is a thin wrapper, not a new format:
```json
{
"jmanifest_version": 1,
"jmanifest_version": 2,
"series": {
"series_tmdb_id": "1396",
"series_imdb_id": "tt0903747",