# mtag-cli Hardening Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Turn `mtag` from a prototype music organizer into a safer CLI with explicit errors, testable planning, dry-run support, conflict handling, and CI gates.

**Architecture:** Split the workflow into scanner, metadata reader, planner, and executor modules. Keep path planning pure and heavily tested, then let the CLI compose those units and report a summary.

**Tech Stack:** Rust 2021, Clap, Lofty, Infer, Indicatif, Thiserror, Anyhow, Tempfile for tests, GitHub Actions.

---

### Task 1: Error And Module Foundation

**Files:**
- Create: `src/error.rs`
- Modify: `src/lib.rs`
- Modify: `Cargo.toml`

- [ ] **Step 1: Write failing tests for public error paths**

Create unit tests that expect scanner and planner APIs to return `Result` instead of panicking for missing paths and invalid destination names.

- [ ] **Step 2: Run test to verify it fails**

Run: `cargo test --all-targets --locked`
Expected: FAIL because the new API and error module do not exist yet.

- [ ] **Step 3: Implement error foundation**

Add `MtagError` with variants for IO, metadata read failure, missing file name, unsafe path component, copy conflicts, and invalid conflict strategy. Export `MtagResult<T>`.

- [ ] **Step 4: Run test to verify it passes**

Run: `cargo test --all-targets --locked`
Expected: PASS for the new error tests.

### Task 2: Scanner And Metadata Reader

**Files:**
- Create: `src/scanner.rs`
- Create: `src/metadata.rs`
- Modify: `src/lib.rs`
- Modify: `src/main.rs`

- [ ] **Step 1: Write failing scanner tests**

Add tempfile-based tests proving recursive scan returns only audio files and returns an error for a missing root.

- [ ] **Step 2: Run test to verify it fails**

Run: `cargo test scanner --locked`
Expected: FAIL because `scanner` is not implemented.

- [ ] **Step 3: Implement scanner and metadata reader**

Move recursive file scanning out of `utils`. Add one-pass Lofty metadata extraction into `TrackMetadata`, preferring `album_artist` when available and falling back to `artist`.

- [ ] **Step 4: Run test to verify it passes**

Run: `cargo test scanner --locked`
Expected: PASS.

### Task 3: Pure Organization Planner

**Files:**
- Create: `src/planner.rs`
- Modify: `src/lib.rs`

- [ ] **Step 1: Write failing planner tests**

Add tests proving path sanitization, album artist fallback, `Various Artists` inference, `.lrc` companion planning, dry-run plan generation, and same-album-name isolation.

- [ ] **Step 2: Run test to verify it fails**

Run: `cargo test planner --locked`
Expected: FAIL because `planner` is not implemented.

- [ ] **Step 3: Implement planner**

Build `CopyPlan` and `CopyTask` from `TrackMetadata` values. Sanitize each path component, use `album_artist` when present, group by album plus album artist hint, and include same-stem `.lrc` files when present.

- [ ] **Step 4: Run test to verify it passes**

Run: `cargo test planner --locked`
Expected: PASS.

### Task 4: Executor And CLI Options

**Files:**
- Create: `src/executor.rs`
- Modify: `src/main.rs`
- Modify: `src/music_organizer/organizer.rs`

- [ ] **Step 1: Write failing executor tests**

Add tempfile tests for `skip`, `overwrite`, `rename`, and `fail` conflict policies.

- [ ] **Step 2: Run test to verify it fails**

Run: `cargo test executor --locked`
Expected: FAIL because conflict policies are not implemented.

- [ ] **Step 3: Implement executor and CLI**

Add `--dry-run`, `--move`, `--on-conflict`, and `--template` flags. Make `main` return `anyhow::Result<()>`, surface readable errors, and print a final summary.

- [ ] **Step 4: Run test to verify it passes**

Run: `cargo test executor --locked`
Expected: PASS.

### Task 5: Docs, CI, And Cleanup

**Files:**
- Create: `.github/workflows/ci.yml`
- Create: `CHANGELOG.md`
- Modify: `README.md`
- Modify: `Cargo.toml`
- Modify: `src/music/song.rs`
- Modify: `src/music/audio.rs`

- [ ] **Step 1: Write or update docs tests where practical**

Add small doc examples for path sanitization and conflict strategy parsing if those APIs remain public.

- [ ] **Step 2: Clean unused code and dependencies**

Remove unused `console`, empty modules, dead `Song` placeholder, and obsolete utility APIs after replacements are in place.

- [ ] **Step 3: Add CI workflow**

Run format, Clippy with `-D warnings`, locked tests, and release build in GitHub Actions.

- [ ] **Step 4: Verify all gates**

Run:

```bash
cargo fmt --check
cargo test --all-targets --locked
cargo test --doc --locked
cargo clippy --all-targets --all-features --locked -- -D warnings
cargo build --release --locked
```

Expected: all commands exit 0 with no warnings.
