vc=88: deferred-hygiene sweep (audit #2 leftovers, no behavior change)
All checks were successful
build-apk / build-and-publish (push) Successful in 7m29s
gitleaks / scan (push) Successful in 42s

M-2: route every SharedPreferences write (Settings/History/Subs/Resume) through
one PrefsWriter — a per-store single-thread dispatcher — so the on-disk apply()
order matches the in-memory CAS order. Previously a Main-thread toggle and an
IO-thread import could land apply() out of order, and ResumePositions detached
ordering entirely via a fresh globalScope.launch per write; a stale value could
then win the next cold-start load. Each write reads the live StateFlow so disk
converges to the latest in-memory state regardless of enqueue order.

L-14: Settings storage-usage sampling (File.length() x4 + Coil diskCache.size)
moved off the composition/Main thread into a LaunchedEffect on Dispatchers.IO.

L-2 / L-4..L-8 / L-15 / L-16: dead code + stale comments from the vc=85 SB/RYD
to Rust migration. Http.kt trimmed to STRAW_USER_AGENT; reconciled the
network_security_config / feed.rs / SubscriptionFeedViewModel / net.rs / CI
comments with reality; recencyScore overflow-guarded; ci/Dockerfile now
pre-installs build-tools 36 (AGP 9.2.1's actual floor, was auto-fetched).

Verified: headless compileDebugKotlin green on the straw-build image.
This commit is contained in:
Cobb 2026-06-21 20:03:45 -07:00
parent 1fe6c12f1d
commit 457166e3b0
14 changed files with 256 additions and 183 deletions

View file

@ -9,6 +9,25 @@ const val STRAW_SDK_TARGET = 35
// Sulkta fork — Straw
//
// vc=88 / 0.1.0-CV — deferred-hygiene sweep (audit #2 leftovers, no behavior change):
// * SharedPreferences writes across every store (Settings, History, Subs,
// ResumePositions) now route through one PrefsWriter — a single-thread
// dispatcher per store — so the on-disk apply() order matches the in-memory
// CAS order. Previously a Main-thread toggle and an IO-thread settings/history
// import could land their apply() out of order, and ResumePositions detached
// write-ordering entirely via a fresh globalScope.launch per write; a stale
// value could then win the next cold-start load. Each write reads the live
// StateFlow so disk always converges to the latest in-memory state. (M-2)
// * Settings storage-usage sampling (File.length() ×4 + Coil diskCache.size)
// moved off the composition/Main thread into a LaunchedEffect on
// Dispatchers.IO — was real synchronous FS I/O stalling the first Settings
// frame. (L-14)
// * Dead code + stale comments from the vc=85 SB/RYD→Rust migration: Http.kt
// trimmed to just STRAW_USER_AGENT (the OkHttp client + bounded-body reader
// went to Rust); reconciled the network_security_config / feed.rs /
// SubscriptionFeedViewModel / net.rs / CI comments with reality. recencyScore
// now overflow-guards a crafted relative-date. (L-2 / L-4..L-8 / L-15 / L-16)
//
// vc=87 / 0.1.0-CU — audit #2 fix sprint (closes two vc=86 regressions + more):
// * FIX a duplicate-key crash: the Subs feed, Search, and Channel lists key
// their LazyColumn by the video url, but the sources weren't fully deduped
@ -247,6 +266,6 @@ const val STRAW_SDK_TARGET = 35
// vc=19 / 0.1.0-AE — rust pipeline cutover. Extraction via
// strawcore-core (Sulkta-Coop/strawcore) via the UniFFI wrapper; no
// NewPipeExtractor in the runtime path.
const val STRAW_VERSION_CODE = 87
const val STRAW_VERSION_NAME = "0.1.0-CU"
const val STRAW_VERSION_CODE = 88
const val STRAW_VERSION_NAME = "0.1.0-CV"
const val STRAW_APPLICATION_ID = "com.sulkta.straw"