docs: complete project research for v1.2.1 Format Parity

This commit is contained in:
2026-03-18 14:33:42 -04:00
parent 664de001ed
commit 279501f972
5 changed files with 1631 additions and 1131 deletions
+119 -121
View File
@@ -1,190 +1,188 @@
# Project Research Summary
**Project:** YellowJacket v1.2 Tag Editing
**Domain:** Audio metadata editing in a desktop music player (Go/Wails)
**Researched:** 2026-03-16
**Project:** YellowJacket v1.2.1 Format Parity
**Domain:** Audio metadata tag writing — OGG Vorbis and WAV format support
**Researched:** 2026-03-18
**Confidence:** HIGH
## Executive Summary
Tag editing for YellowJacket is a cross-cutting feature that touches file I/O (three audio formats), a normalized relational database, an FTS5 search index, a cover art cache pipeline, and the frontend state — all from a single user action. Mature desktop music players (foobar2000, MusicBee, Mp3tag, Kid3) converge on a consistent pattern: modal dialog editing with atomic file writes, inline DB updates (no rescan), and batch editing with three-state field semantics (keep/set/clear). The existing codebase has substantial scaffolding already in place — the `track-details` component has an edit mode UI stub with a no-op save handler, multi-select works in the track list, and the cover art pipeline is fully operational.
YellowJacket v1.2.1 adds OGG Vorbis and WAV tag writing to achieve full format parity across all four supported audio formats. The existing `tagwriter` pipeline was designed for format extension — a switch-case in `pipeline.go` dispatches to format-specific writer functions, and everything downstream (DB sync, events, UI) is format-agnostic. Adding OGG and WAV requires two new writer functions, zero new dependencies, and no frontend changes.
The recommended approach uses **three external libraries** for tag writing `bogem/id3v2/v2` for MP3, `go-flac/go-flac` + `go-flac/flacvorbis` + `go-flac/flacpicture` for FLAC — plus a **custom OGG page rewriter** (deferred to last, since no pure-Go OGG tag writing library exists). A new `backend/tageditor/` package orchestrates the full pipeline: validate → write tags to temp file → atomic rename → update DB entities in a single transaction → update FTS5 → emit event → frontend refreshes. This keeps the existing `library`, `metadata`, and `database` packages unchanged.
The recommended approach is **custom implementations for both formats**: a custom OGG page rewriter (~350 LOC) for OGG Vorbis, and a custom RIFF chunk parser (~200 LOC) wrapping the existing `bogem/id3v2` library for WAV. No pure-Go library exists for OGG Vorbis tag writing, and the Go WAV ecosystem recently lost its most popular library (`go-audio/wav` archived Feb 2026). The OGG container format and RIFF chunk format are both well-documented and simple enough to implement directly. Vorbis Comments (used by OGG) are the exact same metadata format already used in FLAC — field names, encoding, and comment structure are identical, enabling significant code reuse.
The dominant risks are: (1) **FLAC files require full rewrite** for tag changes (no in-place edit), making atomic write-to-temp-then-rename mandatory; (2) the **FTS5 contentless index cannot delete rows**, requiring a schema migration to `contentless_delete=1` before any tag writing code ships; (3) the **normalized schema shares entities** (artists, albums, genres) across tracks, so editing one track must create new entity rows and repoint references rather than mutating shared rows in-place; and (4) a **race condition** between tag editing and library scanning requires mutual exclusion. All four risks have well-understood mitigations documented in the research.
The primary risk is the OGG page infrastructure: CRC32 checksums use a non-standard bit ordering (MSB-first, not the Go standard library's reflected CRC32), page sequence numbers must be strictly sequential, and granule positions must be preserved exactly. These are well-understood constraints with clear specifications, but incorrect implementation produces silently corrupted files. Round-trip testing (write → read back via `dhowden/tag`) is the primary mitigation, following the pattern established by the existing MP3 and FLAC writers.
## Key Findings
### Recommended Stack
Pure-Go tag writing is well-supported for MP3 and FLAC via established libraries. OGG Vorbis tag writing requires custom implementation but shares the Vorbis Comment format with FLAC, so serialization code is reusable. No new dependencies beyond `golang.org/x/text` (already in go.mod) are pulled in transitively. The existing `dhowden/tag` library stays for all READ operations — no conflict with the new write libraries.
Zero new dependencies. Both formats are implemented using Go standard library primitives (`encoding/binary`, `encoding/base64`, `bytes`, `io`) plus existing dependencies for shared functionality.
**Core technologies:**
- **`bogem/id3v2/v2`** (v2.1.4): MP3 ID3v2 read+write — 359 stars, 57 importers, handles encoding (UTF-8/UTF-16) correctly, supports picture frames. HIGH confidence.
- **`go-flac/go-flac/v2` + `go-flac/flacvorbis/v2` + `go-flac/flacpicture`**: FLAC metadata manipulation — copies audio frames as raw bytes (no re-encoding), ~50ms for metadata-only edits on large files. HIGH confidence.
- **Custom OGG page rewriter**: No pure-Go OGG tag writer exists. OGG page framing (CRC, segment tables) is the only new work — Vorbis Comment serialization is shared with FLAC. MEDIUM confidence.
- **stdlib `os.CreateTemp` + `os.Rename`**: Atomic file write pattern — temp file in same directory guarantees same-filesystem rename. No external dependency needed.
**Critical version requirements:**
- SQLite ≥ 3.43.0 for `contentless_delete=1` FTS5 support (bundled `modernc.org/sqlite` provides 3.45+, so already satisfied)
- **Custom OGG page rewriter:** Parse/write OGG pages with CRC32 and segmentation — no pure-Go OGG writing library exists; `mccoyst/ogg` (37 stars, no semver) saves ~80 LOC but adds dependency risk
- **Custom RIFF chunk parser/writer:** Read/write WAV RIFF structure — `go-audio/wav` and `go-audio/riff` were archived Feb 2026; RIFF is simple enough for custom code
- **`bogem/id3v2` (existing):** Generate ID3v2 tags for WAV `id3 ` chunks — same library already used for MP3 writing, all 8 fields + cover art work identically
- **`go-flac/flacpicture` (existing):** Build METADATA_BLOCK_PICTURE binary blocks for OGG cover art — same binary format, just base64-wrapped for OGG
- **`fileutil.AtomicWrite` (existing):** Crash-safe file writes for both formats — proven pattern from MP3/FLAC writers
### Expected Features
**Must have (table stakes):**
- Single track tag editing (title, artist, album, genre, year, track#, disc#, composer)
- Write tags to MP3 (ID3v2) and FLAC (Vorbis Comments)
- Write-to-temp-then-rename corruption safety
- Inline DB + FTS5 update after tag write (no rescan)
- Batch editing with three-state field model (keep/set/clear)
- Cover art set/replace from image file
- Save confirmation and error feedback
- Write all 8 text fields for OGG Vorbis (same Vorbis Comment field names as FLAC)
- Write all 8 text fields for WAV (via ID3v2 in RIFF chunk)
- Preserve existing non-edited metadata (ReplayGain, lyrics, etc.)
- Preserve audio data byte-for-byte (no re-encoding)
- Crash-safe writes via AtomicWrite
- Batch and single-track editing work for both formats
**Should have (differentiators):**
- Progress indicator for batch operations (20+ files)
- Auto-number tracks in batch edit
- Cover art remove (strip embedded art)
- Dirty indicator / unsaved changes warning
- Album artist, comment, lyrics field editing (low-effort additions)
- Total tracks / total discs fields
- OGG cover art via METADATA_BLOCK_PICTURE (base64-encoded FLAC picture block)
- WAV cover art via ID3v2 APIC frame (identical to MP3)
- Preserve existing RIFF INFO chunks when writing ID3v2 to WAV
- Round-trip test coverage (7 tests per format, following FLAC precedent)
**Defer (v2+):**
- MusicBrainz auto-tagging (separate milestone already in PROJECT.md)
- Undo/backup system for tag edits
- Cover art paste from clipboard
- Inline editing in track list columns (fragile UX, complex)
- Raw tag frame editing, custom fields, filename renaming
- OGG Vorbis tag writing (implement last due to custom work required)
- RIFF INFO writing (lossy — can't represent album_artist, disc_number, or cover art)
- Dual-write ID3v2 + RIFF INFO in WAV
- Migrating deprecated OGG `COVERART` field to `METADATA_BLOCK_PICTURE`
- RF64 (>4GB WAV) support
- OGG Opus tag writing (different header structure from Vorbis)
### Architecture Approach
Tag editing is implemented as a new `backend/tageditor/` package that orchestrates the full write pipeline, keeping existing packages focused on their current responsibilities. The service exposes `EditTrack()`, `EditTracks()`, and `SetCoverArt()` as Wails bindings. It uses pointer fields (`*string`, `*int`) to distinguish "no change" (nil) from "set to empty" — mapping directly to the three-state UI model for batch editing.
Both writers integrate into the existing pipeline with minimal modification: add two format constants, extend the `DetectFormat()` switch, and add two cases to the `WriteTrackTags()` format dispatch. No new interfaces, no refactoring. The frontend is completely format-agnostic and requires zero changes.
**Major components:**
1. **`backend/tageditor/tageditor.go`** — Service orchestrator: validates input, coordinates file write → DB update → FTS5 → events
2. **`backend/tageditor/writer.go`** — Format-specific tag writing (MP3 via bogem/id3v2, FLAC via go-flac, OGG via custom)
3. **`backend/events/events.go`** (modified) — New `TagsUpdated` and `TagEditFailed` event constants
4. **`frontend/src/components/track-details/`** (modified) — Wire existing edit UI stub to backend, add batch edit variant
5. **`frontend/src/store/library-store.ts`** (modified) — Listen for `TagsUpdated` event, full re-fetch on change
1. **`ogg.go`** (~350 LOC) — OGG page parser/writer, Vorbis Comment serializer, CRC32, METADATA_BLOCK_PICTURE encoding, `writeOggTags()` orchestrator
2. **`wav.go`** (~200 LOC) — RIFF chunk parser/writer, ID3v2 tag in `id3 ` chunk via `bogem/id3v2`, `writeWavTags()` orchestrator
3. **`tagwriter.go` + `pipeline.go`** (~15 LOC changes) — Format constants, detection, dispatch
4. **`ogg_test.go` + `wav_test.go`** (~600 LOC) — 7 round-trip tests each, following FLAC pattern
**Key patterns:**
- Write-to-temp-then-rename (temp in same directory as target)
- Upsert-and-relink for shared entities (never mutate shared artist/album/genre rows)
- Pointer fields for optional partial updates
- Lazy orphan cleanup (defer to next rescan)
**Key code reuse:**
- Vorbis Comment field mapping: identical to FLAC (extract shared helpers from `flac.go`)
- ID3v2 tag building for WAV: identical to MP3 (`applyTextChanges()`, `applyCoverArtChanges()`)
- AtomicWrite: used as-is by both writers
- `dhowden/tag` for read-back verification in tests
### Critical Pitfalls
1. **FTS5 contentless index can't delete rows (P3)**Migrate to `contentless_delete=1` before writing any tag edit code. Without this, search returns stale results after every edit. This is a prerequisite schema migration.
2. **FLAC requires full file rewrite (P1)** — No in-place edit possible. Write-to-temp-then-rename is mandatory. Temp file must be in the same directory for atomic rename. Verify written file before replacing original.
3. **Shared entity fan-out (P4)**Editing one track's artist must NOT modify the shared `artist_credit` row (would silently change 200 other tracks). Always create new entity rows and repoint the edited track's foreign keys.
4. **Currently-playing file lock (P2)** — On Windows, `os.Rename()` fails if the player holds an open file handle. Must check player state and stop playback before editing the current track.
5. **Scan/edit race condition (P5)**A library scan running during tag editing can overwrite changes. Pause scan during edits using the existing `PauseScan()`/`ResumeScan()` mechanism.
1. **OGG CRC32 non-standard bit ordering (P1)**OGG uses MSB-first CRC32 with polynomial 0x04c11db7. Go's `hash/crc32` uses reflected (LSB-first) ordering and produces wrong checksums. Must implement custom CRC or port from `jfreymuth/oggvorbis/crc.go`.
2. **OGG page sequence number continuity (P2)**Rewriting comment header may change the number of header pages, requiring all subsequent page sequence numbers to be renumbered. Use full-stream rewrite approach (correct by construction).
3. **OGG granule position preservation (P3)**Header pages must have granule position 0; audio pages must preserve original granule positions exactly. Corruption here breaks seeking and duration reporting.
4. **WAV RIFF chunk size updates (P6)** — Adding or resizing the `id3 ` chunk requires updating the outer RIFF header size field. Wrong size makes the file appear truncated to some players.
5. **WAV chunk word alignment (P10)** — RIFF chunks must start at even byte offsets. Odd-length chunks need a padding byte that's NOT included in the chunk's size field but IS part of the physical file.
### WAV Metadata Approach Decision
Research revealed a tension between two approaches:
- **RIFF INFO:** Native WAV format, simple, but can't represent album_artist, disc_number, or cover art
- **ID3v2-in-WAV:** Reuses existing `bogem/id3v2`, full field + cover art support, read by `dhowden/tag`
**Decision: ID3v2-in-WAV.** This gives full field parity with MP3, enables cover art, reuses existing code, and round-trips through `dhowden/tag` (our reader). RIFF INFO is preserved when present but not written to.
## Implications for Roadmap
Based on research, suggested phase structure:
### Phase 1: Schema Migration & Write Safety Foundation
### Phase 1: WAV Tag Writer
**Rationale:** Lower risk, faster to implement. Reuses existing `bogem/id3v2` library and `applyTextChanges()`/`applyCoverArtChanges()` from MP3 writer. RIFF container is simpler than OGG (no checksums, no page segmentation). Building this first proves the pipeline extension pattern works before tackling the harder OGG format.
**Delivers:** WAV text tag writing (all 8 fields) + cover art + round-trip tests
**Addresses:** WAV table stakes + WAV cover art (differentiator, but trivial since it reuses MP3 APIC code)
**Avoids:** P5 (use ID3v2, not RIFF INFO), P6 (careful RIFF size bookkeeping), P10 (chunk alignment padding)
**New code:** ~200 LOC `wav.go` + ~250 LOC `wav_test.go` + ~15 LOC pipeline changes
**Estimated effort:** Small — RIFF parsing is straightforward binary parsing
**Rationale:** The FTS5 migration (P3) is a hard prerequisite — without `contentless_delete=1`, tag edits degrade search quality. The atomic file write mechanism (P1, P6) is the foundation all tag writing depends on. These are small, testable, independent pieces that de-risk everything downstream.
**Delivers:** FTS5 schema migration; atomic write-to-temp-then-rename utility; temp file cleanup on startup
**Addresses:** Write-to-temp-then-rename (table stakes), FTS5 inline update capability
**Avoids:** P3 (stale search), P1 (file corruption), P6 (cross-filesystem rename failure)
### Phase 2: OGG Vorbis Text Tag Writer
**Rationale:** OGG requires the most new infrastructure (page parser, CRC32, segmentation). Text-only tag writing exercises all the hard parts (page rewrite, CRC, sequence numbers) without the added complexity of multi-page comment packets from large cover art. This is the riskiest phase and benefits from Phase 1 having proven the pipeline extension works.
**Delivers:** OGG Vorbis text tag writing (all 8 fields) + round-trip tests
**Addresses:** OGG text field table stakes, audio data preservation, existing comment preservation
**Avoids:** P1 (CRC32), P2 (sequence numbers), P3 (granule positions), P4 (three-header structure), P7 (framing bit), P8 (packet prefix)
**New code:** ~300 LOC `ogg.go` (page infra + text writer) + ~300 LOC `ogg_test.go`
**Estimated effort:** Medium — OGG page infrastructure is the hardest new code in this milestone
### Phase 2: Tag Writing Library Integration
### Phase 3: OGG Vorbis Cover Art
**Rationale:** Separated from Phase 2 because it adds multi-page packet complexity (large base64-encoded images can exceed the ~64KB OGG page limit). Text fields exercise the page infrastructure with small comment packets; cover art stress-tests it with large ones. Can be deferred if Phase 2 runs long without blocking the milestone.
**Delivers:** OGG Vorbis cover art embed/remove via METADATA_BLOCK_PICTURE
**Addresses:** OGG cover art differentiator
**Avoids:** P9 (METADATA_BLOCK_PICTURE format), P15 (multi-page segmentation for large payloads)
**New code:** ~50 LOC additions to `ogg.go` + ~50 LOC additions to `ogg_test.go`
**Estimated effort:** Small if Phase 2's page infrastructure is solid; medium if multi-page edge cases surface
**Rationale:** With the write safety layer in place, integrate the format-specific tag writing libraries. MP3 first (most common format, best library), then FLAC. This phase is pure backend — no UI changes yet. Unit tests with real audio files validate round-trip correctness.
**Delivers:** `backend/tageditor/writer.go` with MP3 + FLAC tag writing; encoding handling (P7); cover art embedding capability
**Uses:** `bogem/id3v2/v2`, `go-flac/go-flac/v2` + `go-flac/flacvorbis/v2` + `go-flac/flacpicture`
**Avoids:** P7 (encoding mismatch), P8 (cover art format issues), P12 (dhowden/tag is read-only)
### Phase 3: Single Track Edit Pipeline
**Rationale:** Wire the full pipeline end-to-end for a single track: backend service → file write → DB entity update → FTS5 re-index → event emission → frontend refresh. This is the core loop that all other features build on. Includes the shared entity upsert-and-relink pattern (P4) and genre dual-representation sync (P10).
**Delivers:** `backend/tageditor/tageditor.go` service; `EditTrack()` Wails binding; wired `track-details` save handler; `TagsUpdated` event; library store refresh
**Implements:** Tageditor service, DB update logic, event system, frontend integration
**Avoids:** P4 (shared entity mutation), P5 (scan race), P10 (genre mismatch), P11 (partial failure), P17 (stale frontend cache)
### Phase 4: Cover Art Editing
**Rationale:** Cover art embedding builds on Phase 2's writer and Phase 3's pipeline but adds image validation, the cover art cache pipeline integration, and file picker UX. Separated because cover art has its own pitfalls (P8, P13) and is independently testable.
**Delivers:** `SetCoverArt()` binding; image resize/validation before embed; cover art cache invalidation and thumbnail regeneration; cover art remove capability
**Avoids:** P8 (oversized images, format issues), P13 (stale cached thumbnails)
### Phase 5: Batch Editing
**Rationale:** Batch editing is the highest-complexity UI feature (three-state field model, mixed-value indicators, progress tracking). It depends on the single-track pipeline being solid. The backend is straightforward (loop over `EditTrack()`), but the frontend UX is where the complexity lives.
**Delivers:** Batch edit dialog with three-state fields; `EditTracks()` binding; progress indicator; auto-number tracks; confirmation dialog for destructive batch operations
**Addresses:** Batch editing (table stakes), progress indicator (differentiator), auto-number (differentiator)
**Avoids:** P9 (orphan entity accumulation — run cleanup after batch), P14 (no undo — confirmation dialog)
### Phase 6: OGG Vorbis Tag Writing (Stretch)
**Rationale:** OGG tag writing requires a custom OGG page rewriter — MEDIUM-HIGH complexity with no library support. The Vorbis Comment serialization is shared with FLAC (Phase 2), so only the OGG page framing is new. This can ship after the core MP3/FLAC editing is stable.
**Delivers:** Custom OGG page rewriter; OGG Vorbis tag writing support; full format coverage (MP3 + FLAC + OGG)
**Avoids:** Scope creep — if OGG proves too complex, MP3 + FLAC cover the vast majority of user libraries
### Phase 4: Edge Cases and Cleanup
**Rationale:** Validation and hardening after core functionality works. Adds detection/rejection of unsupported edge cases, size warnings, and documentation updates.
**Delivers:** RF64 detection, multi-stream OGG detection, large file warnings, PROJECT.md updates
**Addresses:** P13 (multi-stream OGG), P16 (RF64 WAV), P12 (disk space for large files)
**New code:** ~30 LOC validation checks + documentation updates
**Estimated effort:** Small
### Phase Ordering Rationale
- **Schema migration first** because FTS5 `contentless_delete=1` is a hard prerequisite that must be in place before any DB update code is written for tag editing.
- **Write safety before tag libraries** because the atomic write mechanism is tested independently of any format-specific code.
- **MP3 before FLAC before OGG** because library quality/maturity decreases in that order, and MP3 covers the largest user base.
- **Single track before batch** because batch editing is N × single with UI complexity on top — the underlying pipeline must be solid.
- **Cover art as a separate phase** because it has independent pitfalls (image validation, cache invalidation) and is testable in isolation.
- **OGG last** because it requires custom implementation and MP3 + FLAC cover the majority of use cases.
- **WAV before OGG:** WAV is lower risk (reuses existing ID3v2 library, simpler container) and proves the pipeline extension pattern. OGG requires all-new page infrastructure with correctness-critical CRC and sequencing.
- **OGG text before OGG cover art:** Text fields exercise the page rewrite with small comment packets. Cover art adds multi-page complexity that should only be attempted once the core page infrastructure is validated by round-trip tests.
- **Edge cases last:** Detection/rejection of unusual files (RF64, multi-stream) is low risk and low effort — just validation guards at file-open time.
### Research Flags
Phases likely needing deeper research during planning:
- **Phase 2 (Tag Writing):** `go-flac` libraries have smaller communities (44 stars) — verify FLAC write round-trip with edge cases (large files, existing padding blocks, multiple PICTURE blocks) during implementation.
- **Phase 6 (OGG Writing):** Custom OGG page rewriter needs specification-level research (OGG framing RFC). Consider prototyping before committing to scope.
- **Phase 2 (OGG text writer):** The OGG page re-segmentation and CRC implementation is the most complex new code. The spec is clear, but implementation details (lacing values, continuation flags, packet splitting across pages) benefit from studying `jfreymuth/oggvorbis` source as reference. Phase-level research recommended.
Phases with standard patterns (skip research-phase):
- **Phase 1 (Schema Migration):** Well-documented SQLite FTS5 migration. `contentless_delete=1` is a one-line schema change.
- **Phase 3 (Single Track Edit):** The architecture is fully designed — pointer fields, upsert-and-relink, event emission are all standard Go/Wails patterns.
- **Phase 5 (Batch Editing):** The three-state field model is well-understood from foobar2000/MusicBee analysis. Frontend-heavy but no novel backend work.
- **Phase 1 (WAV writer):** RIFF parsing is trivial; ID3v2 tag generation reuses existing code. Well-documented, no unknowns.
- **Phase 3 (OGG cover art):** METADATA_BLOCK_PICTURE format is well-specified; base64 encoding is trivial. Only depends on Phase 2's page infrastructure being correct.
- **Phase 4 (edge cases):** Simple validation checks with clear specifications.
## Confidence Assessment
| Area | Confidence | Notes |
|------|------------|-------|
| Stack | HIGH | MP3 library (bogem/id3v2) verified via pkg.go.dev docs with 359 stars/57 importers. FLAC libraries verified via GitHub READMEs. OGG is the only gap (custom work). |
| Features | HIGH | Cross-referenced 5 desktop music players + Hydrogenaudio tag standards + existing codebase analysis. Table stakes are unambiguous. |
| Architecture | HIGH | Based on full codebase analysis — every integration point verified against actual source files (library.go, search.go, tags.go, track-details.ts, player.go). |
| Pitfalls | HIGH | All critical pitfalls derived from format specifications (FLAC, ID3v2, OGG, FTS5) and codebase analysis (shared entities, file locking, scan race). Mitigations are concrete. |
| Stack | HIGH | Zero new dependencies; all recommendations based on official specs and existing codebase analysis |
| Features | HIGH | Feature set derived from official format specs (Xiph.org, RIFF) and existing codebase field model |
| Architecture | HIGH | Full codebase analysis confirms pipeline was designed for format extension; minimal changes needed |
| Pitfalls | HIGH | Pitfalls sourced from official OGG/RIFF specs, cross-referenced with existing library implementations |
**Overall confidence:** HIGH
### Gaps to Address
- **OGG Vorbis tag writing:** No pure-Go library exists. Custom implementation complexity is estimated at MEDIUM-HIGH but not prototyped. Validate feasibility during Phase 6 planning — consider whether OGG support is worth the custom code, or whether to accept MP3+FLAC-only for v1.2.
- **`go-flac` edge cases:** The go-flac library has 44 stars and a small community. Round-trip testing with edge-case FLAC files (files with existing PADDING blocks, multiple PICTURE blocks, unusual metadata block orders) should be done early in Phase 2 to surface any library bugs.
- **Windows file locking behavior:** The currently-playing-file lock (P2) is well-understood conceptually but the exact interaction between Go's `os.Open`, beep's streamer, and Windows mandatory locking needs validation on a Windows build.
- **Album artist storage:** FEATURES.md notes album artist editing is low-hanging fruit, but ARCHITECTURE.md flags that album artist isn't currently stored as a separate entity. Schema implications should be resolved during Phase 3 planning.
- **`bogem/id3v2` WAV compatibility:** The library's `Open()`/`Save()` API expects MP3 file structure. For WAV, we'll need to use `ParseReader()` to read existing ID3v2 tags from a byte slice, and `WriteTo()` to serialize the tag to bytes for embedding in the RIFF chunk. This needs validation during Phase 1 implementation — if `ParseReader` doesn't work for standalone tag parsing, we may need to create tags from scratch (losing existing ID3v2 data in the WAV).
- **OGG test fixture creation:** Cannot programmatically generate a valid OGG Vorbis file (requires Vorbis codebook data in setup header). Need to embed a minimal OGG fixture via `//go:embed`. Can be created once with ffmpeg during Phase 2 setup.
- **Multi-stream OGG prevalence:** Research confirms multi-stream OGG music files are extremely rare, but we should detect and reject them rather than silently corrupting. Validation during Phase 2.
## Sources
### Primary (HIGH confidence)
- `bogem/id3v2` (n10v/id3v2): https://pkg.go.dev/github.com/bogem/id3v2/v2 — API docs, v2.1.4, write support verified
- `go-flac/go-flac`: https://github.com/go-flac/go-flac — metadata manipulation, Save() copies audio frames as raw bytes
- `go-flac/flacvorbis`: https://github.com/go-flac/flacvorbisVorbis Comment add/parse/marshal
- `go-flac/flacpicture`: https://github.com/go-flac/flacpicture — PICTURE block creation from image data
- SQLite FTS5 docs: https://www.sqlite.org/fts5.html — contentless tables, contentless_delete=1
- FLAC format spec: https://www.xiph.org/flac/format.htmlmetadata block structure
- Vorbis Comment spec: https://www.xiph.org/vorbis/doc/v-comment.html — field format
- OGG framing spec: https://www.xiph.org/ogg/doc/framing.html — page structure
- Hydrogenaudio Tag Mapping: https://wiki.hydrogenaud.io/index.php/Tag_Mapping — field name standards
- YellowJacket codebase: library.go, search.go, tags.go, player.go, track-details.ts, schema files — architecture analysis
- OGG framing specification: https://xiph.org/ogg/doc/framing.html
- OGG RFC 3533: https://xiph.org/ogg/doc/rfc3533.txt
- Vorbis I Specification (comment field): https://xiph.org/vorbis/doc/Vorbis_I_spec.html
- Vorbis Comment specification: https://xiph.org/vorbis/doc/v-comment.html
- METADATA_BLOCK_PICTURE: https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
- FLAC Picture block format: https://xiph.org/flac/format.html#metadata_block_picture
- RIFF/WAV format: https://www.mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html
### Secondary (MEDIUM confidence)
- `dhowden/tag`: https://github.com/dhowden/tag — confirmed read-only, no write API
- `mewkiz/flac`: https://github.com/mewkiz/flac — confirmed codec (encoder/decoder), unsuitable for metadata-only writes
- `jfreymuth/oggvorbis`: https://github.com/jfreymuth/oggvorbis — confirmed decode-only
- MusicBee, foobar2000, Kid3, Mp3tag, Picard — feature pattern analysis
- WAV metadata overview: https://en.wikipedia.org/wiki/WAV#Metadata
- RIFF tag reference: https://exiftool.org/TagNames/RIFF.html
### Tertiary (LOW confidence)
- OGG Vorbis custom writer feasibility — estimated MEDIUM-HIGH complexity based on spec analysis, not prototyped
### Libraries (HIGH confidence — direct code review)
- `jfreymuth/oggvorbis` v1.0.5: OGG page reader reference, CRC32 lookup table
- `dhowden/tag`: Reads OGG + WAV tags; validates round-trip correctness
- `bogem/id3v2` v2.1.4: ID3v2 tag generation for WAV `id3 ` chunks
- `go-flac/flacpicture` v2.0.2: FLAC picture block builder, reused for OGG METADATA_BLOCK_PICTURE
- `go-audio/wav` (ARCHIVED 2026-02-21): Evaluated and rejected
- `mccoyst/ogg` (37 stars, no semver): Evaluated and rejected — marginal benefit vs dependency risk
### Codebase (HIGH confidence — validated in v1.2)
- `backend/tagwriter/flac.go` — Vorbis Comment manipulation patterns to reuse
- `backend/tagwriter/mp3.go` — ID3v2 + AtomicWrite patterns to reuse for WAV
- `backend/tagwriter/pipeline.go` — Format dispatch switch to extend
- `backend/tagwriter/tagwriter.go` — TagChanges model, format detection, helpers
- `backend/fileutil/atomicwrite.go` — Crash-safe file write utility
---
*Research completed: 2026-03-16*
*Research completed: 2026-03-18*
*Ready for roadmap: yes*