docs(phase-18): complete phase execution
This commit is contained in:
@@ -140,7 +140,7 @@ Plans:
|
||||
| 15. Schema Migration & Write Safety | 2/2 | Complete | 2026-03-16 | - |
|
||||
| 16. Tag Writing & Database Sync | 3/3 | Complete | 2026-03-17 | - |
|
||||
| 17. Single Track Edit | 2/2 | Complete | 2026-03-18 | - |
|
||||
| 18. Batch Edit | 2/2 | Complete | 2026-03-18 | - |
|
||||
| 18. Batch Edit | 2/2 | Complete | 2026-03-18 | - |
|
||||
| 19. OGG Vorbis Tag Writing | v1.2 | 0/? | Not started | - |
|
||||
|
||||
---
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.2
|
||||
milestone_name: Tag Editing
|
||||
status: in-progress
|
||||
last_updated: "2026-03-18T18:30:00Z"
|
||||
status: unknown
|
||||
last_updated: "2026-03-18T17:56:56.447Z"
|
||||
progress:
|
||||
total_phases: 4
|
||||
completed_phases: 4
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
phase: 18-batch-edit
|
||||
verified: 2026-03-18T19:00:00Z
|
||||
status: passed
|
||||
score: 10/10 must-haves verified
|
||||
gaps: []
|
||||
human_verification: []
|
||||
---
|
||||
|
||||
# Phase 18: Batch Edit Verification Report
|
||||
|
||||
**Phase Goal:** Users can efficiently edit shared metadata across multiple tracks at once with clear visual feedback and safe defaults
|
||||
**Verified:** 2026-03-18T19:00:00Z
|
||||
**Status:** passed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| 1 | Selecting 2+ tracks and clicking Track Details opens a batch summary view showing 'N tracks selected' header | ✓ VERIFIED | All 4 views (track-list, cover-grid, queue-panel, playlist-details) branch on `filePaths.length === 1` vs else in `onContextMenuAction`, calling `openBatchTrackDetails()` → `showBatch()`. Header renders `${this.batchTracks.length} tracks selected` (line 879). |
|
||||
| 2 | Each field shows shared value (if identical) or 'Multiple values' placeholder (if different) | ✓ VERIFIED | `getMergedFields()` (lines 1997–2082) extracts values per-track, computes `unique = new Set(values)`, sets `mixed: !allSame`. Render shows `${this.countDistinctValues(key)} different values` for mixed, actual value otherwise. |
|
||||
| 3 | In edit mode, typing marks field dirty; only dirty fields are sent as TagChanges | ✓ VERIFIED | `onEditInput()` (lines 1983–1990) adds key to `editValues` on any input. `buildBatchChanges()` (lines 1819–1878) only includes keys present in `editValues`. Untouched fields are never in `editValues`. |
|
||||
| 4 | Clearing a field (empty string) is distinct from 'untouched' — it sends the clear | ✓ VERIFIED | `buildBatchChanges()` checks `if (editKey in this.editValues)` — an empty string IS in editValues (set by `onEditInput`), so it's included. Confirmation shows "Clear {label}" for empty values (line 2128). |
|
||||
| 5 | Confirmation dialog appears before save showing fields and track count | ✓ VERIFIED | `saveBatchEdit()` (line 1587) sets `showConfirmation = true`. `renderConfirmation()` (lines 1011–1044) shows "Apply changes to N tracks?" with per-field change summary from `getConfirmationSummary()`. |
|
||||
| 6 | During batch save, progress bar and 'N of M tracks' counter visible | ✓ VERIFIED | `confirmSave()` sets `batchProgress`, registers `EventsOn(Events.BatchWriteProgress, ...)` (lines 1617–1628). `renderBatchProgress()` (lines 1046–1072) shows `${progress.current} of ${progress.total} tracks` with a CSS-animated progress bar. |
|
||||
| 7 | Cancel button stops batch; already-written tracks keep changes | ✓ VERIFIED | `cancelBatchWrite()` (line 1669) calls `CancelBatchWrite()` Wails binding. Backend `CancelBatchWrite()` (lines 207–219) closes `cancelBatch` channel. `BatchWriteTrackTags` checks channel before each track (lines 252–262); cancelled tracks are skipped, already-written tracks are not reverted. |
|
||||
| 8 | Partial failures show summary with success count and per-failure details | ✓ VERIFIED | `renderBatchResult()` (lines 1074–1125) shows success/failure counts. Failures displayed in expandable `<details>` with file name and error per failure. Backend `BatchResult.Failures` collects per-track errors. |
|
||||
| 9 | Cover art can be set or cleared for all selected tracks at once | ✓ VERIFIED | `renderBatchCoverArt()` calls `renderCoverArtEditable()` in edit mode (line 769), which provides pick/remove controls. `buildBatchChanges()` includes `cover_art` key from `pendingCoverArt` (set) or `clearCoverArt` (remove) — same logic as single-track. Backend applies cover_art change per-track via `WriteTrackTagsByPath`. |
|
||||
| 10 | After batch save completes, dialog returns to read-only summary with refreshed data | ✓ VERIFIED | `closeBatchResult()` (lines 1673–1720) resets result state, calls `libraryStore.getTracks()` and `libraryStore.getAlbums()`, re-resolves `batchTracks` from refreshed data, re-resolves cover art state. Returns to read-only summary. |
|
||||
|
||||
**Score:** 10/10 truths verified
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `backend/tagwriter/pipeline.go` | BatchWriteTrackTags method, BatchResult type, BatchWriteProgress event emission | ✓ VERIFIED | 321 lines. Contains `BatchWriteTrackTags` (line 225), `BatchResult` (line 27), `BatchFailure` (line 21), `CancelBatchWrite` (line 209), `cancelBatch` channel (line 61), `suppressEvents` flag (line 62). Emits `events.BatchWriteProgress` per-track (line 288). `go build` and `go vet` pass. |
|
||||
| `backend/events/events.go` | BatchWriteProgress event constant | ✓ VERIFIED | Line 74: `BatchWriteProgress = "BatchWriteProgress"` in "Tag writing events" const block. |
|
||||
| `frontend/src/events.ts` | Auto-generated BatchWriteProgress constant | ✓ VERIFIED | Line 53: `BatchWriteProgress: "BatchWriteProgress"` in generated Events object. |
|
||||
| `frontend/wailsjs/go/tagwriter/TagWriter.js` | Wails bindings for BatchWriteTrackTags and CancelBatchWrite | ✓ VERIFIED | Lines 5–6: `BatchWriteTrackTags(arg1, arg2)`. Lines 9–10: `CancelBatchWrite()`. |
|
||||
| `frontend/wailsjs/go/tagwriter/TagWriter.d.ts` | TypeScript declarations | ✓ VERIFIED | Line 6: `BatchWriteTrackTags(arg1:Array<string>,arg2:tagwriter.TagChanges):Promise<tagwriter.BatchResult>`. Line 8: `CancelBatchWrite():Promise<void>`. |
|
||||
| `frontend/wailsjs/go/models.ts` | BatchResult and BatchFailure types | ✓ VERIFIED | Lines 675–720: `tagwriter` namespace with `BatchFailure` and `BatchResult` classes with proper field mapping. |
|
||||
| `frontend/src/components/track-details/track-details.ts` | Batch mode: showBatch(), three-state editing, confirmation, progress, cover art | ✓ VERIFIED | 2163 lines. Contains `showBatch()` (line 129), `batchMode` state (line 86), `getMergedFields()` (line 1997), `buildBatchChanges()` (line 1819), `renderConfirmation()` (line 1011), `renderBatchProgress()` (line 1046), `renderBatchResult()` (line 1074), `cancelBatchWrite()` (line 1669), `closeBatchResult()` (line 1673). |
|
||||
| `frontend/src/components/track-list/track-list.ts` | Updated context menu with showBatch | ✓ VERIFIED | Lines 1444–1449: Branches on `filePaths.length === 1`. Lines 1493–1527: `openBatchTrackDetails()` with cover art resolution. |
|
||||
| `frontend/src/components/cover-grid/cover-grid.ts` | Updated context menu with showBatch | ✓ VERIFIED | Lines 1528–1532: Branches on `filePaths.length === 1`. Lines 1588–1625: `openBatchTrackDetails()` with cover art resolution. |
|
||||
| `frontend/src/components/queue-panel/queue-panel.ts` | Updated context menu with showBatch | ✓ VERIFIED | Lines 821–825: Branches on `indices.length === 1`. Lines 877–921: `openBatchTrackDetails()` resolves queue tracks to library tracks. |
|
||||
| `frontend/src/components/playlist-details/playlist-details.ts` | Updated context menu with showBatch | ✓ VERIFIED | Lines 353–357: Branches on `filePaths.length === 1`. Lines 453–495: `openBatchTrackDetails()` with cover art resolution. |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|----|-----|--------|---------|
|
||||
| `track-details.ts` | `tagwriter/TagWriter.js` | `import { BatchWriteTrackTags, CancelBatchWrite }` | ✓ WIRED | Lines 18–20: imports present. `BatchWriteTrackTags` called at line 1631. `CancelBatchWrite` called at lines 1163, 1670. |
|
||||
| `track-list.ts` | `track-details.ts` | `trackDetailsDialog.showBatch(tracks, coverArt, coverArtMixed)` | ✓ WIRED | Line 1522: `this.trackDetailsDialog?.showBatch(tracks, coverArt, coverArtMixed)` |
|
||||
| `cover-grid.ts` | `track-details.ts` | `trackDetailsDialog.showBatch(tracks, coverArt, coverArtMixed)` | ✓ WIRED | Line 1620: `this.trackDetailsDialog?.showBatch(tracks, coverArt, coverArtMixed)` |
|
||||
| `queue-panel.ts` | `track-details.ts` | `trackDetailsDialog.showBatch(tracks, coverArt, coverArtMixed)` | ✓ WIRED | Line 916: `this.trackDetailsDialog?.showBatch(tracks, coverArt, coverArtMixed)` |
|
||||
| `playlist-details.ts` | `track-details.ts` | `trackDetailsDialog.showBatch(tracks, coverArt, coverArtMixed)` | ✓ WIRED | Line 490: `this.trackDetailsDialog?.showBatch(tracks, coverArt, coverArtMixed)` |
|
||||
| `track-details.ts` | `events.ts` | `EventsOn(Events.BatchWriteProgress, ...)` | ✓ WIRED | Line 1617: `EventsOn(Events.BatchWriteProgress, ...)`. Line 1664: `EventsOff(Events.BatchWriteProgress)`. |
|
||||
| `pipeline.go` | `events.go` | `EventsEmit(tw.ctx, events.BatchWriteProgress, ...)` | ✓ WIRED | Line 288: `wailsruntime.EventsEmit(tw.ctx, events.BatchWriteProgress, ...)`. Also emits single `TrackMetadataChanged` at line 303 after batch completes. |
|
||||
| `TagWriter.js` (Wails) | `pipeline.go` (Backend) | Wails binding bridge | ✓ WIRED | JS calls `window['go']['tagwriter']['TagWriter']['BatchWriteTrackTags']` which maps to Go `BatchWriteTrackTags` method. |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan | Description | Status | Evidence |
|
||||
|-------------|------------|-------------|--------|----------|
|
||||
| BATCH-01 | 18-01, 18-02 | User can select multiple tracks and open batch editor | ✓ SATISFIED | All 4 views branch on selection count; `showBatch()` opens batch mode in track-details dialog. Same "Track Details" context menu item adapts for multi-select. |
|
||||
| BATCH-02 | 18-02 | Batch editor uses three-state field model (keep/set/clear) | ✓ SATISFIED | Implicit three-state via `editValues` dirty tracking: untouched = keep, typed = set, cleared = clear. `getMergedFields()` shows shared vs mixed values. `buildBatchChanges()` only sends dirty fields. |
|
||||
| BATCH-03 | 18-01, 18-02 | Batch editor shows progress indicator for large selections | ✓ SATISFIED | Backend emits `BatchWriteProgress` per-track. Frontend renders progress bar with "N of M tracks" counter. CSS-animated fill bar. Cancel button wired to `CancelBatchWrite()`. |
|
||||
| BATCH-04 | 18-02 | User can set cover art for all selected tracks at once | ✓ SATISFIED | Batch edit mode uses same `selectCoverArt()`/`removeCoverArt()` controls. `buildBatchChanges()` includes `cover_art` key. Backend applies to each track via `WriteTrackTagsByPath` pipeline. |
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Line | Pattern | Severity | Impact |
|
||||
|------|------|---------|----------|--------|
|
||||
| — | — | None found | — | — |
|
||||
|
||||
No TODO/FIXME/HACK/PLACEHOLDER patterns in modified files. No empty implementations. No console.log-only handlers. All event listeners properly cleaned up with `EventsOff`. Progress bar and batch result have proper CSS styling (not placeholder). Build and vet pass clean.
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
Human verification was already completed during the phase (Task 3 in Plan 02 was a `checkpoint:human-verify` gate that was approved). The SUMMARY confirms all batch edit flows were tested in the running app:
|
||||
|
||||
1. Batch summary view with merged fields
|
||||
2. Three-state editing
|
||||
3. Confirmation dialog
|
||||
4. Progress bar during batch save
|
||||
5. Results summary
|
||||
6. Cover art batch operations
|
||||
7. Single-track regression check
|
||||
|
||||
No additional human verification needed.
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No gaps found. All 10 observable truths verified. All 11 artifacts exist, are substantive (not stubs), and are properly wired. All 8 key links verified. All 4 requirements (BATCH-01 through BATCH-04) satisfied. Backend compiles and passes vet. No anti-patterns detected.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-03-18T19:00:00Z_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Reference in New Issue
Block a user