# /remind Skill — Top 5 Priorities (Merged from Two Audits) **Datum:** 2026-06-02 **Model:** GLM-5.1:cloud **Zdroje:** `results/2026-06-02_remind-skill-analysis-and-improvements.md` + `results/remind-skill-audit-2026-06-02.md` --- ## 1. Stabilní ID + dedup fix (nahradit SHA1[:8] + substring match) **Problém:** Dva propojené bugy: - `.reminder_state.json` používá `SHA1(text)[:8]` jako dedup klíč — 4 bajty hex, kolize při ~65k reminderů. Změna textu (i překlep) vytvoří nový klíč → duplikátní doručení. - `remove` matchuje substring — `remove --keyword "boty"` smaže i "koupit boty pro dědu". - `cmd_remove` používá `is not` identity check — funguje jen díky referenční shodě, po refaktoringu (deep copy, reload) se rozbije. **Řešení:** - Přidat `id` pole (UUID nebo short hash z text+timestamp) přiřazené při `add`. - `remove` i `update` primárně přes `--id`, `--keyword` jako fallback. - State file klíč → stabilní `id` místo SHA1[:8]. - `cmd_remove` filtrovat přes `id` nebo index, ne přes `is not`. **Dopad:** Zabrání tichým datovým ztrátám a duplikátům. Bez toho je celý skill nespolehlivý. --- ## 2. Garbage collection `at` reminderů + deduplikace při doručení **Problém:** Dva propojené bugy: - Jednorázové `at` remindery zůstávají v `reminder.yaml` navždy. Po odeslání se jen přestanou spouštět, ale loadují se každý minutovým cronem. Po měsících tam budou stovky mrtvých záznamů. - `should_fire()` má 60s okno — s minutovým cronem může `at` reminder doručit dvakrát (např. při dvojím spuštění cronu nebo časovém posunu). Log ukazuje, že to zatím proběhlo OK, ale není to garantováno. **Řešení:** - `remind_send.py` po úspěšném doručení `at` reminderu: buď ho smazat z YAML, nebo přidat `purge` subcommand pro ruční cleanup. - Zužit existující state file pro dedup: zúžit okno na `0 <= delta < 30` a kontrolovat, zda už byl ve stejném minutovém okně doručen (state file už existuje, jen má špatný klíč — viz bod 1). - Alternativně: SQLite state tabulka `fired(text, scheduled_at, fired_at)` s `PRIMARY KEY(text, scheduled_at)`. **Dopad:** Zabrání spamu a nekonečnému růstu YAML souboru. --- ## 3. Atomic writes + odstranění ruční YAML konstrukce **Problém:** Dva propojené problémy v `remind_edit.py`: - Zápis do `reminder.yaml` je neatomický — `with open(REMINDER_FILE, "w")` může při crashu zanechat prázdný/s poškozený soubor = ztráta všech reminderů. - `format_reminder()` ručně skládá YAML stringy (`f"- text: {text}"`) — neescapuje speciální znaky (uvozovky, dvojtečky, newlines), nedrží konzistentní odsazení, duplikuje logiku ruamel.yaml. **Řešení:** - Atomic write: `tmp = path.with_suffix(".tmp")` → `yaml.dump(data, f)` → `os.replace(tmp, path)`. - Nahradit `format_reminder()` builděním dictu a `yaml.dump()` celého dokumentu. Použít `ruamel.yaml.scalarstring.LiteralScalarString` přímo z knihovny (smazat vlastní třídu). - Přidat validaci před zápisem (schema check). **Dopad:** Zabrání ztrátě dat a tichým YAML parse chybám. Největší robustness win s minimálním úsilím. --- ## 4. `update` příkaz + `list` příkaz **Problém:** - `remind_edit.py` má jen `add` a `remove`. Změna času = smazat a vytvořit znovu — rizikové (viz bod 1, substring match). - `list` je dokumentovaný v SKILL.md, ale v kódu neexistuje. Uživatel (nebo LLM) nemá jak zkontrolovat aktuální stav. **Řešení:** - Přidat `update --id X [--cron ...] [--at ...] [--random-* ...]` — najde reminder a upraví jen zadaná pole. - Přidat `list` — vypíše všechny remindery s ID, textem a typem schedule. - Přidat `--dry-run` k `add` a `update` pro bezpečné testování. **Dopad:** Zásadní UX zlepšení, snižuje riziko chyb při úpravách, doplňuje chybějící dokumentovanou funkci. --- ## 5. Testy pro `remind_edit.py` a `remind_send.py` **Problém:** Testy pokrývají jen `random_times.py`. Dva hlavní skripty (CRUD operace, dedup, fire detection, YAML I/O) nemají žádné testy. Jakákoliv změna v bodech 1–4 bez testů = riziko regresí. **Řešení:** Přidat unit testy pro: - `cmd_add` s různými kombinacemi flagů (cron, at, random) - `cmd_remove` s 0/1/N matches, substring kolize - `should_fire` s různými typy reminderů a okraji časových oken - Dedup state management (nový i starý formát) - Atomic write (crash uprostřed zápisu) - Validace `at` v budoucnosti **Dopad:** Bez testů je jakýkoliv refaktoring hazard. S testy se body 1–4 dají implementovat bez strachu z regresí. --- *Zbylé návrhy (SQLite backend, pause/resume, cron until, retry TTL, log enrichment, chat_id z configu, per-reminder TZ) jsou P2–P3 — užitečné, ale nejsou blokátory.*