feat(adhdo2): P2 quality+personalization backlog and P3 Telegram bridge + read-only dashboard#117
Open
adrianwedd wants to merge 12 commits into
Open
feat(adhdo2): P2 quality+personalization backlog and P3 Telegram bridge + read-only dashboard#117adrianwedd wants to merge 12 commits into
adrianwedd wants to merge 12 commits into
Conversation
) - _parse_at: accept ISO-8601 datetime, date-only (midnight), and HH:MM[:SS] time-of-day; invalid input now raises ToolError('usage') instead of an unhandled ValueError (previously '09:30:00' crashed). - Add _parse_at tests covering ISO full/space/date-only, HH:MM rollover, HH:MM:SS, unpadded hour, and invalid inputs. - Add quiet-hours boundary tests (exact start, exact end, wrap-around midnight, non-wrap window, equal start==end) pinning half-open [start, end) semantics; no off-by-one bugs found in nudgelimits. Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
…errors, logical device names, jellyfin fallthrough tests (#114) - cast stop now journals a cast event ({action: stop, device}) like play - device-not-found is now the same ToolError('no_devices') shape across play/stop/volume via shared resolve_device/device_not_found helpers; stop no longer silently ignores a missing device - output and errors report the logical (configured) device name, with the real cast name as cast_name; status rows carry both device+name - volume arg validation returns a usage envelope instead of crashing - tests: stop journaling, symmetric not-found across subcommands, jellyfin fallthrough (unreachable + empty playlist + happy path), logical-name reporting Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
Separate service from adhdo-httpd: bin/adhdo-dashboard serves a single self-contained HTML page (inline CSS/JS, 30s auto-refresh) plus JSON APIs /api/state and /api/journal. GET-only (405 otherwise), output scrubbed via envelope.scrub, bind/port from config (dashboard.bind falls back to lan_ip, port 8766). Includes systemd unit, config example, contract tests, and E2E checklist entry for on-device verification. Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
…ome patterns, nightly rollup+prune, wake-up routine v2 - journal outcome <intervention> <worked|partial|ignored|backfired> [feedback] - journal patterns now surfaces outcome_by_intervention, outcome_by_daypart, success_rate_by_intervention - journal rollup aggregates complete days into rollups and prunes raw events/audit rows older than 90 days (idempotent, skips today) - scripts/adhdo-rollup.sh nightly at 03:15 via install-cron.sh, with journal.db backup copy - session/CLAUDE.md wake-up routine v2: connectors, patterns-before-acting, outcome logging, re-auth nudge on connector failure Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
- envelope: narrow BaseException to Exception so KeyboardInterrupt and SystemExit propagate; drop redundant SystemExit re-raise - nudge: extract prune_cache() and run it unconditionally on every invocation (previously skipped on TTS cache hits) - heartbeat: replace cron */25 (10-min gap at hour boundaries) with a systemd user timer (OnUnitActiveSec=25min) for a true 25-min cadence; install-cron.sh installs and enables it - deploy.sh: install piper-tts idempotently; copy systemd .timer units - docs: catchup-vs-schedule interplay doc, referenced from E2E_CHECKLIST Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
…wake - adhdolib/telegram.py: stdlib-urllib Bot API client, Bridge with chat-ID allowlist, per-chat per-minute rate limit, advisory crisis regex screen (ported/tightened from legacy llm_client.py SafetyMonitor), journaling - bin/adhdo-telegram: run daemon (long-poll, persisted offset, injects via bin/wake's literal-send-keys contract) + send subcommand - token scrubbed from all envelope/error output (sanitize.redact) - systemd/adhdo-telegram.service, config defaults + example, 28 tests - E2E_CHECKLIST.md: on-device bot token/allowlist setup steps Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
# Conflicts: # adhdo2/E2E_CHECKLIST.md
…least-once delivery + daemon resilience + framing-marker neutralization + media-flood rate limit, dashboard generic 500s + proper HEAD + boot-race-hardened unit + real-wiring test, cast stop clears now_playing on missing device, prune_cache race tolerance, doc/test gaps Claude-Session: https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ultracode round covering the implementable remainder of #114 (quality backlog + personalization loop) and all of #115 (Telegram bridge + dashboard). Six parallel implementation streams, then a 5-lens adversarial review (24 agents) whose 11 distinct confirmed findings were all fixed.
P2 — quality backlog (#114)
Exceptioninstead ofBaseException(KeyboardInterrupt/SystemExit propagate)FileNotFoundErrorguarded)*/25cron (10-min hour-boundary gap) toadhdo-heartbeat.timersystemd user timer (OnUnitActiveSec=25min) — true 25-min cadence; install-cron.sh installs it*.timerunitsstopjournals + clearsnow_playing.jsoneven when the device is undiscoverable; uniform device-not-found envelopes; logical device name reported alongside real name; Jellyfin fallthrough pinned by tests; volume arg parsing hardened_parse_ataccepts full ISO-8601 / date-only / HH:MM[:SS] with rollover, usage errors instead of crashes; quiet-hours boundary semantics pinned ([start, end), wrap-around) by testsP2 — personalization loop (#114)
journal outcome <intervention> <worked|partial|ignored|backfired> [feedback]journal patternsnow surfaces outcome_by_intervention / by_daypart / success rates (30-day window)journal rollup+scripts/adhdo-rollup.sh: nightly aggregation, 90-day pruning, DB backup; wired into install-cron.sh at 03:15P3 (#115)
bin/adhdo-telegram,adhdolib/telegram.py, systemd unit): stdlib long-polling, chat-ID allowlist, per-chat rate limit (media counts too), text-only, advisory crisis regex flag, all inbound journaled, injection via bin/wake's escaping contract with framing-marker neutralization (user text can't spoof[event:...]), at-least-once delivery (offset persisted after handling), daemon survives injector/sendMessage failures, token scrubbed from all outputbin/adhdo-dashboard, systemd unit): GET/HEAD only, self-contained HTML +/api/state+/api/journal, secrets scrubbed, generic 500s (detail to stderr), boot-race-hardened unit + bounded bind retryVerification
Closes #115. Part of #114 (connector setup + hardware nudge tuning remain on-device).
https://claude.ai/code/session_01Tbd7qVjznvPwwYaWmUnWHP