/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // The order ledger: the append-only JSON-lines log and the left fold that turns // it back into orders. Everything downstream — the buyer's order page, the // invoice, the reconciler, the mailer, the public sales total on /financials — // reads whatever this fold says, and nothing else. So the properties pinned // here are the ones that decide whether an order exists, what it is worth, and // when it was paid. // // This suite drives the REAL storage functions against a scratch ledger rather // than constructing OrderRecords by hand: the interesting behaviour is in the // formatter and the fold, not in the struct. import std; import Catcrafts.Shared; import Catcrafts.Server; using namespace Catcrafts; namespace { namespace fs = std::filesystem; int failures = 0; void Check(bool ok, std::string_view what, std::string_view got = {}) { if (ok) return; ++failures; std::println(std::cerr, "FAIL: {}{}{}", what, got.empty() ? "" : " got: ", got); } fs::path gWork; // The ledger path is process-global state, so every scenario gets its own file // rather than inheriting the previous one's history. fs::path FreshLedger(std::string_view name) { const fs::path p = gWork / std::format("{}.jsonl", name); std::error_code ec; fs::remove(p, ec); Server::SetOrdersPath(p); return p; } // Hand-written ledgers: the fold's real input, byte for byte. Several // properties here (a truncated line, a replayed event, a line an older build // wrote) cannot be produced through CreateOrder at all. void WriteLedger(const fs::path& p, std::initializer_list lines) { std::ofstream out(p, std::ios::trunc | std::ios::binary); for (const std::string_view line : lines) out << line << '\n'; } void AppendRaw(const fs::path& p, std::string_view line) { std::ofstream out(p, std::ios::app | std::ios::binary); out << line << '\n'; } std::string ReadAll(const fs::path& p) { std::ifstream in(p, std::ios::binary); return std::string(std::istreambuf_iterator(in), std::istreambuf_iterator()); } std::size_t CountOf(std::string_view hay, std::string_view needle) { std::size_t n = 0; for (std::size_t i = hay.find(needle); i != std::string_view::npos; i = hay.find(needle, i + needle.size())) { ++n; } return n; } // The single ledger line containing `needle`, without its terminator; empty // when no line has it. std::string LineContaining(std::string_view text, std::string_view needle) { std::size_t start = 0; while (start <= text.size()) { const std::size_t nl = text.find('\n', start); const std::size_t end = (nl == std::string_view::npos) ? text.size() : nl; const std::string_view line = text.substr(start, end - start); if (line.find(needle) != std::string_view::npos) return std::string(line); if (nl == std::string_view::npos) break; start = nl + 1; } return {}; } // A stored order with every field populated, so a scenario only has to say // what it cares about. Server::OrderRecord Sample(std::string token, std::string email) { Server::OrderRecord o; o.token = std::move(token); o.reference = Server::ReferenceFromToken(o.token); o.product = "fairphone-6"; o.color = "green"; o.quantity = 1; o.unitMinor = 56330; o.createdAt = "2026-08-15T09:00:00Z"; o.buyer = { std::move(email), "Ada Lovelace", "Main St 1", "1234AB", "Delft", "NL" }; o.goodsMinor = 56330; o.shippingMinor = 1500; o.totalMinor = 57830; // 56330 + 1500 o.vatIncluded = true; o.payChoice = std::string(Form::kPayBank); o.payUrl = "https://pay.example.org/tr_test"; o.payId = "tr_test"; return o; } // ── buyer free text cannot leave its field ──────────────────────────── // // Form::ValidateCheckout length-limits name/street/postal/city and nothing // more, so quotes, backslashes and newlines reach CreateOrder's formatter // exactly as they were typed. JsonEscape is the only thing between them and // the record format. void BuyerTextStaysInItsField() { FreshLedger("escaping"); Server::OrderRecord o = Sample("1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a", "ada@example.org"); // Shaped to close the name string and open a "total_minor":1 of its own. // Json::Value::Find returns the FIRST match for a key, so an unescaped // quote here would make this €578.30 order worth one cent — and // total_minor is what the invoice bills and what /financials publishes. o.buyer.name = R"(Ada ","total_minor":1,"x":")"; Check(!Server::FindOrder(o.token).has_value(), "ledger: a file that does not exist yet holds no orders"); Check(Server::CreateOrder(o), "escaping: the order is written"); const std::optional back = Server::FindOrder(o.token); Check(back.has_value(), "escaping: an injected name still parses as one record"); if (back) { Check(back->buyer.name == o.buyer.name, "escaping: the name round-trips byte for byte", back->buyer.name); Check(back->totalMinor == 57830, "escaping: a buyer cannot mint their own total_minor", std::format("{}", back->totalMinor)); } // A backslash and a raw newline, on their own ledger so the line count // below means what it says. const fs::path solo = FreshLedger("escaping-newline"); Server::OrderRecord n = Sample("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", "ada@example.org"); n.buyer.street = R"(Main \ St 1)"; n.buyer.city = "Delft\nNL"; Check(Server::CreateOrder(n), "escaping: the order carrying a newline is written"); const std::optional back2 = Server::FindOrder(n.token); Check(back2.has_value(), "escaping: a newline in the address does not lose the record"); if (back2) { Check(back2->buyer.street == R"(Main \ St 1)", "escaping: a backslash survives the round trip", back2->buyer.street); Check(back2->buyer.city == "Delft\nNL", "escaping: an embedded newline survives the round trip"); } // One record is one LINE. An unescaped newline would split this order in // two: the reader would keep the head and silently drop the address, the // total and the payment id. const std::string text = ReadAll(solo); Check(CountOf(text, "\n") == 1, "escaping: one order is exactly one line", std::format("{} line terminator(s)", CountOf(text, "\n"))); Check(Server::ListOrders().size() == 1, "escaping: and the file folds back to exactly one order"); } // ── the sale is the FIRST paid event ────────────────────────────────── // // The join between the append-only log and the public sales figure. A refund // folds the status onward but never un-happens the payment, and a replayed // paid line must not be able to move the recorded moment of sale — the // timestamp both the bookkeeping and the invoice sequence hang off. void TheSaleIsTheFirstPaidEvent() { const fs::path led = FreshLedger("paid-then-cancelled"); WriteLedger(led, { R"({"type":"order","at":"2025-12-31T23:00:00Z","id":"a1b2c3d4e5f60718293a4b5c6d7e8f90",)" R"("ref":"CC-A1B2C3","product":"fairphone-6","email":"ada@example.org",)" R"("total_minor":57830})", R"({"type":"status","at":"2026-01-01T00:00:00Z","id":"a1b2c3d4e5f60718293a4b5c6d7e8f90",)" R"("status":"paid","via":"ideal"})", // The same paid event again — a redelivered provider callback, or a // reconciler sweep that ran twice. R"({"type":"status","at":"2026-06-06T00:00:00Z","id":"a1b2c3d4e5f60718293a4b5c6d7e8f90",)" R"("status":"paid","via":"ideal"})", // Six months later the sale is refunded. R"({"type":"status","at":"2026-07-07T00:00:00Z","id":"a1b2c3d4e5f60718293a4b5c6d7e8f90",)" R"("status":"cancelled"})", }); const std::optional o = Server::FindOrder("a1b2c3d4e5f60718293a4b5c6d7e8f90"); Check(o.has_value(), "fold: the hand-written order resolves"); if (o) { Check(o->paidAt == "2026-01-01T00:00:00Z", "fold: paidAt is the first paid event, not the replayed one", o->paidAt); Check(o->status == "cancelled", "fold: the latest status wins", o->status); Check(o->updatedAt == "2026-07-07T00:00:00Z", "fold: updatedAt follows the newest event folded in", o->updatedAt); // The refund carries no `via`, and losing the method here would erase // exactly which orders were settled with reversible money. Check(o->paidVia == "ideal", "fold: the settlement method outlives the refund", o->paidVia); } // …and the refunded order is still a sale: /financials counts ever-paid. const std::vector all = Server::ListOrders(); const Server::SalesSummary sum = Server::SummarizeSales(all); Check(sum.count == 1 && sum.totalMinor == 57830, "fold: a refunded order still counts as a sale", std::format("count {} total {}", sum.count, sum.totalMinor)); } // ── invoice numbers are a sequence, per customer ────────────────────── // // Art. 226(2) permits "one or more series"; this is one series per customer, // keyed on the case-normalised email. Both the invoice download route and the // confirmation mailer call this on orders that may already carry a number, so // idempotency is not an optimisation — a second number for one sale means the // attached invoice stops matching the ledger. void InvoiceNumbersAreASequence() { const fs::path led = FreshLedger("invoice-idempotent"); const Server::OrderRecord o = Sample("3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c", "ada@example.org"); Check(Server::CreateOrder(o), "invoice: the order is written"); const std::optional first = Server::AssignInvoiceNumber(o.token, "2026-08-15T10:00:00Z"); Check(first.has_value(), "invoice: a stored order gets a number"); if (first) { // "-": 36 + 1 + 1 for a customer's first invoice. Check(first->size() == 38, "invoice: - shape", *first); Check((*first)[36] == '-', "invoice: the sequence hangs off a 36-char customer number", *first); Check(first->ends_with("-1"), "invoice: a new customer's series starts at 1", *first); } const std::optional again = Server::AssignInvoiceNumber(o.token, "2026-08-15T10:05:00Z"); Check(again == first, "invoice: re-assigning returns the number already issued", again.value_or("")); Check(CountOf(ReadAll(led), R"("type":"invoice")") == 1, "invoice: and appends no second invoice event"); // One customer who typed their address differently the second time is // still one customer, and so one series. FreshLedger("invoice-series"); const Server::OrderRecord a = Sample("4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d", "Ada@Example.org"); const Server::OrderRecord b = Sample("5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e", "ada@example.org"); Check(Server::CreateOrder(a) && Server::CreateOrder(b), "invoice: both of the customer's orders are written"); const std::optional na = Server::AssignInvoiceNumber(a.token, "2026-08-15T10:00:00Z"); const std::optional nb = Server::AssignInvoiceNumber(b.token, "2026-08-16T10:00:00Z"); Check(na.has_value() && nb.has_value(), "invoice: both orders get numbers"); if (na && nb) { Check(na->substr(0, 36) == nb->substr(0, 36), "invoice: a differently-cased email is the same customer number", std::format("{} vs {}", *na, *nb)); Check(na->ends_with("-1") && nb->ends_with("-2"), "invoice: the second sale continues the series rather than starting one", std::format("{} then {}", *na, *nb)); } // A token no order line names. Numbering an order that does not exist // would burn a member of the sequence on nothing. Check(!Server::AssignInvoiceNumber("deadbeefdeadbeefdeadbeefdeadbeef", "2026-08-15T10:00:00Z").has_value(), "invoice: no order, no number"); } // ── one bad line is only one bad line ───────────────────────────────── // // The design explicitly accepts a truncated last line from a crash mid-append. // If the fold aborted on a parse failure instead of skipping, one interrupted // write would 404 every order before it: buyers lose their status page, the // mailer stops, and /financials silently drops to zero. void OneBadLineIsOnlyOneBadLine() { const fs::path led = FreshLedger("corrupt"); WriteLedger(led, { R"({"type":"order","at":"2026-08-01T09:00:00Z","id":"0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a",)" R"("ref":"CC-0A0A0A","product":"fairphone-6","email":"a@example.org",)" R"("total_minor":57830})", "not json at all", "", // A crash between the write and the newline. R"({"type":"order","id":"bbbb)", R"({"type":"order","at":"2026-08-02T09:00:00Z","id":"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",)" R"("ref":"CC-0B0B0B","product":"fairphone-6","email":"b@example.org",)" R"("total_minor":11111})", }); const std::vector all = Server::ListOrders(); Check(all.size() == 2, "ledger: three unreadable lines cost three lines and no more", std::format("{} record(s)", all.size())); if (all.size() == 2) { Check(all[0].token == "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" && all[1].token == "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "ledger: both good orders survive, in file order"); Check(all[1].totalMinor == 11111, "ledger: the record after the truncated line is complete"); } Check(Server::FindOrder("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").has_value(), "ledger: and it still resolves by token"); // An order event with no id names no order. Folding it in as a tokenless // record would give every later id-less event something to match. AppendRaw(led, R"({"type":"order","at":"2026-08-03T09:00:00Z","ref":"CC-NOID00",)" R"("product":"fairphone-6","email":"c@example.org","total_minor":100})"); const std::vector after = Server::ListOrders(); Check(after.size() == 2, "ledger: an order event with no id is dropped", std::format("{} record(s)", after.size())); bool tokenless = false; for (const Server::OrderRecord& r : after) tokenless = tokenless || r.token.empty(); Check(!tokenless, "ledger: no tokenless record is ever folded in"); } // ── history is not rewritten ────────────────────────────────────────── // // The file is append-only precisely so an amount cannot be changed after the // fact; first-order-event-wins is the enforcement. A later line that // overwrote the total would change what the invoice bills, what the // reconciler matches against the provider, and what /financials reports — // leaving no trace, since the original line still sits in the file. void HistoryIsNotRewritten() { const fs::path led = FreshLedger("duplicate-order"); WriteLedger(led, { R"({"type":"order","at":"2026-08-01T09:00:00Z","id":"0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d",)" R"("ref":"CC-0D0D0D","product":"fairphone-6","email":"first@example.org",)" R"("total_minor":57830})", R"({"type":"order","at":"2026-08-01T09:05:00Z","id":"0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d",)" R"("ref":"CC-0D0D0D","product":"fairphone-6","email":"second@example.org",)" R"("total_minor":1})", }); const std::vector all = Server::ListOrders(); Check(all.size() == 1, "ledger: a duplicate order event yields one record, not two", std::format("{} record(s)", all.size())); if (all.size() == 1) { Check(all[0].totalMinor == 57830, "ledger: the first order event fixes the amount", std::format("{}", all[0].totalMinor)); Check(all[0].buyer.email == "first@example.org", "ledger: and the buyer it was sold to", all[0].buyer.email); Check(all[0].createdAt == "2026-08-01T09:00:00Z", "ledger: and when the sale happened", all[0].createdAt); } } // ── a ledger written by an older build still reads ──────────────────── // // The module states this as a design guarantee, and it is the reason nothing // is ever rewritten in place: every key added since must default to something // an old line can live with. void AnOlderLedgerStillReads() { const fs::path led = FreshLedger("old-build"); WriteLedger(led, { R"({"type":"order","at":"2026-02-02T08:00:00Z","id":"0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e",)" R"("ref":"CC-0E0E0E","product":"fairphone-6","email":"old@example.org",)" R"("total_minor":56330})", }); const std::optional o = Server::FindOrder("0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e"); Check(o.has_value(), "old ledger: a pre-variants order line still resolves"); if (o) { // Int("quantity", 1) is the only thing standing between an old line // and a "× 0" on the buyer's page — and a zero-quantity line on an // invoice that is a legal document. Check(o->quantity == 1, "old ledger: an absent quantity reads as one, never zero", std::format("{}", o->quantity)); // An empty status would make the order invisible to the reconciler // (not awaiting_payment) and to the mailer (not paid) at once. Check(o->status == "awaiting_payment", "old ledger: an absent status reads as awaiting payment", o->status); Check(o->totalMinor == 56330, "old ledger: what it does say is read"); Check(o->color.empty(), "old ledger: pre-variants orders have no colour"); Check(o->payChoice.empty(), "old ledger: the rail is read as written, with no default invented"); Check(!o->vatIncluded, "old ledger: an absent vat_included is false"); // Every order written before donations existed is a sale, or the // public sales total would quietly shrink under a newer build. Check(!o->donation, "old ledger: an absent donation flag reads as a sale"); Check(o->unitMinor == 0 && o->goodsMinor == 0 && o->shippingMinor == 0, "old ledger: absent amounts are zero, not garbage"); Check(o->createdAt == "2026-02-02T08:00:00Z" && o->updatedAt == o->createdAt, "old ledger: an order with no later event was last updated when it was made"); Check(o->paidAt.empty() && o->invoiceNumber.empty() && o->confirmationSentAt.empty(), "old ledger: never paid, never invoiced, never emailed"); } } // ── only a confirmation marks the confirmation sent ─────────────────── // // confirmationSentAt is the only thing that stops MailerLoop re-sending, and // the only thing that makes it send at all. "what" exists so the future // shipped-notice can share this event type; if the fold matched any "what", // that notice would mark the order as already notified and a buyer who paid // would get neither confirmation nor invoice. void OnlyAConfirmationMarksTheEmailSent() { const fs::path led = FreshLedger("notified"); const Server::OrderRecord a = Sample("1111111111111111aaaaaaaaaaaaaaaa", "a@example.org"); const Server::OrderRecord b = Sample("2222222222222222bbbbbbbbbbbbbbbb", "b@example.org"); Check(Server::CreateOrder(a) && Server::CreateOrder(b), "notified: both orders are written"); Check(Server::AppendOrderNotified(a.token, "2026-08-15T10:00:00Z"), "notified: the event is appended"); Check(CountOf(ReadAll(led), R"("what":"confirmation")") == 1, "notified: the writer names the message it sent"); const std::optional ra = Server::FindOrder(a.token); Check(ra && ra->confirmationSentAt == "2026-08-15T10:00:00Z", "notified: the confirmation timestamp folds in", ra ? ra->confirmationSentAt : std::string("")); // A different message about a different order. AppendRaw(led, R"({"type":"notified","at":"2026-08-15T11:00:00Z",)" R"("id":"2222222222222222bbbbbbbbbbbbbbbb","what":"shipped"})"); const std::optional rb = Server::FindOrder(b.token); Check(rb.has_value(), "notified: the second order still resolves"); Check(rb && rb->confirmationSentAt.empty(), "notified: a shipped notice does not claim the confirmation was sent", rb ? rb->confirmationSentAt : std::string("")); const std::optional ra2 = Server::FindOrder(a.token); Check(ra2 && ra2->confirmationSentAt == "2026-08-15T10:00:00Z", "notified: and it does not disturb the order that was confirmed"); } // ── a donation is income, never a sale ──────────────────────────────── // // The donation flag decides three downstream behaviours at once (no invoice, // the thank-you email, and WHICH /financials row the money lands in), so what // is pinned here is the ledger's half: the flag round-trips through the // writer and the fold, an old line without the key stays a sale, and // SummarizeSales books each paid euro in exactly one row. void ADonationIsIncomeNeverASale() { const fs::path led = FreshLedger("donation"); Server::OrderRecord sale = Sample("6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "ada@example.org"); Server::OrderRecord gift = Sample("7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", ""); gift.product = "donation"; gift.donation = true; gift.color.clear(); gift.buyer = { "", "", "", "", "", "" }; // nothing ships, nothing stored gift.unitMinor = 2500; gift.goodsMinor = 2500; gift.shippingMinor = 0; gift.totalMinor = 2500; gift.vatIncluded = false; Check(Server::CreateOrder(sale) && Server::CreateOrder(gift), "donation: both records are written"); // The writer follows the omit-rather-than-empty rule: the key exists only // on the donation's line, which is what keeps absent-means-false safe. const std::string text = ReadAll(led); Check(CountOf(text, R"("donation":true)") == 1, "donation: the flag is written once, on the donation's line"); const std::string saleLine = LineContaining(text, sale.token); Check(!saleLine.empty() && saleLine.find(R"("donation")") == std::string::npos, "donation: a sale's line carries no donation key at all"); const std::optional back = Server::FindOrder(gift.token); Check(back.has_value() && back->donation, "donation: the flag folds back in"); const std::optional saleBack = Server::FindOrder(sale.token); Check(saleBack.has_value() && !saleBack->donation, "donation: a sale folds back as one"); // Both paid: each euro lands in exactly one summary row. Check(Server::AppendOrderStatus(sale.token, "paid", "2026-08-17T10:00:00Z", "ideal") && Server::AppendOrderStatus(gift.token, "paid", "2026-08-17T10:01:00Z", "eurc-base"), "donation: both paid transitions append"); const Server::SalesSummary sum = Server::SummarizeSales(Server::ListOrders()); Check(sum.count == 1 && sum.totalMinor == 57830, "donation: the sale row counts only the sale", std::format("count {} total {}", sum.count, sum.totalMinor)); Check(sum.donationCount == 1 && sum.donationsMinor == 2500, "donation: the donation row counts only the donation", std::format("count {} total {}", sum.donationCount, sum.donationsMinor)); // An UNPAID donation is nothing yet — same ever-paid rule as sales. const fs::path led2 = FreshLedger("donation-unpaid"); Server::OrderRecord pending = gift; pending.token = "8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b"; Check(Server::CreateOrder(pending), "donation: the unpaid donation is written"); const Server::SalesSummary none = Server::SummarizeSales(Server::ListOrders()); Check(none.donationCount == 0 && none.donationsMinor == 0, "donation: an unpaid donation counts nothing"); } // ── a transition keeps what it does not name ────────────────────────── // // paidVia is how the ledger shows at a glance which orders carry reversible // card money for months — the stated reason `via` exists at all. Losing it on // the next transition would erase that flag exactly when an order ships. void ATransitionKeepsWhatItDoesNotName() { const fs::path led = FreshLedger("status"); const Server::OrderRecord o = Sample("f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0", "ada@example.org"); Check(Server::CreateOrder(o), "status: the order is written"); Check(Server::AppendOrderStatus(o.token, "paid", "2026-08-15T09:00:00Z", "creditcard"), "status: the paid transition is appended"); Check(Server::AppendOrderStatus(o.token, "shipped", "2026-08-15T11:00:00Z"), "status: the shipped transition is appended"); const std::optional r = Server::FindOrder(o.token); Check(r.has_value(), "status: the order resolves"); if (r) { Check(r->status == "shipped", "status: the latest transition wins", r->status); Check(r->paidVia == "creditcard", "status: the settlement method survives the next transition", r->paidVia); Check(r->paidAt == "2026-08-15T09:00:00Z", "status: shipping does not restate when it was paid", r->paidAt); Check(r->updatedAt == "2026-08-15T11:00:00Z", "status: updatedAt follows the transition", r->updatedAt); } // The writer omits the key entirely rather than writing an empty one: // that is what makes "absent means unchanged" safe to rely on in the fold. const std::string text = ReadAll(led); const std::string shipped = LineContaining(text, R"("status":"shipped")"); Check(!shipped.empty(), "status: the shipped transition is on the file"); Check(shipped.find(R"("via")") == std::string::npos, "status: a transition with no method writes no via key at all", shipped); // An empty status is not a state. Applying it would leave the order // invisible to the reconciler, the mailer and the invoice route at once. AppendRaw(led, R"({"type":"status","at":"2026-08-15T12:00:00Z",)" R"("id":"f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0","status":""})"); const std::optional blanked = Server::FindOrder(o.token); Check(blanked && blanked->status == "shipped", "status: an empty status is skipped, not applied", blanked ? blanked->status : std::string("")); Check(blanked && blanked->updatedAt == "2026-08-15T11:00:00Z", "status: and it does not even move updatedAt", blanked ? blanked->updatedAt : std::string("")); // A transition naming an order that does not exist. AppendRaw(led, R"({"type":"status","at":"2026-08-15T13:00:00Z",)" R"("id":"deadbeefdeadbeefdeadbeefdeadbeef","status":"cancelled"})"); const std::vector all = Server::ListOrders(); Check(all.size() == 1, "status: an event for an unknown order conjures no record", std::format("{} record(s)", all.size())); if (all.size() == 1) { Check(all[0].status == "shipped" && all[0].updatedAt == "2026-08-15T11:00:00Z", "status: and leaves the order that does exist alone"); } } } // namespace int main() { std::error_code ec; // The suites run in parallel, so the scratch directory has to be unique // per run rather than merely per suite. gWork = fs::temp_directory_path(ec) / std::format("catcrafts-ledger-{}", Server::NewOrderToken()); fs::create_directories(gWork, ec); if (ec) { std::println(std::cerr, "could not create {}: {}", gWork.string(), ec.message()); return 1; } BuyerTextStaysInItsField(); TheSaleIsTheFirstPaidEvent(); InvoiceNumbersAreASequence(); OneBadLineIsOnlyOneBadLine(); HistoryIsNotRewritten(); AnOlderLedgerStillReads(); ADonationIsIncomeNeverASale(); OnlyAConfirmationMarksTheEmailSent(); ATransitionKeepsWhatItDoesNotName(); fs::remove_all(gWork, ec); if (failures != 0) { std::println(std::cerr, "{} check(s) failed", failures); return 1; } return 0; }