Requirements register, spec rewrite, and TRACES tags

jRay had no requirement IDs, so nothing in this repo could be traced to and
the CI gate had no denominator to read. The other two components had already
moved to registers; this brings the plugin level with them.

Adds docs/requirements.md with 46 permanent JR-nnn IDs, each carrying a parent
requirement, priority, status and verification tier, plus a per-requirement
verification plan. JR is flat rather than split by theme: the plugin is one
deployable with one audience, and JRay-public-server already ships UR/DR, so a
second repo using those prefixes would make UR-007 ambiguous across registers.

Rewrites SPEC.md as requirements prose with Current:/Gap: on every one. It had
drifted into a format-plus-API reference that documented schema_version 1 while
owning a format whose v2 shape was specified only in the other two repos, said
nothing about SR-002's scene-scoped semantics, and carried the manifest
exchange as a "planned" aside while its configuration classes were already
implemented. Plugin-side exchange obligations move here from the server's
spec, where they were an ownership inversion.

Adds JR-038..041 for PR-005, which had no software row in any repo -- it was
held structurally by SR-004 and GR-005 both being prohibitions, and a goal
preserved only by prohibitions is the kind that erodes unnoticed. jRay is the
component that actually opens a socket.

Tags 18 units with the requirements they satisfy. Tags name what the code
satisfies, so FileTransformationRegistration is not tagged JR-021: that
requirement is a prohibition and was still violated elsewhere when this was
written.

Vendors jray-project as a submodule for the system spec and shared gate.

TRACES: JR-001, JR-004, JR-005, JR-007, JR-008, JR-009, JR-010, JR-011
TRACES: JR-012, JR-013, JR-014, JR-015, JR-016, JR-017, JR-018, JR-019
TRACES: JR-020, JR-024, JR-025, JR-036, JR-038

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 18:57:48 +02:00
co-authored by Claude Opus 5
parent 32f976e79f
commit 3b24fe1b3c
20 changed files with 1299 additions and 213 deletions
@@ -14,6 +14,11 @@ namespace Jellyfin.Plugin.JRay.Services;
/// Stores truth files pushed directly to JRay (e.g. by a remote extraction
/// worker) under the plugin's configuration directory, keyed by item id.
/// </summary>
/// <remarks>
/// Deliberately outside the media library filesystem, so a worker that cannot
/// write beside the media file is not a second-class producer.
/// </remarks>
// TRACES: JR-009, JR-010 | PR-004
public sealed class ManagedTruthStore : IManagedTruthStore
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
@@ -17,6 +17,7 @@ namespace Jellyfin.Plugin.JRay.Services;
/// reads. All access is synchronised so the work-discovery API and the
/// config page can touch it concurrently.
/// </summary>
// TRACES: JR-016 | PR-003
public sealed class MediaPolicyStore : IMediaPolicyStore
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
@@ -11,6 +11,7 @@ namespace Jellyfin.Plugin.JRay.Services;
/// hold only one action, the only conflicts possible are across scopes, and
/// specificity resolves those.
/// </summary>
// TRACES: JR-016 | PR-003
public static class PolicyResolver
{
/// <summary>
@@ -16,6 +16,13 @@ namespace Jellyfin.Plugin.JRay.Services;
/// item's source file, and caches the parsed result for a configurable
/// duration.
/// </summary>
/// <remarks>
/// Managed truth — pushed by a worker, or fetched from a manifest server —
/// takes precedence over a sidecar file. Storing fetched manifests through the
/// managed store is what keeps this a two-way rule rather than a three-way one,
/// so the read path never learns that the exchange exists.
/// </remarks>
// TRACES: JR-008, JR-010, JR-011 | PR-001
public sealed class TruthDataService : ITruthDataService
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);