# Plan: fs-provider Ordered tasks; each names its verification (tests in `fsdy/src/lib.rs` and/or gates in `quality/fs-provider.md`). Stubs, tests, and workspace wiring exist; all 13 fsdy tests fail on `todo!()` at plan time. - [x] **T1 — `TrackFile::parse` + `playable()` validation.** TOML parse into the schema structs; `playable()` enforces exactly-one, http(s) scheme, absolute link, no `/fs` link. Verifies: `parse_accepts_a_full_track_file`, `parse_defaults_optional_metadata`, `parse_rejects_wrong_playable_cardinality`, `parse_rejects_invalid_playables`; gate "link chains impossible". - [x] **T2 — `TrackFile::to_track`.** Single conversion site; link rewrites the path, file/url keep it; album/duration mapped. Verifies: `to_track_rewrites_the_path_only_for_links`; gate "single file-to-Track conversion". - [x] **T3 — path scheme: `is_track_path` + `disk_path`.** Suffix+prefix check; decode-validate-join with `.`/`..`/empty/separator rejection in one helper. Verifies: `track_paths_need_the_suffix_and_the_provider_prefix`, `client_paths_cannot_escape_the_root`; gate "one validation place". - [x] **T4 — `init` + `settings`.** Parse `Settings`, default root `dirs::audio_dir()`, `Config` error when neither; nonexistent root accepted; write-back serialization. Verifies: `settings_round_trip_through_the_config_write_back`, `init_accepts_a_root_that_does_not_exist_yet`. - [x] **T5 — `read_track_file` + `get_metadata_for_track` + `get_urls_for_track`.** tokio::fs read, parse, playable dispatch (relative file joined onto the track file's dir; link → `MalformedPath` warn). Verifies: `urls_resolve_per_playable_kind`, `metadata_of_a_link_track_carries_the_target_path`; gates "plain paths/URLs only", "no file contents in logs". - [x] **T6 — `list_dir` + `get_lib_node` + `get_lib_root`.** Sorted case-insensitive listing; skip symlinks/hidden/non-UTF-8/foreign/ broken (warn with file name); encoded child paths; parent links. Verifies: `listing_sorts_and_skips_foreign_hidden_and_broken_entries`, `listing_a_missing_directory_is_an_error_not_a_panic`, `nodes_link_back_to_their_parent`, `resolving_a_tree_streams_chunks_in_listing_order`; gates "symlinks skipped", "listing order = resolve order", "tokio::fs only". - [x] **T7 — orchestrator wiring.** `fs_client: Option>` in `ProviderOrchestrator`; non-fatal init from `fsdy.toml` with write-back; `/fs` arms in every trait method; root child only when present; `crabidy-server/Cargo.toml` gains `fsdy`. Verifies: gates under "Orchestrator wiring"; workspace build. - [x] **T8 — full verification.** All fsdy tests + whole workspace suite green; clippy/fmt/taplo/markdownlint clean; walk the remaining gates and tick them; no `todo!()` left. - [x] **T9 — live smoke test.** Build a real tree under a temp root (nested dirs, a relative-file track, a url track, a `/tidal` link track), run the server pointing at it, list `/fs` over the provider layer, and resolve a directory — remove any temporary probe afterwards. Verifies: end-to-end behavior of D2/D4 outside unit scope. - [x] **T10 — docs.** `plan/summary.md` section incl. deviations; reconcile `architecture/fs-provider.md` if the implementation diverged.