Date: 2026-03-18 20:25 Model: Claude Opus 4.6 Type: general Artifact: ## Offline Download — Draft Proposal ### Problem Cloud tracks can only be streamed. No way to downl
This is a reasonable starting point for a requirements discussion, but it's not yet a proposal that can be implemented. It correctly identifies the two core tensions (model predicate and playback routing) but doesn't resolve either one. It also inherits some issues flagged in prior reviews that remain unaddressed.
The framing is good. My assessment of the options:
Option A is dangerous. Changing hasLocalFile to !filePath.isEmpty will silently change behavior everywhere hasLocalFile is currently used — including the export pipeline (mentioned in context). Every callsite assumes hasLocalFile = true means "this is a local-only track with a user-managed file." Broadening that predicate without auditing every consumer is a regression vector. [CHECK THIS]: The proposal doesn't enumerate all current consumers of hasLocalFile. This must happen before choosing A.
Option B is the safest starting point, but the name isAvailableOffline is slightly misleading — local-only tracks are also "available offline." A better name might be hasDownloadedFile or isCloudCached. Option B also has the advantage of being additive (no existing behavior changes).
Option C (separate localCachePath) adds the most clarity and is what I'd actually recommend, because it makes the distinction between "original local file path" and "downloaded cache file path" explicit at the data layer. This matters for:
My recommendation: Option C, with hasLocalFile left unchanged and a new computed property like hasPlayableLocalFile = !filePath.isEmpty || localCachePath != nil.
The proposal asks the right question but doesn't answer it. Here's what the answer should be:
// Current (implicit)
if track.isCloud { useStreamingPlayer() } else { useAudioEngine() }
// Proposed (explicit)
if track.hasPlayableLocalFile { useAudioEngine() } else { useStreamingPlayer() }
This is the correct direction, but prior reviews correctly flag that AudioEngine's format support is unverified for cloud-origin files. The backend may serve formats (OGG, lossy AAC variants) that AVAudioFile can't open. This must be tested before committing to this routing change. If AudioEngine can't handle a format, you need a fallback — either stay on AVPlayer for that file or transcode at download time.
Add an acceptance criterion: "Downloaded file can be opened by AVAudioFile; if not, playback falls back to AVPlayer with a warning that EQ is unavailable."
The proposal doesn't specify where downloads go. Prior reviews flagged this as blocking, and I agree:
~/Library/Caches/ — OS can purge. Unacceptable for explicit user-initiated downloads. [LIKELY HALLUCINATION in prior context]: The path ~/Library/Caches/MixBoard/CloudTracks/ was mentioned in a prior review as being specified somewhere, but this proposal doesn't reference it. If it's in knowledge.md, it needs to change.~/Library/Application Support/MixBoard/CloudTracks/ — Correct location. Survives OS cleanup, backed up by Time Machine, user-deletable via "Remove Download."Download state model: The designer proposal mentions four states (none, downloading, downloaded, error) but the model question doesn't include a downloadState field. This needs to be explicit in the Track model, not inferred from file existence. File existence checks are slow and race-prone.
Partial download / resume: What happens if the app quits mid-download? Is the partial file cleaned up or resumed? This is a requirement, not an implementation detail.
Concurrent download limits: "Download All" on a 200-track album will saturate bandwidth and memory. Specify a concurrency cap (e.g., 3 concurrent).
Disk space: No mention of checking available space before starting downloads or surfacing "disk full" errors.
"Remove Download" behavior: Mentioned in the context menu but not specified. Does it delete the file, nil out localCachePath, and revert to streaming? Does it require confirmation?
Scope boundary: The proposal bundles album-level batch download into v1. Prior Review 1 recommended phasing this after single-track download stabilizes. I agree — batch introduces queue management complexity that isn't addressed here.
hasLocalFile = !filePath.isEmpty && !isCloud — appears consistent with user-provided context. No hallucination detected.StreamingPlayer, AudioEngine, PlayerViewModel — consistent with user context. No hallucination detected.No hallucinations detected in the artifact itself. Prior review references to specific file paths (~/Library/Caches/MixBoard/CloudTracks/) are [UNVERIFIED] against actual codebase.
The proposal is a good discussion starter but needs to:
Application Support, not Caches)downloadState enum to the Track modelWithout items 1–4, this cannot be implemented safely.