72 lines
3.9 KiB
Markdown
72 lines
3.9 KiB
Markdown
# Quality gates — fyyd provider
|
|
|
|
LLM-verified gates for `architecture/fyyd-provider.md`. Automatic tests live
|
|
in `fyyd/src/lib.rs` (provider logic against a fake `Fyyd`) and
|
|
`crabidy-server/src/settings.rs` (the provider toggle).
|
|
|
|
## Correctness / semantics
|
|
|
|
- [x] Tree shape matches D3: `/fyyd` → `search` (creatable) + `hot`;
|
|
`/fyyd/search/<term>` and `/fyyd/hot` list **podcasts** as children
|
|
(not tracks); `/fyyd/<branch>/<podcast>` lists **episodes** as tracks;
|
|
`/fyyd/<branch>/<podcast>/<episode>` is the track leaf. Verified by
|
|
`root_lists_search_and_hot`, `search_terms_list_podcasts_as_children`,
|
|
`a_podcast_lists_its_episodes_as_tracks`, `hot_lists_featured_podcasts`.
|
|
- [x] A podcast listing node is not itself queueable; each podcast child is
|
|
queueable and downloadable (queue/capture a whole podcast). An episode
|
|
list node is queueable and downloadable. `is_track_path` is true only
|
|
for episode leaves. Verified by the tests above and
|
|
`tracks_resolve_streams_and_metadata`.
|
|
- [x] Search terms are creatable/renamable/deletable exactly like
|
|
tidal/youtube (in-memory, dedup, implicit recreation on stale paths),
|
|
and only `/fyyd/search` is creatable. Verified by
|
|
`search_terms_list_podcasts_as_children`,
|
|
`search_terms_rename_and_delete`, `foreign_and_malformed_paths_are_rejected`.
|
|
- [x] Playback resolves an episode to its `enclosure` URL; a track's
|
|
`artist` is the podcast title and `provider_item_id` is the fyyd
|
|
episode id. Verified by `tracks_resolve_streams_and_metadata`.
|
|
- [x] The download blessing is applied centrally (node downloadable when
|
|
queueable or track-bearing; children mirror queueability), so `W`
|
|
captures work with no capture-side change.
|
|
|
|
## Robustness (hard rules)
|
|
|
|
- [x] No panic on any input: malformed/foreign paths, empty create/rename
|
|
input, a missing enclosure, and every backend failure return a typed
|
|
`ProviderError`, never a panic. Verified by
|
|
`foreign_and_malformed_paths_are_rejected`,
|
|
`a_missing_enclosure_is_an_error_not_a_panic`,
|
|
`backend_failures_are_typed_never_panics`.
|
|
- [x] Every external call is bounded by a timeout (`call_timeout_secs`,
|
|
default 30) set on the `reqwest` client; every listing is capped
|
|
(`search_results`, `hot_count`, `episodes_per_podcast`). D5.
|
|
- [x] fyyd responses decode defensively: the `data` envelope is unwrapped,
|
|
DTO fields use `#[serde(default)]`, entries without a usable id are
|
|
dropped, and non-positive durations degrade to `None`. Failures are
|
|
typed `FetchError` → `ProviderError::FetchError`.
|
|
- [x] No secrets: fyyd's public API uses no credentials, so nothing secret
|
|
is logged; only public URLs/ids appear in traces.
|
|
|
|
## Integration / operability
|
|
|
|
- [x] `fyyd` is a registered provider: in `ALL_PROVIDERS`, `ProviderToggles`
|
|
(`all()` + `provider_toggles()`), and the default `crabidy-server.toml`.
|
|
Disabling it in the `providers` list drops the `/fyyd` subtree. Covered
|
|
by the existing settings tests (which iterate `ALL_PROVIDERS`).
|
|
- [x] Init is non-fatal: a client that fails to build disables `/fyyd` with
|
|
a warning and leaves every other provider and the server running (D1).
|
|
A missing `fyyd.toml` is normal (no credentials needed).
|
|
- [x] The orchestrator routes every `ProviderClient` method for `/fyyd`
|
|
paths to the fyyd client (owns-check + `fyyd_provider()`), and
|
|
`get_lib_root` lists `fyyd` only when the client is mounted. No proto
|
|
change and no new `ProviderCommand` were needed.
|
|
|
|
## Live validation (deferred, needs network)
|
|
|
|
- [ ] Against the real `api.fyyd.de`: a search returns podcasts, a podcast
|
|
lists episodes with non-empty `enclosure` URLs, and an enclosure plays
|
|
through the audio player. If a field name differs from the documented
|
|
shape, the fix is confined to `fyyd/src/api.rs` DTOs (design risk noted
|
|
in the architecture doc). This gate cannot run in the offline unit
|
|
suite.
|