Restore trailer return to the signed-in title #81

Closed
justinzeus wants to merge 1 commit from fm/tv-bug-trailer-return into fm/tv-round2
Owner

Restore trailer return to the same title and person

Fix the reproduced low-memory process-death return without enabling general automatic sign-in or bypassing protected profiles. With automatic sign-in off, only the first valid trailer handoff return may continue; ordinary background returns show the profile picker.

Cause: (a), reproduced; complementary (c) live-return bug

The independent m3 walker reproduced the chooser only after killing Wolfskin while an opaque external trailer stand-in owned the foreground. Ordinary Back and activity-only destruction returned to the same title/person. Debug rc2 and Opt13 showed that distinction. This lane did not drive the emulator or TV; an actual TV PID death was not observed because ADB is off.

Saved navigation already survives, but repository identity and shell state do not. Auto-off startup cannot recover the signed-in person; auto-on can recover the saved person but a new ShellState still initializes its launch chooser. Task clearing and a synthetic root Back are not the reproduced cause. YouTube package selection and NEW_TASK remain unchanged; no manifest or Back-owner change.

Narrow continuation, not a cold-login shortcut

  • Only a resolved exported YouTube handoff from a currently signed-in, unprotected title creates return metadata.
  • The new record in Android's saved Activity Bundle contains server/person UUIDs, exact title route, elapsed handoff time and boot counter—no token, password or PIN. No new last-person preference or Intent-extra restore path.
  • Same saved task, strictly less than ten minutes from handoff, same boot. Saving/recreating does not renew the deadline. Missing boot proof, malformed/expired state, another route, missing saved task state and fresh explicit launches follow ordinary startup policy.
  • Installing a saved token requires an empty live identity and fresh setup Loading entry. Re-read the profile: exact most-recent server/person IDs, present nonblank token, no PIN and no requireLogin. Signout, deleted/tokenless people and another saved person invalidate this exception, even with automatic sign-in on.
  • The existing TV recommendations worker can already authenticate that exact person before the activity leaves Loading. Continue only that same unprotected repository identity, without reinstalling credentials. A surviving activity can continue its active matching entry only with a pending handoff for that person and exact title, within the same-boot, under-ten-minute window. The handoff is cleared on return, so a second ordinary background return shows the picker with automatic sign-in off. Automatic sign-in on is unchanged. Different/protected current identities and an explicit picker stay gated.
  • Recheck pending authorization/deadline after profile lookup, before installing credentials. New startup work cancels old return work; a saved trailer task does not replay its original launch intent. UI commits check the current identity and owning setup entry; existing asynchronous revalidation/recovery guards remain.
  • Only acceptance of that exact person creates a one-use permission to close a fresh shell's chooser and reach the saved title. Ordinary cold automatic sign-in still opens the chooser.

MainActivityViewModel is separated from the activity to keep each production file under 500 lines. Constructor callsite migrations are mechanical. Lane C overlap: WolfskinApp.kt constructor/load and fresh-session initialization only; its picker/person-switch/Back handlers are unchanged. TitleDestination captures the actual external handoff. docker/README.md documents the window and failure gates.

Trailer-only correction

The live-return exception now requires a pending record for the same unprotected person/server and exact title, strictly under ten minutes and on the same boot. Ordinary warm returns with Sign in automatically off show the profile picker; the record is cleared on return, so the next ordinary background return shows the picker again. Automatic sign-in on and the saved-task process-death authentication gates are unchanged. Immutable record snapshots bridge onRestart/onResume cleanup without extending the deadline or lending authorization to a later return.

Pushed correction: 98db417ca29ddb1b8684007abc11d98007958670 on fm/tv-bug-trailer-return. The candidate counterpart is ready for review at #83 (base fm/tv-round2-candidate3, head 4a6d318f8f4d8d93c82d509ae7c54e83cff4f480). The candidate itself at #82 has not been updated; that correction remains a separate reviewable pull request. Cherry-pick resolution omitted only the constructor migration for NavigationCutTest, which does not exist on this original branch.

Verification of this correction through the locked docker/gradle.sh wrapper: baseline 10 cases / 2 expected ordinary-return failures; candidate 85 cases across nine classes / all pass; original trailer branch 77 cases across eight classes / all pass. Both passing runs have zero errors/skips and exclude the inherited design suite with -x :wolfskin-design:testDebugUnitTest. Coverage includes second ordinary return, expiry, boot/identity/title mismatch, pending-handoff protection changes, explicit picker, cold launch, auto-on and asynchronous cleanup/expiry. Native returned-title and saved-task frames were inspected: Locke and Justin’s J avatar, no chooser. No full suite, APK build, ADB, emulator/TV action, release or installation. The instrumentation caller was migrated but not executed.

Correction proof: /root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-trailer-narrow/ (red-native.log, both green*.log, scoped XML/JSON results and native-frames/). The original implementation evidence below is historical, not a claim that its broader warm-return policy remains.

Original implementation regression and runtime proof

Run Cases Failures
Live-return failing-before 8 2
Process-death failing-before 22 4
Final scoped production-code batch 140 0
Final bounded setup-harness recheck 4 0

Both final runs also have zero errors and skips. The final batch covers 27 touched/affected classes; the focused recheck repeats its four setup-navigation cases after making their asynchronous wait bounded and constructing the Activity-dependent factory on the native main thread. No production-code changes followed that original passing batch before the trailer-only correction described above.

The four process-death failures before the fix were lost identity with auto-off, a fresh chooser obscuring the title with auto-on, an unrelated most-recent person replacing the interrupted actor, and an existing picker being treated as eligible. These define the new task-bound continuation contract, not a change to ordinary cold auto-login policy. PIN/requireLogin, fresh launches, missing token/person, wrong route and hours-later controls passed before and remain gated after.

Native runtime smoke exercised real Room-backed repository acceptance, the actual startup view model, a new production shell and the real title surface. The observed 1920×1080 returned frame shows Locke, Justin's J avatar and no chooser. Matching auto-on and worker-prepopulated frames are preserved. This is native Compose/Robolectric proof, not a patched-device claim.

All test commands used docker/gradle.sh and its shared lock. Final invocations explicitly use -x :wolfskin-design:testDebugUnitTest and scoped --tests selectors. No APK assembly or TV mutation. An intermediate native run exposed a main-thread runBlocking harness deadlock; own-container JVM stacks identified it, only that container was stopped, UI commits now use Main.immediate, and the full corrected batch passed.

An initial earlier invocation inadvertently traversed the inherited design-test dependency: 44 classes / 253 cases emitted zero-failure XML before the time-limited command ended. This is disclosed, not claimed as a completed full-suite gate. Subsequent invocations explicitly excluded it. The complete observed inventory is included below so no auth/identity execution is omitted.

Proof directory: /root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-bug-trailer-return/ (process-red/, final-green/, final-harness-green.xml, summaries, native frames and deadlock stack).

Original auth/identity test inventory

The following exhaustive native inventory includes every earlier native case as well as the final scoped run. The original coverage was added in MainActivityTrailerRestoreTest (21 cases), TrailerReturnStateTest (12), MainActivityResumeTest (4) and SignedInContentTest (5). Existing real PIN/requireLogin unlock, expired-login recovery, person-switch, saved-session and cold-picker controls are included by exact name.

All 140 scoped native case names

com.github.damontecres.wholphin.MainActivityResumeTest

recreatedActivityWithoutALiveIdentityStillUsesTheColdStartPicker
warmReturnCannotUnlockPinOrRequireLoginProfiles
warmReturnDoesNotDismissAnExplicitPickerOrAnotherPersonsEntry
warmReturnKeepsTheSignedInPersonAndTitleWithAutomaticSignInOff

com.github.damontecres.wholphin.MainActivityTrailerRestoreTest

aCachedPersonCannotDismissAnExplicitPickerWithSavedTrailerMetadata
aDifferentCurrentWorkerIdentityCannotBeReplacedByTheCapturedPerson
aDifferentMostRecentPersonCannotReplaceTheTrailerIdentityEvenWithAutomaticSignInOn
aDifferentRestoredDestinationCannotReuseTheIdentityRecord
aFreshColdLaunchWithoutSavedTaskStateKeepsThePicker
aFreshLaunchCannotUseAPreviousTrailerSnapshot
aNewExplicitLaunchCancelsAnOlderPendingTaskRestore
aProtectedCurrentWorkerIdentityStillRequiresUnlocking
aRecommendationsWorkerRestoredPersonReturnsToTheSameTitleWithoutSigningInAgain
aReturnHoursLaterCannotRestoreThePerson
aWorkerRestoredPersonWithoutTrailerMetadataCannotSkipTheColdPicker
anExistingPickerCannotBeBypassedByATrailerSnapshot
automaticSignInWithoutATrailerRecordStillShowsTheColdChooser
clearingTheSavedLoginInvalidatesAnOtherwiseEligibleTaskSnapshot
expiryDuringProfileLookupCannotInstallTheSavedToken
missingTokenCannotBeRecoveredFromTheSavedTask
processDeathDoesNotReopenTheFreshShellChooserWithAutomaticSignInOn
processDeathReturnsToTheSamePersonAndTitleWithAutomaticSignInOff
protectionAddedWhileTheProcessWasDeadStillRequiresUnlocking
removedPeopleAreNotRecreatedByTheSavedTask
restoringATrailerTaskDoesNotReplayItsOriginalLaunchIntent

