Files
JRay-public-server/docs/traceability.md
T
dtourolleandClaude Opus 5 0ff1018bcc
CI / static musl binary (push) Has been skipped
CI / fmt, clippy, test (push) Failing after 2m0s
CI / advisories and licences (push) Successful in 27s
Withdraw the file-hash tier; document the legal posture
Removes `cut.video_hash` and the `exact` match tier on legal grounds. The
OpenSubtitles hash was the strongest technical signal available — it identifies
a specific file, so it cannot produce a false positive — and that is exactly
the problem.

Every tier must be a claim about a *cut*, never about a copy. A TMDB id
discloses "some copy of this film", which is what a library catalogue
discloses. A file hash discloses "this exact release": it made a read endpoint
into a release-level oracle, and made an instance's database a mapping from
file fingerprints to the instances holding them. That is a far more specific
disclosure than PR-005 permits, and a dataset no volunteer operator should be
asked to hold. The audio signature is the replacement: derived from content, it
identifies the cut rather than the copy, so two encodes of the same edit agree.

The field is deleted rather than kept as a vestigial null, on the same
reasoning §2 applied to `anneal_sec` — a key naming a signal the format no
longer has is actively misleading — so an upload carrying one is now an
unknown-field 400, with a test asserting it.

**Every content_id changes**, including for manifests that never carried a
hash, because the canonical `cut` object lost a key. The golden vector is
regenerated and re-verified against an independent Python implementation; the
plugin and extraction repos must adopt the new value or federation
deduplication silently breaks. Free now, pre-release; not free later.

Adds docs/legal-posture.md, the operator-facing half of what §5a asks for:
what an instance holds exhaustively, what it structurally cannot do, and how
that sits against the intermediary-liability regimes that plausibly apply.

208 tests. Coverage 25/32.

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

TRACES: UR-011 | SR-004, PR-005
2026-07-31 09:52:03 +02:00

19 KiB

Requirements traceability matrix

Generated: 2026-07-31T07:49:04+00:00

Denominators are read from 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

Metric Value
Source files scanned 29
TRACES tags found 43
EXCEPTION tags found 0
Requirements defined 32
Requirements covered 25
Coverage 78.1% (25/32)
Coverage of CI-executable scope 78.1% (25/32)
Tagged but unexecuted in CI 0
Orphan tags 0

By type

Type Covered Tagged but unexecuted Defined
UR 15 0 18
DR 10 0 14
  • PR tags present (separate taxonomy, not counted in coverage): PR-004, PR-005, PR-006
  • SR tags present (separate taxonomy, not counted in coverage): SR-001, SR-002, SR-003, SR-004, SR-005

Not executable in CI

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.

Orphan tags

A tag naming an ID requirements.md does not define. This is what renumbering produces, and what a typo produces.

None.

Requirements tracing up to nothing

A register row whose Traces to cell names no parent. Work serving no stated goal is how scope creeps in, and it is invisible unless something looks.

None.

Recorded exceptions

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.

Register

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-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-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-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-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
DR-004 Done unset 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…
DR-006 Done unset PR-004 covered src/ratelimit.rs Rate-limit counters in process memory; no external counter store
DR-007 Done unset PR-004 untagged - Ship a single static binary plus one database file; container optional
DR-008 Done T2 SR-004 covered src/auth.rs, src/config.rs X-Forwarded-For honoured only from explicitly configured proxies
DR-009 Done T2 SR-004 covered src/app.rs Body caps enforced while streaming, before parsing, per route
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 unset 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-014 Done unset PR-004 untagged - Portable SQL — no SQLite-specific form where a standard one exists

Detailed mapping

DR-002

Locations: 3

DR-003

Locations: 1

DR-004

Locations: 1

  • src/db/repo.rs:331 — pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>

DR-005

Locations: 1

  • src/db/repo.rs:702 — pub fn lease_jobs(tx: &Transaction<'_>, now: &str, limit: usize) -> anyhow::Result<Vec<Jo…

DR-006

Locations: 1

DR-008

Locations: 2

DR-009

Locations: 1

DR-010

Locations: 1

DR-011

Locations: 3

DR-013

Locations: 3

PR-004

Locations: 3

PR-005

Locations: 2

PR-006

Locations: 9

SR-001

Locations: 7

SR-002

Locations: 4

SR-003

Locations: 11

SR-004

Locations: 16

SR-005

Locations: 2

UR-001

Locations: 3

UR-002

Locations: 2

UR-003

Locations: 6

UR-004

Locations: 2

  • src/auth.rs:76 — pub fn client_ip(headers: &HeaderMap, peer: Option<IpAddr>, trusted_proxies: &[IpAddr]) -…
  • src/ratelimit.rs:93 — impl Default for RateLimiter

UR-005

Locations: 6

UR-006

Locations: 3

UR-007

Locations: 1

UR-008

Locations: 6

UR-009

Locations: 1

  • src/validate.rs:364 — pub fn validate_audio_signature(sig: &str, runtime_sec: f64) -> VResult<()>

UR-010

Locations: 4

UR-011

Locations: 4

UR-012

Locations: 2

UR-013

Locations: 4

UR-014

Locations: 3

UR-017

Locations: 2