Zalohovani vsech podstatnych souboru

This commit is contained in:
lachtan
2026-06-10 06:39:52 +02:00
parent 1e10891945
commit 67e29c8b88
69 changed files with 9115 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
# /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 14 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 14 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 P2P3 — užitečné, ale nejsou blokátory.*