docs(16-03): complete WriteTrackTags pipeline plan
- SUMMARY.md with pipeline architecture, 5 tests, 7 files - STATE.md: Phase 16 complete (3/3), decisions, session - ROADMAP.md: Phase 16 marked complete - REQUIREMENTS.md: SYNC-01/02/03/04 and WRITE-06 marked complete
This commit is contained in:
+10
-10
@@ -19,14 +19,14 @@ Requirements for v1.2 Tag Editing milestone. Each maps to roadmap phases.
|
||||
- [ ] **WRITE-03**: Write metadata tags to OGG Vorbis files via custom page rewriter
|
||||
- [x] **WRITE-04**: Embed cover art image (JPEG/PNG) in MP3 and FLAC files
|
||||
- [x] **WRITE-05**: All file writes use atomic write-to-temp-then-rename to prevent corruption
|
||||
- [ ] **WRITE-06**: Currently-playing file is stopped before writing (player safety)
|
||||
- [x] **WRITE-06**: Currently-playing file is stopped before writing (player safety)
|
||||
|
||||
### Database Sync
|
||||
|
||||
- [ ] **SYNC-01**: After tag write, update DB entities inline (upsert-and-relink for artist, album, genre)
|
||||
- [ ] **SYNC-02**: After tag write, update FTS5 search index for affected tracks
|
||||
- [ ] **SYNC-03**: Orphaned entities (artists, albums, genres no longer referenced) cleaned up
|
||||
- [ ] **SYNC-04**: Scan pipeline paused during tag writes to prevent race conditions
|
||||
- [x] **SYNC-01**: After tag write, update DB entities inline (upsert-and-relink for artist, album, genre)
|
||||
- [x] **SYNC-02**: After tag write, update FTS5 search index for affected tracks
|
||||
- [x] **SYNC-03**: Orphaned entities (artists, albums, genres no longer referenced) cleaned up
|
||||
- [x] **SYNC-04**: Scan pipeline paused during tag writes to prevent race conditions
|
||||
|
||||
### Single Track Edit
|
||||
|
||||
@@ -98,11 +98,11 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
| WRITE-03 | Phase 19 | Pending |
|
||||
| WRITE-04 | Phase 16 | Complete |
|
||||
| WRITE-05 | Phase 15 | Complete |
|
||||
| WRITE-06 | Phase 16 | Pending |
|
||||
| SYNC-01 | Phase 16 | Pending |
|
||||
| SYNC-02 | Phase 16 | Pending |
|
||||
| SYNC-03 | Phase 16 | Pending |
|
||||
| SYNC-04 | Phase 16 | Pending |
|
||||
| WRITE-06 | Phase 16 | Complete |
|
||||
| SYNC-01 | Phase 16 | Complete |
|
||||
| SYNC-02 | Phase 16 | Complete |
|
||||
| SYNC-03 | Phase 16 | Complete |
|
||||
| SYNC-04 | Phase 16 | Complete |
|
||||
| EDIT-01 | Phase 17 | Pending |
|
||||
| EDIT-02 | Phase 17 | Pending |
|
||||
| EDIT-03 | Phase 17 | Pending |
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
### v1.2 Tag Editing (Phases 15-19)
|
||||
|
||||
- [x] **Phase 15: Schema Migration & Write Safety** — FTS5 contentless_delete migration and atomic file write utility (completed 2026-03-16)
|
||||
- [ ] **Phase 16: Tag Writing & Database Sync** — Format-specific tag writers (MP3, FLAC, cover art) with inline DB + FTS5 update pipeline (3 plans)
|
||||
- [x] **Phase 16: Tag Writing & Database Sync** — Format-specific tag writers (MP3, FLAC, cover art) with inline DB + FTS5 update pipeline (3 plans) (completed 2026-03-17)
|
||||
- [ ] **Phase 17: Single Track Edit** — End-to-end single track editing: UI → file write → DB sync → view refresh
|
||||
- [ ] **Phase 18: Batch Edit** — Multi-select batch editing with three-state field model, progress, and batch cover art
|
||||
- [ ] **Phase 19: OGG Vorbis Tag Writing** — Custom OGG page rewriter for Vorbis Comment tag writing (stretch)
|
||||
@@ -72,7 +72,7 @@ Plans:
|
||||
3. Cover art images (JPEG/PNG) can be embedded in both MP3 and FLAC files — the embedded image is readable back and the existing cover art pipeline (extraction, thumbnails) works with the newly embedded art
|
||||
4. After a tag write, the database reflects the new metadata within the same operation: artist/album/genre entities are created or relinked (never mutated in-place), orphaned entities with zero remaining references are cleaned up, and the FTS5 index is updated — no library rescan needed
|
||||
5. If the currently-playing track is being edited, playback is stopped before the file write begins — the user does not experience a crash or corrupted audio stream
|
||||
**Plans:** 2/3 plans executed
|
||||
**Plans:** 3/3 plans complete
|
||||
Plans:
|
||||
- [ ] 16-01-PLAN.md — Tagwriter foundation + sqlc queries + MP3 writer (Wave 1)
|
||||
- [ ] 16-02-PLAN.md — FLAC writer with go-flac ecosystem (Wave 1)
|
||||
@@ -129,7 +129,7 @@ Plans:
|
||||
| 13. Library Views & Phantom Tracks | v1.1 | 2/2 | Complete | 2026-03-16 |
|
||||
| 14. Performance Optimization | v1.1 | 4/4 | Complete | 2026-03-15 |
|
||||
| 15. Schema Migration & Write Safety | 2/2 | Complete | 2026-03-16 | - |
|
||||
| 16. Tag Writing & Database Sync | 2/3 | In Progress| | - |
|
||||
| 16. Tag Writing & Database Sync | 3/3 | Complete | 2026-03-17 | - |
|
||||
| 17. Single Track Edit | v1.2 | 0/? | Not started | - |
|
||||
| 18. Batch Edit | v1.2 | 0/? | Not started | - |
|
||||
| 19. OGG Vorbis Tag Writing | v1.2 | 0/? | Not started | - |
|
||||
|
||||
+19
-14
@@ -2,13 +2,13 @@
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.2
|
||||
milestone_name: Tag Editing
|
||||
status: unknown
|
||||
last_updated: "2026-03-17T14:42:46.662Z"
|
||||
status: in-progress
|
||||
last_updated: "2026-03-17T14:55:31Z"
|
||||
progress:
|
||||
total_phases: 2
|
||||
completed_phases: 1
|
||||
completed_phases: 2
|
||||
total_plans: 5
|
||||
completed_plans: 4
|
||||
completed_plans: 5
|
||||
---
|
||||
|
||||
# YellowJacket — Project State
|
||||
@@ -22,17 +22,17 @@ See: .planning/PROJECT.md (updated 2026-03-16)
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: Phase 16 — Tag Writing & Database Sync (in progress)
|
||||
Plan: 2 of 3 complete
|
||||
Status: Executing Phase 16 plans — Plans 01 (MP3 writer + sqlc) and 02 (FLAC writer) complete
|
||||
Last activity: 2026-03-17 — Completed 16-01 (MP3 writer + orphan queries)
|
||||
Phase: Phase 16 — Tag Writing & Database Sync (complete)
|
||||
Plan: 3 of 3 complete
|
||||
Status: Phase 16 complete — all 3 plans done (MP3 writer, FLAC writer, WriteTrackTags pipeline)
|
||||
Last activity: 2026-03-17 — Completed 16-03 (WriteTrackTags pipeline + DB sync)
|
||||
|
||||
### Phase Overview
|
||||
|
||||
| Phase | Status |
|
||||
|-------|--------|
|
||||
| 15. Schema Migration & Write Safety | Complete (2/2 plans) |
|
||||
| 16. Tag Writing & Database Sync | In Progress (2/3 plans) |
|
||||
| 16. Tag Writing & Database Sync | Complete (3/3 plans) |
|
||||
| 17. Single Track Edit | Not started |
|
||||
| 18. Batch Edit | Not started |
|
||||
| 19. OGG Vorbis Tag Writing | Not started |
|
||||
@@ -61,6 +61,7 @@ Last activity: 2026-03-17 — Completed 16-01 (MP3 writer + orphan queries)
|
||||
| 15 | 02 | 16min | 2 | 2 |
|
||||
| 16 | 01 | 28min | 2 | 14 |
|
||||
| 16 | 02 | 20min | 2 | 6 |
|
||||
| 16 | 03 | 9min | 2 | 7 |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@@ -88,6 +89,10 @@ Decisions from v1.0 and v1.1 are archived in PROJECT.md Key Decisions table. Key
|
||||
| `replaceVorbisComment` as filter+add pattern | flacvorbis has no Set/Replace — must remove existing entries then Add new value |
|
||||
| id3v2 WriteTo + manual audio copy for AtomicWrite | `tag.Save()` writes to original file; use `WriteTo(tmp)` + seek past tag + `io.Copy` audio data |
|
||||
| Snapshot tag size before `id3v2.Open()` | `originalSize` is unexported; read 10-byte ID3v2 header and decode synchsafe size ourselves |
|
||||
| PlayerStopper interface for tagwriter→player decoupling | Breaks import cycle; playerAdapter in app.go wraps *player.Player |
|
||||
| pipelineMu sync.Mutex for scan/write mutual exclusion | Simple mutex on Library; both scan and write pipelines acquire at start, release at end |
|
||||
| FTS5 delete+insert within DB transaction | Execute directly on *sql.Tx for atomicity with entity relink |
|
||||
| Global genre orphan cleanup via DELETE WHERE id NOT IN | Simpler than tracking old genre IDs; safe because genres only referenced via recording_genres |
|
||||
|
||||
### v1.2 Roadmap Decisions
|
||||
|
||||
@@ -117,7 +122,7 @@ Decisions from v1.0 and v1.1 are archived in PROJECT.md Key Decisions table. Key
|
||||
|
||||
- ~~**Phase 16:** go-flac libraries (44 stars) — verify round-trip with edge-case FLAC files early~~ — **RESOLVED: 16-02 completed** — 7 round-trip tests pass, dhowden/tag reads what go-flac writes
|
||||
- **Phase 19:** Custom OGG page rewriter — prototype before committing; consider dropping if too complex
|
||||
- **Phase 16:** Album artist storage — not currently a separate entity; resolve during planning
|
||||
- ~~**Phase 16:** Album artist storage — not currently a separate entity; resolve during planning~~ — **RESOLVED: 16-CONTEXT.md** — Album artist stays as text field on audio_files, no new entity table
|
||||
|
||||
### Deferred Improvements
|
||||
|
||||
@@ -128,9 +133,9 @@ Decisions from v1.0 and v1.1 are archived in PROJECT.md Key Decisions table. Key
|
||||
### Last Session
|
||||
|
||||
**Date:** 2026-03-17
|
||||
**What happened:** Executed Phase 16 Plan 01 — MP3 tag writer with n10v/id3v2, orphan-counting sqlc queries, and 5 round-trip tests. Plans 01 and 02 now both complete.
|
||||
**Where we stopped:** Completed 16-01-PLAN.md — Plan 03 remaining
|
||||
**Next action:** Execute 16-03-PLAN.md (WriteTrackTags entry point + DB sync)
|
||||
**What happened:** Executed Phase 16 Plan 03 — WriteTrackTags pipeline with DB sync, player safety, scan/write mutex, events, and app wiring. Phase 16 now complete (3/3 plans).
|
||||
**Where we stopped:** Completed 16-03-PLAN.md — Phase 16 complete
|
||||
**Next action:** Plan Phase 17 (Single Track Edit UI)
|
||||
|
||||
---
|
||||
*State initialized: 2026-02-27*
|
||||
@@ -144,4 +149,4 @@ Decisions from v1.0 and v1.1 are archived in PROJECT.md Key Decisions table. Key
|
||||
| 19 | fix phantom playlist tracks with multi-root path resolution | 2026-03-16 | 9144ded | [19-fix-phantom-playlist-tracks](./quick/19-fix-phantom-playlist-tracks/) |
|
||||
|
||||
Last activity: 2026-03-16 - Completed quick task 19: fix phantom playlist tracks with multi-root path resolution
|
||||
*Last updated: 2026-03-17 — Completed 16-01 (MP3 writer + orphan queries) — Phase 16 in progress (2/3)*
|
||||
*Last updated: 2026-03-17 — Completed 16-03 (WriteTrackTags pipeline + DB sync) — Phase 16 complete (3/3)*
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
phase: 16-tag-writing-database-sync
|
||||
plan: 03
|
||||
subsystem: tagwriter, database, library
|
||||
tags: [tag-writing, db-sync, fts5, orphan-cleanup, pipeline, wails-binding, mutual-exclusion]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 16-tag-writing-database-sync
|
||||
provides: writeMp3Tags and writeFlacTags format-specific writers, TagChanges type, orphan-counting sqlc queries
|
||||
- phase: 15-schema-migration-write-safety
|
||||
provides: AtomicWrite utility, FTS5 contentless_delete=1 migration
|
||||
provides:
|
||||
- WriteTrackTags single entry point for file write + DB sync + event emission
|
||||
- syncDatabase transactional DB sync (entity relink, FTS5, orphan cleanup)
|
||||
- TagWriter Wails binding accessible from frontend
|
||||
- TrackMetadataChanged event constant (Go + TypeScript)
|
||||
- pipelineMu scan/write mutual exclusion on Library
|
||||
- PlayerStopper and PipelineLocker interfaces for dependency inversion
|
||||
affects: [17-single-track-edit, 18-batch-edit]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [pipeline-mutex, player-adapter-interface, transactional-db-sync]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- backend/tagwriter/pipeline.go
|
||||
- backend/tagwriter/dbsync.go
|
||||
- backend/tagwriter/pipeline_test.go
|
||||
modified:
|
||||
- backend/app.go
|
||||
- backend/events/events.go
|
||||
- backend/library/library.go
|
||||
- frontend/src/events.ts
|
||||
|
||||
key-decisions:
|
||||
- "PlayerStopper interface to break tagwriter→player import cycle with playerAdapter in app.go"
|
||||
- "pipelineMu sync.Mutex on Library for scan/write mutual exclusion (not RWMutex — only one pipeline at a time)"
|
||||
- "FTS5 delete+insert within same DB transaction for consistency"
|
||||
- "Global genre orphan cleanup via DELETE WHERE id NOT IN (SELECT DISTINCT genre_id FROM recording_genres)"
|
||||
|
||||
patterns-established:
|
||||
- "Pipeline mutex: AcquirePipelineLock/ReleasePipelineLock wrapping both scan and write pipelines"
|
||||
- "Transactional DB sync: single tx for entity relink + FTS5 + orphan cleanup"
|
||||
- "Player safety check: CurrentFilePath() + StopAndRelease() before file write"
|
||||
|
||||
requirements-completed: [SYNC-01, SYNC-02, SYNC-03, SYNC-04, WRITE-06]
|
||||
|
||||
# Metrics
|
||||
duration: 9min
|
||||
completed: 2026-03-17
|
||||
---
|
||||
|
||||
# Phase 16 Plan 03: WriteTrackTags Pipeline + DB Sync Summary
|
||||
|
||||
**WriteTrackTags pipeline orchestrating format-specific file write → transactional DB sync (entity relink + FTS5 + orphan cleanup) → TrackMetadataChanged event emission, with player safety and scan/write mutual exclusion**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 9 min
|
||||
- **Started:** 2026-03-17T14:46:40Z
|
||||
- **Completed:** 2026-03-17T14:55:31Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 7
|
||||
|
||||
## Accomplishments
|
||||
- Complete WriteTrackTags entry point that Phase 17's UI will call — one function does everything
|
||||
- Transactional DB sync handling artist/album/genre entity relink with upsert-and-relink pattern
|
||||
- Orphan cleanup for artist_credits, release_groups, and genres within the same transaction
|
||||
- FTS5 search index updated atomically (delete old + insert new) inside the transaction
|
||||
- Player auto-stopped before writing currently-playing file via PlayerStopper interface
|
||||
- Scan/write mutual exclusion via pipelineMu on Library (scan blocks write and vice versa)
|
||||
- TrackMetadataChanged event emitted after successful write+sync, auto-generated in TypeScript
|
||||
- TagWriter wired into app.go as Wails binding (frontend-accessible)
|
||||
- 5 integration tests covering player safety, scan mutex, orphan cleanup, genre relink, and full DB sync
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: DB sync module** - `2966079` (feat) — syncDatabase with entity relink, FTS5, orphan cleanup
|
||||
2. **Task 2: Pipeline + wiring + tests** - `64322f9` (feat) — TagWriter, player safety, events, app.go, 5 tests
|
||||
|
||||
**Plan metadata:** (this commit)
|
||||
|
||||
## Files Created/Modified
|
||||
- `backend/tagwriter/dbsync.go` — syncDatabase: transactional entity relink, FTS5 update, orphan cleanup with SAFETY comments
|
||||
- `backend/tagwriter/pipeline.go` — TagWriter struct, WriteTrackTags entry point, PlayerStopper/PipelineLocker interfaces
|
||||
- `backend/tagwriter/pipeline_test.go` — 5 integration tests with mockPlayer, mockPipelineLocker, in-memory test DB
|
||||
- `backend/app.go` — playerAdapter, NewTagWriter creation, SetContext, FEBindings registration
|
||||
- `backend/events/events.go` — TrackMetadataChanged constant
|
||||
- `backend/library/library.go` — pipelineMu field, AcquirePipelineLock/ReleasePipelineLock methods, pipelineMu wrapping scanInternal
|
||||
- `frontend/src/events.ts` — Auto-generated TrackMetadataChanged event
|
||||
|
||||
## Decisions Made
|
||||
- **PlayerStopper interface** — Defined in tagwriter package to break circular import (tagwriter cannot import player). playerAdapter in app.go wraps *player.Player to satisfy the interface.
|
||||
- **pipelineMu sync.Mutex** — Added to Library struct (not the existing `mu`). Scan acquires at start of scanInternal, write acquires before file write. Both defer unlock. Simple mutex (not RWMutex) because only one pipeline should run at a time.
|
||||
- **FTS5 within transaction** — Execute FTS5 DELETE/INSERT directly on `*sql.Tx` rather than through DB helper methods, ensuring they're part of the same atomic operation.
|
||||
- **Global genre orphan cleanup** — Instead of tracking old genre IDs (which requires extra bookkeeping since genres are deleted before re-linking), use `DELETE FROM genres WHERE id NOT IN (SELECT DISTINCT genre_id FROM recording_genres)`. Safe and complete.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
None
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Phase 16 complete (all 3 plans done) — MP3 writer, FLAC writer, and WriteTrackTags pipeline
|
||||
- Ready for Phase 17 (Single Track Edit UI) which calls WriteTrackTags from the frontend
|
||||
- All format-specific writers, DB sync, player safety, and scan mutex are tested and lint-clean
|
||||
|
||||
---
|
||||
*Phase: 16-tag-writing-database-sync*
|
||||
*Completed: 2026-03-17*
|
||||
Reference in New Issue
Block a user