داده، SQL، قراردادها و ماشین حالت · فصل ۶ — Event، Outbox، Reconciliation و State Machine · 74
Append-only Ledger and Correction without Mutation
Design one bounded append-only ledger where corrections are new entries that reference prior facts, then prove a projection can be rebuilt without rewriting history. میتواند «Append-only Ledger و Correction-not-Mutation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
Lesson summary
Design one bounded append-only ledger where corrections are new entries that reference prior facts, then prove a projection can be rebuilt without rewriting history.
میتواند «Append-only Ledger و Correction-not-Mutation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
This lesson produces
میتواند «Append-only Ledger و Correction-not-Mutation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
Who it is for
Foundation
Worked baseline, explicit evidence table, local fixture and one guided failure probe.
Repair
Reduce to one broken contract/protocol assumption, observe it, repair it, then restore the full case.
Experienced
Compress introductory syntax; require independent compatibility/reliability decision, negative evidence and residual-limit statement.
Prerequisites
1. Current balance is not history
A ledger can show the correct current balance and still have weak historical integrity. If an operator edits yesterday's debit from -12000 to -10000, today's balance may look right, but the system has erased the fact that the original posting was accepted with the wrong amount. That loss matters for audit, replay, incident analysis, and correction reasoning.
The bounded outcome here is Append-only Ledger Integrity Record v1. You will preserve accepted history, express a correction as an additional entry, rebuild a projection deterministically, reject a duplicate posting identity, and state what the evidence does not prove.
2. Append-only is a storage discipline, not a compliance certificate
The Azure Event Sourcing pattern is useful as an architectural analogy because it stores a sequence of changes in an append-only store and derives current state by replay. This lesson does not equate a small ledger with event sourcing, accounting law, fraud prevention, or blockchain. The analogy owns one narrow idea: prior accepted facts are preserved and later facts are appended.
Your decision must therefore separate three layers: stored history, derived projection, and external business approval. A technically coherent history does not prove the correction was authorized or legally valid.
3. The smallest owned ledger model
Each entry in the local fixture has entry_id, business_key, entry_type, amount_delta, corrects_entry, and accepted_at. business_key identifies a posting attempt within the bounded service. corrects_entry is empty for ordinary entries and points to the earlier accepted entry when a correction is intended.
The starter begins with one accepted debit: E1, business key debit-001, amount delta -12000. The intended correction is not an update. A new entry E2 adds +2000 and explicitly references E1, so replay produces the corrected projection -10000 while the original debit remains inspectable.
4. Correction means append a new fact
A correction entry answers two different questions. Its numeric delta changes the projection, while its corrects_entry relation explains why this later fact exists. A projection can accidentally calculate to the expected number even when the lineage field is missing. That is why projection correctness and correction lineage are separate evidence dimensions.
The local oracle accepts a correction only when the referenced entry already exists and the correction itself has a distinct entry and business identity. It does not decide whether the amount or reason was approved by the business owner.
5. Projection rebuild must start from clean state
A derived balance is disposable. The decisive test is whether the system can discard the projection and rebuild it from the accepted ledger entries under one declared order and calculation rule. The local fixture orders by accepted_at, then entry_id, and sums amount_delta.
The integrity record stores both the ordered input trace and the rebuilt result. A matching projection supports reproducibility for this fixture; it does not prove every domain invariant or the legal meaning of the entries.
6. Posting identity and duplicate acceptance
The bounded service needs a stable posting identity so retrying the same posting does not silently append a second business fact. In the local harness, business_key must be unique. The duplicate probe attempts to append another entry with debit-001 and expects a rejection without changing prior history.
PostgreSQL 18 documents unique constraints as a database mechanism for enforcing uniqueness over a column or set of columns. In this lesson that fact is only a local storage-boundary analogy. A unique key is not a universal exactly-once guarantee across distributed systems.
7. Transaction boundary is local and explicit
The PostgreSQL 18 transaction documentation describes a transaction as an all-or-nothing group of database steps. That is useful for reasoning about a local append plus related local metadata, but it does not create distributed atomicity across services, brokers, payment networks, or external approvals.
The executable learner fixture is intentionally self-contained and in-memory. It models the local invariants without claiming that its behavior is a PostgreSQL runtime observation. Vendor facts and local observations remain separate in the evidence record.
8. Negative probe: mutation of prior history
The first deliberate failure edits the original debit in place. The history fingerprint computed before correction no longer matches the stored prior fact, so the integrity rule fails even if the final balance equals the desired value.
This probe is important because a balance-only test would miss the defect. The evidence must preserve the before/after entry trace and classify the failure as HISTORY_MUTATION_DETECTED.
9. Negative probe: duplicate posting identity
The second probe attempts to append a new entry using an already accepted business_key. The expected result is DUPLICATE_POSTING_REJECTED, with the ledger length and historical entries unchanged.
This is evidence for the bounded posting-identity rule only. It does not prove duplicate suppression across independent databases or a distributed retry path.
10. Negative probe: missing correction link
The third probe appends a numeric adjustment that produces the expected balance but leaves corrects_entry empty. Replay still produces -10000, yet the correction lineage is not verifiable. The case must therefore fail the integrity decision with CORRECTION_LINEAGE_MISSING.
This is the core distinction between state correctness and historical explainability: the same projection can be reached by histories with very different integrity properties.
11. Evidence completeness is part of the contract
The final decision needs more than green runtime output. The learner record requires entry evidence, projection evidence, posting-identity evidence, correction-lineage evidence, residual domain rule, and the changed-context transfer decision. Removing one required field makes the record insufficient even if all executable probes ran successfully.
The runner writes raw local observations only. It does not fill the final bounded decision or residual risk for the learner.
12. Transfer: imported correction in a refund ledger
The changed context uses separate DEBIT and CREDIT entry types and imports an historical correction. You must keep the imported fact immutable, choose an explicit correction link, declare the replay ordering rule, and explain how duplicate posting identity is bounded.
The answer is not allowed to solve the transfer by rewriting the imported row. It must also state one residual uncertainty about business approval, settlement, compliance, or external system behavior.
13. What this lesson proves—and what it does not
A successful local record can support five bounded claims: prior history stayed intact, the correction is a new linked fact, the projection rebuilt deterministically, duplicate posting identity was rejected locally, and technical integrity was separated from external approval.
It does not prove legal compliance, fraud resistance, exactly-once delivery, blockchain properties, event-sourcing architecture, or correctness of an external accounting decision. Those are explicit non-goals, not missing polish.
14. Freshness and source discipline
The source boundary is exactly three official pages: Microsoft Azure Event Sourcing as an append-only architectural analogy, PostgreSQL 18 Transactions for local atomicity semantics, and PostgreSQL 18 Constraints for local uniqueness semantics. They were rechecked on 2026-09-15 with no material change to the locked claims.
The Azure analogy is reviewed by 2026-12-31. PostgreSQL tool-specific claims are reviewed by 2026-10-17 or earlier if implementation behavior changes.
Assessment
There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.
DAT-010-S1 retrieval
State the append-only correction rule and one explicit non-goal.
DAT-010-S2 application
Append a linked correction and rebuild the projection from clean state.
DAT-010-S3 diagnosis
Why can a correct final balance still fail historical integrity?
DAT-010-S4 decision
Explain why local uniqueness is not a distributed exactly-once guarantee.
DAT-010-S5 transfer
Design correction/replay rules for an imported refund correction without rewriting history.
Assessment rubric
PASS requires preserved prior history, an appended linked correction, deterministic projection rebuild, bounded duplicate-posting evidence, explicit residual domain rule, and independent changed-context transfer.
References & freshness
Case studies
Lesson visuals
Lab files
Lesson media & slides
Teaching files (download)