keep-readmodel-consistent-with-ledger

Ensures every read-model projection stays consistent with the append-only event ledger.

Updated Jul 9, 2026
One-click install
npx skills add https://github.com/shuddl/shuddl-os --skill keep-readmodel-consistent-with-ledger-shuddl
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: keep-readmodel-consistent-with-ledger
Source: https://github.com/shuddl/shuddl-os/tree/main/.claude/skills/keep-readmodel-consistent-with-ledger
Command: npx skills add https://github.com/shuddl/shuddl-os --skill keep-readmodel-consistent-with-ledger-shuddl

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Corrections, voids, and reissues in an event-sourced ledger can silently update one read-model (like money_lines) while leaving a sibling projection (like the invoices AR row) frozen at its issue-time state, causing AR reports and QB exports to disagree weeks later. ## Core Features & Use Cases - Fan-out enumeration discipline: Lists every read-model an event kind feeds (money_lines, invoices, status_cache, messages, passports) so no projection is missed when handling invoice.corrected or new event kinds. - Void/correction handling rules: Defines that a void must emit an invoices upsert with {total_cents: 0, status: 'void'} in the same db.batch() as the money_lines netting, not return an empty array. - Reconciliation test guidance: Requires asserting SUM(invoices.total_cents outstanding) equals SUM(money_lines net) across issue, reissue, and void shapes. - Use Case: When reviewing a change to packages/ledger/src/projection/money.ts that handles invoice.corrected, apply this Skill to verify both the money_lines credits and the invoices AR row are updated atomically. ## Quick Start Review my changes to the invoice.corrected handler in packages/ledger/src/projection/money.ts and check that every affected read-model is updated consistently with the ledger.

Frequently Asked Questions about keep-readmodel-consistent-with-ledger

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I keep read-model projections consistent with an event ledger?▼

Enumerate every read-model each event kind feeds and write the effect of each correction explicitly to all of them in the same transaction. Netting one projection like money_lines does not automatically update sibling rows such as the invoices AR table.

How should a voided invoice be handled in event sourcing projections?▼

Treat a void as a new correction event, not a delete or no-op. Net money_lines to zero with credit lines and also update the invoices row to {total_cents: 0, status: 'void'} in the same db.batch() so both read-models agree.

Why does my AR report show a voided invoice as outstanding?▼

This happens when the void branch nets money_lines to zero but returns an empty array for the invoices projection, leaving the row frozen at its issue-time total. The AR surface reads invoices.total_cents directly, not a sum of money_lines.

Does a TypeScript never-exhaustiveness guard catch missing projection writes?▼

No. An exhaustiveness guard catches a missing event kind but cannot catch a missing read-model write within a handled kind. A void branch can compile cleanly while silently dropping the invoices update.

When should I not use this projection consistency discipline?▼

Do not apply it to pure ledger append logic such as events inserts, hashing, or sequencing, which have no read-model fan-out. Cross-tenant isolation concerns are also a separate discipline.