Disciplines · Proposals

YSD-19047 — Which right each analyzer spends when it reads a source

own analysis runs for the first time.

6sections7 minread

On this page
  • Status: proposed
  • Priority: EXT — blocking for the Phase 2 exit (the rights-aware qualifier faults on every output of every deployment until this is answered, and no amount of measurement changes that)
  • Decision owner: @GreyChimp
  • Drafted: 2026-08-17 by Claude Code (Opus 5)
  • Approval: pending

Question#

run-phase-two-exit.ts was built on 2026-08-17 and pointed at a deployment's own analysis runs for the first time. Four of the five output qualifiers hold over real records. The fifth reports one fault per output:

text
  rights-aware           4 fault(s)
  analysis-without-a-rights-decision — no rights decision covers running this
  analysis on this source; an output produced without one was produced on an
  assumption

That is not a defect in the reader. It is what the reader found, and it was measured rather than assumed:

  • requestAnalysis, executeAnalysisRun, POST /editions/:id/analyses and POST /analyses/:id/execute never call resolveRights, evaluateRights or activeGrantFor. The whole analysis path asks nothing.
  • The single rights touch on the path is inside createAnchor, and it calls activeGrantFor, whose own comment reads: "Probe with the grant's own first action so the action clause of grantFailure never fails." An anchor therefore proves that SOME live grant covered the subject. It never proves that transcription, model-analysis or frame-extraction was granted.
  • grep finds no AnalysisMethodRightsAction map anywhere in the tree. REPRESENTATION_ACTIONS (YSD-2102) maps five representations to actions, DERIVATIVE_OPERATION_ACTION (YSD-4031) maps five derivative operations, and ACTION_CONSENT_SCOPE maps actions to consent scopes. The twelve analyzers Phase 2 ships are in none of them.

So rights-aware cannot be evidenced, and it cannot be evidenced by a reader: resolving the position now would read today's grants at yesterday's instant, and a grant is amended by superseding it, so that answers "would this be permitted under the licence as it now reads" — a model of the decision, not the decision. The read model returns rights: null for exactly that reason.

The question is therefore: which rights action does each of the twelve analysis methods exercise, and what happens to the two whose read the action vocabulary cannot express?

The twelve, with what each actually reads:

Method What it reads Backed by Candidate action
shot-detection video frames (scdet) code frame-extraction
scene-grouping video frames (appearance) code frame-extraction
scene-segmentation video frames + audio bed code unexpressible
camera-motion video frames code frame-extraction
programme-loudness audio only code unexpressible
causal-attribution video frames, two editions code frame-extraction
project-shot-scale video frames, whole corpus code frame-extraction
palette-extraction video frames code frame-extraction
speech-transcription audio → text model transcription
object-detection video frames model model-analysis
speaker-diarization audio model model-analysis
pose-estimation video frames (person boxes) model model-analysis

Two of the twelve have no honest entry. RIGHTS_ACTIONS (YSD-4002) is twelve separately-controlled actions and none of them names reading the audio track to measure it. transcription is speech becoming text and neither method produces text; proxy-generation is generating a rendition and a loudness figure is not one — though REPRESENTATION_ACTIONS does gate a waveform on it; model-analysis is model processing and both are code-backed meters. Picking any of the three would be inventing a rights rule, and picking the loosest would under-gate a real read of licensed audio.

Two further questions ride along and are answered by the recommendation rather than left implicit:

  1. Does a model-backed analyzer that reads frames also spend frame-extraction? A grant may carry frame-extraction and withhold model-analysis — that distinction is the point of having both — but the converse combination is a licence that permits running a model and not looking at the frames, which is not a state of the world.
  2. What does a manual anchor spend? createAnchor today throws RightsDeniedError('playback', …) while checking something weaker than playback. The error message has been naming an action the code does not check since the function was written.

Recommendation#

Adopt the candidate column for the ten expressible methods, with model-analysis alone for the three model-backed frame/audio readers and transcription alone for the recognizer — one action per method, the action that names what the analyzer IS — and refuse the two unexpressible ones as undecided rather than mapping them.

ObservedRights.decision already has three values and the third is undecided. A run of programme-loudness or scene-segmentation records undecided, proceeds, and the Phase 2 exit refuses it as analysis-over-a-denied-source — "the rights decision for … was undecided, and the analyzer read it anyway". That is a true sentence about those two analyzers and the honest place for the gap to sit until the action vocabulary grows an entry for reading audio to measure it, which is a change to YSD-4002 and belongs to whoever owns that.