com.github.damontecres.wholphin.SignedInContentTest

closingTrailerKeepsTheSameTitleMountedWithAutomaticSignInOff
profileProtectedWhileAwayDoesNotReappearOnReturn
protectionAddedAfterOpeningTheTitleIsReadAtStopNotFromTheOldEntry
stoppedPinProtectedTitleRemainsHiddenUntilThePickerUnlocksIt
stoppedRequireLoginTitleRemainsHiddenUntilAuthentication

com.github.damontecres.wholphin.TestMainActivityViewModel

Test auto sign disabled in with current server
Test auto sign in with unprotected profile
Test auto sign in, cold load, with protected profile
Test auto sign in, hot load, with protected profile
Test auto sign in, no current user
Test intent result is error, does not have server
Test intent result is error, has server
Test intent result is noop, hot reload
Test intent result is target, has no server
Test intent result is target, has server
Test intent result is target, has server, no home backstack
savedColdLaunchNavigatesBeforeSessionRevalidationCompletes

com.github.damontecres.wholphin.services.ServerSavedSessionTest

anotherUsersResponseCannotRenameTheSavedPerson
lateLaunchRefreshCannotReplaceTheSelectedPerson
launchNameRefreshPreservesSettingsAndPinChangedWhileTheRequestWaits
savedProtectedPeopleRemainLocked
savedSessionIsUsableWhileUserRevalidationWaitsAndSystemInfoRunsInParallel

org.justinvisser.wolfskin.tv.AnimeAvailabilityTest

configuredAnimeAudienceNeedsActualTitlesBeforeItCreatesATabOrHomeShelf

org.justinvisser.wolfskin.tv.AnimeRootRemovalTest

removedAnimeRootReturnsHomeWithoutDiscardingPushedPagesOrAvatarFocus

org.justinvisser.wolfskin.tv.ConductarrAudienceRecoveryTest

operatorSuccessWithFailedOrEmptyAudiencesKeepsTheNameRuleAndForegroundCanHeal
retryingSignedInPeopleKeepsTheUncertainSubmissionLedger

org.justinvisser.wolfskin.tv.ConductarrTitleSurfaceTest

realTitleOffersNoFakePlaybackAndSharedRequestForMindelHasARealReceipt

org.justinvisser.wolfskin.tv.DiscoverRefreshMotionTest

loadedCatalogueRefreshKeepsReadyActionsOpaqueAndStationary
loadedFixtureRefreshKeepsTheSameReadyHeaderAndCatalogueIdentity
loadedHeldRefreshKeepsTheHeaderVisibleWhilePlaybackIsRevalidated

org.justinvisser.wolfskin.tv.DiscoverTitleTimingTest

detailsPushKeepsTheOutgoingDiscoverHeroUntilNavigationReplacesIt
discoverDetailsFillCastAndRelatedAfterAsyncReplyAndBackRestoresDiscover

org.justinvisser.wolfskin.tv.FirstSignInNavigationTest

firstContinueThenMoviesRendersMindelsGridWithoutReenteringThePicker

org.justinvisser.wolfskin.tv.PersonPickerSessionTest

avatarLeftThenOneOkKeepsPickerClosed
avatarRightThenOneOkKeepsPickerClosed
fastLeftLeftOkKeepsPickerClosed
gearAndBackThenOneOkKeepsPickerClosed
initialPersonNeedsOnlyOneOk
launchLeftThenOneOkKeepsPickerClosed
launchRightThenOneOkKeepsPickerClosed

org.justinvisser.wolfskin.tv.PersonSwitchThreadingTest

homeAndTitleRetriesReplaceSignedOutClientsWithoutMainThreadDisposal
pickerSwitchesKeepPersonDataAndDisposeEveryClientOffMainWithoutWaiting
rapidPickerChoicesIgnoreLateSignInAndCanReturnToTheOriginalPerson

org.justinvisser.wolfskin.tv.SavedPeoplePickerTest

savedPeopleAreVisibleBeforeTheFirstNetworkResponse

org.justinvisser.wolfskin.tv.ShellStartupTimingTest

firstFramePickerAndEveryTabWorkBeforeSavedPeopleArrive
switchingPersonDuringHouseholdReadKeepsTheNewIdentityAndReturnsHome

org.justinvisser.wolfskin.tv.TitleAsyncFocusTest

failedRetryKeepsThePersonsSavedTitleAndShowsSharedRecovery
loadingPersonFocusesItsFirstCreditBeforeRealRemoteNavigation
loadingToReadyRestoresRealKeyFocusAndSheetReturn

org.justinvisser.wolfskin.tv.TitleEntryBackTest

homeTitleBackKeepsTheExactPreOpenViewport
homeTitleBackKeepsTheExactPreOpenViewport[34]
immediateSecondSystemBackUsesHomeBeforeExitRecomposition
immediateSecondSystemBackUsesHomeBeforeExitRecomposition[34]
nativeBackKeyWaitsForSystemCompletionBeforePoppingTheTitle
nativeBackKeyWaitsForSystemCompletionBeforePoppingTheTitle[34]
outgoingLoadedPersonCannotConsumeTheNextHomeBack
outgoingLoadedPersonCannotConsumeTheNextHomeBack[34]
outgoingLoadedTitleCannotConsumeTheNextHomeBack
outgoingLoadedTitleCannotConsumeTheNextHomeBack[34]
predictivePersonBackPopsOnlyOneEntry
predictivePersonBackPopsOnlyOneEntry[34]
predictiveTitleBackPopsOnlyOneEntry
predictiveTitleBackPopsOnlyOneEntry[34]
reducedMotionHomeTitleBackKeepsTheExactPreOpenViewport
reducedMotionHomeTitleBackKeepsTheExactPreOpenViewport[34]

org.justinvisser.wolfskin.tv.TitlePlaybackNavigationTest

primarySeriesActionReResolvesNextUpButRestartAndExplicitEpisodesKeepTheirIdentity
repeatedEpisodeChoicesReplaceOnlyEpisodesAndBackPreservesTheirSeriesParent

org.justinvisser.wolfskin.tv.TitleRequestSafetyTest

missingCatalogueIdentityShowsRecoveryAndCannotProduceAFakeHideReceipt

org.justinvisser.wolfskin.tv.TitleThemeMusicTest

catalogueOnlyAndDisabledTitlesStaySilentAndDisablingStopsPlayingTheme
episodeUsesItsSeriesAndMissingSeriesStaysSilent
heldMovieStartsOnceAcrossRefreshAndRecreationNeverOverlaps
outgoingEntryStopsEvenWhileStillComposedAndCanResumeOnBack
pausedPageStopsAndOnlyResumedPageRestarts
personSwitchReleasesOldThemeAndSignOutDisposesIt
realEpisodePageStartsSeriesThemeAndStopsBeforePlaybackNavigation

org.justinvisser.wolfskin.tv.TitleTrailerTest

installedYoutubeHandlerReceivesAnExplicitPackageAndNoBrowserUrl
missingYoutubeHandlerStaysOnTheTitleEvenWhenABrowserExists
nonYoutubeTrailerNeverOpensAGeneralViewHandler

org.justinvisser.wolfskin.tv.TrailerReturnStateTest

aNewProcessCanRecoverTheExactTaskIdentityWithoutCopyingCredentials
aNormalResumeStopsLaterUnrelatedSavesFromReusingTheHandoff
aPersonProtectionOrDestinationChangeInvalidatesTheTaskSnapshot
aRecreatedActivityResumeDoesNotDiscardItsValidatedRestoration
anotherRecoveredTitleAndMalformedStateDoNotAuthorizeRestoration
confirmationCannotDismissTheChooserForAnotherOrNowProtectedPerson
differentAndUnknownBootsCannotRestoreATask
freshLaunchAndCancelledHandoffHaveNoRestorationCapability
protectedAndTokenlessPeopleCannotCreateAHandoffRecord
savingAnOlderHandoffDoesNotRenewItsAuthorizationTime
skippingTheColdChooserRequiresConfirmedIdentityAndIsOneUse
theReturnWindowExpiresAtTenMinutesAndRejectsFutureTimestamps

org.justinvisser.wolfskin.tv.WolfskinRootExitTest

animeContentThenNavBackFinishesTheActivity
animeContentThenNavBackFinishesTheActivity[34]
coldPickerBackFinishesWithoutSelectingAnAvatarOrShowingUpstreamUi
coldPickerBackFinishesWithoutSelectingAnAvatarOrShowingUpstreamUi[34]
comingInSheetDismissesBeforeContentNavAndExit
comingInSheetDismissesBeforeContentNavAndExit[34]
discoverContentThenNavBackFinishesTheActivity
discoverContentThenNavBackFinishesTheActivity[34]
hardwareBackUsesTheSameContentNavExitLadder
hardwareBackUsesTheSameContentNavExitLadder[34]
homeContentThenNavBackFinishesTheActivity
homeContentThenNavBackFinishesTheActivity[34]
moviesContentThenNavBackFinishesTheActivity
moviesContentThenNavBackFinishesTheActivity[34]
reopenedPickerBackDismissesToNavAndTheFollowingBackExits
reopenedPickerBackDismissesToNavAndTheFollowingBackExits[34]
showsContentThenNavBackFinishesTheActivity
showsContentThenNavBackFinishesTheActivity[34]

