Files
JRay-public-server/docs/traceability.md
T
dtourolleandClaude Opus 5 545c7d92a2
CI / fmt, clippy, test (push) Failing after 1m20s
CI / static musl binary (push) Has been skipped
CI / advisories and licences (push) Successful in 25s
Federation: replicate content, re-derive judgement (UR-008)
Implements §9a. The replication surface is four reads and no writes: a change
feed, fetch by content_id, a batch have, and a human-facing peer directory —
plus a capabilities endpoint carrying the accepted envelope versions, which
lets a client discover a schema mismatch in one request instead of a 400 per
manifest across a library sweep.

Pull, never push: a pulling server chooses what it ingests and when. Push would
let any peer inject work into the validation queue — the same abuse surface as
anonymous upload, at higher volume.

Nothing inherits a peer's judgement. A pulled manifest runs the full §6 stage 1
and 2 validation and this server's own cast check, and the fetched body must
hash to the content_id that was asked for — the check that stops an
intermediary or a misbehaving peer substituting content under a trusted id.
A peer's retraction flags for review rather than delisting, because
auto-delisting would hand every peer a remote delete primitive; only the opt-in
per-peer abuse channel delists, because a takedown propagating at the speed of
manual review is the wrong failure mode for that one case.

A test caught a real bug in the first cut: the feed cursor was a ULID, and
ULIDs are only monotonic *between* milliseconds — two generated in the same
millisecond carry independent random components and can sort opposite to write
order. A peer resuming from `seq > cursor` would then silently skip an entry:
replication losing manifests with no error anywhere. The cursor is now an
AUTOINCREMENT integer, and the test asserts strict monotonicity rather than
merely sortedness.

Peer administration is deliberately not an API. §9a requires that a peering
exist only because an operator typed a URL, so nothing a remote server returns
can establish or widen one; there_is_no_endpoint_that_creates_a_peering asserts
that absence rather than trusting it.

212 tests. Coverage 25/32 (78%).

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

TRACES: UR-008 | PR-006
2026-07-31 09:28:32 +02:00

19 KiB

Requirements traceability matrix

Generated: 2026-07-31T07:28: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 Planned unset 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:337 — pub fn insert_manifest(tx: &Transaction<'_>, m: &NewManifest<'_>) -> anyhow::Result<()>

DR-005

Locations: 1

  • src/db/repo.rs:709 — 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:378 — 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