Traceability: move per-repo settings into traceability.toml
CI / fmt, clippy, test (push) Failing after 1m22s
CI / static musl binary (push) Has been skipped
CI / advisories and licences (push) Successful in 25s

The shared extractor now takes its per-repo taxonomy from a config file rather
than CLI flags, so the wrapper shrinks to the one thing it alone knows: the
repo root, which the vendored gate cannot infer because its own default
resolves inside the submodule.

Coverage unchanged at 23/32; the gate reports the scan as '26 (.rs under src,
tests)', which is the config being read rather than defaults being guessed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 18:56:13 +02:00
co-authored by Claude Opus 5
parent a1e789a6fe
commit c73f417d45
5 changed files with 131 additions and 76 deletions
+44
View File
@@ -360,6 +360,50 @@ tail.
The result is ~1.7 KB per manifest — negligible against a ~4.8 KiB manifest. The result is ~1.7 KB per manifest — negligible against a ~4.8 KiB manifest.
##### Normative v1 parameters
**The six steps above are not sufficient to reproduce a byte stream.** Each
choice below was underspecified and is now pinned; two independent
implementations that differ on any one of them produce signatures that never
match, which silently defeats the entire mechanism.
| Parameter | v1 value |
|---|---|
| Hann window | **Periodic** (not symmetric) |
| Band value | **Mean of linear magnitudes** in the band — not sum, not max, and taken before the log |
| Peak tie-break | Lowest band index wins |
| Energy class | `log10(frame band-energy / upper-median frame energy)`, quantised at **−0.6 / −0.2 / +0.2** |
| Byte layout | `(band << 2) | class` — 5-bit band, 2-bit class |
| Base64 | Standard alphabet, with padding |
| Frame count | Whole frames only. Over 1 323 000 samples this yields **1288** frames, not "~1290" |
The energy class is normalised against the **upper-median frame energy** rather
than an absolute level, which is what makes it invariant to gain and to trim
differences between releases. The thresholds straddle the median rather than
sitting on it, so a frame near the centre of the distribution does not flip class
under small perturbations.
##### Conformance fixture
A golden fixture is the authoritative tiebreak, because prose cannot pin
floating-point behaviour:
`scene-actor-extraction/tests/fixtures/audio/jray_audio_v1_golden.json`.
It carries the expected signature, the decoded-window PCM checksum, the full
32-entry band→FFT-bin table, and the parameter contract — **an implementation can
be written from that file alone.** The PCM checksum is asserted separately from
the signature so a codec-level divergence is distinguishable from a DSP one.
**Implementations should compute the FFT themselves** (radix-2, double
precision) rather than depending on a library whose version could change the
numerics. Verified decision margins on the fixture are 1.3% between the two
strongest bands and 3.6e-3 in log10 to an energy-class edge — many orders above
double-precision noise, so any two correct implementations agree.
Measured on that fixture: the peak-band sequence survives a stereo/44.1 kHz round
trip and AAC 128 kbit/s re-encoding **exactly** (score 1.00), which is the
codec-robustness this design claims.
This is deliberately a **peak-bin** signature rather than a full spectrum: This is deliberately a **peak-bin** signature rather than a full spectrum:
peaks survive lossy re-encoding, loudness normalisation and channel-layout peaks survive lossy re-encoding, loudness normalisation and channel-layout
differences, whereas absolute magnitudes do not. It follows the same principle differences, whereas absolute magnitudes do not. It follows the same principle
+43 -43
View File
@@ -1,11 +1,11 @@
# Requirements traceability matrix # Requirements traceability matrix
<!-- GENERATED FILE - do not edit by hand. --> <!-- GENERATED FILE - do not edit by hand. -->
<!-- Regenerate: python3 scripts/traceability/extract_traces.py --format markdown --markdown-out docs/traceability.md --> <!-- Regenerate: scripts/traceability/traceability-gate.sh -->
**Generated:** 2026-07-30T16:25:39+00:00 **Generated:** 2026-07-30T16:55:59+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 CI host can execute — CI is an Intel N100 with no discrete GPU. 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`).
## Summary ## Summary
@@ -18,7 +18,7 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
| Requirements covered | 23 | | Requirements covered | 23 |
| **Coverage** | **71.9%** (23/32) | | **Coverage** | **71.9%** (23/32) |
| Coverage of CI-executable scope | 71.9% (23/32) | | Coverage of CI-executable scope | 71.9% (23/32) |
| Tagged but unexecuted in CI (T4/GPU) | 0 | | Tagged but unexecuted in CI | 0 |
| Orphan tags | 0 | | Orphan tags | 0 |
### By type ### By type
@@ -33,7 +33,7 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
## Not executable in CI ## Not executable in CI
CI runs on an Intel N100 with no discrete GPU. These requirements have no verification tier that can run here, so a tag on them is evidence of *intent*, not of verification. They are never counted as covered. These requirements have no verification tier this repo's CI host can run, so a tag on them is evidence of *intent*, not of verification. They are never counted as covered.
_None._ _None._
@@ -51,7 +51,7 @@ _None._
## Recorded exceptions ## Recorded exceptions
Deliberate, documented departures from an invariant (`EXCEPTION: AR-nnn <reason>`). Reported separately and never counted as coverage — an exception is a decision to be reviewed, not evidence a requirement is met. Deliberate, documented departures from an invariant (`EXCEPTION: XX-nnn <reason>`). Reported separately and never counted as coverage — an exception is a decision to be reviewed, not evidence a requirement is met.
_None._ _None._
@@ -98,9 +98,9 @@ _None._
**Locations:** 3 **Locations:** 3
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `Unknown` - [`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: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) — `Unknown` - [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
### DR-003 ### DR-003
@@ -124,7 +124,7 @@ _None._
**Locations:** 1 **Locations:** 1
- [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `struct Window` - [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `impl Default for RateLimiter`
### DR-008 ### DR-008
@@ -149,8 +149,8 @@ _None._
**Locations:** 3 **Locations:** 3
- [`src/content_id.rs:52`](../src/content_id.rs#L52) — `Unknown` - [`src/content_id.rs:52`](../src/content_id.rs#L52) — `pub fn canonical_json(`
- [`src/content_id.rs:129`](../src/content_id.rs#L129) — `fn push_opt_num(s: &mut String, v: Option<i64>)` - [`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:78`](../src/validate.rs#L78) — `pub fn to_centiseconds(secs: f64) -> i64`
### DR-013 ### DR-013
@@ -173,27 +173,27 @@ _None._
**Locations:** 1 **Locations:** 1
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `Unknown` - [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
### PR-006 ### PR-006
**Locations:** 5 **Locations:** 5
- [`src/api/fetch.rs:128`](../src/api/fetch.rs#L128) — `Unknown` - [`src/api/fetch.rs:128`](../src/api/fetch.rs#L128) — `pub async fn get_series(`
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `Unknown` - [`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) — `Unknown` - [`src/api/upload.rs:101`](../src/api/upload.rs#L101) — `pub async fn post_bundle(`
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `Unknown` - [`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:540`](../src/validate.rs#L540) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
### SR-001 ### SR-001
**Locations:** 7 **Locations:** 7
- [`src/api/exists.rs:61`](../src/api/exists.rs#L61) — `Unknown` - [`src/api/exists.rs:61`](../src/api/exists.rs#L61) — `pub async fn exists(`
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `Unknown` - [`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) — `Unknown` - [`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/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) — `Unknown` - [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
- [`src/matching.rs:52`](../src/matching.rs#L52) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>` - [`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` - [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
@@ -201,7 +201,7 @@ _None._
**Locations:** 3 **Locations:** 3
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `Unknown` - [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown` - [`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/validate.rs:486`](../src/validate.rs#L486) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<(i64, i64)>>`
@@ -210,8 +210,8 @@ _None._
**Locations:** 8 **Locations:** 8
- [`src/api/json.rs:100`](../src/api/json.rs#L100) — `fn require_utf8(bytes: &[u8]) -> Result<&str, ApiError>` - [`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) — `Unknown` - [`src/content_id.rs:52`](../src/content_id.rs#L52) — `pub fn canonical_json(`
- [`src/content_id.rs:129`](../src/content_id.rs#L129) — `fn push_opt_num(s: &mut String, v: Option<i64>)` - [`src/content_id.rs:129`](../src/content_id.rs#L129) — `pub fn content_id(`
- [`src/error.rs:8`](../src/error.rs#L8) — `Unknown` - [`src/error.rs:8`](../src/error.rs#L8) — `Unknown`
- [`src/model.rs:198`](../src/model.rs#L198) — `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:78`](../src/validate.rs#L78) — `pub fn to_centiseconds(secs: f64) -> i64`
@@ -222,9 +222,9 @@ _None._
**Locations:** 16 **Locations:** 16
- [`src/api/report.rs:56`](../src/api/report.rs#L56) — `Unknown` - [`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) — `Unknown` - [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
- [`src/api/upload.rs:223`](../src/api/upload.rs#L223) — `Unknown` - [`src/api/upload.rs:223`](../src/api/upload.rs#L223) — `pub async fn post_token(`
- [`src/app.rs:26`](../src/app.rs#L26) — `pub fn router(state: AppState) -> Router` - [`src/app.rs:26`](../src/app.rs#L26) — `pub fn router(state: AppState) -> Router`
- [`src/auth.rs:22`](../src/auth.rs#L22) — `pub fn hash_token(token: &str) -> String` - [`src/auth.rs:22`](../src/auth.rs#L22) — `pub fn hash_token(token: &str) -> String`
- [`src/auth.rs:76`](../src/auth.rs#L76) — `pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…` - [`src/auth.rs:76`](../src/auth.rs#L76) — `pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…`
@@ -233,7 +233,7 @@ _None._
- [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>` - [`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:156`](../src/model.rs#L156) — `Unknown`
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown` - [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
- [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `struct Window` - [`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: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: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:354`](../src/validate.rs#L354) — `pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>`
@@ -244,28 +244,28 @@ _None._
**Locations:** 2 **Locations:** 2
- [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>` - [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `Unknown` - [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
### UR-001 ### UR-001
**Locations:** 3 **Locations:** 3
- [`src/api/exists.rs:61`](../src/api/exists.rs#L61) — `Unknown` - [`src/api/exists.rs:61`](../src/api/exists.rs#L61) — `pub async fn exists(`
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `Unknown` - [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
- [`src/matching.rs:52`](../src/matching.rs#L52) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>` - [`src/matching.rs:52`](../src/matching.rs#L52) — `pub fn match_cut(client: &ClientCut, stored: &StoredCut) -> Option<CutMatch>`
### UR-002 ### UR-002
**Locations:** 2 **Locations:** 2
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `Unknown` - [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `pub async fn post_manifest(`
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `Unknown` - [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
### UR-003 ### UR-003
**Locations:** 6 **Locations:** 6
- [`src/api/upload.rs:29`](../src/api/upload.rs#L29) — `Unknown` - [`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/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:156`](../src/model.rs#L156) — `Unknown`
- [`src/model.rs:198`](../src/model.rs#L198) — `Unknown` - [`src/model.rs:198`](../src/model.rs#L198) — `Unknown`
@@ -277,14 +277,14 @@ _None._
**Locations:** 2 **Locations:** 2
- [`src/auth.rs:76`](../src/auth.rs#L76) — `pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…` - [`src/auth.rs:76`](../src/auth.rs#L76) — `pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…`
- [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `struct Window` - [`src/ratelimit.rs:76`](../src/ratelimit.rs#L76) — `impl Default for RateLimiter`
### UR-005 ### UR-005
**Locations:** 6 **Locations:** 6
- [`src/api/report.rs:56`](../src/api/report.rs#L56) — `Unknown` - [`src/api/report.rs:56`](../src/api/report.rs#L56) — `pub async fn post_report(`
- [`src/api/upload.rs:223`](../src/api/upload.rs#L223) — `Unknown` - [`src/api/upload.rs:223`](../src/api/upload.rs#L223) — `pub async fn post_token(`
- [`src/auth.rs:22`](../src/auth.rs#L22) — `pub fn hash_token(token: &str) -> String` - [`src/auth.rs:22`](../src/auth.rs#L22) — `pub fn hash_token(token: &str) -> String`
- [`src/castcheck.rs:82`](../src/castcheck.rs#L82) — `pub fn evaluate(submitted: &[SubmittedActor], credits: &[CastMember]) -> CastCheckOutcome` - [`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/castcheck.rs:215`](../src/castcheck.rs#L215) — `pub fn category_guard_violation(matched: &[MatchedActor], title_is_adult: bool) -> Option…`
@@ -294,15 +294,15 @@ _None._
**Locations:** 3 **Locations:** 3
- [`src/api/fetch.rs:128`](../src/api/fetch.rs#L128) — `Unknown` - [`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) — `Unknown` - [`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:540`](../src/validate.rs#L540) — `pub fn validate_bundle_envelope(b: &SeriesBundle) -> VResult<()>`
### UR-007 ### UR-007
**Locations:** 1 **Locations:** 1
- [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `Unknown` - [`src/api/exists.rs:74`](../src/api/exists.rs#L74) — `pub async fn exists_batch(`
### UR-009 ### UR-009
@@ -314,9 +314,9 @@ _None._
**Locations:** 4 **Locations:** 4
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `Unknown` - [`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/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) — `Unknown` - [`src/db/repo.rs:405`](../src/db/repo.rs#L405) — `pub fn actors_for_manifest(`
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown` - [`src/model.rs:179`](../src/model.rs#L179) — `Unknown`
### UR-011 ### UR-011
@@ -333,13 +333,13 @@ _None._
**Locations:** 2 **Locations:** 2
- [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>` - [`src/db/repo.rs:337`](../src/db/repo.rs#L337) — `pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>`
- [`src/ingest.rs:50`](../src/ingest.rs#L50) — `Unknown` - [`src/ingest.rs:50`](../src/ingest.rs#L50) — `pub fn persist(`
### UR-013 ### UR-013
**Locations:** 3 **Locations:** 3
- [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `Unknown` - [`src/api/fetch.rs:267`](../src/api/fetch.rs#L267) — `pub fn reconstruct(`
- [`src/model.rs:179`](../src/model.rs#L179) — `Unknown` - [`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/validate.rs:486`](../src/validate.rs#L486) — `fn validate_scenes(idx: usize, a: &Actor, runtime_sec: f64) -> VResult<Vec<(i64, i64)>>`
+10 -32
View File
@@ -3,8 +3,9 @@
# Requirement traceability gate for JRay-public-server. # Requirement traceability gate for JRay-public-server.
# #
# A thin wrapper over the shared implementation in the `jray-project` submodule. # A thin wrapper over the shared implementation in the `jray-project` submodule.
# Everything repo-specific lives here; the tooling itself is identical across all # Everything repo-specific lives in `traceability.toml` at the repo root, so this
# three components, so a fix to the gate benefits every repo rather than one. # script only has to point the shared gate at the right tree — and a fix to the
# gate benefits every component rather than one.
# #
# scripts/traceability-gate.sh # scripts/traceability-gate.sh
# #
@@ -12,8 +13,8 @@
# #
# git submodule update --init --recursive # git submodule update --init --recursive
# #
# Environment (passed through to the shared gate): # Environment (passed through):
# MIN_COVERAGE minimum overall coverage percent # MIN_COVERAGE override the threshold in traceability.toml
# ALLOW_ORPHANS set to 1 to report orphan tags without failing # ALLOW_ORPHANS set to 1 to report orphan tags without failing
set -eu set -eu
@@ -28,31 +29,8 @@ if [ ! -f "$VENDOR/scripts/traceability/traceability-gate.sh" ]; then
exit 2 exit 2
fi fi
# Why each override is needed, since omitting any of them fails silently in a # REPO_ROOT is the one thing the shared gate cannot infer: its own default is
# way that looks like "no work done" rather than "misconfigured": # two levels above itself, which is inside the submodule once vendored. The
# # taxonomy, languages and thresholds all come from traceability.toml, which the
# REPO_ROOT the shared gate defaults to two levels above itself, which is # extractor discovers from this root.
# inside the submodule once vendored. REPO_ROOT="$REPO_ROOT" exec sh "$VENDOR/scripts/traceability/traceability-gate.sh" "$@"
# TYPES this repo's register uses UR/DR. The default is the extraction
# pipeline's AR/DP/IR/GR/VR, under which the register parses to
# ZERO requirements.
# SUFFIXES this repo is Rust. The default is C++/Python, under which the
# source tree scans to ZERO files.
# SYSTEM_SPEC the PR/SR requirements live in the project home, which is the
# submodule itself — so it ships with the tool that reads it.
#
# MIN_COVERAGE stays 0 until the TRACES annotation pass lands. That does not
# make the gate toothless: orphan tags, a >100% ratio, a register parsing to
# nothing and an empty source scan are all hard failures from day one. Raise it
# as tags land, and treat every raise as a ratchet.
REPO_ROOT="$REPO_ROOT" \
REQUIREMENTS="$REPO_ROOT/docs/requirements.md" \
SYSTEM_SPEC="$VENDOR/SPEC.md" \
TYPES="UR,DR" \
SUFFIXES=".rs" \
SCAN_ROOTS="src,tests" \
MIN_COVERAGE="${MIN_COVERAGE:-0}" \
ALLOW_ORPHANS="${ALLOW_ORPHANS:-0}" \
TRACES_JSON="${TRACES_JSON:-$REPO_ROOT/traces-report.json}" \
TRACES_MD="${TRACES_MD:-$REPO_ROOT/docs/traceability.md}" \
exec sh "$VENDOR/scripts/traceability/traceability-gate.sh"
+33
View File
@@ -0,0 +1,33 @@
# Traceability configuration for JRay-public-server.
#
# Read by the shared extractor in the jray-project submodule, which is the same
# implementation every JRay component uses. Everything repo-specific lives here
# rather than in the tool; run `extract_traces.py --print-example-config` for
# the annotated schema.
#
# This file's directory is taken as the repo root, so the gate works from any
# subdirectory.
# The prefixes this repo's register defines. Nothing else enters the fraction:
# UT/IT are evidence for requirements, PR/SR belong to the system spec.
requirement_types = ["UR", "DR"]
languages = ["rust"]
source_roots = ["src", "tests"]
# Every test here runs on any machine in seconds — no GPU, no fixtures, no
# external services. Unlike the extraction pipeline, this repo has no tier that
# cannot execute in CI, so nothing is ever counted as tagged-but-unverified.
ci_executable_tiers = ["T1", "T2", "static"]
# 0 until the remaining work lands: UR-007 is plugin-side, UR-008 is federation,
# and UR-015..018 are the pending SR-003 schema bump. This is not a gate that
# cannot fail — orphan tags, a >100% ratio, a register that parses to nothing
# and an empty source scan are all hard failures already. Ratchet this up as
# tags land; never reset it down.
min_coverage = 0.0
# The system spec owning PR/SR, vendored as a submodule so it ships with the
# tool that reads it.
system_spec = "scripts/vendor/jray-project/SPEC.md"