Replace the single comma-separated text box with an add/remove list of
native HH:MM pickers for the Immich scheduled-assets, periodic-summary,
and memory slots. The backend already stored comma-separated *_times and
scheduled one cron job per time; this makes entering several times per
day discoverable and hardens the read/write path.
Backend:
- services/time_list.py: normalize_time_list (validate / dedup / sort /
cap at 24, raising TimeListError) + lenient parse_hhmm_list; the
scheduler now uses the shared parser (drops its private copy).
- tracking_configs API normalizes *_times on every write (422 on bad
input) and rejects enabling a slot whose times list is empty.
- scheduler warns when an enabled slot has zero or dropped fire times,
restoring the observability lost with the old per-call warning.
Frontend:
- TimeListEditor.svelte: add/remove native time rows, dedupe + sort on
emit, per-day cap, collapses on-screen duplicates, aria-labelled rows;
syncs from the value prop only on external changes (untrack guard) so
keyboard entry isn't clobbered mid-edit.
- Descriptor-driven save guard: an enabled feature section must have at
least one time.
- i18n (en/ru) keys; refreshed help text; removed dead invalidTimeList.
Tests: time_list normalization/parsing (incl. non-ASCII/odd shapes) and
the enabled-implies-times validation.