# Riff complexity review — 2026-10-18 This is an engineering assessment, not a replacement specification. The comparisons below use primary project and platform documentation checked on 2026-10-18. The judgments are inferences: there is no universal player architecture against which every different implementation is wrong. A simpler alternative is useful only if it preserves the author's adopted behavior and operating conditions. Recommendations here do not authorize removing a requirement. ## Comparison | Riff decision | Established alternative | Constraint or author requirement | Assessment | Recommendation | | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Media3 owns playback and sessions | Android recommends a service-owned Player/MediaSession for background playback. [Media3 service](https://developer.android.com/media/media3/session/background-playback) | Playback survives Activity lifecycle; supported media controls remain available. | Justified use of platform machinery. | Keep the platform owner; reduce policy duplication around it, not the service itself. | | Separate Player and Indexer processes | An Android service need not have a separate process. [Processes](https://developer.android.com/guide/components/processes-and-threads) | The adopted boundary isolates indexing/native decoder failures from playback and keeps mutable ownership exclusive. | Justified by the failure model, with real IPC and memory cost. | Keep isolation; measure combined resident memory before adding more processes or mirrors. | | Stop-and-wait application SEQ/ACK above Binder | AIDL already supplies cross-process calls and ordered calls from one sender thread; synchronous return can acknowledge short work. [AIDL](https://developer.android.com/develop/background-work/services/aidl) | BEGIN must be registered before opening a source; duplicate effects and endpoint incarnation matter. | Application acknowledgment is justified. General retransmission of every control/status message is a simplification candidate; Binder is not a lossy datagram link. | Retain current protocol while required. A separate proposal could compare request IDs plus explicit completion/reconnect reconciliation; it must preserve journal semantics. | | Four-file immutable catalog, checksums, CURRENT/PREVIOUS and read-only descriptors | FlatBuffers supports direct access without unpacking; SQLite offers transactional indexed data. [FlatBuffers](https://flatbuffers.dev/), [SQLite](https://www.sqlite.org/appfileformat.html) | Indexer exclusively produces coherent catalogs; Player must not mix generations or retain writable authority. | Atomic cohort and exact-reader lifetime are justified. The number of artifacts and model projections add cost whose performance benefit is not yet fully measured. | Keep commit/validation boundaries. Measure allocation, mapping, validation and replacement costs at the specified cardinalities before redesigning storage. | | Full snapshot rebuilding and allocated model projections | Direct FlatBuffers access or indexed database queries can avoid reconstructing a complete object graph. [FlatBuffers](https://flatbuffers.dev/) | Ready UI catalogs and a strict cold-start deadline on a weak HU. | Scalability concern, not a demonstrated current throughput failure. Existing acceptance gaps remain open. | Profile `PlayerCuetreeClient`, catalog construction and validation; prioritize bounded startup reads over another caching layer. | | SQLite WAL/FULL plus two same-root recovery snapshots | SQLite transactions, WAL checkpointing and its online backup API provide ordinary durability/recovery tools. [WAL](https://www.sqlite.org/wal.html), [backup](https://sqlite.org/backup.html) | Power interruption, current-schema corruption recovery and no backup on a second medium. | WAL/FULL and verified recovery copies are justified. Full integrity scans/raw-copy publication can threaten the readiness deadline. | Keep corruption/access distinctions and complete companions. Benchmark startup; changing to an incremental backup requires an available Android binding and an adopted recovery design. | | Source TTL measured by publication generation | MPD database update directly discovers additions/modifications/deletions. [MPD protocol](https://mpd.readthedocs.io/en/stable/protocol.html) | Missing removable sources must preserve albums, playlists and references until the adopted TTL. | Retention is justified; publication-based aging is an explicit, unusual product choice. Busy analysis can spend TTL faster than an idle library. | Document the clock clearly. A scan/time-based clock would be a requirement change, not a cleanup. | | Logical MediaID, lazy low component and retained short alias | Many catalogs use paths or external release/recording identifiers. Kodi recommends MusicBrainz identities to disambiguate names. [Kodi tagging](https://kodi.wiki/view/Music_tagging) | Offline equivalent copies, stable durable references and collision disambiguation without full reads on every file. | Justified functionality; lazy alias handling is costly to reason about. | Preserve nullable-low and alias tests. Consider an always-full identity only with measured I/O cost and an explicit format decision. | | Global weighted album grouping with release barriers | Kodi relies on embedded tags; beets normally starts from album directories and can group by Album Artist/Album. [Kodi](https://kodi.wiki/view/Music_tagging), [beets](https://beets.readthedocs.io/en/stable/guides/tagger.html) | Offline, scattered, incomplete and conflicting metadata; no demand that users retag the library first. | Justified by inputs. Complexity is inherent in resolving ambiguity conservatively. | Keep weights, evidence priority and complete-linkage barriers. Avoid adding fuzzy similarity without representative error measurements. | | Filename ordinals and exact trailing version bases | beets offers a separate filename-derived tagging plugin; its import can handle singletons. [beets](https://beets.readthedocs.io/en/stable/guides/tagger.html) | iTunes-style names and short release variants without rewriting tags. | Small, justified evidence adapters. | Keep narrow syntax, complete listing proof, factual-tag priority and no fabricated totals. | | Personal/global Singles, including album fragments and DJ sets | MusicBrainz distinguishes primary Album/Single/EP from secondary Live/DJ-mix attributes. [Release types](https://musicbrainz.org/doc/Release_Group/Type) | Author explicitly wants local presentation baskets, including fragments and set-only artists. | Justified product policy; it is not a claim about an official release type. | Retain transparent thresholds and no artist allowlist. False positives in Electronic+Live remain an accepted heuristic risk worth measuring. | | FILF fragments and frozen audiobook queues | CUE sheets describe indexed positions in larger audio files; Media3 can execute clipped items. [Kodi CUE](https://kodi.wiki/view/Cue_sheets), [Media items](https://developer.android.com/media/media3/exoplayer/media-items) | Chapter metadata, repeated positions, bookmark continuity and no duplicate base container in albums/Singles. | Justified. A plain file list cannot express these requirements. | Preserve occurrence identity and explicit ownership. Never replace them with global MediaID deduplication. | | Frozen durable queue revisions around Media3 | Media3 playlists support ordered items, repeats, shuffle and live mutations. [Playlists](https://developer.android.com/media/media3/exoplayer/playlists) | Active playback must survive edits/rescans/reactions and restore its exact permutation/position. | Justified persistence layer beyond the platform playlist. | Keep revision authority; avoid a second independently editable queue model. | | Decoder calibration, AU batches, three window sessions and fallback | MediaCodec provides synchronous/asynchronous modes and platform-dependent batching APIs. [MediaCodec](https://developer.android.com/reference/android/media/MediaCodec) | Offline AI/gain throughput on weak hardware and known codec irregularities; exact procedure is adopted. | Largest optimization candidate requiring stronger end-to-end evidence. Platform availability alone does not justify exhaustive calibration each run. | Measure calibration cost, break-even workset and fallback rate against a simple single-AU baseline. Do not remove checks without proving equivalent PCM and cancellation. | | Custom ReplayGain target/envelope and 75 ms limiter | ReplayGain defines track/album gain and clipping guidance; mature players apply that metadata. [ReplayGain specification](https://wiki.hydrogenaudio.org/index.php?title=Revised_ReplayGain_specification) | Author selected N/I/F, runtime targets and controlled loudness for the driving environment. | Basic gain is standard; exact target transition and limiter are bespoke but explicitly required. | Keep one processor and conformance fixtures. Use representative listening/output measurements before adding DSP sophistication. | | Offline probabilistic AI selection | MPD exposes simpler random playback; a weighted recommender is a separate product feature. [MPD](https://mpd.readthedocs.io/en/stable/user.html) | Author requires A/V/PTE, preferences, history and exact weighted draws without replacement. | Justified by the feature request, not necessary for a basic player. | Keep hard eligibility and frozen requests; do not add online learning or live queue refill without new requirements. | | Shared schema and four-layer skin inheritance | Platform resources/themes are simpler when only one design ships. [Android resources](https://developer.android.com/guide/topics/resources/providing-resources) | File-only named user skins and one immutable configuration per process are explicitly adopted. | Shared validation is justified. Multi-skin inheritance is optional-product complexity, not demanded by device safety. | Keep current compatibility with the specification; avoid a skin editor or more inheritance levels. Consider scope reduction only with the author. | | Physical density calibration and fixed comfort factors | Android ordinarily uses system density with dp/sp and font scaling. [Density](https://developer.android.com/training/multiscreen/screendensities) | Unreliable HU density plus author-selected calibration and target geometry. | Calibration is justified for this hardware; the universal 9-inch/7:9 policy is a product assumption, not an Android rule. | Retain policy but make its assumptions visible in maintainer docs. Resolve phone fixture failures before expanding exceptions. | | Global brightness recovery lease | Android exposes a window brightness override and separately protected system settings. [Window brightness](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#screenBrightness) | An explicitly provisioned HU workaround, disabled by default, must restore only its own change. | Justified narrowly; global write ownership creates unavoidable recovery complexity. | Keep opt-in and external-change precedence. Never infer permission or activation from a device model. | | Large multipurpose controllers and repeated contract prose | Smaller responsibility-focused owners reduce coupled edits; this is an internal maintainability judgment, not an industry benchmark. | Current shared UI, store transaction ownership and single renderer must remain. | Actual maintenance debt: controller 2,797 lines, state store 2,102, playback service 1,179 at review. Size is a warning, not proof of a bug. | Extract cohesive policies only with behavior-preserving tests. Hardcoded EN/RU classification was also real policy duplication; it is replaced by build-generated vocabulary and GNRE identities. This audit consolidates duplicated storage prose and splits queue/history/focus ownership; it does not replace the controller wholesale. | ## Priorities First keep the corrected failure boundaries: a cancellation fence must wait for the writer, and an access error must not become corruption. Next measure cold-start memory/time and decoder-calibration break-even cost. Those measurements can justify a simplification without guessing. The strongest candidates for a separately approved redesign are the general IPC retransmission layer, repeated full-model materialization, decoder calibration for small worksets, and broad skin inheritance if named skins are no longer wanted. Their accepted contracts currently remain in force. Weighted grouping, FILF ownership, source retention and immutable queues should not be removed merely because a basic player omits them.