Repoint the last legacy column readers onto canonical contract resolution
(settings cutover task A4a):
- access.Resolver and policy.ViewerResolver now resolve
catalog.metadata_language through settingsresolve (profile scope ->
contract default) via a shared access.PreferredMetadataLanguage helper,
instead of reading user_profiles.preferred_metadata_language. Resolution
is deliberately unconstrained: the policy input this preference feeds is
the one a constraint would have to reference, which is circular — see the
key's manifest notes.
- playback start now resolves playback.audio_language canonically for the
profile default instead of reading user_profiles.language, matching the
catalog detail path. Series and library override handling is unchanged.
- items.go needed no change: it already consumes the resolver-produced
scope.PreferredMetadataLanguage.
The legacy columns keep their values but are no longer read on these
paths; a profile with only a column value now resolves to the contract
default, and a stored canonical value wins. Tests pin both directions in
access, policy (including scope parity, where the column is now a decoy),
and the playback handler. Read cost is one batched store read per
resolution, same as the profile-row read it replaces.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>