store: refusals leave the live books untouched; per-filing names; spec suite
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The refusal property gained the converse law (an accepted command journals something; only batch runs may find nothing to do) and checks the store's class and payroll listings. It found a schedule registered with an out-of-range total whose first month was refused after its entry was begun: the live ledger kept a draft the journal never had. - Core: compound commands (post_schedule_month, reverse_entry, close_period_to, create_invoice, create_bill, receive_payment, pay_bill, run_payroll, remit_payroll_taxes) run inside Ledger::atomically, so a refusal partway leaves the ledger exactly as it was. - Core: a schedule total no line could carry, or finer than a cent, and an asset cost beyond the line range, are refused at registration. Replay keeps older schedules (replay_register_schedule). - Store: add_line, add_line_fx, mark_cleared, set_fx_rate, post_schedule_month and close_period_to changed the live ledger before journaling; they now run on a copy, journal what it produced, then swap it in, so a failed write leaves the live books as journaled. New spec-blind suite tests/spec_store.rs (57 tests written from the store's specs alone). Its two findings, adjudicated: - A file filed twice under different names listed the first name and type for both (the projection kept them per blob). Schema v8 gives each attachment its own; older databases backfill and heal by verify. - Withdrawn attachments stay in the store's listing, marked (the MCP listing hides them): the spec and doc said "omit" and are corrected. Also removes journal::truncate_to_last_good_seq: unused, and it dropped everything after the first bad complete line, which the books now treat as corruption for a person, never repaired automatically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
8a49f0ff0e
commit
4d8d5daf37
11 files changed
+2075
-75
No files matched your search
@@ -21,15 +21,13 @@ easily backupable, journable":
|
||||
from rewriting the chain — nothing local does.
|
||||
- **Backupable.** The backup is `cp -r $WANDERBOOKS_DATA /backup`: the
|
||||
journal file plus the blob directory. Plain files, no WAL-file timing
|
||||
windows, no special backup API. A torn tail from a mid-copy is detectable
|
||||
(the last line fails hash/parse) and recoverable (truncate to the last
|
||||
good seq — the projection never saw it). The live journal recovers the
|
||||
same way on its own: an append cut off by a crash or power loss (bytes
|
||||
after the last newline) was never acknowledged, so opening the books
|
||||
saves those bytes to `journal.jsonl.torn.<time>`, truncates to the last
|
||||
newline, and journals a `journal.tail_repaired` line; `books.digest`
|
||||
reports it. Damage before the last newline is corruption and still
|
||||
refuses to open. Better: the journal is
|
||||
windows, no special backup API. A copy taken mid-write, like a crash or
|
||||
power loss mid-append, can end in a cut-off line (bytes after the last
|
||||
newline). It was never acknowledged, so opening the books saves those
|
||||
bytes to `journal.jsonl.torn.<time>`, truncates to the last newline, and
|
||||
journals a `journal.tail_repaired` line; `books.digest` reports it.
|
||||
Damage before the last newline is corruption and refuses to open: that
|
||||
is for a human, never repaired automatically. Better: the journal is
|
||||
git-friendly, so an optional `wanderbooks backup` that commits it to a
|
||||
private git repo gives versioned, distributed, deduplicated backup with
|
||||
full history.
|
||||
|
||||
Reference in new issue
Block a user