Files
nanobot-runtime/results/remind-skill-top5-priorities-2026-06-02.md
2026-06-10 06:39:52 +02:00

4.8 KiB
Raw Permalink Blame History

/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.