Deliberation: requirements — Claude Opus 4.6
Date: 2026-03-18 12:04
Model: Claude Opus 4.6
Type: requirements
Artifact: ## Cloud Download Brief (Draft) ### Problem Cloud tracks in MixBoard playlists cannot be exported t
Requirements Review: Cloud Download Brief
Are These the Right Requirements?
Mostly yes, but the brief is trying to ship two features as one, and the prior reviews have correctly flagged this. The core user problem is clear: "I hit Export and some tracks get skipped silently." That's the problem worth solving. But the brief conflates this with "make cloud tracks behave like local tracks permanently," which is a fundamentally different feature with different complexity.
Let me be specific about what I think is right and wrong.
1. The Two Usage Patterns Are Two Different Features
The brief identifies export-triggered download and standalone download as "two usage patterns." They're not patterns — they're two distinct features with different architectures.
- Export-triggered: Transient. Download → export → optionally clean up. The file is a means to an end.
- Standalone download: Persistent. Download → update Track model → now it's a local track forever. This is an offline library feature.
Recommendation: Ship pattern 1 only. Pattern 2 ("Download to Library") is marked as optional but its existence is bleeding into the acceptance criteria — specifically "Downloaded files are persisted across app restarts" — which only makes sense for pattern 2 and actively harms pattern 1 by creating orphan files and state management obligations.
The prior reviews both converged on this. I agree with them. JIT staging during export is the right v1.
2. Acceptance Criteria Problems
Let me go line by line:
| Criterion |
Verdict |
| Cloud tracks in a playlist can be included in DAW session export |
✅ This is the actual goal. Good. |
| Download progress is visible to the user |
✅ But where? In the export sheet? A separate view? This is undertestable as written. |
| Downloaded files are persisted across app restarts |
⚠️ This is a scope decision disguised as an acceptance criterion. If you're doing JIT staging, this is wrong. If you're doing standalone download, this needs storage location, naming, and cleanup rules. Either way, it shouldn't be here without a conscious decision. |
| User can cancel an in-progress download |
✅ But what happens to the export? Does cancelling one download cancel the whole export? Cancel just that track? This is the partial-failure gap flagged in prior reviews and still unresolved. |
| Export waits for all downloads to complete |
⚠️ What if one fails? This criterion implies all-or-nothing but doesn't say so. Spell it out: does the export proceed with available tracks, or abort entirely? Real users would probably want a choice. |
| Error during download shows clear message and doesn't corrupt partial export |
✅ Good, but "doesn't corrupt" is not testable. Define what "not corrupt" means — no partial file written to export directory? Export operation rolled back? |
What's missing from acceptance criteria:
- What happens to staged files after export completes? After export fails? After app crash?
- Maximum concurrent downloads (serial vs parallel) — this affects UX timing significantly
- File naming strategy for downloaded files (what if two tracks have the same server filename?)
- Disk space check before starting downloads
- Behavior when the same cloud track appears multiple times in a playlist (download once or twice?)
3. "Track model changes — store cached/downloaded file path"
This is the most dangerous line in the brief. Both prior reviews flagged it and I'm going to be blunt: do not mutate Track for v1.
The moment you write a cachedFilePath to the persistent Track model, you've signed up for:
- Stale path detection (file deleted but path still set)
- Migration strategy when you change storage location
hasLocalFile semantics becoming ambiguous (originally local vs. downloaded)
- Every downstream consumer of Track needing to understand the difference
For JIT staging, the download service should return a temporary file URL. The exporter uses it. Done. The Track model doesn't know or care.
4. Implicit Assumptions That Should Be Explicit
- [CHECK THIS] "No auth on file routes" — the brief states this but
ChadMusicAPIClient.streamURL(for:) builds an HTTP URL. Does this URL contain a token as a query parameter? A signed URL? "No auth headers" ≠ "no auth." Verify this by examining the actual URL structure.
- [UNVERIFIED]
ChadMusicAPIClient.streamURL(for:) — mentioned in context but not confirmed to exist with this exact signature in the codebase.
- [UNVERIFIED]
Track.isCloud, Track.hasLocalFile, Track.filePath — these field names are used consistently across reviews but I cannot confirm they exist as named.
- Assumption: The stream URL returns a downloadable file (not an HLS manifest or chunked stream). If
AVPlayer is using HLS, you can't just HTTP GET the same URL and get a WAV/MP3. This would break the entire approach.
- Assumption: Downloaded files are in a format the exporters can handle. The non-goal says "original format preserved," but do the exporters handle all formats the server might serve? What formats does the server serve?
- Assumption: Files are reasonably sized. A playlist of 20 cloud tracks at lossless quality could be 2GB+. No mention of disk space handling.
5. What Would a Real User Care About MORE?
A real user hitting Export with cloud tracks probably cares about:
- "Just make it work" — they don't want to think about downloading. Export should handle it transparently. ✅ Pattern 1 addresses this.
- "How long will this take?" — Progress with time estimate, not just a spinner. The brief says "progress visible" but not how.
- "What if my internet drops mid-export?" — Retry logic is not mentioned anywhere.
- "Can I still use the app while it downloads?" — Is the UI blocked? Can they edit the playlist while downloads are in flight?
A real user probably does not care about:
- Whether the file persists after export (they have the DAW session now)
- Downloading to library as a separate action (they're already streaming it fine)
6. Requirements in Tension
- "Downloaded files are persisted across app restarts" vs Non-goal: "Cache eviction / storage management" — You can't have persistence without eventually needing eviction. These are in direct tension. JIT staging resolves this.
- "Export waits for all downloads" vs user expectation of fast export — If 8 of 10 tracks are cloud, this could take minutes. The brief doesn't set expectations about this UX transition (export was instant, now it might take 5 minutes).
- AudioStitcher needs
hasLocalFile — mentioned in context but not in the brief's scope. Is AudioStitcher in scope or not? If yes, it's a separate integration point that needs its own criteria.
Bottom Line
The brief correctly identifies the user problem but over-scopes the solution. Strip it down to:
- Export-triggered JIT download to temp directory
- No Track model changes
- All-or-nothing export with clear error on failure + option to export with available tracks only
- Cleanup temp files after export completes/fails
- Verify the stream URL returns a downloadable file, not an HLS stream
Ship that. Then decide if standalone download is worth building based on whether users actually ask for it.
Session State
**Blocking findings**:
- Persistence criterion ("persisted across app restarts") contradicts non-goal of no cache eviction — forces v1 into offline library territory without acknowledging it. Must decide: JIT staging or persistent download.
- Partial failure policy still undefined after two prior reviews. "Export waits for all downloads" doesn't specify behavior when downloads fail. This is untestable.
- Unverified assumption that `streamURL(for:)` returns a directly downloadable file vs HLS manifest. If HLS, the entire download approach breaks.
- Track model mutation proposed without migration/staleness strategy — high irreversibility risk.
**Advisory findings**:
- AudioStitcher integration mentioned in context but absent from scope/criteria — clarify in/out
- No retry logic for transient network failures
- No disk space pre-check before downloading potentially large files
- Duplicate cloud tracks in playlist should download once (deduplication)
- File naming collision risk for server-side filenames
- Export UX transition (instant → potentially minutes) needs design consideration
- Download concurrency policy still unspecified (serial vs bounded parallel)
- [UNVERIFIED] `ChadMusicAPIClient.streamURL(for:)` exact signature
- [UNVERIFIED] `Track.isCloud`, `Track.hasLocalFile`, `Track.filePath` field names
- [CHECK THIS] "No auth on file routes" — verify URL doesn't contain tokens/signatures
**Decisions**:
- Recommend JIT staging (export-triggered, temp directory) as v1 scope
- Recommend no Track model changes in v1
- Recommend standalone download ("Download to Library") deferred to v2
**Open Questions**:
- Does `streamURL(for:)` return a direct file URL or HLS manifest?
- What audio formats does the server serve, and do all exporters handle them?
- Serial or bounded-parallel downloads in v1?
- On partial download failure: abort export, or offer to proceed with available tracks?
- Is AudioStitcher in scope for v1?
- What is the expected file size range for cloud tracks?
**Key Entities**:
- `DownloadService.swift` (proposed)
- `Track.filePath`, `Track.hasLocalFile`, `Track.isCloud` [UNVERIFIED field names]
- `ChadMusicAPIClient.streamURL(for:)` [UNVERIFIED]
- `ExportSheet`
- `MixExporter`
- `AudioStitcher`
- `CloudBrowserView`
- Export formats: Audition, CueSheet, DAWProject, EDL, M3U