On question 1: one action, not a set. A grant that lists model-analysis has permitted a model to process the material; requiring frame-extraction alongside it would deny object detection to a licence that plainly intended to allow it, and would make the two actions mean the same thing wherever a model is involved. On question 2: playback, which is what createAnchor's own error message has claimed all along.

The mapping ships as ANALYSIS_METHOD_RIGHTS_ACTION, declared satisfies Record<AnalysisMethod, RightsAction | 'undecided'> next to DETECTION_CORRECTION_ROUTES, so an analyzer added to Phase 2 does not compile until somebody says which right it spends — the same shape, and for the same reason, as the table that made "every output remains correctable" checkable.

requestAnalysis then resolves one decision per (pinned edition, method action) at request time, records it on the run, and — deny-by-default, the posture rights-gate.ts states in its first paragraph — refuses the run when the resolution is deny. It does not refuse undecided: those two analyzers ship today and turning them off is a product decision this one does not make.

Options considered#

  • Map the two audio readers to proxy-generation, following REPRESENTATION_ACTIONS.waveform. Rejected. The precedent is real but it is about generating a rendition of the audio, and neither method generates one. A grant that permits proxies would silently permit measurement, and a licensor who granted proxy generation did not thereby agree to loudness metering.
  • Map them to model-analysis as the catch-all processing action. Rejected as plainly false: both are code-backed meters with no model, and the workspace already refuses to let a code-backed analyzer wear a model's clothes (confidence: { status: 'missing', reason: 'not-applicable' } on every one of their outputs, because a threshold is not a probability).
  • Add an audio-analysis action to RIGHTS_ACTIONS. Not rejected — deferred. It is very likely the right end state, and it is a change to the twelve separately-controlled actions of YSD-4002: every grant in every deployment would need re-review to say whether it carries the new action, and a decision that rewrites a rights vocabulary is not one to take inside a phase exit. Recording undecided keeps the gap visible until it is taken.
  • Require the union of every action an analyzer touches. Rejected for the reason under question 1: it collapses frame-extraction and model-analysis into one right wherever a model runs, and denies analyses that licences obviously intended to permit.
  • Leave the path ungated and let the gate report rights: null forever. Rejected. That is today's state, and it means every machine reading of licensed material in this product is performed on an assumption nobody recorded — which is the sentence the fault prints.
  • Ten mapped methods, two recorded undecided, refuse on deny, and playback for manual anchors — recommended.

Consequences#

  • The Phase 2 exit becomes passable for a deployment whose grants carry the right actions, and stays failed for one whose grants do not — which is the distinction the qualifier was written to draw.
  • Analyses start being refused. A deployment whose grants list only playback can no longer run shot detection, and that is the deny-by-default rule rights-gate.ts already applies everywhere else, arriving late at the one path that skipped it. Fixtures across the study suites grant playback alone and will have to say what they actually permit.
  • programme-loudness and scene-segmentation keep running and stop being able to pass the exit. That is a visible, bounded debt with a named owner rather than an invisible one.
  • createAnchor starts checking the action its error message names. A grant that covers a subject but withholds playback no longer yields anchors.
  • Every analysis run gains a durable record of the rights position it was given, which is the input ObservedRights was declared for and has never had.

Machine-enforced outcome#

On approval, ANALYSIS_METHOD_RIGHTS_ACTION carries the approved mapping and no other, declared satisfies Record<AnalysisMethod, …> so a new analyzer cannot be added without an entry; requestAnalysis records one resolved decision per pinned edition and method action on the run it creates, and throws RightsDeniedError when a resolution denies; assembleObservedAnalysisRuns reads those decisions back into ObservedRights instead of returning null; and a method mapped undecided reaches the gate as undecided rather than as any permitted action.

Pending control#

The Phase 2 exit refuses, once per output, while this decision is unmade. assembleObservedAnalysisRuns sets rights: null on every ObservedOutput because nothing on the analysis path records a decision, and phaseTwoExit turns that into analysis-without-a-rights-decision — so no deployment can report the rights-aware qualifier as holding, and no reader can clear it by resolving rights after the fact. The refusal is asserted against a real run on production persistence in phase-two-exit.integration.spec.ts, which expects one such fault per detection; a change that quietly started manufacturing the decision would fail that suite rather than pass it.