The gear was dead on that tab and the cache window was unreachable, so
whatever hours value happened to be in the shared prefs was permanent.
It reads 24h on this account; the reference offers 24/36/48/72 and
defaults to 48.
Only the WRITER was missing. `reco_cache_ttl_secs()` already read
`reco_cache_ttl_hours` from the shared per-user discover prefs, and
`refresh()` was already written — and carrying `#[allow(dead_code)]`
because nothing called it.
TTL_HOURS is the reference's table verbatim (discover_prefs.rs:100).
That matters because the value lands in the file BOTH builds read: if
the two disagree on the index mapping, a window chosen in one reads
back as a different one in the other. The QML option order is the other
half of the same contract, noted at both ends.
The setter republishes the RESOLVED index rather than the one it was
handed, so a failed write (no per-user store) snaps the select back to
what is actually stored instead of showing a window nobody saved. The
index is seeded at shell entry next to publish_settings(), the first
point where the per-user directory is known — without it the select
would open on the store's 48h default and misreport anyone who chose
otherwise.
The modal now has two modes on the same six blocks the reference gates
(DiscoverConfigModal.slint:187/213/221/250/261/326): section tabs keep
the list, banner, count and reset footer; Recommendations hides those
and shows the explainer, the window select and Refresh now. Its
empty-state line is hidden there too — DiscoveryTab has no
"recommendations" arm, so an empty row list is by design and "No
sections to configure yet" would be a permanent lie.
All seven strings already existed translated in all eight catalogs.
Two comments removed on the way: both claimed the external reco engine
was "not ported" and justified the disabled gear with it. It has been
ported for a long time (recommendations_qt.rs, 745 lines) — the fossil
was the only thing still keeping the setting out of reach.
cc