Writing for the decider: a corrupt or drifted archive summary can carry negative, fractional, or non-finite word counts into Postlude’s activity map instead of stopping at the database boundary. That can render a day at an impossible weight and conceal the row-contract failure that caused it.
Evidence
PR #20 introduced a reusable non-negative integer WordCount schema for full entry rows, but EntrySummaryFromRow still decodes journal_word_count and scripture_word_count with unrestricted Schema.Number. Verification probes against both the pre-fix and final PR heads accepted -1, 1.5, and NaN.
Failure scenario
If a malformed driver result or later database drift reaches listBetween, the archive accepts an impossible weight instead of returning JournalReadError. The heatmap then buckets data that the persisted schema says cannot exist.
Suggested verification
Reuse WordCount for both summary fields. Add summary-decoder tests for zero and positive integers, then prove negative, fractional, and non-finite sibling inputs fail.
Found while verifying fixes in #20. It predates the fix commits, so the bounded repair pass cannot absorb it.
Writing for the decider: a corrupt or drifted archive summary can carry negative, fractional, or non-finite word counts into Postlude’s activity map instead of stopping at the database boundary. That can render a day at an impossible weight and conceal the row-contract failure that caused it.
Evidence
PR #20 introduced a reusable non-negative integer
WordCountschema for full entry rows, butEntrySummaryFromRowstill decodesjournal_word_countandscripture_word_countwith unrestrictedSchema.Number. Verification probes against both the pre-fix and final PR heads accepted-1,1.5, andNaN.Failure scenario
If a malformed driver result or later database drift reaches
listBetween, the archive accepts an impossible weight instead of returningJournalReadError. The heatmap then buckets data that the persisted schema says cannot exist.Suggested verification
Reuse
WordCountfor both summary fields. Add summary-decoder tests for zero and positive integers, then prove negative, fractional, and non-finite sibling inputs fail.Found while verifying fixes in #20. It predates the fix commits, so the bounded repair pass cannot absorb it.