Repository navigation
Route: one capability value per playback request; the planner reads no global - #1054
Merged
Merged
Conversation
… media follows) Refs #1044 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… recovery flight read it (wip, tests next) PlaybackSession holds an Arc<Caps> read once where an attempt starts (request_play_with_queue, and the native-audio conversion's dispatch); ResolveEnv, the rebase/recovery/retranscode/ABR captures and TranscodeSpec carry it, so the route's gates and the profile string PMS reads come from the same value instead of two reads of the process-wide answer. Refs #1044 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d refusal reaching its flight) Caps A (a DTS row) and B (= A.without(Audio dts)) pick differently and profile differently with no global installed; the native-audio recovery flight's replacement /decision carries the ceiling learned mid-attempt. Refs #1044 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ost-lesson caps Refs #1044 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… none The app's play start (request_movie / request_episode / the content and queue paths) reads devcaps::caps() ONCE and hands it to the route's request_play* entry points, which begin the attempt on it. The planner, the resolve worker and every mid-film rebuild plan from that value (PlaybackSession::caps, ResolveEnv::caps); route no longer reads the process-wide answer to plan, and plan.rs holds no devcaps::caps( and no zero-argument is_dp_audio( / is_dp_audio_track( (the cfg(test) pick wrappers take the &Caps too). The pump's ConvertNativeAudio no longer re-reads the global after the lesson: dispatch_native_audio_conversion narrows the playing attempt by what the demuxer fed (Caps::without), so the replacement /decision carries the learned ceiling from the attempt's own value. The #1034 pin test (the refusal reaching its recovery flight) is unchanged. ci/check-deps.sh: the `globals` rule is widened to devcaps::caps( and the zero-argument is_dp_audio( / is_dp_audio_track( (qualified, or bare after an import; the _with forms do not match). It is a coverage expansion, not a shrink: no machine reads them, so zero ledger lines were seeded and PINNED_LEDGER_TOTALS is unchanged. A self-test covers the shapes. Refs #1044 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…, not only the conversion's The failed-open recovery chose the Original trial's rollback over the conversion when both applied, and only the conversion narrowed the attempt's Caps. The refusal was learned (the process-wide answer lost the audio), but the attempt kept the value the play started on, so the rollback's rebase profile, a later retry and a quality change offered native Opus again. The pipeline refused it again, `learn` returned false (known combination), and a manual Original ended on the read-out where main converted. recover_failed_source_route now narrows the attempt (PlaybackSession::narrow_attempt) before it picks the recovery, once per learned refusal; dispatch_native_audio_conversion no longer repeats it. The pump rig test a_native_audio_refusal_learned_during_the_original_trial_reaches_the_rollbacks_profile failed on the rollback's /decision profile before this and passes after. Also: the docs the change made false (learn_native_audio_refusal, devcaps::learn_refusal, the Caps struct, plex/mod.rs's allow list, webos5-port.md's codec-capability bullet, sans-io.md), and FlightRig now begins its attempt on the thread's devcaps::caps() so rig tests plan from the table they install rather than the pre-probe fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… does without HEVC The previous wording said "H.264 alone" for a set whose table lists no HEVC decoder, which drops the VP9 / AV1 copy lanes a table may still list. The direct-play list omits hevc (direct_play_video_codecs) and the transcode target's encode head is h264 (Caps::encode_vcodec). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 26, 2026
GLinnik21
added a commit
that referenced
this pull request
Oct 26, 2026
…ture (#1060) A play the TV refuses before its first picture is rescued by one registered state machine, `OpenRecovery` (`player/recovery.rs`, `ci/machines.ini`), which replaces the `open_failure_action` decision function. A manual-quality DTS play refused with `num=601` (#695) now retries with the server converting the DTS track instead of ending on the error screen. - The machine holds the request's capability value (#1054), reads no global and performs no IO; `player/pump.rs` drives it and `engine.rs` steps `LoadStarted`. Effects: `ConfirmRefusal`, `Rollback`, `ConvertFacet`, `StartAutoHls`, `ShowError`. - The ladder for a refusal before the refusing Engine's first picture: roll back a pending HLS→Original trial; Force Direct Play reads out; the audio facet rung converts a refused non-AAC/AC3/E-AC3 track once, and only if excluding it narrows the request; Auto then starts the retained HLS bootstrap; else the read-out. At most `MAX_RECOVERY_FLIGHTS = 2` flights per request. - Fixed: a native-audio stall of an already-learned combination left the viewer on "Buffering…" forever; it now reads out. - Fixed: a refused foreground-resume Load was handled twice (pump read-out plus lifecycle retry). The Load call's synchronous refusal belongs to the foreground lifecycle (`Engine.foreground_follows_load`). - A refused restored Load after Home no longer spins on "Connecting"; after a DTS rescue the ABR climb re-grades the Original candidate's audio (`regrade_original_audio`). - New delivery reason `refusal_recovery`; debug-only `plxnative-refuse601` trigger. - The conversion keeps the refused track (0.8.0 landed on the AC3 sibling); the stored refusal makes the next play pick the sibling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dr-Amp
pushed a commit
to Dr-Amp/plx-native
that referenced
this pull request
Oct 26, 2026
Brings in main's GLinnik21#1054 (one capability value per playback request), GLinnik21#1060 (OpenRecovery state machine for refusals before the first picture) and GLinnik21#1053 (tools/pr-land.py). Live TV adapts to the capability value: request_live takes the Arc<Caps> the way request_play does, and the app passes it at play start. ResolveEnv no longer derives Default, so the channel tests build their environment from ResolveEnv::snapshot and set the live channel on it. The LiveTune type moves above the ResolveEnv doc comment, which it had split. Signed-off-by: Dr-Amp <dr_amp@users.noreply.github.com>
GLinnik21
added a commit
that referenced
this pull request
Oct 26, 2026
…1063) Tests pin that Force Direct Play refuses audio the install has learned the TV refuses before any Load, naming the codec and offering "Switch to Auto and play". No production change: the Forced gate reads the attempt's start value (#1054, #1062), and main has refused this case since #1034. - `forced_direct_play_refuses_a_learned_refusal_before_the_load`: Forced plus a stored `dca 6` row gives `ForcedFailure::Audio { codec: "DTS" }` and no part URL. - `forced_direct_play_plays_the_ac3_sibling_of_a_learned_dts`: with an AC3 sibling, Forced plays the sibling. - `the_play_start_value_lacks_an_applied_refusal`: the first test of the app's `start_caps()`. - Red observed by mutation (the wrapper returning the boot value; the Forced pick reading the global; the Forced arm using the codec-level check). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First PR of the playback-refusal series (#918). It is a pure refactor: each playback request carries one capability value, read once at play start, and every plan, profile and recovery in that request uses it. The planner no longer reads the process-wide
devcaps::caps().Closes #1044
What changed
app/playback.rs,app/content.rsandapp/playback/queue_transport.rsreaddevcaps::caps()once and pass theArc<Caps>intoroute::request_play*. That callsPlaybackSession::begin_attempt, the field's only start writer.PlaybackSession.capsis anOption<Arc<Caps>>becausePlaybackSession::IDLEis aconst. TheOptionis handled only inattempt_caps(); the planner takes&Caps.TranscodeSpec.caps), the MDE ask, the Encode claim,RetranscodeClaimInputs,RebasePlan,OriginalRecoveryPlanandHlsAbrControl.ResolveEnvcarries the value intobuild_stream,classify_outcomeand the preview paths.is_dp_audio,is_dp_audio_track,profile_extraandforced_direct_profileare deleted;is_dp_audio_track_with(&Caps, ..)is the only form left.Caps::without(&Facet)narrows a copy by the same rule a learned refusal applies (refusal_ceiling, shared withapply_learned).engine.rs(×3), the Forced preview, the track menu's "converted by the server" read-out,app/diagnostics.rsandlab/snapshot.rs.Gate: coverage expansion, not a shrink
ci/check-deps.sh'sglobalsrule now also matchesdevcaps::caps,is_dp_audioandis_dp_audio_track. Both qualified and bare-after-import spellings match, with the same import rule aspeek/revision; the_withforms do not.PINNED_LEDGER_TOTALSis unchanged.route/plan.rsis now pinned at zero global capability reads. A later change that puts one back failsmake check.DepGates.test_globals_ledger_sees_the_capability_answer_readers_in_a_machine.Tests
New, all green:
devcaps::tests::without_an_audio_facet_narrows_a_copy_by_the_learned_refusal_ruleplan::track_selection_tests::an_attempt_without_dts_picks_the_ac3_sibling_while_the_wider_attempt_keeps_the_dtsdecision::plan_tests::a_transcode_profile_names_the_codecs_of_the_attempts_own_caps. It needs no global installed or read.player::pump::flight_tests::a_native_audio_refusal_learned_during_the_original_trial_reaches_the_rollbacks_profile. Written first; it failed on the branch before the fix ("the rollback's profile must carry the Opus ceiling the pipeline just refused"), then passed.The flight rig now begins its attempt from the thread's table, so rig tests plan from the table they install. No rig test changed outcome.
Crate suites, on the committed tree:
make test-crate C=plx_platform:test result: ok. 307 passed; 0 failedmake test-crate C=plx_plex:test result: ok. 735 passed; 0 failedmake test-crate C=plx_media:test result: ok. 1766 passed; 0 failed; 64 ignoredmake test-hostsim C=plx_media:test result: ok. 1934 passed; 0 failed; 64 ignoredmake test-crate C=app:test result: ok. 1059 passed; 0 failedmake test-hostsim:test result: ok. 1172 passed; 0 failedbash ci/check-deps.sh:check-deps: all gates greenpython3 ci/check-module-layers.py: greenmake check,--no-default-featuresand the ARM build are left to this PR's CI.Docs
session::learn_native_audio_refusalanddevcaps::learn_refusalno longer claim the conversion plans against the global answer.Capsdoc says the value is read once per attempt.plex/mod.rs's dead-code list dropsprofile_for, which production now reaches.docs/webos5-port.md's "codec capability is still asserted, not probed" bullet had been false since the profile started deriving from the set's own codec table. It now says what is probed and what is still asserted (bitDepth=10, the unreadable-table fallback).docs/sans-io.mddescribes the gate.Notes
transcoder.rs,plan.rsanddevcaps.rs. Whichever lands second merges main.🤖 Generated with Claude Code