When yesterday's input changes today's answer¶
A periodic batch job can start again from the full source history. An incremental system publishes results sooner, but a correction to an earlier fact can invalidate results it has already published. Updating the transaction alone is not enough: its consequences must be repaired too.
amends demonstrates correction-aware incremental processing: repairing published results when authoritative business records are amended or cancelled. The same problem arises when modernizing financial processing, logistics, orders and shipments, maintenance histories, and claims workflows.
Sorrell Consulting's independent reference implementation uses a deliberately small, synthetic inventory ledger to make the repair decisions inspectable. It is an engineering example, not a production solution for those domains.
See the correction¶
A receipt adds inventory; an issue removes it. The daily closing balance is the inventory remaining after that day's active movements. Start with 100 units and a reorder threshold of 60 units, the example's low-stock boundary.
Issue 50 units on Day 1, issue 20 on Day 2, and receive 50 on Day 3. Now correct the Day 1 issue to 30 units. This higher source revision completely replaces the original issue. The charts show how the daily closes and alert change:
Original history
After the correction
Triangles mark crossing days; the dashed line is the 60-unit threshold. Hover or tap a point for its exact value. Connecting lines join discrete daily observations, not a continuous intraday inventory path. The table and explanation contain the same information without JavaScript.
An alert records a downward crossing: the previous close is at or above 60 and the next close is below 60, using opening inventory as the first day's predecessor. Originally, Day 1 qualifies; remaining below 60 on Day 2 does not generate another alert. After correction, Day 1 closes at 70 and Day 2 at 50. Withdraw the original Day 1 alert and publish the newly valid Day 2 alert.
| Observation | Original inventory (units) | Corrected inventory (units) | Alert consequence |
|---|---|---|---|
| Opening | 100 | 100 | Supplies the first day's predecessor; no activity row or alert |
| Day 1 close | 50 | 70 | Original alert must be withdrawn |
| Day 2 close | 30 | 50 | Corrected history requires a new alert |
| Day 3 close | 80 | 100 | No new downward crossing in either history |
The Day 3 receipt does not erase a valid earlier crossing. The correction changes the history that justified it. An alert describes a historical event; withdrawing it cannot undo an email, purchase, or other external action already taken.
Follow the repair¶
The highest source revision determines which transaction value applies. If that revision contains conflicting values, the affected item/location's results remain blocked until the ambiguity is resolved. For an unambiguous change, the processor recalculates balances and alerts from the earliest affected day forward. That remaining portion of history is the affected suffix; recalculating it is a refold. Earlier unaffected results stay intact. Resolving conflicting highest revisions can require recalculating the whole item/location history instead.
Changed results and intended publications commit together in PostgreSQL. This transactional outbox lets a separate relay retry delivery after a publication failure. Consumers keep the latest stored results, the materialized view, and retain each deletion's version—a tombstone—so an older delayed message cannot recreate a withdrawn fact. Transport can repeat messages; PostgreSQL and the broker do not share one atomic transaction.
If a worker crashes before its transaction commits, partial work rolls back. The selected crash walkthrough observes that boundary, installs new database ownership, resumes processing, and verifies the result. A lost commit reply is different: recovery must reread durable state to find out whether the transaction committed.
Only days with active transactions have stored closing-balance rows. Cancelling the last movement on a day withdraws its row; the preceding balance carries forward implicitly. A missing row does not mean zero inventory.
Check the answer independently¶
A separately implemented full-history calculation, the independent oracle, reconstructs applicable source revisions and derives balances and alerts without reusing incremental repair decisions. Both paths are checked against hand-calculated fixtures. They still share input decoding and representation, so a shared defect remains possible.
Operational verification requires a stable source history, completed processing and delivery, a drained and stopped relay whose exit has been awaited, and a view at the captured output end. It then compares the view with the oracle's reconstruction of that same history. Zero lag alone is insufficient. A strict PASS means complete, unqualified agreement at that boundary; missing history, unresolved conflicts, and other qualifications remain visible in the verification result.
Choose a path¶
View the core demonstration output: an observed in-memory run showing the original history, correction, and disappearance of a cancelled day's balance. Unlike the conceptual diagrams, this is execution output; it does not establish PostgreSQL, broker, or process-crash behavior.
- Run it: the evaluation guide starts with
make core-demoin memory, then adds real PostgreSQL/Redpanda and the selected crash. - Understand the solution: architecture and design, followed by the technical guide and its worked code path.
- Inspect the rules and evidence: semantic contract, testing strategy, and advanced drills.
- Operate an existing run: runbook, verification, and replay/rebuild.
This is a local reference implementation using synthetic data. It provides no production security, high availability, live rebuild cutover, bounded recovery time, or throughput guarantee. Selected tests and failure schedules are evidence, not exhaustive proof. Read the limitations before extending the pattern.