personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs(APPS): note post-hook idempotency requirement

`sol dream --refresh` re-fires post_process on existing outputs; call
out the natural-key-dedup and atomic-replace patterns, and cite V6 from
the 2026-04-17 layer-violations audit as the cautionary example.

+9
+9
docs/APPS.md
··· 345 345 return result + "\n\n## Generated by hook" 346 346 ``` 347 347 348 + **Hook idempotency:** Post-hooks that write to shared journal state must be safe to run more than once on the same inputs. `sol dream --refresh` bypasses the "output already exists" early-return in `think/talents.py` and re-executes the talent, which re-fires `post_process` against a fresh LLM result — so any side-effect the hook performs (writing events, appending to a log, updating an index file) will happen again. Pick one of these two patterns: 349 + 350 + - **Natural-key dedup.** Read the existing output, compute a natural key per row (e.g., `(facet, event_day, title, start, end)` for facet events), skip rows already present, and append only the new ones. Use this when the output is append-only history and you want to preserve prior writes from other agents. 351 + - **Atomic replace.** Recompute the full output, write it to a temp file, and rename into place. `atomic_write()` in `think/entities/core.py` is the established helper for text outputs; for JSONL, write the full set of lines to a tempfile and `os.replace()`. Use this when the hook owns the file end-to-end. 352 + 353 + An earlier `write_events_jsonl` hook in `think/hooks.py` opened facet-event logs in `"a"` mode with no dedup and doubled row counts on every `sol dream --refresh` — see the 2026-04-17 layer-violations audit (V6) in the sol pbc internal extro repo (`vpe/workspace/solstone-layer-violations-audit.md`) for the full write-up. 354 + 355 + See `docs/coding-standards.md` L8/L9 for the broader principles. 356 + 348 357 **Reference implementations:** 349 358 - System generator templates: `talent/*.md` (files with `schedule` field but no `tools` field) 350 359 - Extraction hooks: `talent/occurrence.py`, `talent/anticipation.py`