CHAPTER 42: Revision rules and recovery after export failure

42a: A correction replaces a total; a replay adds nothing
42b: Accepted history and a published report can diverge

HOW TO RUN
Open a terminal in the extracted companion folder, the folder containing
automation, sql and visual_labs. Run:

    python visual_labs/ch42/walkthrough.py

Use python3 or py instead of python if that is the command established in
Chapter 15. No extra Python package is needed. Run it only after predicting
the displayed states. The exact output is also in expected_output.txt.

When a lab imports the automation examples, its short Path/sys.path setup
locates those existing modules relative to this file. It changes where this
Python process looks for imports; it does not change your operating-system
configuration. Preserve the extracted folder structure.

SOURCE AND MEANING
The original two day files and 1 October correction are read unchanged.
The script calls the original import_and_report function against temporary
databases and report files. It does not modify an existing campaign history.
The equal-revision conflict is a new copied fixture in the temporary folder.

FOLLOW BEFORE YOU RUN
Trace the first day's original import, exact replay, revision-2 correction and
stale revision-1 replay. Explain why the date total changes from EUR 420 / 20
to EUR 430 / 21 even though only Spring search appears in the correction.
Newsletter remains EUR 120 / 8 because omission is not deletion here.

PREDICT, RUN, COMPARE
The first demonstration also changes the copied correction to EUR 320 while
claiming revision 2. Predict the rejection and retained history. For board 42b,
the script starts a fresh temporary database, imports both original dates and
deliberately replaces this process's report-writing function with one that
raises an error. The database still accepts the valid correction. The helper
restores the ordinary writer in finally, then repeats the correction to rebuild
the report. This is controlled fault injection, not an external outage.

ONE MORE INPUT TO REASON THROUGH
After a valid revision 2 is stored, what if revision 3 supplies exactly the
same cost and enquiry values? Should the campaign totals change?

EXPLAINED ANSWER
The stored revision advances to 3; cost and enquiry totals stay EUR 430 / 21
for 1 October. A later revision-2 delivery becomes stale even if its values are
identical. The rule uses source revisions as well as values. You can check in
a fresh disposable run by passing revision=3 for the same correction, then
inspecting revision with a SELECT query. Do not invent revisions to bypass an
unexplained source problem in a live integration.

ABOUT THE SMALL HARNESS
Each SQLite connection is closed in finally. The report-writing replacement
exists only in the current Python process and is also restored in finally.
The source file defining the function is never edited. The demonstration
compares actual database and CSV totals so the recovery result is observable.

EXPECTED OUTPUT (verified by execution)

42a: Original import, exact replay, correction, stale replay
Original: EUR 420.00; 20 enquiries
Exact replay: EUR 420.00; 20 enquiries
Correction revision 2: EUR 430.00; 21 enquiries
Stale replay rejected: Older revision would replace newer data
Retained: EUR 430.00; 21 enquiries
Equal-revision conflict rejected: Changed values need a newer revision
42b: Accepted history versus exported view
Before correction, database: EUR 700.00; 35 enquiries
Before correction, report: EUR 700.00; 35 enquiries
Export failure: Simulated report write failure
After failure, database: EUR 710.00; 36 enquiries
After failure, report: EUR 700.00; 35 enquiries
After safe repeat, database: EUR 710.00; 36 enquiries
After safe repeat, report: EUR 710.00; 36 enquiries
Combined cost per enquiry: EUR 19.72

All data in this lab are fictional teaching examples.
