feat(audio): store, serve and match the v1 audio signature
Completes UR-009. The register recorded the signature as stored; it was not. `ingest` validated `cut.audio_signature` and wrote NULL, so every served manifest came back without one — which also meant the plugin's own alignment (jRay JR-047, Done) had nothing to align against and could never run. That is the failure mode a status field is least able to catch: every validation test passed and the feature delivered nothing. Now stored, coarse-indexed and served back byte-identically, with a held manifest adopting an incoming signature it lacked (§9a). `audio`-tier matching runs on every read endpoint via an `audio_signature` parameter, and `POST /manifests/search` answers the unknown-providence case with a runtime prefilter, a bounded scan and honest truncation reporting. Three rules §3 did not previously state, now normative: - **±1 frame of slack in the score.** scene-actor-extraction VR-014 measured the exact-frame rule demoting 27 of 40 correctly aligned releases to `loose`, because the two windows are cut on their own file's frame grid and those grids do not coincide. With ±1 frame all 40 reach `audio` (worst 0.906) and the strongest false match is unmoved at 0.16. - **The offset has two terms.** Both windows are anchored at their own file's runtime/2, so the slide alone is wrong by half the runtime difference on every shifted release. A signature without a runtime therefore cannot align, and is refused by name rather than answered at a lower tier. - **A signature verdict is final**, including its refusals. Falling back to the runtime tier after the audio declined would let a coincidence overturn direct evidence, inverting the ordering the tier table exists to state. The slide precomputes each frame's neighbourhood as a 32-bit bin set rather than re-deriving it across 1201 slides — 3.3 ms to 1.1 ms per candidate, with a test asserting exact equivalence to the rule written the obvious way. The 1000-candidate search cap follows from that measurement as a ~1.1 s ceiling per request, not a round number. jRay's matcher still implements the pre-slack rule and will label some alignments `loose` that this server calls `audio`. Nothing misaligns — JR-047 makes the local answer win — but that register now carries the follow-up. TRACES: UR-008, UR-009 | SR-003
This commit is contained in:
+122
-70
@@ -3,7 +3,7 @@
|
||||
<!-- GENERATED FILE - do not edit by hand. -->
|
||||
<!-- Regenerate: scripts/traceability/traceability-gate.sh -->
|
||||
|
||||
**Generated:** 2026-07-31T14:25:51+00:00
|
||||
**Generated:** 2026-07-31T20:41:09+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`).
|
||||
|
||||
@@ -11,8 +11,8 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| Source files scanned | 29 |
|
||||
| TRACES tags found | 50 |
|
||||
| Source files scanned | 32 |
|
||||
| TRACES tags found | 69 |
|
||||
| EXCEPTION tags found | 0 |
|
||||
| Requirements defined | 33 |
|
||||
| Requirements covered | 31 |
|
||||
@@ -59,27 +59,27 @@ _None._
|
||||
|
||||
| ID | Status | Tier | Traces to | Trace state | Tagged in | Requirement |
|
||||
|---|---|---|---|---|---|---|
|
||||
| UR-001 | Done | T2 | SR-001 | covered | `src/api/exists.rs`, `src/matching.rs` | Cheap existence probe, separate from the fetch, returning availabilit… |
|
||||
| UR-002 | Done | T2 | PR-006 | covered | `src/api/upload.rs`, `src/ingest.rs` | Accept a contributed manifest for a media item |
|
||||
| UR-001 | Done | T2 | SR-001 | covered | `src/api/exists.rs`, `src/matching.rs`, `tests/audio.rs` | Cheap existence probe, separate from the fetch, returning availabilit… |
|
||||
| UR-002 | Done | T2 | PR-006 | covered | `src/api/upload.rs`, `src/ingest.rs`, `tests/audio.rs` | Accept a contributed manifest for a media item |
|
||||
| UR-003 | Done | T1, T2 | SR-004 | covered | `src/api/upload.rs`, `src/castcheck.rs`, `src/model.rs`, `src/validate.rs`, `src/worker.rs` | Content verification: strict schema, size caps, approximate TMDB cast… |
|
||||
| UR-004 | Done | T1, T2 | SR-004 | covered | `src/auth.rs`, `src/ratelimit.rs` | Rate limiting, per token where present and per source IP otherwise |
|
||||
| UR-005 | Done | T1, T2 | SR-004 | covered | `src/api/report.rs`, `src/api/upload.rs`, `src/auth.rs`, `src/castcheck.rs`, `src/worker.rs` | Trust without accounts: not usable as a content store, nor for prank … |
|
||||
| UR-006 | Done | T2 | PR-006 | covered | `src/api/fetch.rs`, `src/api/upload.rs`, `src/validate.rs` | Serve and accept a whole series in one operation |
|
||||
| UR-007 | In Progress | unset | PR-005 | covered | `src/api/exists.rs` | Plugin queries an ordered, configurable list of servers |
|
||||
| UR-008 | Done | T1, T2 | PR-006 | covered | `src/api/federation.rs`, `src/worker.rs` | Servers replicate manifests between each other |
|
||||
| UR-009 | In Progress | T1 | SR-003 | covered | `src/validate.rs` | Store an audio spectral-peak signature for content-based identificati… |
|
||||
| UR-008 | Done | T1, T2 | PR-006 | covered | `src/api/federation.rs`, `src/db/repo.rs`, `src/worker.rs`, `tests/audio.rs` | Servers replicate manifests between each other |
|
||||
| UR-009 | Done | T1, T2 | SR-003 | covered | `src/api/mod.rs`, `src/api/search.rs`, `src/audio_sig.rs`, `src/db/repo.rs`, `src/matching.rs`, `src/validate.rs`, `tests/audio.rs` | Store an audio spectral-peak signature for content-based identificati… |
|
||||
| UR-010 | Done | T1, T2 | SR-001 | covered | `src/api/fetch.rs`, `src/castcheck.rs`, `src/db/repo.rs`, `src/model.rs` | Identity crossing the API boundary is TMDB/IMDB ids, never a name alo… |
|
||||
| UR-011 | Done | T2 | SR-004 | covered | `src/model.rs`, `src/validate.rs` | Reject any field capable of carrying binary or attacker-chosen content |
|
||||
| UR-011 | Done | T2 | SR-004 | covered | `src/model.rs`, `src/validate.rs`, `tests/audio.rs` | Reject any field capable of carrying binary or attacker-chosen content |
|
||||
| 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/api/federation.rs`, `src/model.rs`, `src/validate.rs` | Reject an unknown `jmanifest_version` outright, never guess |
|
||||
| UR-014 | Done | T1 | SR-003 | covered | `src/api/federation.rs`, `src/model.rs`, `src/validate.rs`, `tests/audio.rs` | Reject an unknown `jmanifest_version` outright, never guess |
|
||||
| UR-015 | Done | T2 | SR-003 | covered | `src/validate.rs`, `tests/api.rs` | Accept `extraction.extinction_sec` in place of `anneal_sec` |
|
||||
| UR-016 | Done | T2 | SR-003 | covered | `src/validate.rs`, `tests/api.rs` | 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 | covered | `src/ingest.rs` | Exclude belief and route from `content_id`, replicating them as attri… |
|
||||
| UR-019 | Done | T2 | PR-006 | covered | `src/api/upload.rs` | Contributed manifests are CC0 1.0; the grant is delivered with the to… |
|
||||
| DR-001 | Done | T1 | SR-004 | covered | `src/model.rs`, `tests/api.rs` | Strict parse boundary: unknown fields rejected structurally, not by v… |
|
||||
| DR-002 | Done | T1 | SR-004 | covered | `src/api/fetch.rs`, `src/db/repo.rs` | Fully relational storage — no JSON blob on the write path |
|
||||
| DR-002 | Done | T1 | SR-004 | covered | `src/api/fetch.rs`, `src/db/repo.rs`, `tests/audio.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 |
|
||||
| DR-004 | Done | T1 | PR-004 | covered | `src/db/repo.rs` | All database access behind a repository layer, not scattered through … |
|
||||
| DR-005 | Done | T1 | PR-004 | covered | `src/db/repo.rs` | Background work in-process, with the job queue as a table so it survi… |
|
||||
@@ -90,7 +90,7 @@ _None._
|
||||
| DR-010 | Done | T1 | SR-003 | covered | `src/api/json.rs` | Request bodies are UTF-8 only, rejected with a diagnosable error othe… |
|
||||
| DR-011 | Done | T1 | SR-003 | covered | `src/content_id.rs`, `src/validate.rs` | `content_id` canonical form is byte-stable and cross-implementation t… |
|
||||
| DR-012 | Done | static | PR-004 | untagged | - | Dependency audit: advisories, licence policy, source policy |
|
||||
| DR-013 | Done | T1 | SR-003 | covered | `src/api/json.rs`, `src/app.rs`, `src/error.rs` | API errors use the status codes the spec names, not the framework's d… |
|
||||
| DR-013 | Done | T1 | SR-003 | covered | `src/api/json.rs`, `src/app.rs`, `src/error.rs`, `tests/audio.rs` | API errors use the status codes the spec names, not the framework's d… |
|
||||
| DR-014 | Done | static | PR-004 | covered | `src/db/mod.rs` | Portable SQL — no SQLite-specific form where a standard one exists |
|
||||
|
||||
## Detailed mapping
|
||||
@@ -99,16 +99,17 @@ _None._
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/model.rs:323`](../src/model.rs#L323) — `fn unknown_field_at_top_level_is_rejected()`
|
||||
- [`tests/api.rs:278`](../tests/api.rs#L278) — `async fn unknown_field_anywhere_is_rejected_with_400()`
|
||||
- [`src/model.rs:324`](../src/model.rs#L324) — `fn unknown_field_at_top_level_is_rejected()`
|
||||
- [`tests/api.rs:279`](../tests/api.rs#L279) — `async fn unknown_field_anywhere_is_rejected_with_400()`
|
||||
|
||||
### DR-002
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/fetch.rs:269`](../src/api/fetch.rs#L269) — `pub fn reconstruct(`
|
||||
- [`src/db/repo.rs:331`](../src/db/repo.rs#L331) — `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:426`](../src/db/repo.rs#L426) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/db/repo.rs:500`](../src/db/repo.rs#L500) — `pub fn actors_for_manifest(`
|
||||
- [`tests/audio.rs:258`](../tests/audio.rs#L258) — `async fn a_contributed_signature_survives_storage_byte_for_byte()`
|
||||
|
||||
### DR-003
|
||||
|
||||
@@ -120,13 +121,13 @@ _None._
|
||||
|
||||
**Locations:** 1
|
||||
|
||||
- [`src/db/repo.rs:331`](../src/db/repo.rs#L331) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/db/repo.rs:426`](../src/db/repo.rs#L426) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
|
||||
### DR-005
|
||||
|
||||
**Locations:** 1
|
||||
|
||||
- [`src/db/repo.rs:702`](../src/db/repo.rs#L702) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
- [`src/db/repo.rs:797`](../src/db/repo.rs#L797) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
|
||||
### DR-006
|
||||
|
||||
@@ -163,11 +164,13 @@ _None._
|
||||
|
||||
### DR-013
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 5
|
||||
|
||||
- [`src/api/json.rs:100`](../src/api/json.rs#L100) — `fn require_utf8(bytes: &[u8]) -> Result<&str, ApiError>`
|
||||
- [`src/app.rs:26`](../src/app.rs#L26) — `pub fn router(state: AppState) -> Router`
|
||||
- [`src/error.rs:8`](../src/error.rs#L8) — `Unknown`
|
||||
- [`tests/audio.rs:442`](../tests/audio.rs#L442) — `async fn a_signature_without_a_runtime_is_refused_by_name()`
|
||||
- [`tests/audio.rs:460`](../tests/audio.rs#L460) — `async fn a_malformed_signature_is_a_bad_request_not_a_silent_downgrade()`
|
||||
|
||||
### DR-014
|
||||
|
||||
@@ -182,14 +185,16 @@ _None._
|
||||
- [`src/config.rs:10`](../src/config.rs#L10) — `Unknown`
|
||||
- [`src/db/mod.rs:30`](../src/db/mod.rs#L30) — `pub mod repo;`
|
||||
- [`src/db/mod.rs:36`](../src/db/mod.rs#L36) — `struct ReadPool`
|
||||
- [`src/db/repo.rs:702`](../src/db/repo.rs#L702) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
- [`src/db/repo.rs:797`](../src/db/repo.rs#L797) — `pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…`
|
||||
|
||||
### PR-005
|
||||
|
||||
**Locations:** 2
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
|
||||
- [`src/api/federation.rs:212`](../src/api/federation.rs#L212) — `pub async fn get_peers(`
|
||||
- [`src/api/search.rs:113`](../src/api/search.rs#L113) — `pub async fn post_search(`
|
||||
- [`tests/audio.rs:480`](../tests/audio.rs#L480) — `async fn search_identifies_a_file_with_no_metadata_at_all()`
|
||||
|
||||
### PR-006
|
||||
|
||||
@@ -214,42 +219,59 @@ _None._
|
||||
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
|
||||
- [`src/api/fetch.rs:269`](../src/api/fetch.rs#L269) — `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/matching.rs:54`](../src/matching.rs#L54) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/model.rs:173`](../src/model.rs#L173) — `Unknown`
|
||||
- [`src/db/repo.rs:500`](../src/db/repo.rs#L500) — `pub fn actors_for_manifest(`
|
||||
- [`src/matching.rs:94`](../src/matching.rs#L94) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/model.rs:174`](../src/model.rs#L174) — `Unknown`
|
||||
|
||||
### SR-002
|
||||
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/fetch.rs:269`](../src/api/fetch.rs#L269) — `pub fn reconstruct(`
|
||||
- [`src/model.rs:173`](../src/model.rs#L173) — `Unknown`
|
||||
- [`src/model.rs:232`](../src/model.rs#L232) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/model.rs:174`](../src/model.rs#L174) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/validate.rs:496`](../src/validate.rs#L496) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<SceneCs>>`
|
||||
|
||||
### SR-003
|
||||
|
||||
**Locations:** 15
|
||||
**Locations:** 32
|
||||
|
||||
- [`src/api/federation.rs:258`](../src/api/federation.rs#L258) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`src/api/federation.rs:261`](../src/api/federation.rs#L261) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`src/api/json.rs:100`](../src/api/json.rs#L100) — `fn require_utf8(bytes: &[u8]) -> Result<&str, ApiError>`
|
||||
- [`src/api/mod.rs:38`](../src/api/mod.rs#L38) — `pub fn client_cut(&self) -> Result<ClientCut, ApiError>`
|
||||
- [`src/api/search.rs:113`](../src/api/search.rs#L113) — `pub async fn post_search(`
|
||||
- [`src/audio_sig.rs:113`](../src/audio_sig.rs#L113) — `pub fn compare(reference: &[u8], query: &[u8]) -> Option<SlideMatch>`
|
||||
- [`src/content_id.rs:57`](../src/content_id.rs#L57) — `pub fn canonical_json(`
|
||||
- [`src/content_id.rs:132`](../src/content_id.rs#L132) — `pub fn content_id(`
|
||||
- [`src/db/repo.rs:316`](../src/db/repo.rs#L316) — `pub fn adopt_audio_signature(`
|
||||
- [`src/error.rs:8`](../src/error.rs#L8) — `Unknown`
|
||||
- [`src/ingest.rs:387`](../src/ingest.rs#L387) — `fn content_id_excludes_belief_and_route()`
|
||||
- [`src/model.rs:191`](../src/model.rs#L191) — `Unknown`
|
||||
- [`src/model.rs:232`](../src/model.rs#L232) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/model.rs:258`](../src/model.rs#L258) — `Unknown`
|
||||
- [`src/ingest.rs:406`](../src/ingest.rs#L406) — `fn content_id_excludes_belief_and_route()`
|
||||
- [`src/matching.rs:94`](../src/matching.rs#L94) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/model.rs:192`](../src/model.rs#L192) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_stored(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:364`](../src/validate.rs#L364) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/validate.rs:731`](../src/validate.rs#L731) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:323`](../tests/api.rs#L323) — `async fn the_withdrawn_anneal_sec_field_is_rejected()`
|
||||
- [`tests/api.rs:347`](../tests/api.rs#L347) — `async fn the_schema_bump_fields_round_trip()`
|
||||
- [`src/validate.rs:755`](../src/validate.rs#L755) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:324`](../tests/api.rs#L324) — `async fn the_withdrawn_anneal_sec_field_is_rejected()`
|
||||
- [`tests/api.rs:348`](../tests/api.rs#L348) — `async fn the_schema_bump_fields_round_trip()`
|
||||
- [`tests/audio.rs:258`](../tests/audio.rs#L258) — `async fn a_contributed_signature_survives_storage_byte_for_byte()`
|
||||
- [`tests/audio.rs:292`](../tests/audio.rs#L292) — `async fn a_manifest_without_a_signature_serves_no_signature_field()`
|
||||
- [`tests/audio.rs:304`](../tests/audio.rs#L304) — `async fn a_held_manifest_adopts_a_signature_it_lacked()`
|
||||
- [`tests/audio.rs:343`](../tests/audio.rs#L343) — `async fn a_matching_signature_reaches_the_audio_tier_on_a_fetch()`
|
||||
- [`tests/audio.rs:360`](../tests/audio.rs#L360) — `async fn a_shifted_release_matches_and_gets_its_offset()`
|
||||
- [`tests/audio.rs:402`](../tests/audio.rs#L402) — `async fn a_signature_that_disagrees_is_not_served_on_a_runtime_coincidence()`
|
||||
- [`tests/audio.rs:419`](../tests/audio.rs#L419) — `async fn exists_reports_the_audio_tier_too()`
|
||||
- [`tests/audio.rs:442`](../tests/audio.rs#L442) — `async fn a_signature_without_a_runtime_is_refused_by_name()`
|
||||
- [`tests/audio.rs:480`](../tests/audio.rs#L480) — `async fn search_identifies_a_file_with_no_metadata_at_all()`
|
||||
- [`tests/audio.rs:506`](../tests/audio.rs#L506) — `async fn search_recovers_the_offset_for_a_differently_trimmed_release()`
|
||||
- [`tests/audio.rs:532`](../tests/audio.rs#L532) — `async fn search_declines_content_it_does_not_hold()`
|
||||
- [`tests/audio.rs:567`](../tests/audio.rs#L567) — `async fn search_is_absent_when_the_operator_has_not_enabled_it()`
|
||||
|
||||
### SR-004
|
||||
|
||||
**Locations:** 18
|
||||
**Locations:** 20
|
||||
|
||||
- [`src/api/report.rs:56`](../src/api/report.rs#L56) — `pub async fn post_report(`
|
||||
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
|
||||
@@ -259,38 +281,43 @@ _None._
|
||||
- [`src/auth.rs:76`](../src/auth.rs#L76) — `pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…`
|
||||
- [`src/castcheck.rs:82`](../src/castcheck.rs#L82) — `pub fn evaluate(submitted: &[SubmittedActor], credits: &[CastMember]) -> CastCheckOutcome`
|
||||
- [`src/castcheck.rs:215`](../src/castcheck.rs#L215) — `pub fn category_guard_violation(matched: &[MatchedActor], title_is_adult: bool) -> Option…`
|
||||
- [`src/db/repo.rs:331`](../src/db/repo.rs#L331) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/model.rs:150`](../src/model.rs#L150) — `Unknown`
|
||||
- [`src/model.rs:258`](../src/model.rs#L258) — `Unknown`
|
||||
- [`src/model.rs:323`](../src/model.rs#L323) — `fn unknown_field_at_top_level_is_rejected()`
|
||||
- [`src/db/repo.rs:426`](../src/db/repo.rs#L426) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/model.rs:151`](../src/model.rs#L151) — `Unknown`
|
||||
- [`src/model.rs:259`](../src/model.rs#L259) — `Unknown`
|
||||
- [`src/model.rs:324`](../src/model.rs#L324) — `fn unknown_field_at_top_level_is_rejected()`
|
||||
- [`src/ratelimit.rs:93`](../src/ratelimit.rs#L93) — `impl Default for RateLimiter`
|
||||
- [`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:364`](../src/validate.rs#L364) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`src/worker.rs:150`](../src/worker.rs#L150) — `async fn run_cast_check(&self, payload: &str) -> Result<(), JobError>`
|
||||
- [`tests/api.rs:278`](../tests/api.rs#L278) — `async fn unknown_field_anywhere_is_rejected_with_400()`
|
||||
- [`tests/api.rs:279`](../tests/api.rs#L279) — `async fn unknown_field_anywhere_is_rejected_with_400()`
|
||||
- [`tests/audio.rs:460`](../tests/audio.rs#L460) — `async fn a_malformed_signature_is_a_bad_request_not_a_silent_downgrade()`
|
||||
- [`tests/audio.rs:551`](../tests/audio.rs#L551) — `async fn search_applies_the_same_structural_rules_as_an_upload()`
|
||||
|
||||
### SR-005
|
||||
|
||||
**Locations:** 2
|
||||
**Locations:** 3
|
||||
|
||||
- [`src/db/repo.rs:331`](../src/db/repo.rs#L331) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/db/repo.rs:426`](../src/db/repo.rs#L426) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
|
||||
- [`tests/audio.rs:588`](../tests/audio.rs#L588) — `async fn search_never_returns_a_pending_manifest()`
|
||||
|
||||
### UR-001
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/exists.rs:61`](../src/api/exists.rs#L61) — `pub async fn exists(`
|
||||
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
|
||||
- [`src/matching.rs:54`](../src/matching.rs#L54) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/matching.rs:94`](../src/matching.rs#L94) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`tests/audio.rs:419`](../tests/audio.rs#L419) — `async fn exists_reports_the_audio_tier_too()`
|
||||
|
||||
### UR-002
|
||||
|
||||
**Locations:** 2
|
||||
**Locations:** 3
|
||||
|
||||
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
|
||||
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
|
||||
- [`tests/audio.rs:588`](../tests/audio.rs#L588) — `async fn search_never_returns_a_pending_manifest()`
|
||||
|
||||
### UR-003
|
||||
|
||||
@@ -298,8 +325,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:150`](../src/model.rs#L150) — `Unknown`
|
||||
- [`src/model.rs:258`](../src/model.rs#L258) — `Unknown`
|
||||
- [`src/model.rs:151`](../src/model.rs#L151) — `Unknown`
|
||||
- [`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:150`](../src/worker.rs#L150) — `async fn run_cast_check(&self, payload: &str) -> Result<(), JobError>`
|
||||
|
||||
@@ -337,20 +364,42 @@ _None._
|
||||
|
||||
### UR-008
|
||||
|
||||
**Locations:** 6
|
||||
**Locations:** 8
|
||||
|
||||
- [`src/api/federation.rs:66`](../src/api/federation.rs#L66) — `pub async fn get_changes(`
|
||||
- [`src/api/federation.rs:108`](../src/api/federation.rs#L108) — `pub async fn get_manifest_by_content_id(`
|
||||
- [`src/api/federation.rs:160`](../src/api/federation.rs#L160) — `pub async fn post_have(`
|
||||
- [`src/api/federation.rs:212`](../src/api/federation.rs#L212) — `pub async fn get_peers(`
|
||||
- [`src/api/federation.rs:258`](../src/api/federation.rs#L258) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`src/api/federation.rs:261`](../src/api/federation.rs#L261) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`src/db/repo.rs:316`](../src/db/repo.rs#L316) — `pub fn adopt_audio_signature(`
|
||||
- [`src/worker.rs:107`](../src/worker.rs#L107) — `async fn run_federation_pull(&self, payload: &str) -> Result<(), JobError>`
|
||||
- [`tests/audio.rs:304`](../tests/audio.rs#L304) — `async fn a_held_manifest_adopts_a_signature_it_lacked()`
|
||||
|
||||
### UR-009
|
||||
|
||||
**Locations:** 1
|
||||
**Locations:** 21
|
||||
|
||||
- [`src/api/mod.rs:38`](../src/api/mod.rs#L38) — `pub fn client_cut(&self) -> Result<ClientCut, ApiError>`
|
||||
- [`src/api/search.rs:113`](../src/api/search.rs#L113) — `pub async fn post_search(`
|
||||
- [`src/audio_sig.rs:113`](../src/audio_sig.rs#L113) — `pub fn compare(reference: &[u8], query: &[u8]) -> Option<SlideMatch>`
|
||||
- [`src/db/repo.rs:316`](../src/db/repo.rs#L316) — `pub fn adopt_audio_signature(`
|
||||
- [`src/matching.rs:94`](../src/matching.rs#L94) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
|
||||
- [`src/validate.rs:364`](../src/validate.rs#L364) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`tests/audio.rs:258`](../tests/audio.rs#L258) — `async fn a_contributed_signature_survives_storage_byte_for_byte()`
|
||||
- [`tests/audio.rs:292`](../tests/audio.rs#L292) — `async fn a_manifest_without_a_signature_serves_no_signature_field()`
|
||||
- [`tests/audio.rs:304`](../tests/audio.rs#L304) — `async fn a_held_manifest_adopts_a_signature_it_lacked()`
|
||||
- [`tests/audio.rs:343`](../tests/audio.rs#L343) — `async fn a_matching_signature_reaches_the_audio_tier_on_a_fetch()`
|
||||
- [`tests/audio.rs:360`](../tests/audio.rs#L360) — `async fn a_shifted_release_matches_and_gets_its_offset()`
|
||||
- [`tests/audio.rs:402`](../tests/audio.rs#L402) — `async fn a_signature_that_disagrees_is_not_served_on_a_runtime_coincidence()`
|
||||
- [`tests/audio.rs:419`](../tests/audio.rs#L419) — `async fn exists_reports_the_audio_tier_too()`
|
||||
- [`tests/audio.rs:442`](../tests/audio.rs#L442) — `async fn a_signature_without_a_runtime_is_refused_by_name()`
|
||||
- [`tests/audio.rs:460`](../tests/audio.rs#L460) — `async fn a_malformed_signature_is_a_bad_request_not_a_silent_downgrade()`
|
||||
- [`tests/audio.rs:480`](../tests/audio.rs#L480) — `async fn search_identifies_a_file_with_no_metadata_at_all()`
|
||||
- [`tests/audio.rs:506`](../tests/audio.rs#L506) — `async fn search_recovers_the_offset_for_a_differently_trimmed_release()`
|
||||
- [`tests/audio.rs:532`](../tests/audio.rs#L532) — `async fn search_declines_content_it_does_not_hold()`
|
||||
- [`tests/audio.rs:551`](../tests/audio.rs#L551) — `async fn search_applies_the_same_structural_rules_as_an_upload()`
|
||||
- [`tests/audio.rs:567`](../tests/audio.rs#L567) — `async fn search_is_absent_when_the_operator_has_not_enabled_it()`
|
||||
- [`tests/audio.rs:588`](../tests/audio.rs#L588) — `async fn search_never_returns_a_pending_manifest()`
|
||||
|
||||
### UR-010
|
||||
|
||||
@@ -358,23 +407,25 @@ _None._
|
||||
|
||||
- [`src/api/fetch.rs:269`](../src/api/fetch.rs#L269) — `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/model.rs:173`](../src/model.rs#L173) — `Unknown`
|
||||
- [`src/db/repo.rs:500`](../src/db/repo.rs#L500) — `pub fn actors_for_manifest(`
|
||||
- [`src/model.rs:174`](../src/model.rs#L174) — `Unknown`
|
||||
|
||||
### UR-011
|
||||
|
||||
**Locations:** 4
|
||||
**Locations:** 6
|
||||
|
||||
- [`src/model.rs:150`](../src/model.rs#L150) — `Unknown`
|
||||
- [`src/model.rs:258`](../src/model.rs#L258) — `Unknown`
|
||||
- [`src/model.rs:151`](../src/model.rs#L151) — `Unknown`
|
||||
- [`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:364`](../src/validate.rs#L364) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
|
||||
- [`tests/audio.rs:460`](../tests/audio.rs#L460) — `async fn a_malformed_signature_is_a_bad_request_not_a_silent_downgrade()`
|
||||
- [`tests/audio.rs:551`](../tests/audio.rs#L551) — `async fn search_applies_the_same_structural_rules_as_an_upload()`
|
||||
|
||||
### UR-012
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/db/repo.rs:331`](../src/db/repo.rs#L331) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/db/repo.rs:426`](../src/db/repo.rs#L426) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
|
||||
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
|
||||
|
||||
### UR-013
|
||||
@@ -382,45 +433,46 @@ _None._
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/fetch.rs:269`](../src/api/fetch.rs#L269) — `pub fn reconstruct(`
|
||||
- [`src/model.rs:173`](../src/model.rs#L173) — `Unknown`
|
||||
- [`src/model.rs:232`](../src/model.rs#L232) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/model.rs:174`](../src/model.rs#L174) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/validate.rs:496`](../src/validate.rs#L496) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<SceneCs>>`
|
||||
|
||||
### UR-014
|
||||
|
||||
**Locations:** 3
|
||||
**Locations:** 4
|
||||
|
||||
- [`src/api/federation.rs:258`](../src/api/federation.rs#L258) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`src/model.rs:258`](../src/model.rs#L258) — `Unknown`
|
||||
- [`src/api/federation.rs:261`](../src/api/federation.rs#L261) — `pub async fn get_capabilities(State(state): State<AppState>) -> ApiResult<Response>`
|
||||
- [`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>`
|
||||
- [`tests/audio.rs:567`](../tests/audio.rs#L567) — `async fn search_is_absent_when_the_operator_has_not_enabled_it()`
|
||||
|
||||
### UR-015
|
||||
|
||||
**Locations:** 3
|
||||
|
||||
- [`src/validate.rs:731`](../src/validate.rs#L731) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:323`](../tests/api.rs#L323) — `async fn the_withdrawn_anneal_sec_field_is_rejected()`
|
||||
- [`tests/api.rs:347`](../tests/api.rs#L347) — `async fn the_schema_bump_fields_round_trip()`
|
||||
- [`src/validate.rs:755`](../src/validate.rs#L755) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:324`](../tests/api.rs#L324) — `async fn the_withdrawn_anneal_sec_field_is_rejected()`
|
||||
- [`tests/api.rs:348`](../tests/api.rs#L348) — `async fn the_schema_bump_fields_round_trip()`
|
||||
|
||||
### UR-016
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/validate.rs:731`](../src/validate.rs#L731) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:347`](../tests/api.rs#L347) — `async fn the_schema_bump_fields_round_trip()`
|
||||
- [`src/validate.rs:755`](../src/validate.rs#L755) — `fn extinction_sec_replaces_anneal_sec()`
|
||||
- [`tests/api.rs:348`](../tests/api.rs#L348) — `async fn the_schema_bump_fields_round_trip()`
|
||||
|
||||
### UR-017
|
||||
|
||||
**Locations:** 2
|
||||
|
||||
- [`src/model.rs:191`](../src/model.rs#L191) — `Unknown`
|
||||
- [`src/model.rs:232`](../src/model.rs#L232) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
- [`src/model.rs:192`](../src/model.rs#L192) — `Unknown`
|
||||
- [`src/model.rs:233`](../src/model.rs#L233) — `pub fn from_stored(s: &str) -> Option<Self>`
|
||||
|
||||
### UR-018
|
||||
|
||||
**Locations:** 1
|
||||
|
||||
- [`src/ingest.rs:387`](../src/ingest.rs#L387) — `fn content_id_excludes_belief_and_route()`
|
||||
- [`src/ingest.rs:406`](../src/ingest.rs#L406) — `fn content_id_excludes_belief_and_route()`
|
||||
|
||||
### UR-019
|
||||
|
||||
|
||||
Reference in New Issue
Block a user