Skip to content

Release v0.9.9: watcher reliability hardening, config upgrade safety, and UX/logging improvements#15

Merged
loganbuilt merged 15 commits intomainfrom
feature/community-resolution-cache
Mar 11, 2026
Merged

Release v0.9.9: watcher reliability hardening, config upgrade safety, and UX/logging improvements#15
loganbuilt merged 15 commits intomainfrom
feature/community-resolution-cache

Conversation

@loganbuilt
Copy link
Copy Markdown
Collaborator

Summary
This release stabilizes watcher behavior and reduces false negatives/notification noise while preserving scheduler behavior. It also hardens config upgrade defaults and improves OAuth/UI/log clarity.

What’s included
Watcher reliability and batching
Reset watcher poll state on app/container startup so watched playlists poll immediately (next_poll_at=now, interval reset to min, counters reset).
Added OAuth-missing fallback path in watcher polling:
If account client is unavailable, watcher now attempts yt-dlp playlist fallback instead of hard-skipping.
Subscribe-mode detection hardened:
No longer misses unseen videos when seen items appear first.
Newly detected subscribe IDs are marked seen at detection time to prevent retrigger churn.
Batch aggregation improved (watcher-only):
Batch waits for quiet window and poll coverage across watched playlists (or max batch wait safety cap).
During open batch window, prioritizes polling unpolled playlists.
Watcher Telegram spam control:
Added watcher-only Telegram cooldown.
Watcher summary correctness:
Fixed attempted-count race by supporting watcher attempted override.
Watcher summary now waits for terminal job states (bounded wait) before dispatching Telegram, improving timing and label resolution.
Config defaults / upgrade safety
Missing config keys are auto-backfilled on load/write-back.
Backfill only adds missing keys; existing values are not overwritten.
Sample/demo entities (e.g., example_account, sample playlists) are not injected into user configs during upgrades.
Watcher skew/backoff behavior
Skew guard logic preserved but startup flow now guarantees immediate poll (prevents long idle-after-restart surprises from persisted backoff).
Logging improvements
OAuth refresh messaging updated:
Retry line normalized to: Refreshing credentials - Attempt X/Y
Success line: [Success] Credentials Refreshed account=
UI/UX
OAuth helper modal sizing improved for smaller viewports:
Modal/card constrained to viewport height with internal scrolling so action buttons remain reachable without browser zoom-out.
Non-goals / unchanged
Scheduler run summary and scheduler Telegram flow unchanged.
Core download pipeline behavior unchanged outside watcher-specific paths.
Risk / compatibility
Low-to-moderate runtime risk, scoped primarily to watcher code paths.
Config compatibility improved for upgrades; no expected breaking schema changes.
Validation performed
Static compile checks passed for modified Python modules (py_compile).
Added/updated watcher runtime hardening tests for key regressions (environment may skip certain test modules depending on local test prerequisites).

…ghtening retry strategy, and adding candidate cooldown cache

Skip yt-dlp metadata probe for music-track downloads by default (music_skip_metadata_probe=true) to reduce pre-download overhead.
Keep JS runtime + cookies on first music-track attempt when configured, and avoid redundant/low-value retry branches (audio_best removed for music-track).
Add SQLite-backed music candidate cooldown cache (music_candidate_failures) to temporarily suppress repeatedly unavailable candidates per recording MBID.
Exclude cooled-down candidate IDs during music-track selection and clear cooldown on successful completion.
Add config defaults/validation for new tuning keys:
music_skip_metadata_probe
music_candidate_cooldown_enabled
music_candidate_cooldown_seconds
music_candidate_cooldown_min_failures
Add observability logs for probe skipping and candidate cooldown behavior.
…config_sample.json.

Existing user-provided values are preserved (not overwritten).
load_config(..., write_back_defaults=True) persists missing keys back to disk.
Skew limit now accounts for:
current playlist interval (watch.current_interval_min)
policy max interval
baseline guardrail
Replaced old clamp threshold logic in watcher supervisor with this helper.
…eduler run/TG logic.

Batch now waits for poll coverage:
After first detection, watcher keeps a batch window open.
It tracks playlists polled in that window.
It triggers batch when:
quiet window elapsed and all configured playlists were polled at least once, or
max batch wait is hit (safety cap).
It actively polls unpolled playlists during open batch window:
Prevents getting stuck waiting on long per-playlist backoff before batch summary.
Watcher Telegram cooldown added:
If a watcher summary was just sent, next watcher summary is skipped until cooldown expires.
This avoids watcher TG spam from frequent small updates.
Batch attempted-count race fixed:
attempted_total now uses actual batch job IDs queued by watcher run, not only completed/failed statuses at that instant.
This prevents false attempted_total=0 and unintended TG skip.
…en jobs are enqueued but not yet terminal in DB.
…terminal states before sending Telegram (up to a bounded wait), instead of firing immediately after enqueue.
@loganbuilt loganbuilt merged commit b1a1060 into main Mar 11, 2026
1 check passed
@loganbuilt loganbuilt deleted the feature/community-resolution-cache branch March 11, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant