Files
libfreemkv/docs/aacs-trace.md
T
Matthew Jackson 0cd967a5ac fix: close code-audit test gaps + doc drift (1.7.4 delta, #45/#52/#46)
Test gaps (guarded code was untested):
- disc: cover is_complete_feature_presentation's CHAPTER_SPAN_MIN_FRAC (0.5)
  boundary — clustered marks (span < 0.5*dur) are not a feature; marks at the
  0.5 threshold are. Adds bd_title_chaptered_span helper (issue #45).
- hevc: exercise the length-prefix self-check WIRING in HevcParser::parse
  end-to-end — a desynced access unit is dropped, a well-formed one emitted.
  Adds a test-only FORCE_FRAMING_DESYNC seam (frame_data is length-prefixed by
  construction, so no real input desyncs it) (issue #52).
- labels: cover resolve_feature_hint's winner_hint early-return — a non-empty
  winner_hint wins over the Tier-2 bdj_feature menu-walk result (issue #46).

Doc drift:
- keysource.md: resolve_unit_keys + UnitKeyResolution (matched/miss_path/
  matched_entry/store_entries de-conflation).
- aacs-trace.md: MatchedEntry, KeyStep.matched_entry/store_entries, and the
  KeyNode::NoDerivableKey node.
- hevc.md: add the "length-prefix self-check (issue #52)" section the hevc.rs
  comment points to.

Craft:
- labels: hoist the duplicated MIN_FEATURE_SECS (60) from fox.rs and
  paramount.rs to a single shared const in labels/mod.rs.
2026-09-20 20:44:28 -07:00

2.3 KiB

AACS resolution trace shape

src/aacs/trace.rs defines the structured trace of a resolution attempt (the unlock phase, then the key-resolution phase).

  • No user-facing English: every step's STATE is a typed enum variant. Applications render these into localized text — the library never does. This module only defines the shape and is wired through the resolve/handshake return path far enough to compile.
  • The who of each step is the source's label() / unlocker's name() — a stable identifier string (a NAME, like a codec id, NOT user-facing prose), carried verbatim so an app renderer never has to match an enum back to a name it already has. Only the OUTCOME / path enums are structured states the app maps to i18n English.

KeyStep — a source's contribution to the key phase

Each source that ran contributes one KeyStep: who (its label()), path (the Vec<KeyNode> it walked), and outcome (KeyOutcome). Two fields de-conflate a keyless result — WHY a matched disc produced no usable key:

  • matched_entry: Option<MatchedEntry> — the shape of the source's MATCHED entry when it matched this disc; None for a true miss or a source kind with no such shape. An app MAY log it verbatim and render a matched-but-no-key verdict.
  • store_entries: Option<usize> — per-disc entries loaded in the source's store, when known, so a true-miss verdict can name the store size (… not in keydb (N entries loaded)). None for a source that carries no such count.

MatchedEntry — booleans-and-lengths, never material

A shape summary of a matched entry — safe to print at any log level, no key MATERIAL: has_vuk, has_unit_keys, unit_keys_len, has_media_key, has_keydb_vid, enc_title_keys_len, vid_available. It answers "the disc WAS found — so why no key?" (e.g. a Media Key present but no VID on this path).

KeyNode::NoDerivableKey

A derivation-path node distinct from NoEntry: the source MATCHED this disc but could not derive any usable key from the matched entry (no derivation material for the path taken). NoEntry = the disc was not found at all; NoDerivableKey = found, but the key was not — the node that turns a flat no entry verdict into matched disc > … > NO KEY. See docs/keysource.md (resolve_unit_keys) for how a source populates it.