Skip to content

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

The numerical table below gives every value.
Day 1: 100 → 50 units. Original alert.

After the correction

The numerical table below gives every value.
Day 1 alert withdrawn. Day 2: 70 → 50 units. New alert.

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.

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.

Source repository · Apache-2.0 license