3.9 KiB
3.9 KiB
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
- Tree shape matches D3:
/fyyd→search(creatable) +hot;/fyyd/search/<term>and/fyyd/hotlist podcasts as children (not tracks);/fyyd/<branch>/<podcast>lists episodes as tracks;/fyyd/<branch>/<podcast>/<episode>is the track leaf. Verified byroot_lists_search_and_hot,search_terms_list_podcasts_as_children,a_podcast_lists_its_episodes_as_tracks,hot_lists_featured_podcasts. - 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_pathis true only for episode leaves. Verified by the tests above andtracks_resolve_streams_and_metadata. - Search terms are creatable/renamable/deletable exactly like
tidal/youtube (in-memory, dedup, implicit recreation on stale paths),
and only
/fyyd/searchis creatable. Verified bysearch_terms_list_podcasts_as_children,search_terms_rename_and_delete,foreign_and_malformed_paths_are_rejected. - Playback resolves an episode to its
enclosureURL; a track'sartistis the podcast title andprovider_item_idis the fyyd episode id. Verified bytracks_resolve_streams_and_metadata. - The download blessing is applied centrally (node downloadable when
queueable or track-bearing; children mirror queueability), so
Wcaptures work with no capture-side change.
Robustness (hard rules)
- 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 byforeign_and_malformed_paths_are_rejected,a_missing_enclosure_is_an_error_not_a_panic,backend_failures_are_typed_never_panics. - Every external call is bounded by a timeout (
call_timeout_secs, default 30) set on thereqwestclient; every listing is capped (search_results,hot_count,episodes_per_podcast). D5. - fyyd responses decode defensively: the
dataenvelope is unwrapped, DTO fields use#[serde(default)], entries without a usable id are dropped, and non-positive durations degrade toNone. Failures are typedFetchError→ProviderError::FetchError. - No secrets: fyyd's public API uses no credentials, so nothing secret is logged; only public URLs/ids appear in traces.
Integration / operability
fyydis a registered provider: inALL_PROVIDERS,ProviderToggles(all()+provider_toggles()), and the defaultcrabidy-server.toml. Disabling it in theproviderslist drops the/fyydsubtree. Covered by the existing settings tests (which iterateALL_PROVIDERS).- Init is non-fatal: a client that fails to build disables
/fyydwith a warning and leaves every other provider and the server running (D1). A missingfyyd.tomlis normal (no credentials needed). - The orchestrator routes every
ProviderClientmethod for/fyydpaths to the fyyd client (owns-check +fyyd_provider()), andget_lib_rootlistsfyydonly when the client is mounted. No proto change and no newProviderCommandwere needed.
Live validation (deferred, needs network)
- Against the real
api.fyyd.de: a search returns podcasts, a podcast lists episodes with non-emptyenclosureURLs, and an enclosure plays through the audio player. If a field name differs from the documented shape, the fix is confined tofyyd/src/api.rsDTOs (design risk noted in the architecture doc). This gate cannot run in the offline unit suite.