org.justinvisser.wolfskin.tv.WolfskinSetupNavigationTest

coldStartLegacySignOutDrawerSwitchAndIntentFailureNeverComposeStockSelectors
coldStartSavedPeopleKeepTheirOwnColorsWithoutConductarr
unconfiguredFirstRunOffersUrlInsteadOfStockServerSelector
unreachableSelectionRendersWolfskinRecoveryFrame

org.justinvisser.wolfskin.tv.WolfskinSetupRollbackTest

rollbackRendersBothStockSelectors

org.justinvisser.wolfskin.tv.WolfskinSetupTest

expiredLaunchRecoveryIgnoresOutagesLateIdentitiesAndRollbackMode
pinAndRequireLoginCannotReuseSavedTokenWithoutUnlocking
All 253 observed inherited design-case names (not a completed full-suite gate)

org.justinvisser.wolfskin.design.CardBottomPixelTest

completedHomeProgressUsesTheSameWatchedStripAsLibraryCards
realPosterBottomRowsStayOpaqueAtRestAndFocused

org.justinvisser.wolfskin.design.CardCaptionMotionTest

changingTitleWhileStillFocusedRestoresOpaqueCaptionPixels
movingAcrossAFocusedHomeShelfKeepsEachSelectedCaptionVisible

org.justinvisser.wolfskin.design.CardGeometryTest

filmographyKeepsUnfocusedMetadataAndDistinguishesSeriesFromFilmRuntime
homePosterWideAndTileShelvesReserveTheirCaptionBands
loadingCaptionBandsReserveSpaceWithoutPaintingBars
narrowCaptionsEllipsiseOnlyTheTitleAndKeepRuntimeAndCheck
unfocusedLibraryTitlesKeepCardWidthAndGridPitch

org.justinvisser.wolfskin.design.ComingInRatingsGateTest

savedOfflineRowsOnlyShowPreviouslyReadRatingsAcrossHouseholdRequests
signOutClearsCachedVisibilityAndSignInUsesFreshRatingAndLocale
uncachedDwellCancelsOnLeaveAndReentryStartsAFreshRead

org.justinvisser.wolfskin.design.DiscoverCaptureTest

focusFilterChip
st029_discover
st030_picksCollection
st031_hidden
st032_restore
st033_failedBadge
st034_retryTail
st035_duplicateTail
st036_needsSignIn
st037_series
st038_noSeeds
st039_trendingCollection
st040_service
st041_unreachable
st058_hiddenReceipt
st059_hiddenTitle
st071_requestSelf
st072_requestOther
st073_addHeld
st074_receipt
st075_notConfirmed
st076_pending
st077_refused
st078_recipientsLoading
st079_recipientsUnavailable
st080_seasonsUnknown
st087_sharedReceipt
st105_pickPlate
st110_heldRatings

org.justinvisser.wolfskin.design.DiscoverDetailsFocusTest

heroDetailsRetainsDestinationFocusDuringLoadingAndLateMetadata

org.justinvisser.wolfskin.design.DiscoverHeroSequenceTest

failedArtBlendsToItsFinalFallbackWithoutErasingThePreviousHero
initialCopyEntersOnceAndDoesNotReplayOnDestinationRemount
interruptedHeroNeverSnapsToAnIntermediateSelection
reducedMotionKeepsTheBlendButRemovesCopyTranslation
repeatedPressesRetargetTheCurrentCompositeWithoutSnapBack
slowArtRetainsBothThePaintedHeroAndItsCopyUntilReady

org.justinvisser.wolfskin.design.DiscoverKeysTest

cardOkWaitsForReleaseAndFocusMoveCancelsActivation
choosingAnUncertainRecipientAgainNeverResubmits
closingAnUncertainReceiptNeverTurnsReopeningIntoAnotherPost
collectionBackRestoresTheExactOrigin
collectionDismissalAndUndoKeepTheOriginalOrderAndFocus
collectionRetryReadsNewTitlesAndOpensTheFirstAppendedTitle
downClampsToOccupiedCardsAndThenTheTail
dutchPlateUsesLocaleAndStaysOnOneLine
firstEntryStartsLeftmostAndOnlyMovedLanesRememberTheirPosition
heldOkOpensSheetButNeverSubmits
leavingTheTabResetsLaneMovementButPushedTitlesDoNot
notInterestedInEightPressesAndUndoRestoresEveryIndex
openDiscoverInFourPresses
rebuildingDiscoverDoesNotReuseThePreviousInstancesLaneColumns
requestForMindelInNinePresses
requestForYourselfInSevenPresses
requestingForAnotherPersonKeepsYourOwnRequestedAction
serviceLanesKeepIndependentPositionsAndResetWithTheRootVisit
showAgainRestoresTheHiddenPickAndAnnouncesItsReturn
uncertainOutcomeChecksWithoutResending
unknownSeriesSeasonsNeverSubmitAndBackRestoresOpener

org.justinvisser.wolfskin.design.DiscoverLaneProjectionTest

addedOnlySeedsKeepTheirPicksWithoutClaimingTheyWereWatched
catalogueDeduplicationKeepsMediaTypesDistinctAndHiddenPicksLast
discardedSeedGroupRemainsAvailableInCatalogue
watchedLanesKeepWireOrderAndStableIdentityWhenTitlesCollide

org.justinvisser.wolfskin.design.DiscoverNetworkHeroTest

delayedNetworkSuccessCannotDipThePaintedHeroOpacity

org.justinvisser.wolfskin.design.DuplicateLazyKeysTest

castCreditedForTwoRolesComposes
episodeListedTwiceComposes
filmographyWithARepeatedCreditComposes
homeShelfWithARepeatedCardComposes
libraryGridWithARepeatedTitleComposes
relatedTitleListedTwiceComposes
repeatedKeysKeepTheFirstAndSuffixTheRest
repeatedSeasonNumberComposes
requestListedTwiceComposes

org.justinvisser.wolfskin.design.FocusRingTest

ringStraddlesOpaqueSurfaceAndDisappearsWithoutFocus

org.justinvisser.wolfskin.design.HeroMotionTest

heroWaitsForArtBlendsOnlyItsBoundedRegionAndKeepsTheLatestSelection
homeHeroRetainsTheOutgoingCopyAnchorWhenTheNextTitleWraps

org.justinvisser.wolfskin.design.HomeArtTest

imageFailureShowsTheTitleFallbackInsteadOfAnEmptyCard

org.justinvisser.wolfskin.design.HomeCaptureTest

focusHeroDetails
spacingNextUpFirstFocused
st005_loading
st006_justinNext
st007_mindelResume
st008_sharedResume
st009_deepTrending
st010_heroNav
st011_deepBackNav
st012_explore
st013_unsigned
st014_discoverNav
st015_offlineSaved
st016_conductarrDown
st017_conductarrSaved
st018_jellyfinDown
st019_picksUnavailable
st020_missingArt
st096_widestTilePlate
st099_posterPlate
st100_episodePlate
st101_unratedEpisode
st102_filmTile
st103_heroRatings
xHomeDiscoverStart

org.justinvisser.wolfskin.design.HomeGradientTest

focusedAndUnfocusedTileAndWideScrimsReachTheBottomWithoutDarkeningTheUpperImage

org.justinvisser.wolfskin.design.HomeHeroActionsTest

latePlaybackReadinessKeepsDetailsBoundsForResumePlayAndEpisodeLabels

org.justinvisser.wolfskin.design.HomeHeroSequenceTest

initialSequentialBurstAndRemountKeepHomeCopyReadable

org.justinvisser.wolfskin.design.HomeKeysTest

approvedHomePathsMatchFocusAndCounts
asynchronousFreshHomePlaysNextInTwoPresses
asynchronousHomeDoesNotStealFocusAfterNavInput
cardsActivateOnlyOnReleaseAndMovementCancelsArming
heldOkRepeatEventsDoNotReplayButtonsOrActivateCardsBeforeRelease
loadingHasNavFocus
pointerHoverMovesFocusWithoutActivatingTheCard
rememberedColumnsClampToShortRowsAndTheFinalSeeAll
returningHomeRestoresTheExactViewportAndArrowReentersVisibleContent
visitedMixedWidthRowsKeepColumnsAndTrackWhenMovingInsideTheMiddle

org.justinvisser.wolfskin.design.HomeNavigationTest

downAdvancesEveryRowAndScrollsAfterEpisodeBack
downScrollAfterBackIsMonotonicAtSixteenMillisecondFrames
loadingToReadyThenRefreshDoesNotTrapFocusOnPendingRows
outgoingEpisodeDuringBackCannotTakeOverTheHomeScroller
refreshReorderInsertionRemovalAndSkeletonReadyKeepDownProgress

org.justinvisser.wolfskin.design.HomeRatingCacheTest

