vc=86: audit-fix sprint (HIGH H2 + 5 MED/LOW from the 2026-06-21 audit)

- Audio-only toggle no longer drops the max-resolution cap: both the
  fullscreen button (PlayerScreen) and the detail Audio pill (VideoDetailBody)
  rebuilt TrackSelectionParameters from a fresh Builder, wiping the data-saver
  ceiling. Now buildUpon() the existing params so the cap survives. (H2)
- Subscriptions Refresh button no longer sticks at "..." forever on a warm
  restart within the cache TTL: refreshIfStale clears the initial loading
  seed when it decides nothing needs refreshing. (M2)
- Search + Channel result lists get a stable item key (video url) so paging /
  shorts-filtering stops re-binding rows to new data (re-triggered thumbnail
  loads, scroll shift). (M3, M4)
- IosSafeHttpDataSource: the unknown-length (LENGTH_UNSET) chunk path rolls
  forward to the next Range chunk at inner-EOF instead of re-reading the
  exhausted source forever (was truncating playback to the first chunk). (M5)
- strawcore channel_feed_rss propagates the real failure (network/HTTP/parse)
  instead of collapsing every error to an empty list, so a broken fetch is
  distinguishable from "no new videos" (subscription_feed keeps its per-channel
  tolerance for fan-out). (M6)
- Feed recency: a clock-skewed future upload emits "0 seconds ago" (parses to
  top) instead of "just now" (which Kotlin's recency parser couldn't read, so
  the item sank to the bottom). (L4)

Deferred to a follow-up: M1 (bg-refresh cache-key mismatch — needs a worker
redesign) + M7 (build config-cache wiring). Verified: cargo check/clippy +
full Android compileDebugKotlin green.
This commit is contained in:
Sulkta 2026-06-21 13:37:51 -07:00
parent a36e673627
commit d6399b367d
8 changed files with 89 additions and 17 deletions

View file

@ -9,6 +9,29 @@ const val STRAW_SDK_TARGET = 35
// Sulkta fork — Straw
//
// vc=86 / 0.1.0-CT — audit-fix sprint (code-audit HIGH H2 + 5 MED/LOW):
// * Audio-only toggle no longer drops your max-resolution cap. Both the
// fullscreen button and the detail "Audio" pill rebuilt the track-
// selection params from a fresh Builder, wiping the data-saver ceiling;
// they now buildUpon() the existing params so the cap survives.
// * Subscriptions "Refresh" button no longer sticks at "..." forever on a
// warm restart within the cache TTL — refreshIfStale now clears the
// initial loading seed when it decides nothing needs refreshing.
// * Search + Channel result lists carry a stable item key (the video url)
// so appending a page / filtering shorts stops re-binding rows to new
// data (which re-triggered thumbnail loads + shifted scroll).
// * iOS-safe data source: the unknown-length (LENGTH_UNSET) chunk path now
// rolls forward to the next Range chunk at inner-EOF instead of
// re-reading the exhausted source forever (was truncating playback to
// the first chunk on any inner that reports no length).
// * strawcore channel_feed_rss now PROPAGATES the real failure (network /
// HTTP / parse) instead of collapsing every error to an empty list, so a
// broken channel fetch is distinguishable from "no new videos" (the
// bulk subscription_feed keeps its per-channel tolerance).
// * Feed recency: a clock-skewed future upload emits "0 seconds ago"
// (parses to top) instead of "just now" (which the Kotlin recency parser
// couldn't read → sank the item to the bottom).
//
// vc=85 / 0.1.0-CS — image caching + SB/RYD → Rust + crash/autoplay fixes:
// * Thumbnails + channel icons stay cached. Coil's default disk cache is
// only 2% of the phone's FREE space, so on a storage-tight device the
@ -202,6 +225,6 @@ const val STRAW_SDK_TARGET = 35
// vc=19 / 0.1.0-AE — rust pipeline cutover. Extraction via
// strawcore-core (Sulkta-OSS/strawcore) via the UniFFI wrapper; no
// NewPipeExtractor in the runtime path.
const val STRAW_VERSION_CODE = 85
const val STRAW_VERSION_NAME = "0.1.0-CS"
const val STRAW_VERSION_CODE = 86
const val STRAW_VERSION_NAME = "0.1.0-CT"
const val STRAW_APPLICATION_ID = "com.sulkta.straw"