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:
+6
-3
@@ -71,6 +71,7 @@ impl TestServer {
|
||||
server_id: "local.example".into(),
|
||||
publish_peer_directory: publish_directory,
|
||||
contact: Some("admin@local.example".into()),
|
||||
enable_audio_search: true,
|
||||
request_timeout: std::time::Duration::from_secs(30),
|
||||
job_batch: 8,
|
||||
job_poll_interval: std::time::Duration::from_secs(3600),
|
||||
@@ -397,7 +398,9 @@ async fn capabilities_advertise_the_envelope_version() {
|
||||
assert_eq!(status, StatusCode::OK);
|
||||
assert_eq!(body["jmanifest_versions"], json!([2]));
|
||||
assert_eq!(body["federation"], true);
|
||||
// Deferred by design (§3 sequencing), and advertised as absent rather than
|
||||
// left for a client to discover by failure.
|
||||
assert_eq!(body["audio_search"], false);
|
||||
// §3: the audio surfaces are advertised rather than assumed, because search
|
||||
// is optional for a server to implement. This build implements both, so a
|
||||
// client that reads this and then sends a signature must not get a 404.
|
||||
assert_eq!(body["audio_search"], true);
|
||||
assert_eq!(body["audio_tier_matching"], true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user