3f4ecf9529
Two CRITICAL data-integrity bugs surfaced by the audit, fixed under TDD
(regression tests added first, confirmed RED, then GREEN).
C4 — non-atomic JSONL append:
events.jsonl / interactions.jsonl were appended with open("a") and no
trailing-newline guard. If a prior write was truncated mid-line (crash /
power loss, no final newline), the next record was concatenated onto the
broken line, the merged line failed to parse, and the reader silently
dropped it via `except JSONDecodeError: continue` — losing both the
corrupt fragment AND the new valid event. meta counts also drifted because
event_count/interaction_count were blindly incremented.
Fix: prepend a newline when the file does not end in one; recount
event_count/interaction_count from actually-readable lines; log corrupt
lines (line number + snippet) instead of dropping them silently.
C5 — frontmatter numeric coercion corrupted the primary key:
_parse_frontmatter coerced any all-digit value to int, so `slug: 007`
parsed to 7 and, after the parse->render round-trip update_state performs
on every call, was permanently rewritten as `slug: 7`, breaking all
slug-based directory lookups silently.
Fix: restrict int/float coercion to a numeric-key whitelist
(age/score/signal_score/...); identifier fields like slug stay strings.
Deferred (noted in audit, not in this commit): cross-process file locking
for concurrent writers; write-side slug quoting in skill_writer.py.