Ship the SR-003 schema bump: jmanifest_version 2
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:
+50
-39
@@ -3,7 +3,7 @@
|
||||
<!-- GENERATED FILE - do not edit by hand. -->
|
||||
<!-- Regenerate: scripts/traceability/traceability-gate.sh -->
|
||||
|
||||
**Generated:** 2026-07-30T16:55:59+00:00
|
||||
**Generated:** 2026-07-31T07:12:27+00:00
|
||||
|
||||
Denominators are read from [`requirements.md`](requirements.md) at run time, never hardcoded. Coverage counts a requirement only when it is tagged in source **and** has a verification tier this repo's CI host can execute (`T1, T2, static`).
|
||||
|
||||
@@ -12,12 +12,12 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| Source files scanned | 26 |
|
||||
| TRACES tags found | 35 |
|
||||
| TRACES tags found | 37 |
|
||||
| EXCEPTION tags found | 0 |
|
||||
| Requirements defined | 32 |
|
||||
| Requirements covered | 23 |
|
||||
| **Coverage** | **71.9%** (23/32) |
|
||||
| Coverage of CI-executable scope | 71.9% (23/32) |
|
||||
| Requirements covered | 24 |
|
||||
| **Coverage** | **75.0%** (24/32) |
|
||||
| Coverage of CI-executable scope | 75.0% (24/32) |
|
||||
| Tagged but unexecuted in CI | 0 |
|
||||
| Orphan tags | 0 |
|
||||
|
||||
@@ -25,7 +25,7 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
|
||||
|
||||
| Type | Covered | Tagged but unexecuted | Defined |
|
||||
|---|---|---|---|
|
||||
| UR | 13 | 0 | 18 |
|
||||
| UR | 14 | 0 | 18 |
|
||||
| DR | 10 | 0 | 14 |
|
||||
|
||||
- **PR** tags present (separate taxonomy, not counted in coverage): PR-004, PR-005, PR-006
|
||||
@@ -73,10 +73,10 @@ _None._
|
||||
| UR-012 | Done | T2 | SR-005 | covered | `src/db/repo.rs`, `src/ingest.rs` | Never accept, store, or serve gallery data — reference faces or embed… |
|
||||
| UR-013 | Done | T1 | SR-002 | covered | `src/api/fetch.rs`, `src/model.rs`, `src/validate.rs` | Windows are scene-scoped claims; never reinterpret their boundaries |
|
||||
| UR-014 | Done | T1 | SR-003 | covered | `src/model.rs`, `src/validate.rs` | Reject an unknown `jmanifest_version` outright, never guess |
|
||||
| UR-015 | Planned | unset | SR-003 | untagged | - | Accept `extraction.extinction_sec` in place of `anneal_sec` |
|
||||
| UR-016 | Planned | unset | SR-003 | untagged | - | Accept and store `extraction.gallery_scope`; rank on it (§7) |
|
||||
| UR-017 | Planned | unset | SR-003 | untagged | - | Accept per-window belief and identification route; `scenes` becomes o… |
|
||||
| UR-018 | Planned | unset | SR-003 | untagged | - | Exclude belief from `content_id`, replicating it as an attribute |
|
||||
| UR-015 | Done | T2 | SR-003 | untagged | - | Accept `extraction.extinction_sec` in place of `anneal_sec` |
|
||||
| UR-016 | Done | T2 | SR-003 | untagged | - | Accept and store `extraction.gallery_scope`; rank on it (§7) |
|
||||
| UR-017 | Done | T1, T2 | SR-003 | covered | `src/model.rs` | Accept per-window belief and identification route; `scenes` are objec… |
|
||||
| UR-018 | Done | T1 | SR-003 | untagged | - | Exclude belief and route from `content_id`, replicating them as attri… |
|
||||
| DR-001 | Done | T1 | SR-004 | untagged | - | Strict parse boundary: unknown fields rejected structurally, not by v… |
|
||||
| DR-002 | Done | unset | SR-004 | covered | `src/api/fetch.rs`, `src/db/repo.rs` | Fully relational storage — no JSON blob on the write path |
|
||||
| DR-003 | Done | T1 | PR-004 | covered | `src/db/mod.rs` | Single serialized writer connection, with a read pool alongside |
|
||||
@@ -100,7 +100,7 @@ _None._
|
||||
|
||||
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
|
||||
- [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
|
||||
- [`src/db/repo.rs:412`](../src/db/repo.rs#L412) — `pub fn actors_for_manifest(`
|
||||
|
||||
### DR-003
|
||||
|
||||
@@ -118,7 +118,7 @@ _None._
|
||||
|
||||
**Locations:** 1
|
||||
|
||||
- [`src/db/repo.rs:691`](../src/db/repo.rs#L691) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
- [`src/db/repo.rs:709`](../src/db/repo.rs#L709) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
|
||||
### DR-006
|
||||
|
||||
@@ -151,7 +151,7 @@ _None._
|
||||
|
||||
- [`src/content_id.rs:52`](../src/content_id.rs#L52) — `pub fn canonical_json(`
|
||||
- [`src/content_id.rs:129`](../src/content_id.rs#L129) — `pub fn content_id(`
|
||||
- [`src/validate.rs:78`](../src/validate.rs#L78) — `pub fn to_centiseconds(secs: f64) -> i64`
|
||||
- [`src/validate.rs:102`](../src/validate.rs#L102) — `pub fn to_centiseconds(secs: f64) -> i64`
|
||||
|
||||
### DR-013
|
||||
|
||||
@@ -167,7 +167,7 @@ _None._
|
||||
|
||||
- [`src/config.rs:10`](../src/config.rs#L10) — `Unknown`
|
||||
- [`src/db/mod.rs:30`](../src/db/mod.rs#L30) — `struct ReadPool`
|
||||
- [`src/db/repo.rs:691`](../src/db/repo.rs#L691) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
- [`src/db/repo.rs:709`](../src/db/repo.rs#L709) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
|
||||
### PR-005
|
||||
|
||||
@@ -183,7 +183,7 @@ _None._
|
||||
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
|
||||
- [`src/api/upload.rs:101`](../src/api/upload.rs#L101) — `pub async fn post_bundle(`
|
||||
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
|
||||
- [`src/validate.rs:540`](../src/validate.rs#L540) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
|
||||
- [`src/validate.rs:586`](../src/validate.rs#L586) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
|
||||
|
||||
### SR-001
|
||||
|
||||
@@ -193,30 +193,33 @@ _None._
|
||||
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
|
||||
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
|
||||
- [`src/castcheck.rs:82`](../src/castcheck.rs#L82) — `pub fn evaluate(submitted: &[SubmittedActor], credits: &[CastMember]) -> CastCheckOutcome`
|
||||
- [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
|
||||
- [`src/db/repo.rs:412`](../src/db/repo.rs#L412) — `pub fn actors_for_manifest(`
|
||||
- [`src/matching.rs:52`](../src/matching.rs#L52) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
|
||||
|
||||
### SR-002
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
|
||||
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
|
||||
- [`src/validate.rs:486`](../src/validate.rs#L486) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<(i64, i64)>>`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_str(s: &str) -> Option<Self>`
|
||||
- [`src/validate.rs:510`](../src/validate.rs#L510) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<SceneCs>>`
|
||||
|
||||
### SR-003
|
||||
|
||||
**Locations:** 8
|
||||
**Locations:** 10
|
||||
|
||||
- [`src/api/json.rs:100`](../src/api/json.rs#L100) — `fn require_utf8(bytes: &[u8]) -> Result<&str, ApiError>`
|
||||
- [`src/content_id.rs:52`](../src/content_id.rs#L52) — `pub fn canonical_json(`
|
||||
- [`src/content_id.rs:129`](../src/content_id.rs#L129) — `pub fn content_id(`
|
||||
- [`src/error.rs:8`](../src/error.rs#L8) — `Unknown`
|
||||
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
|
||||
- [`src/validate.rs:78`](../src/validate.rs#L78) — `pub fn to_centiseconds(secs: f64) -> i64`
|
||||
- [`src/validate.rs:203`](../src/validate.rs#L203) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/validate.rs:354`](../src/validate.rs#L354) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/model.rs:197`](../src/model.rs#L197) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_str(s: &str) -> Option<Self>`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/validate.rs:102`](../src/validate.rs#L102) — `pub fn to_centiseconds(secs: f64) -> i64`
|
||||
- [`src/validate.rs:227`](../src/validate.rs#L227) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/validate.rs:378`](../src/validate.rs#L378) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
|
||||
### SR-004
|
||||
|
||||
@@ -232,11 +235,11 @@ _None._
|
||||
- [`src/castcheck.rs:215`](../src/castcheck.rs#L215) — `pub fn category_guard_violation(matched: &[MatchedActor], title_is_adult: bool) -> Option…`
|
||||
- [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/model.rs:156`](../src/model.rs#L156) — `Unknown`
|
||||
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `impl Default for RateLimiter`
|
||||
- [`src/validate.rs:112`](../src/validate.rs#L112) — `fn is_allowed_text_char(c: char) -> bool`
|
||||
- [`src/validate.rs:203`](../src/validate.rs#L203) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/validate.rs:354`](../src/validate.rs#L354) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/validate.rs:136`](../src/validate.rs#L136) — `fn is_allowed_text_char(c: char) -> bool`
|
||||
- [`src/validate.rs:227`](../src/validate.rs#L227) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/validate.rs:378`](../src/validate.rs#L378) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/worker.rs:96`](../src/worker.rs#L96) — `async fn run_cast_check(&self, payload: &str) -> Result<(), JobError>`
|
||||
|
||||
### SR-005
|
||||
@@ -268,8 +271,8 @@ _None._
|
||||
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
|
||||
- [`src/castcheck.rs:82`](../src/castcheck.rs#L82) — `pub fn evaluate(submitted: &[SubmittedActor], credits: &[CastMember]) -> CastCheckOutcome`
|
||||
- [`src/model.rs:156`](../src/model.rs#L156) — `Unknown`
|
||||
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
|
||||
- [`src/validate.rs:203`](../src/validate.rs#L203) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/validate.rs:227`](../src/validate.rs#L227) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/worker.rs:96`](../src/worker.rs#L96) — `async fn run_cast_check(&self, payload: &str) -> Result<(), JobError>`
|
||||
|
||||
### UR-004
|
||||
@@ -296,7 +299,7 @@ _None._
|
||||
|
||||
- [`src/api/fetch.rs:128`](../src/api/fetch.rs#L128) — `pub async fn get_series(`
|
||||
- [`src/api/upload.rs:101`](../src/api/upload.rs#L101) — `pub async fn post_bundle(`
|
||||
- [`src/validate.rs:540`](../src/validate.rs#L540) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
|
||||
- [`src/validate.rs:586`](../src/validate.rs#L586) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
|
||||
|
||||
### UR-007
|
||||
|
||||
@@ -308,7 +311,7 @@ _None._
|
||||
|
||||
**Locations:** 1
|
||||
|
||||
- [`src/validate.rs:354`](../src/validate.rs#L354) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/validate.rs:378`](../src/validate.rs#L378) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
|
||||
### UR-010
|
||||
|
||||
@@ -316,7 +319,7 @@ _None._
|
||||
|
||||
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
|
||||
- [`src/castcheck.rs:82`](../src/castcheck.rs#L82) — `pub fn evaluate(submitted: &[SubmittedActor], credits: &[CastMember]) -> CastCheckOutcome`
|
||||
- [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
|
||||
- [`src/db/repo.rs:412`](../src/db/repo.rs#L412) — `pub fn actors_for_manifest(`
|
||||
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
|
||||
|
||||
### UR-011
|
||||
@@ -324,9 +327,9 @@ _None._
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/model.rs:156`](../src/model.rs#L156) — `Unknown`
|
||||
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
|
||||
- [`src/validate.rs:112`](../src/validate.rs#L112) — `fn is_allowed_text_char(c: char) -> bool`
|
||||
- [`src/validate.rs:354`](../src/validate.rs#L354) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/validate.rs:136`](../src/validate.rs#L136) — `fn is_allowed_text_char(c: char) -> bool`
|
||||
- [`src/validate.rs:378`](../src/validate.rs#L378) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
|
||||
### UR-012
|
||||
|
||||
@@ -337,16 +340,24 @@ _None._
|
||||
|
||||
### UR-013
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
|
||||
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
|
||||
- [`src/validate.rs:486`](../src/validate.rs#L486) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<(i64, i64)>>`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_str(s: &str) -> Option<Self>`
|
||||
- [`src/validate.rs:510`](../src/validate.rs#L510) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<SceneCs>>`
|
||||
|
||||
### UR-014
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
|
||||
- [`src/validate.rs:203`](../src/validate.rs#L203) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/validate.rs:227`](../src/validate.rs#L227) — `pub fn validate_manifest(mut m: Jmanifest) -> VResult<ValidManifest>`
|
||||
|
||||
### UR-017
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/model.rs:197`](../src/model.rs#L197) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_str(s: &str) -> Option<Self>`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user