cacheIsSharedByCatalogueIdentityAndExpiresAtSixHours
cacheKeepsObservedAbsenceAndEvictsOldestBeyondCapacity
decimalScoresFollowLocaleButPercentagesDoNot
episodeScoresShareSeriesSeasonIdentityWithoutCrossingEpisodesOrSeasons
seasonCapacityCountsSeasonsNotEpisodesAndIsIndependentOfTitleCapacity

org.justinvisser.wolfskin.design.HomeRatingsUiTest

dutchDecimalPlateStaysOnOneLine
focusDwellDefersUncachedPlateButCachedFocusReturnsImmediately
signedOutHomeNeverDrawsHeroOrPlateScores

org.justinvisser.wolfskin.design.HomeRowEntryTest

unvisitedRowsStartLeftmostAcrossCardWidths
visitedColumnsAndFirstVisiblePositionsSurviveRowChangesAndRootTabLeave

org.justinvisser.wolfskin.design.HomeRowsTest

firstReadSkeletonHasNoFocusableContent
heldShelvesAreUnwatchedFirstAndSeeAllUsesFullDestinationCount
heroChainUsesResumeThenNextThenNewThenPickAndNeverRepeatsHeroOnShelves
mergedWatchRowPrefersResumePerSeriesAndInterleavesByWatchRecency
oldCachedEpisodesWithoutSeriesIdsDeduplicateBySeriesName
unavailableLibraryKeepsDiscoverAndFocusableRecoveryInsteadOfHeldShelves

org.justinvisser.wolfskin.design.HomeViewportTest

rowEndsRowChangesAndTitleBackPreserveTheFocusedCardMargin

org.justinvisser.wolfskin.design.LibraryCaptureTest

focusToolbarChip
spacingLetterRailClearsFocusedFifthColumn
spacingShowsFirstFocused
st021_sharedMovies
st022_ratingSort
st023_rowEndClamps
st024_anime
st025_unwatched
st026_empty
st027_unavailable
st028_loading
st030_fullPicks
st035_duplicateOnlyTail
st039_trending
st095_widestPosterPlate
st097_criticsPlate
st098_tmdbPlate
st112_cachedWhileDown
st113_uncachedWhileDown
unsignedRatingsHidden

org.justinvisser.wolfskin.design.LibraryKeysTest

cardActsOnReleaseAndHeldRepeatCannotOpenTwice
downClampsShortLastRowBeforeEnteringRecoveryTail
mixedCatalogueRowsKeepMovieAndSeriesWithTheSameNumericIdentityDistinct
mixedSeeAllPreservesFullListAndClampsShortRow
railGateJumpAndBackRespectOriginalCard
rowEdgesToolbarSortAndBackKeepExactCard
scoresFollowLocaleAndUnratedSortsLast
spiritedAwayInApprovedTwentyPresses

org.justinvisser.wolfskin.design.LibraryPaginationTest

duplicateOnlyReadWaitsForExplicitRetryThenAppendsUniqueTitles
failedReadRetainsTitlesAndRetriesSamePage

org.justinvisser.wolfskin.design.LibrarySpacingRegressionTest

crossingRailThresholdKeepsTheSameDeepFocusedPosterVisible

org.justinvisser.wolfskin.design.MotionSurfaceTest

animatingSkeletonDoesNotPerformMainThreadDiskOrNetworkWork
captionExitKeepsTranslationFixedAtRestAndDuringInterruptedEntry
lateRatingsGenresAndOverviewFadeInsideTheirExistingSlots
pendingCastAndEpisodesAreSkippedUntilRealCardsExist
reducedMotionFreezesPulseWhileNormalMotionBreathesWithoutRelayout
reducedMotionReadinessSnapsAndRemovingItRestoresTheCollapsedStack
shelvesJoiningAnActiveLoadShareTheSameBreathingPhase
titleSkeletonIgnoresDownAndBackPopsWithoutOpeningThePicker

org.justinvisser.wolfskin.design.NavSpringTest

criticallyDampedBlobMatchesLockedCurveWithoutOvershoot

org.justinvisser.wolfskin.design.NetworkArtTransitionTest

onlyNetworkSuccessFadesAndReducedMotionCapsItsDuration

org.justinvisser.wolfskin.design.PickerNavigationTest

downFromEveryAvatarReachesSettingsAndUpReturnsToTheOrigin
settingsBackThenUpKeepsTheAvatarThatOpenedTheGear
settingsGearIsCenteredUnderTheWholePeopleRowForAnyProfileCount

org.justinvisser.wolfskin.design.RecoveryCaptureTest

dutchDiscoverHeroScoreRendersComma
dutchLibraryScoreRendersCommaWithoutBreakingThePlate
failedDiscoverBackdropUsesTheSharedAmbientFallback
failedPosterReadUsesTheSameMissingArtFallbackAsHome
libraryWithoutSavedDataOffersRecovery
savedDiscoverKeepsHeroAndRecoveryWithoutAllowingRequests
savedLibraryHasNavAndHeaderChipAndAReachableRetryTail
savedRequestsKeepTheirRowsAndRecoveryAfterFailure
st090_offlinePlayToastRetainsHomeAndFocusedResume
unavailableDiscoverRetryShowsExactFailureToast

org.justinvisser.wolfskin.design.RecoveryStateTest

DownCannotLeaveNavForSkeletonOnlyHomeLibraryOrDiscover
failedDiscoverRefreshKeepsTitlesAndFocusButDisablesWritesUntilRecovery
requestsKeepSavedRowsOnFailureAndRecoveryNeverOpensTheLastTitle
revokedDiscoverIdentityDropsSavedTitlesInsteadOfPaintingThemWhileSignedOut
switchingPeopleNeverShowsAnotherPersonsCachedRequestsOrSavedChip

org.justinvisser.wolfskin.design.RequestsCaptureTest

st081_empty
st082_stages
st083_unavailable
st084_loading
st085_partial
st086_readiness
st088_sharedActor
st111_focusedRatings

org.justinvisser.wolfskin.design.RequestsKeysTest

approvedNinePressPathUsesRealShellFocus
cachedRatingsRenderInTheTelevisionLocale
emptyAndLoadingTrapDirectionsWhileUnavailableRetries
readinessWindowAndTitleRoundTripPreserveRequest
refreshKeepsStableFocusAndSharedActorNeverBecomesYou
selectingARootAfterARequestTitleDiscardsTheSheetReturnLink

org.justinvisser.wolfskin.design.ScreenEntryNavigationTest

discoverBackRestoresShelfAndDownReachesFinalShelf
libraryBackRestoresCardAndDownReachesFinalGridRow
personBackRestoresCreditAndDownReachesFinalGridRow
titleBackRestoresRowAndDownReachesRelatedShelf

org.justinvisser.wolfskin.design.ShellCaptureTest

focusNavAvatar
st001_launch
st002_gear
st003_loading
st004_unavailable
st010_homeNav
st011_rememberedNav
st014_discoverNav
st091_settings
st092_requestsCountFixture
st093_profileFocus

org.justinvisser.wolfskin.design.ShellKeysTest

destinationViewsAreIsolatedAndReselectResets
heldOkCannotActivateNewOverlay
openSettingsInEightPresses
playbackHandOffInTwelvePresses
rootBackAndNavDownPreserveViewAndWrap
settingsBackBackInTenPresses
switchPersonInSixPresses
updatesUseTwoPressesFromRequestsWithoutClassicHandOff

org.justinvisser.wolfskin.design.ShellSnapshotReadTest

launchedSnapshotFlowReadsDefaultsAndThenRetainsExplicitNavigationMemory
unseenViewCanBeReadInAReadOnlySnapshot

org.justinvisser.wolfskin.design.SnapshotReadAuditTest

knownWriterIsRejectedWithoutRejectingItsCollector
shellReadAccessorDoesNotInsertMemory
snapshotObserversDoNotCallKnownStateWriters

org.justinvisser.wolfskin.design.TitleReadinessMotionTest

aPinnedEpisodeShelfDoesNotBounceWhenReadinessChangesAboveIt
lateReadinessExpansionAndRemovalStayMonotonicAndMoveTheWholeStack

org.justinvisser.wolfskin.design.WolfskinImagesTest

jellyfinSurfacesReplaceStaleDimensionsAndEncodingWithoutLosingIdentity
localAndUnrelatedSourcesRemainUntouched
tmdbSurfacesNeverDownloadOriginalArtwork

AI-assisted implementation. Tier C identity/navigation change: requires the planned Opus safety/auth review before merge. This worker does not merge.

