Fallback mounts completion review
The user selected admission-time fallback for configured continuous mounts after the earlier freeze baseline. This review applies to the current implementation, including native/Ogg FLAC, rather than the historical relay-only executable identity. No takeover milestone is started.
Configuration model:
MountConfig.fallback: Option<String>insrc/config.rsdefaults to absent. The operator contract and complete example are in Fallback mounts.Graph validation:
fallback::chainsinsrc/fallback.rs, called byConfig::validatebeforeServer::bind, rejects unknown/noncanonical targets, self/cyclic routes, duplicate paths and depth over eight mount nodes. An iterative seen-set validates every configured route. Existing reserved-path rules exclude HLS.Resolution:
fallback::Routes::newcompiles ordered shared mount references.Routes::listenerattempts at most eight candidates, falling through only onNotFound.Routes::metadataresolves HEAD without admission. No redirect, recursive runtime lookup or routing mutex is added.Admission linearization:
Mount::listener_with_contextprepares the join and obtains global/serving permits, then holds serving admission and record locks. It verifies exact activeArcidentity, Streaming phase and uncancelled generation before registration. Its finalLifecycle::admitload is the drain boundary.SourceLease::dropcloses/releases its own generation under the same admission lock; administrative source disconnect already uses that lock. Failed commit releases permits by RAII. A disconnect immediately after successful admission may normally close that listener.Identity and ownership:
ListenerRecordstores requested identity; its owner remains the serving mount.ListenerInfoexposes both identities and preservesmountas serving. The serving generation owns cursor/initialization/ring references and local permit. The request does not create a second lease or claim the primary.Response/codec:
server::routeuses the admitted generation's headers and media. Cross-format continuous fallback is accepted, including MP3 URL to Ogg. Cached serving initialization is delivered and no audio conversion occurs. HEAD also reports serving MIME. Hard-coded player assumptions remain a client compatibility limitation.Metadata: station headers, track and ICY decisions come from the serving generation; no merging or overriding is introduced. Ogg/native FLAC retain their normal no-ICY-insertion behavior.
Limits/accounting: one global listener permit plus one serving permit; existing inbound connection caps and drain still apply. Full usable mounts fail instead of falling through.
ListenerLease::serving_bytessupplies transport accounting toProgress; serving registry/stats count once. A fixed unlabeled fallback admission counter counts successful commits only. Startup reservation adds 2,048 bytes per listener for the retained requested path; tightly sized old budgets may need increasing.Relay interaction: encoder and relay generations use the same routing path. Integration tests exercise local request to connected relay, relay stop closing the listener and reconnect through the relay's local backup. Relay exclusivity/transport policy is unchanged.
Management/logs: mount
fallback; listenerrequested_mount/serving_mount; servingmountand serving pagination preserved;/api/statscounter andfallback-mountscapability added. One bounded structured admission event includes both identities and generation; close logs include both identities.Concurrency evidence: deterministic barriers stop admission after selection/permit acquisition and before commit. Tests cover primary disconnect, fallback disconnect/reconnect, rejection of stale generation, primary return during backup commit, drain winning commit and permit rollback. Twenty-four simultaneous requests cannot exceed a serving cap of three or double-count. HTTP tests cover limits, drain, format initialization, identity, byte ownership and source closure.
Limitations: admission-time routing only; no migration/live failback, priority, takeover, emergency semantics, HLS fallback, reload or codec conversion. Sequential observations are not a graph-wide atomic snapshot. Each candidate is visited once; a replacement on an already examined mount waits for a later request. Capacity exhaustion does not trigger alternate routing. No profiling or optimization was performed.
Primary return: existing backup listeners remain on their exact backup generation, with its metadata/accounting. Requests that observe the restored primary select it. A request already preparing a backup may still commit there. Backup source loss ends its existing listeners; reconnect resolves from the primary again.
Recommended next feature: review a separate explicit source-takeover policy, if the live-DJ workflow needs it, including authorization, incumbent handling, listener format boundaries and restoration semantics. Approve that design before implementation. Manual player validation of fallback across codecs is the immediate operational follow-up. No source takeover is implemented by this milestone.
Validation
Final validation on 2026-10-08:
cargo test --locked --all-targets: 122 passed (81 library, 12 relay integration, 29 streaming integration), including 13 new fallback tests. The binary target has no tests.cargo clippy --locked --all-targets --all-features -- -D warnings: passed.cargo fmt --all --check: passed.git diff --checkand whitespace checks of new fallback source/docs: passed.
New tests are in src/fallback.rs, src/mounts.rs, tests/streaming.rs and tests/relays.rs. Existing codec, parser/property, source-generation, relay, HLS, management, drain and memory-bound tests remain part of the regression gate.