## Restore trailer return to the same title and person Fix the reproduced low-memory process-death return without enabling general automatic sign-in or bypassing protected profiles. With automatic sign-in off, only the first valid trailer handoff return may continue; ordinary background returns show the profile picker. ### Cause: (a), reproduced; complementary (c) live-return bug The independent m3 walker reproduced the chooser only after killing Wolfskin while an opaque external trailer stand-in owned the foreground. Ordinary Back and activity-only destruction returned to the same title/person. Debug rc2 and Opt13 showed that distinction. This lane did not drive the emulator or TV; an actual TV PID death was not observed because ADB is off. Saved navigation already survives, but repository identity and shell state do not. Auto-off startup cannot recover the signed-in person; auto-on can recover the saved person but a new `ShellState` still initializes its launch chooser. Task clearing and a synthetic root Back are not the reproduced cause. YouTube package selection and NEW_TASK remain unchanged; no manifest or Back-owner change. ### Narrow continuation, not a cold-login shortcut - Only a resolved exported YouTube handoff from a currently signed-in, unprotected title creates return metadata. - The new record in Android's saved Activity Bundle contains server/person UUIDs, exact title route, elapsed handoff time and boot counter—no token, password or PIN. No new last-person preference or Intent-extra restore path. - **Same saved task, strictly less than ten minutes from handoff, same boot.** Saving/recreating does not renew the deadline. Missing boot proof, malformed/expired state, another route, missing saved task state and fresh explicit launches follow ordinary startup policy. - Installing a saved token requires an empty live identity and fresh setup Loading entry. Re-read the profile: exact most-recent server/person IDs, present nonblank token, no PIN and no requireLogin. Signout, deleted/tokenless people and another saved person invalidate this exception, even with automatic sign-in on. - The existing TV recommendations worker can already authenticate that exact person before the activity leaves Loading. Continue only that same unprotected repository identity, without reinstalling credentials. A surviving activity can continue its active matching entry only with a pending handoff for that person and exact title, within the same-boot, under-ten-minute window. The handoff is cleared on return, so a second ordinary background return shows the picker with automatic sign-in off. Automatic sign-in on is unchanged. Different/protected current identities and an explicit picker stay gated. - Recheck pending authorization/deadline after profile lookup, before installing credentials. New startup work cancels old return work; a saved trailer task does not replay its original launch intent. UI commits check the current identity and owning setup entry; existing asynchronous revalidation/recovery guards remain. - Only acceptance of that exact person creates a one-use permission to close a *fresh* shell's chooser and reach the saved title. Ordinary cold automatic sign-in still opens the chooser. `MainActivityViewModel` is separated from the activity to keep each production file under 500 lines. Constructor callsite migrations are mechanical. Lane C overlap: `WolfskinApp.kt` constructor/load and fresh-session initialization only; its picker/person-switch/Back handlers are unchanged. `TitleDestination` captures the actual external handoff. `docker/README.md` documents the window and failure gates. ### Trailer-only correction The live-return exception now requires a pending record for the same unprotected person/server and exact title, strictly under ten minutes and on the same boot. Ordinary warm returns with **Sign in automatically** off show the profile picker; the record is cleared on return, so the next ordinary background return shows the picker again. Automatic sign-in on and the saved-task process-death authentication gates are unchanged. Immutable record snapshots bridge `onRestart`/`onResume` cleanup without extending the deadline or lending authorization to a later return. Pushed correction: `98db417ca29ddb1b8684007abc11d98007958670` on `fm/tv-bug-trailer-return`. The candidate counterpart is ready for review at https://git.justinvisser.org/justinzeus/wolfskin/pulls/83 (base `fm/tv-round2-candidate3`, head `4a6d318f8f4d8d93c82d509ae7c54e83cff4f480`). The candidate itself at https://git.justinvisser.org/justinzeus/wolfskin/pulls/82 has not been updated; that correction remains a separate reviewable pull request. Cherry-pick resolution omitted only the constructor migration for `NavigationCutTest`, which does not exist on this original branch. Verification of this correction through the locked `docker/gradle.sh` wrapper: baseline **10 cases / 2 expected ordinary-return failures**; candidate **85 cases across nine classes / all pass**; original trailer branch **77 cases across eight classes / all pass**. Both passing runs have zero errors/skips and exclude the inherited design suite with `-x :wolfskin-design:testDebugUnitTest`. Coverage includes second ordinary return, expiry, boot/identity/title mismatch, pending-handoff protection changes, explicit picker, cold launch, auto-on and asynchronous cleanup/expiry. Native returned-title and saved-task frames were inspected: Locke and Justin’s J avatar, no chooser. No full suite, APK build, ADB, emulator/TV action, release or installation. The instrumentation caller was migrated but not executed. Correction proof: `/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-trailer-narrow/` (`red-native.log`, both `green*.log`, scoped XML/JSON results and `native-frames/`). The original implementation evidence below is historical, not a claim that its broader warm-return policy remains. ### Original implementation regression and runtime proof | Run | Cases | Failures | |---|---:|---:| | Live-return failing-before | 8 | 2 | | Process-death failing-before | 22 | 4 | | Final scoped production-code batch | 140 | 0 | | Final bounded setup-harness recheck | 4 | 0 | Both final runs also have zero errors and skips. The final batch covers 27 touched/affected classes; the focused recheck repeats its four setup-navigation cases after making their asynchronous wait bounded and constructing the Activity-dependent factory on the native main thread. No production-code changes followed that original passing batch before the trailer-only correction described above. The four process-death failures before the fix were lost identity with auto-off, a fresh chooser obscuring the title with auto-on, an unrelated most-recent person replacing the interrupted actor, and an existing picker being treated as eligible. These define the new task-bound continuation contract, not a change to ordinary cold auto-login policy. PIN/requireLogin, fresh launches, missing token/person, wrong route and hours-later controls passed before and remain gated after. Native runtime smoke exercised real Room-backed repository acceptance, the actual startup view model, a new production shell and the real title surface. The observed 1920×1080 returned frame shows **Locke**, Justin's **J** avatar and no chooser. Matching auto-on and worker-prepopulated frames are preserved. This is native Compose/Robolectric proof, not a patched-device claim. All test commands used `docker/gradle.sh` and its shared lock. Final invocations explicitly use `-x :wolfskin-design:testDebugUnitTest` and scoped `--tests` selectors. No APK assembly or TV mutation. An intermediate native run exposed a main-thread `runBlocking` harness deadlock; own-container JVM stacks identified it, only that container was stopped, UI commits now use Main.immediate, and the full corrected batch passed. An initial earlier invocation inadvertently traversed the inherited design-test dependency: 44 classes / 253 cases emitted zero-failure XML before the time-limited command ended. This is disclosed, **not** claimed as a completed full-suite gate. Subsequent invocations explicitly excluded it. The complete observed inventory is included below so no auth/identity execution is omitted. Proof directory: `/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-bug-trailer-return/` (`process-red/`, `final-green/`, `final-harness-green.xml`, summaries, native frames and deadlock stack). ### Original auth/identity test inventory The following exhaustive native inventory includes every earlier native case as well as the final scoped run. The original coverage was added in `MainActivityTrailerRestoreTest` (21 cases), `TrailerReturnStateTest` (12), `MainActivityResumeTest` (4) and `SignedInContentTest` (5). Existing real PIN/requireLogin unlock, expired-login recovery, person-switch, saved-session and cold-picker controls are included by exact name. <details> <summary>All 140 scoped native case names</summary> ### `com.github.damontecres.wholphin.MainActivityResumeTest` ```text recreatedActivityWithoutALiveIdentityStillUsesTheColdStartPicker warmReturnCannotUnlockPinOrRequireLoginProfiles warmReturnDoesNotDismissAnExplicitPickerOrAnotherPersonsEntry warmReturnKeepsTheSignedInPersonAndTitleWithAutomaticSignInOff ``` ### `com.github.damontecres.wholphin.MainActivityTrailerRestoreTest` ```text aCachedPersonCannotDismissAnExplicitPickerWithSavedTrailerMetadata aDifferentCurrentWorkerIdentityCannotBeReplacedByTheCapturedPerson aDifferentMostRecentPersonCannotReplaceTheTrailerIdentityEvenWithAutomaticSignInOn aDifferentRestoredDestinationCannotReuseTheIdentityRecord aFreshColdLaunchWithoutSavedTaskStateKeepsThePicker aFreshLaunchCannotUseAPreviousTrailerSnapshot aNewExplicitLaunchCancelsAnOlderPendingTaskRestore aProtectedCurrentWorkerIdentityStillRequiresUnlocking aRecommendationsWorkerRestoredPersonReturnsToTheSameTitleWithoutSigningInAgain aReturnHoursLaterCannotRestoreThePerson aWorkerRestoredPersonWithoutTrailerMetadataCannotSkipTheColdPicker anExistingPickerCannotBeBypassedByATrailerSnapshot automaticSignInWithoutATrailerRecordStillShowsTheColdChooser clearingTheSavedLoginInvalidatesAnOtherwiseEligibleTaskSnapshot expiryDuringProfileLookupCannotInstallTheSavedToken missingTokenCannotBeRecoveredFromTheSavedTask processDeathDoesNotReopenTheFreshShellChooserWithAutomaticSignInOn processDeathReturnsToTheSamePersonAndTitleWithAutomaticSignInOff protectionAddedWhileTheProcessWasDeadStillRequiresUnlocking removedPeopleAreNotRecreatedByTheSavedTask restoringATrailerTaskDoesNotReplayItsOriginalLaunchIntent ``` ### `com.github.damontecres.wholphin.SignedInContentTest` ```text closingTrailerKeepsTheSameTitleMountedWithAutomaticSignInOff profileProtectedWhileAwayDoesNotReappearOnReturn protectionAddedAfterOpeningTheTitleIsReadAtStopNotFromTheOldEntry stoppedPinProtectedTitleRemainsHiddenUntilThePickerUnlocksIt stoppedRequireLoginTitleRemainsHiddenUntilAuthentication ``` ### `com.github.damontecres.wholphin.TestMainActivityViewModel` ```text Test auto sign disabled in with current server Test auto sign in with unprotected profile Test auto sign in, cold load, with protected profile Test auto sign in, hot load, with protected profile Test auto sign in, no current user Test intent result is error, does not have server Test intent result is error, has server Test intent result is noop, hot reload Test intent result is target, has no server Test intent result is target, has server Test intent result is target, has server, no home backstack savedColdLaunchNavigatesBeforeSessionRevalidationCompletes ``` ### `com.github.damontecres.wholphin.services.ServerSavedSessionTest` ```text anotherUsersResponseCannotRenameTheSavedPerson lateLaunchRefreshCannotReplaceTheSelectedPerson launchNameRefreshPreservesSettingsAndPinChangedWhileTheRequestWaits savedProtectedPeopleRemainLocked savedSessionIsUsableWhileUserRevalidationWaitsAndSystemInfoRunsInParallel ``` ### `org.justinvisser.wolfskin.tv.AnimeAvailabilityTest` ```text configuredAnimeAudienceNeedsActualTitlesBeforeItCreatesATabOrHomeShelf ``` ### `org.justinvisser.wolfskin.tv.AnimeRootRemovalTest` ```text removedAnimeRootReturnsHomeWithoutDiscardingPushedPagesOrAvatarFocus ``` ### `org.justinvisser.wolfskin.tv.ConductarrAudienceRecoveryTest` ```text operatorSuccessWithFailedOrEmptyAudiencesKeepsTheNameRuleAndForegroundCanHeal retryingSignedInPeopleKeepsTheUncertainSubmissionLedger ``` ### `org.justinvisser.wolfskin.tv.ConductarrTitleSurfaceTest` ```text realTitleOffersNoFakePlaybackAndSharedRequestForMindelHasARealReceipt ``` ### `org.justinvisser.wolfskin.tv.DiscoverRefreshMotionTest` ```text loadedCatalogueRefreshKeepsReadyActionsOpaqueAndStationary loadedFixtureRefreshKeepsTheSameReadyHeaderAndCatalogueIdentity loadedHeldRefreshKeepsTheHeaderVisibleWhilePlaybackIsRevalidated ``` ### `org.justinvisser.wolfskin.tv.DiscoverTitleTimingTest` ```text detailsPushKeepsTheOutgoingDiscoverHeroUntilNavigationReplacesIt discoverDetailsFillCastAndRelatedAfterAsyncReplyAndBackRestoresDiscover ``` ### `org.justinvisser.wolfskin.tv.FirstSignInNavigationTest` ```text firstContinueThenMoviesRendersMindelsGridWithoutReenteringThePicker ``` ### `org.justinvisser.wolfskin.tv.PersonPickerSessionTest` ```text avatarLeftThenOneOkKeepsPickerClosed avatarRightThenOneOkKeepsPickerClosed fastLeftLeftOkKeepsPickerClosed gearAndBackThenOneOkKeepsPickerClosed initialPersonNeedsOnlyOneOk launchLeftThenOneOkKeepsPickerClosed launchRightThenOneOkKeepsPickerClosed ``` ### `org.justinvisser.wolfskin.tv.PersonSwitchThreadingTest` ```text homeAndTitleRetriesReplaceSignedOutClientsWithoutMainThreadDisposal pickerSwitchesKeepPersonDataAndDisposeEveryClientOffMainWithoutWaiting rapidPickerChoicesIgnoreLateSignInAndCanReturnToTheOriginalPerson ``` ### `org.justinvisser.wolfskin.tv.SavedPeoplePickerTest` ```text savedPeopleAreVisibleBeforeTheFirstNetworkResponse ``` ### `org.justinvisser.wolfskin.tv.ShellStartupTimingTest` ```text firstFramePickerAndEveryTabWorkBeforeSavedPeopleArrive switchingPersonDuringHouseholdReadKeepsTheNewIdentityAndReturnsHome ``` ### `org.justinvisser.wolfskin.tv.TitleAsyncFocusTest` ```text failedRetryKeepsThePersonsSavedTitleAndShowsSharedRecovery loadingPersonFocusesItsFirstCreditBeforeRealRemoteNavigation loadingToReadyRestoresRealKeyFocusAndSheetReturn ``` ### `org.justinvisser.wolfskin.tv.TitleEntryBackTest` ```text homeTitleBackKeepsTheExactPreOpenViewport homeTitleBackKeepsTheExactPreOpenViewport[34] immediateSecondSystemBackUsesHomeBeforeExitRecomposition immediateSecondSystemBackUsesHomeBeforeExitRecomposition[34] nativeBackKeyWaitsForSystemCompletionBeforePoppingTheTitle nativeBackKeyWaitsForSystemCompletionBeforePoppingTheTitle[34] outgoingLoadedPersonCannotConsumeTheNextHomeBack outgoingLoadedPersonCannotConsumeTheNextHomeBack[34] outgoingLoadedTitleCannotConsumeTheNextHomeBack outgoingLoadedTitleCannotConsumeTheNextHomeBack[34] predictivePersonBackPopsOnlyOneEntry predictivePersonBackPopsOnlyOneEntry[34] predictiveTitleBackPopsOnlyOneEntry predictiveTitleBackPopsOnlyOneEntry[34] reducedMotionHomeTitleBackKeepsTheExactPreOpenViewport reducedMotionHomeTitleBackKeepsTheExactPreOpenViewport[34] ``` ### `org.justinvisser.wolfskin.tv.TitlePlaybackNavigationTest` ```text primarySeriesActionReResolvesNextUpButRestartAndExplicitEpisodesKeepTheirIdentity repeatedEpisodeChoicesReplaceOnlyEpisodesAndBackPreservesTheirSeriesParent ``` ### `org.justinvisser.wolfskin.tv.TitleRequestSafetyTest` ```text missingCatalogueIdentityShowsRecoveryAndCannotProduceAFakeHideReceipt ``` ### `org.justinvisser.wolfskin.tv.TitleThemeMusicTest` ```text catalogueOnlyAndDisabledTitlesStaySilentAndDisablingStopsPlayingTheme episodeUsesItsSeriesAndMissingSeriesStaysSilent heldMovieStartsOnceAcrossRefreshAndRecreationNeverOverlaps outgoingEntryStopsEvenWhileStillComposedAndCanResumeOnBack pausedPageStopsAndOnlyResumedPageRestarts personSwitchReleasesOldThemeAndSignOutDisposesIt realEpisodePageStartsSeriesThemeAndStopsBeforePlaybackNavigation ``` ### `org.justinvisser.wolfskin.tv.TitleTrailerTest` ```text installedYoutubeHandlerReceivesAnExplicitPackageAndNoBrowserUrl missingYoutubeHandlerStaysOnTheTitleEvenWhenABrowserExists nonYoutubeTrailerNeverOpensAGeneralViewHandler ``` ### `org.justinvisser.wolfskin.tv.TrailerReturnStateTest` ```text aNewProcessCanRecoverTheExactTaskIdentityWithoutCopyingCredentials aNormalResumeStopsLaterUnrelatedSavesFromReusingTheHandoff aPersonProtectionOrDestinationChangeInvalidatesTheTaskSnapshot aRecreatedActivityResumeDoesNotDiscardItsValidatedRestoration anotherRecoveredTitleAndMalformedStateDoNotAuthorizeRestoration confirmationCannotDismissTheChooserForAnotherOrNowProtectedPerson differentAndUnknownBootsCannotRestoreATask freshLaunchAndCancelledHandoffHaveNoRestorationCapability protectedAndTokenlessPeopleCannotCreateAHandoffRecord savingAnOlderHandoffDoesNotRenewItsAuthorizationTime skippingTheColdChooserRequiresConfirmedIdentityAndIsOneUse theReturnWindowExpiresAtTenMinutesAndRejectsFutureTimestamps ``` ### `org.justinvisser.wolfskin.tv.WolfskinRootExitTest` ```text animeContentThenNavBackFinishesTheActivity animeContentThenNavBackFinishesTheActivity[34] coldPickerBackFinishesWithoutSelectingAnAvatarOrShowingUpstreamUi coldPickerBackFinishesWithoutSelectingAnAvatarOrShowingUpstreamUi[34] comingInSheetDismissesBeforeContentNavAndExit comingInSheetDismissesBeforeContentNavAndExit[34] discoverContentThenNavBackFinishesTheActivity discoverContentThenNavBackFinishesTheActivity[34] hardwareBackUsesTheSameContentNavExitLadder hardwareBackUsesTheSameContentNavExitLadder[34] homeContentThenNavBackFinishesTheActivity homeContentThenNavBackFinishesTheActivity[34] moviesContentThenNavBackFinishesTheActivity moviesContentThenNavBackFinishesTheActivity[34] reopenedPickerBackDismissesToNavAndTheFollowingBackExits reopenedPickerBackDismissesToNavAndTheFollowingBackExits[34] showsContentThenNavBackFinishesTheActivity showsContentThenNavBackFinishesTheActivity[34] ``` ### `org.justinvisser.wolfskin.tv.WolfskinSetupNavigationTest` ```text coldStartLegacySignOutDrawerSwitchAndIntentFailureNeverComposeStockSelectors coldStartSavedPeopleKeepTheirOwnColorsWithoutConductarr unconfiguredFirstRunOffersUrlInsteadOfStockServerSelector unreachableSelectionRendersWolfskinRecoveryFrame ``` ### `org.justinvisser.wolfskin.tv.WolfskinSetupRollbackTest` ```text rollbackRendersBothStockSelectors ``` ### `org.justinvisser.wolfskin.tv.WolfskinSetupTest` ```text expiredLaunchRecoveryIgnoresOutagesLateIdentitiesAndRollbackMode pinAndRequireLoginCannotReuseSavedTokenWithoutUnlocking ``` </details> <details> <summary>All 253 observed inherited design-case names (not a completed full-suite gate)</summary> ### `org.justinvisser.wolfskin.design.CardBottomPixelTest` ```text completedHomeProgressUsesTheSameWatchedStripAsLibraryCards realPosterBottomRowsStayOpaqueAtRestAndFocused ``` ### `org.justinvisser.wolfskin.design.CardCaptionMotionTest` ```text changingTitleWhileStillFocusedRestoresOpaqueCaptionPixels movingAcrossAFocusedHomeShelfKeepsEachSelectedCaptionVisible ``` ### `org.justinvisser.wolfskin.design.CardGeometryTest` ```text filmographyKeepsUnfocusedMetadataAndDistinguishesSeriesFromFilmRuntime homePosterWideAndTileShelvesReserveTheirCaptionBands loadingCaptionBandsReserveSpaceWithoutPaintingBars narrowCaptionsEllipsiseOnlyTheTitleAndKeepRuntimeAndCheck unfocusedLibraryTitlesKeepCardWidthAndGridPitch ``` ### `org.justinvisser.wolfskin.design.ComingInRatingsGateTest` ```text savedOfflineRowsOnlyShowPreviouslyReadRatingsAcrossHouseholdRequests signOutClearsCachedVisibilityAndSignInUsesFreshRatingAndLocale uncachedDwellCancelsOnLeaveAndReentryStartsAFreshRead ``` ### `org.justinvisser.wolfskin.design.DiscoverCaptureTest` ```text focusFilterChip st029_discover st030_picksCollection st031_hidden st032_restore st033_failedBadge st034_retryTail st035_duplicateTail st036_needsSignIn st037_series st038_noSeeds st039_trendingCollection st040_service st041_unreachable st058_hiddenReceipt st059_hiddenTitle st071_requestSelf st072_requestOther st073_addHeld st074_receipt st075_notConfirmed st076_pending st077_refused st078_recipientsLoading st079_recipientsUnavailable st080_seasonsUnknown st087_sharedReceipt st105_pickPlate st110_heldRatings ``` ### `org.justinvisser.wolfskin.design.DiscoverDetailsFocusTest` ```text heroDetailsRetainsDestinationFocusDuringLoadingAndLateMetadata ``` ### `org.justinvisser.wolfskin.design.DiscoverHeroSequenceTest` ```text failedArtBlendsToItsFinalFallbackWithoutErasingThePreviousHero initialCopyEntersOnceAndDoesNotReplayOnDestinationRemount interruptedHeroNeverSnapsToAnIntermediateSelection reducedMotionKeepsTheBlendButRemovesCopyTranslation repeatedPressesRetargetTheCurrentCompositeWithoutSnapBack slowArtRetainsBothThePaintedHeroAndItsCopyUntilReady ``` ### `org.justinvisser.wolfskin.design.DiscoverKeysTest` ```text cardOkWaitsForReleaseAndFocusMoveCancelsActivation choosingAnUncertainRecipientAgainNeverResubmits closingAnUncertainReceiptNeverTurnsReopeningIntoAnotherPost collectionBackRestoresTheExactOrigin collectionDismissalAndUndoKeepTheOriginalOrderAndFocus collectionRetryReadsNewTitlesAndOpensTheFirstAppendedTitle downClampsToOccupiedCardsAndThenTheTail dutchPlateUsesLocaleAndStaysOnOneLine firstEntryStartsLeftmostAndOnlyMovedLanesRememberTheirPosition heldOkOpensSheetButNeverSubmits leavingTheTabResetsLaneMovementButPushedTitlesDoNot notInterestedInEightPressesAndUndoRestoresEveryIndex openDiscoverInFourPresses rebuildingDiscoverDoesNotReuseThePreviousInstancesLaneColumns requestForMindelInNinePresses requestForYourselfInSevenPresses requestingForAnotherPersonKeepsYourOwnRequestedAction serviceLanesKeepIndependentPositionsAndResetWithTheRootVisit showAgainRestoresTheHiddenPickAndAnnouncesItsReturn uncertainOutcomeChecksWithoutResending unknownSeriesSeasonsNeverSubmitAndBackRestoresOpener ``` ### `org.justinvisser.wolfskin.design.DiscoverLaneProjectionTest` ```text addedOnlySeedsKeepTheirPicksWithoutClaimingTheyWereWatched catalogueDeduplicationKeepsMediaTypesDistinctAndHiddenPicksLast discardedSeedGroupRemainsAvailableInCatalogue watchedLanesKeepWireOrderAndStableIdentityWhenTitlesCollide ``` ### `org.justinvisser.wolfskin.design.DiscoverNetworkHeroTest` ```text delayedNetworkSuccessCannotDipThePaintedHeroOpacity ``` ### `org.justinvisser.wolfskin.design.DuplicateLazyKeysTest` ```text castCreditedForTwoRolesComposes episodeListedTwiceComposes filmographyWithARepeatedCreditComposes homeShelfWithARepeatedCardComposes libraryGridWithARepeatedTitleComposes relatedTitleListedTwiceComposes repeatedKeysKeepTheFirstAndSuffixTheRest repeatedSeasonNumberComposes requestListedTwiceComposes ``` ### `org.justinvisser.wolfskin.design.FocusRingTest` ```text ringStraddlesOpaqueSurfaceAndDisappearsWithoutFocus ``` ### `org.justinvisser.wolfskin.design.HeroMotionTest` ```text heroWaitsForArtBlendsOnlyItsBoundedRegionAndKeepsTheLatestSelection homeHeroRetainsTheOutgoingCopyAnchorWhenTheNextTitleWraps ``` ### `org.justinvisser.wolfskin.design.HomeArtTest` ```text imageFailureShowsTheTitleFallbackInsteadOfAnEmptyCard ``` ### `org.justinvisser.wolfskin.design.HomeCaptureTest` ```text focusHeroDetails spacingNextUpFirstFocused st005_loading st006_justinNext st007_mindelResume st008_sharedResume st009_deepTrending st010_heroNav st011_deepBackNav st012_explore st013_unsigned st014_discoverNav st015_offlineSaved st016_conductarrDown st017_conductarrSaved st018_jellyfinDown st019_picksUnavailable st020_missingArt st096_widestTilePlate st099_posterPlate st100_episodePlate st101_unratedEpisode st102_filmTile st103_heroRatings xHomeDiscoverStart ``` ### `org.justinvisser.wolfskin.design.HomeGradientTest` ```text focusedAndUnfocusedTileAndWideScrimsReachTheBottomWithoutDarkeningTheUpperImage ``` ### `org.justinvisser.wolfskin.design.HomeHeroActionsTest` ```text latePlaybackReadinessKeepsDetailsBoundsForResumePlayAndEpisodeLabels ``` ### `org.justinvisser.wolfskin.design.HomeHeroSequenceTest` ```text initialSequentialBurstAndRemountKeepHomeCopyReadable ``` ### `org.justinvisser.wolfskin.design.HomeKeysTest` ```text approvedHomePathsMatchFocusAndCounts asynchronousFreshHomePlaysNextInTwoPresses asynchronousHomeDoesNotStealFocusAfterNavInput cardsActivateOnlyOnReleaseAndMovementCancelsArming heldOkRepeatEventsDoNotReplayButtonsOrActivateCardsBeforeRelease loadingHasNavFocus pointerHoverMovesFocusWithoutActivatingTheCard rememberedColumnsClampToShortRowsAndTheFinalSeeAll returningHomeRestoresTheExactViewportAndArrowReentersVisibleContent visitedMixedWidthRowsKeepColumnsAndTrackWhenMovingInsideTheMiddle ``` ### `org.justinvisser.wolfskin.design.HomeNavigationTest` ```text downAdvancesEveryRowAndScrollsAfterEpisodeBack downScrollAfterBackIsMonotonicAtSixteenMillisecondFrames loadingToReadyThenRefreshDoesNotTrapFocusOnPendingRows outgoingEpisodeDuringBackCannotTakeOverTheHomeScroller refreshReorderInsertionRemovalAndSkeletonReadyKeepDownProgress ``` ### `org.justinvisser.wolfskin.design.HomeRatingCacheTest` ```text cacheIsSharedByCatalogueIdentityAndExpiresAtSixHours cacheKeepsObservedAbsenceAndEvictsOldestBeyondCapacity decimalScoresFollowLocaleButPercentagesDoNot episodeScoresShareSeriesSeasonIdentityWithoutCrossingEpisodesOrSeasons seasonCapacityCountsSeasonsNotEpisodesAndIsIndependentOfTitleCapacity ``` ### `org.justinvisser.wolfskin.design.HomeRatingsUiTest` ```text dutchDecimalPlateStaysOnOneLine focusDwellDefersUncachedPlateButCachedFocusReturnsImmediately signedOutHomeNeverDrawsHeroOrPlateScores ``` ### `org.justinvisser.wolfskin.design.HomeRowEntryTest` ```text unvisitedRowsStartLeftmostAcrossCardWidths visitedColumnsAndFirstVisiblePositionsSurviveRowChangesAndRootTabLeave ``` ### `org.justinvisser.wolfskin.design.HomeRowsTest` ```text firstReadSkeletonHasNoFocusableContent heldShelvesAreUnwatchedFirstAndSeeAllUsesFullDestinationCount heroChainUsesResumeThenNextThenNewThenPickAndNeverRepeatsHeroOnShelves mergedWatchRowPrefersResumePerSeriesAndInterleavesByWatchRecency oldCachedEpisodesWithoutSeriesIdsDeduplicateBySeriesName unavailableLibraryKeepsDiscoverAndFocusableRecoveryInsteadOfHeldShelves ``` ### `org.justinvisser.wolfskin.design.HomeViewportTest` ```text rowEndsRowChangesAndTitleBackPreserveTheFocusedCardMargin ``` ### `org.justinvisser.wolfskin.design.LibraryCaptureTest` ```text focusToolbarChip spacingLetterRailClearsFocusedFifthColumn spacingShowsFirstFocused st021_sharedMovies st022_ratingSort st023_rowEndClamps st024_anime st025_unwatched st026_empty st027_unavailable st028_loading st030_fullPicks st035_duplicateOnlyTail st039_trending st095_widestPosterPlate st097_criticsPlate st098_tmdbPlate st112_cachedWhileDown st113_uncachedWhileDown unsignedRatingsHidden ``` ### `org.justinvisser.wolfskin.design.LibraryKeysTest` ```text cardActsOnReleaseAndHeldRepeatCannotOpenTwice downClampsShortLastRowBeforeEnteringRecoveryTail mixedCatalogueRowsKeepMovieAndSeriesWithTheSameNumericIdentityDistinct mixedSeeAllPreservesFullListAndClampsShortRow railGateJumpAndBackRespectOriginalCard rowEdgesToolbarSortAndBackKeepExactCard scoresFollowLocaleAndUnratedSortsLast spiritedAwayInApprovedTwentyPresses ``` ### `org.justinvisser.wolfskin.design.LibraryPaginationTest` ```text duplicateOnlyReadWaitsForExplicitRetryThenAppendsUniqueTitles failedReadRetainsTitlesAndRetriesSamePage ``` ### `org.justinvisser.wolfskin.design.LibrarySpacingRegressionTest` ```text crossingRailThresholdKeepsTheSameDeepFocusedPosterVisible ``` ### `org.justinvisser.wolfskin.design.MotionSurfaceTest` ```text animatingSkeletonDoesNotPerformMainThreadDiskOrNetworkWork captionExitKeepsTranslationFixedAtRestAndDuringInterruptedEntry lateRatingsGenresAndOverviewFadeInsideTheirExistingSlots pendingCastAndEpisodesAreSkippedUntilRealCardsExist reducedMotionFreezesPulseWhileNormalMotionBreathesWithoutRelayout reducedMotionReadinessSnapsAndRemovingItRestoresTheCollapsedStack shelvesJoiningAnActiveLoadShareTheSameBreathingPhase titleSkeletonIgnoresDownAndBackPopsWithoutOpeningThePicker ``` ### `org.justinvisser.wolfskin.design.NavSpringTest` ```text criticallyDampedBlobMatchesLockedCurveWithoutOvershoot ``` ### `org.justinvisser.wolfskin.design.NetworkArtTransitionTest` ```text onlyNetworkSuccessFadesAndReducedMotionCapsItsDuration ``` ### `org.justinvisser.wolfskin.design.PickerNavigationTest` ```text downFromEveryAvatarReachesSettingsAndUpReturnsToTheOrigin settingsBackThenUpKeepsTheAvatarThatOpenedTheGear settingsGearIsCenteredUnderTheWholePeopleRowForAnyProfileCount ``` ### `org.justinvisser.wolfskin.design.RecoveryCaptureTest` ```text dutchDiscoverHeroScoreRendersComma dutchLibraryScoreRendersCommaWithoutBreakingThePlate failedDiscoverBackdropUsesTheSharedAmbientFallback failedPosterReadUsesTheSameMissingArtFallbackAsHome libraryWithoutSavedDataOffersRecovery savedDiscoverKeepsHeroAndRecoveryWithoutAllowingRequests savedLibraryHasNavAndHeaderChipAndAReachableRetryTail savedRequestsKeepTheirRowsAndRecoveryAfterFailure st090_offlinePlayToastRetainsHomeAndFocusedResume unavailableDiscoverRetryShowsExactFailureToast ``` ### `org.justinvisser.wolfskin.design.RecoveryStateTest` ```text DownCannotLeaveNavForSkeletonOnlyHomeLibraryOrDiscover failedDiscoverRefreshKeepsTitlesAndFocusButDisablesWritesUntilRecovery requestsKeepSavedRowsOnFailureAndRecoveryNeverOpensTheLastTitle revokedDiscoverIdentityDropsSavedTitlesInsteadOfPaintingThemWhileSignedOut switchingPeopleNeverShowsAnotherPersonsCachedRequestsOrSavedChip ``` ### `org.justinvisser.wolfskin.design.RequestsCaptureTest` ```text st081_empty st082_stages st083_unavailable st084_loading st085_partial st086_readiness st088_sharedActor st111_focusedRatings ``` ### `org.justinvisser.wolfskin.design.RequestsKeysTest` ```text approvedNinePressPathUsesRealShellFocus cachedRatingsRenderInTheTelevisionLocale emptyAndLoadingTrapDirectionsWhileUnavailableRetries readinessWindowAndTitleRoundTripPreserveRequest refreshKeepsStableFocusAndSharedActorNeverBecomesYou selectingARootAfterARequestTitleDiscardsTheSheetReturnLink ``` ### `org.justinvisser.wolfskin.design.ScreenEntryNavigationTest` ```text discoverBackRestoresShelfAndDownReachesFinalShelf libraryBackRestoresCardAndDownReachesFinalGridRow personBackRestoresCreditAndDownReachesFinalGridRow titleBackRestoresRowAndDownReachesRelatedShelf ``` ### `org.justinvisser.wolfskin.design.ShellCaptureTest` ```text focusNavAvatar st001_launch st002_gear st003_loading st004_unavailable st010_homeNav st011_rememberedNav st014_discoverNav st091_settings st092_requestsCountFixture st093_profileFocus ``` ### `org.justinvisser.wolfskin.design.ShellKeysTest` ```text destinationViewsAreIsolatedAndReselectResets heldOkCannotActivateNewOverlay openSettingsInEightPresses playbackHandOffInTwelvePresses rootBackAndNavDownPreserveViewAndWrap settingsBackBackInTenPresses switchPersonInSixPresses updatesUseTwoPressesFromRequestsWithoutClassicHandOff ``` ### `org.justinvisser.wolfskin.design.ShellSnapshotReadTest` ```text launchedSnapshotFlowReadsDefaultsAndThenRetainsExplicitNavigationMemory unseenViewCanBeReadInAReadOnlySnapshot ``` ### `org.justinvisser.wolfskin.design.SnapshotReadAuditTest` ```text knownWriterIsRejectedWithoutRejectingItsCollector shellReadAccessorDoesNotInsertMemory snapshotObserversDoNotCallKnownStateWriters ``` ### `org.justinvisser.wolfskin.design.TitleReadinessMotionTest` ```text aPinnedEpisodeShelfDoesNotBounceWhenReadinessChangesAboveIt lateReadinessExpansionAndRemovalStayMonotonicAndMoveTheWholeStack ``` ### `org.justinvisser.wolfskin.design.WolfskinImagesTest` ```text jellyfinSurfacesReplaceStaleDimensionsAndEncodingWithoutLosingIdentity localAndUnrelatedSourcesRemainUntouched tmdbSurfacesNeverDownloadOriginalArtwork ``` </details> AI-assisted implementation. Tier C identity/navigation change: requires the planned Opus safety/auth review before merge. This worker does not merge.
justinzeus added 2 commits 2026-11-08 06:47:22 +01:00
justinzeus added 1 commit 2026-11-08 13:12:53 +01:00
Limit auto-off warm continuation to trailer handoffs
All checks were successful
review/delta-claude Delta check: trailer-only narrowing correct, no safeguard weakened, 0 blockers
98db417ca2
Author
Owner

Landed through the round 2 candidate #82 (merged into fm/tv-round2 as c21d17df). Closing as superseded; nothing from this branch is lost.

Landed through the round 2 candidate https://git.justinvisser.org/justinzeus/wolfskin/pulls/82 (merged into fm/tv-round2 as c21d17df). Closing as superseded; nothing from this branch is lost.
justinzeus closed this pull request 2026-11-08 13:59:35 +01:00
All checks were successful
review/delta-claude Delta check: trailer-only narrowing correct, no safeguard weakened, 0 blockers

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
exploring
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: justinzeus/wolfskin#81
No description provided.