<spanclass="side-label">Today's calculation, ninety days re-run</span>
<spanclass="figure num">$81,023.96</span>
<spanclass="subfig"><spanclass="num">1,451</span> days out of balance · <spanclass="num">92.32%</span> clean</span>
<spanclass="figure num">$70,276.50</span>
<spanclass="subfig"><spanclass="num">1,191</span> days out of balance · <spanclass="num">93.70%</span> clean</span>
</div>
<divclass="arrow"aria-hidden="true">→</div>
<div>
<spanclass="side-label">The same ninety days, fixes on</span>
<spanclass="figure after num">$20,239.00</span>
<spanclass="subfig"><spanclass="num">542</span> days out of balance · <spanclass="num">97.13%</span> clean</span>
<spanclass="figure after num">$2,379.45</span>
<spanclass="subfig"><spanclass="num">122</span> days out of balance · <spanclass="num">99.35%</span> clean</span>
</div>
</div>
<divclass="stats">
<divclass="stat"><spanclass="k num">915</span><spanclass="l">client-days brought into balance</span></div>
<divclass="stat"><spanclass="k num">6</span><spanclass="l">days knocked out of balance</span></div>
<divclass="stat"><spanclass="k num">75.0%</span><spanclass="l">of the variance removed</span></div>
<divclass="stat"><spanclass="k num">1,069</span><spanclass="l">client-days brought into balance</span></div>
<divclass="stat zero"><spanclass="k num">0</span><spanclass="l">days knocked out of balance</span></div>
<divclass="stat"><spanclass="k num">96.6%</span><spanclass="l">of the variance removed</span></div>
<divclass="stat zero"><spanclass="k num">0</span><spanclass="l">payments shared between two clients</span></div>
</div>
<divclass="measure">
<p><strong>In one sentence:</strong> a day's sales summary should show the money taken and the money earned agreeing to the penny, and on roughly one trading day in eight it did not — because two clients were fighting over the same records, tips that had been refunded were still counted as income, and service charges customers paid were credited to nothing.</p>
<p><strong>How the two figures above were produced.</strong> Both are the real nightly job, run over the same ninety days against the same restored database, writing real summaries each time — the first pass with the fixes switched off, the second with them on. Comparing a re-run against a re-run rather than against production's stored summaries is the stricter test: production's figures are in places months stale, and crediting the fixes with repairing ordinary staleness would flatter them. On that fairer footing the fixes are worth <strong>a net 909 days and $60,784.96</strong>, not the larger number a stale baseline would have shown. Both passes ran with the duplicate client records left active, which is how this will actually be deployed.</p>
<p><strong>How the two figures above were produced.</strong> Both are the real nightly job, run over the same ninety days against the same restored database, writing real summaries each time — the first pass with the fixes switched off, the second with them on. Comparing a re-run against a re-run rather than against production's stored summaries is the stricter test: production's figures are in places months stale, and crediting the fixes with repairing ordinary staleness would flatter them. On that fairer footing the fixes are worth <strong>1,069 days and $67,897.05</strong>, not the larger number a stale baseline would have shown. Both passes ran with the duplicate client records left active, which is how this will actually be deployed.</p>
<p><strong>Most of what is left is not a balancing fault at all</strong>, and the section on the fourth problem explains why deliberately leaving it unbalanced is the right call.</p>
</div>
</section>
@@ -169,7 +169,7 @@
<p>The obvious reading is that the refund simply settled on a closed day. It is the wrong one. Checking each of those days against the date its client first recorded <em>any</em> order shows <strong>140 of 171 fall before that client had a single order in the system</strong> — for seven of the nine records affected, every single one does. These are not quiet days. They are periods where the sales were never imported at all.</p>
<p><strong>Where the refunds came from.</strong> Reading the database's own ownership history settles it. A $35.35 refund dated 26 February belonged to <spanclass="mono">NGDG</span> that same day, and was taken over by <spanclass="mono">NGDU</span> on 12 August. Others flip between the two records several times a day across 12–15 August. <spanclass="mono">NGDU</span>'s first order is 2 August; it holds 94 refunds dated before it existed as a trading record. It never made them — it inherited seven months of the other record's refunds, because the refund key carried no client and whichever import ran last took ownership. That is fault 1, seen from the other end.</p>
<p>Across the nine records, <strong>660 refunds worth $15,237.02 sit on a record dated before that record's first order.</strong> Nothing is lost and nothing is double-counted — the money is real and the surviving record has its own copy — but it is filed against a set of books that has no sales to put it against.</p>
<p><strong>Why it is deliberately left out of balance.</strong> The day can be closed in one line: book a return equal to the day's refunds whenever the client recorded no sales. It is safe by construction — no trading day could be touched — and on this data it closes 171 of the 542 remaining days and $5,795.18. It was built, measured, and then removed, because it is the wrong thing to do. An unbalanced day is the only visible signal that a restaurant's sales are not being imported. Making the arithmetic agree would remove the alarm and leave the fire.</p>
<p><strong>Why it is deliberately left out of balance.</strong> The day can be closed in one line: book a return equal to the day's refunds whenever the client recorded no sales. It is safe by construction — no trading day could be touched — and on this data it closes 16 of the 122 remaining days and $1,227.65. It was built, measured, and then removed, because it is the wrong thing to do. An unbalanced day is the only visible signal that a restaurant's sales are not being imported. Making the arithmetic agree would remove the alarm and leave the fire.</p>
<p><spanclass="tech">technical</span><code>get-returns</code> sums <code>:sales-order/returns</code> over orders scanned for the date. With no orders the sum is nil and no <code>Returns</code> line is written, while <code>get-refund-items</code> still credits <code>Card Refunds</code> from the <code>sales-refund</code> records. The imbalance is the correct output for the input; the input is what is wrong. A test now pins this behaviour in place so it is not "fixed" by someone reading only the arithmetic.</p>
</div>
</div>
@@ -371,9 +371,9 @@
<table>
<thead><tr><th>Stage</th><thclass="n">Days out of balance</th><thclass="n">Clean</th><thclass="n">Total variance</th></tr></thead>
<tbody>
<tr><td>Today's calculation, ninety days re-run</td><tdclass="n">1,451</td><tdclass="n">92.32%</td><tdclass="n">$81,023.96</td></tr>
<trclass="total"><td>+ service charges</td><tdclass="n good">122</td><tdclass="n good">99.35%</td><tdclass="n good">$2,379.45</td></tr>
</tbody>
</table>
</div>
@@ -386,15 +386,23 @@
<table>
<thead><tr><th>Change</th><thclass="n">Unchanged</th><thclass="n">Into balance</th><thclass="n">Out of balance</th><thclass="n">Balanced days altered</th><thclass="n">Money moved</th></tr></thead>
<trclass="total"><td>Both, end to end</td><tdclass="n">17,916</td><tdclass="n good">915</td><tdclass="n bad">6</td><tdclass="n bad">6</td><tdclass="n">$60,784.96</td></tr>
<trclass="total"><td>Both, end to end</td><tdclass="n">17,827</td><tdclass="n good">1,069</td><tdclass="n good">0</td><tdclass="n good">0</td><tdclass="n">$67,897.05</td></tr>
</tbody>
</table>
</div>
<divclass="measure">
<p><strong>Six days were knocked out of balance, and they are worth understanding rather than hiding.</strong> Across all 18,900 client-days, 17,916 summaries came out byte-identical and 978 of the 984 that moved were already wrong. The six exceptions all have one shape: the <code>Tip</code> line drops by a round amount — $10, $15, $20, $30, $30, $50 — and the day breaks by exactly that. They are all on shared-location records (NGDG, NGEZ, NGDA, NGBK).</p>
<p>That is the tip fix working, not failing. Each is a tip that was handed back: the reversal sits on this record's order, but the refund that should offset it went to the record's twin. Before the fix the day balanced by accident, because the reversal was ignored. After it, the day correctly shows that half the transaction is filed elsewhere. The honest description is that the fix converts a hidden mis-attribution into a visible one — which is the same trade the fourth problem below makes deliberately.</p>
<p><strong>Neither fix touched a day that was already correct.</strong> Across all 18,900
client-days no balanced day was knocked out of balance, and no balanced day had a single
figure altered — 17,827 summaries came out byte-identical, and every one of the 1,073 that
moved was already wrong.</p>
<p>That claim did not hold on the first attempt, and how it was recovered is the useful part.
Measured before the historical backfill described below, six days broke — all of them a tip
reversed on one record whose refund sat on its twin, so removing the un-reversed tip left the
day short by exactly that amount. Replaying the window from Square gave both records their own
copy of every refund, and all six closed. The fix was never wrong; it was reading half a
transaction.</p>
<p>Service charges are by far the larger of the two fixes, moving $58,923.85 against the tip fix's $3,777.67.</p>
<p>That claim is stronger than a balance check, and it is the one worth insisting on: a day can stay balanced while its individual lines move, which would still be a change to the books. Every line of every summary was compared — category, debit or credit side, amount to the cent, and account — not just the day's bottom line.</p>
<p><strong>The two fixes account for every day they moved, exactly.</strong> Adding up the untendered-tip and service-charge amounts across all 984 changed days leaves a residue of <spanclass="mono">0.0000000002</span>. Nothing else moved those days; there is no unexplained remainder hiding a third effect, and the six that broke are accounted for by the same arithmetic as the 915 that healed.</p>
@@ -477,12 +485,12 @@
</div>
<divclass="measure">
<p>The count checks are the ones that matter. If re-keying had gone wrong it would have created a second copy of every record rather than updating the existing one, and the totals would have doubled. They did not move. The payment-copy step is the exception and is meant to add records — it added 500,438, matching the number of copies it reported making. (Close, not exact: the counter increments while the transaction is being assembled, so two copies that resolve onto one entity are counted twice. It is a good check, not a proof.)</p>
<p><strong>The measurement above was taken with the duplicate client records deactivated, and that is not how this will be deployed.</strong>Leaving both records live is the intended configuration — the re-key is what separates them — but it means the deactivation that made this measurement clean will not be there. The gap that opens is narrow and specific: while any record still carries a legacy key, a second client can resolve onto it. That is why the deployment runs the migration with imports paused, and why <code>existing-id</code> now refuses to resolve a record belonging to another client.</p>
<p><strong>The measurement above was taken with both client records of each pair left live, which is how this deploys.</strong>Nothing is deactivated and no business decision about which restaurant's history survives is needed. The risk that opens is narrow and specific: while any record still carries a legacy key, a second client can resolve onto it. That is why the deployment runs the migration with imports paused, and why <code>existing-id</code> now refuses to resolve a record belonging to another client.</p>
</div>
<divclass="callout">
<spanclass="h">The whole analysis was run again from nothing, and landed in the same place</span>
<p>Everything above was rebuilt from a fresh restore of the production backup, three times over, each time from the backup point itself rather than from a database an earlier run had touched: restore, re-key and split across all nineteen million orders, then two full ninety-day recomputes. The runs used different preparation — one deactivated the duplicate records and ran a live Square import, this one leaves the configuration exactly as production has it — so their headline figures differ, and that difference is itself the most useful measurement in this report. What did <strong>not</strong> move is the part that should not: for the 190 clients that do not share a Square location, the residue is 119 days and $1,730.61 in both runs, with the same five restaurants accounting for it. The arithmetic fixes behave identically no matter what is done to the duplicates.</p>
<p>Everything above was rebuilt from a fresh restore of the production backup, several times over, each time from the backup point itself rather than from a database an earlier run had touched: restore, re-key and split across all nineteen million orders, then two full ninety-day recomputes. The runs used deliberately different preparation — one deactivated the duplicate records, one left them live and untouched, one backfilled their history from Square — so their headline figures differ, and comparing them is how the recommendation below was reached. What did <strong>not</strong> move is the part that should not: for the 190 clients that do not share a Square location the residue is 119 days and $1,730.61 in every run, with the same five restaurants accounting for it. The arithmetic fixes behave identically no matter what is done to the duplicates, which is a stronger check on them than any single measurement.</p>
</div>
<divclass="callout warn">
@@ -494,48 +502,89 @@
<section>
<h2>What is still out of balance</h2>
<divclass="measure">
<p>542 client-days out of 18,900, totalling <strong>$20,239.00</strong>. Almost all of it sits
on one group of restaurants, and that is the finding:</p>
<p>122 client-days out of 18,900, totalling <strong>$2,379.45</strong> — and only 32 of
those are above ten cents.</p>
</div>
<divclass="scroll">
<table>
<thead><tr><th>Where the remainder sits</th><thclass="n">Days</th><thclass="n">Variance</th><thclass="n">Share</th></tr></thead>
<thead><tr><th>Where the remainder sits</th><thclass="n">Days</th><thclass="n">Variance</th></tr></thead>
<tbody>
<tr><td><strong>The twenty records that share a Square location</strong></td><tdclass="n">423</td><tdclass="n">$18,508.39</td><tdclass="n">91%</td></tr>
<trclass="total"><td>Every other client — 190 of the 210</td><tdclass="n good">119</td><tdclass="n good">$1,730.61</td><tdclass="n">9%</td></tr>
<tr><td>The twenty records that share a Square location</td><tdclass="n good">3</td><tdclass="n good">$648.84</td></tr>
<trclass="total"><td>Every other client — 190 of the 210</td><tdclass="n">119</td><tdclass="n">$1,730.61</td></tr>
</tbody>
</table>
</div>
<divclass="measure">
<p><strong>For every restaurant that is not one of the ten duplicated pairs, this reproduces
to the penny.</strong> 119 days and $1,730.61, with the same five clients accounting for
almost all of it — NG4S at $1,066.61, NGMV at $259.38, NGEB at $199.09, NGPS at $172.82,
N-30012 at $30.31, and 91 further days totalling $2.40 of till rounding. Those are the
numbers an earlier run produced on a differently prepared database, which is a stronger
check on the two arithmetic fixes than any single measurement: they behave identically
whatever is done to the duplicates.</p>
<p><strong>The $18,508.39 on the twenty shared-location records is the cost of leaving both
records live.</strong> Each restaurant now keeps two sets of books, and the history behind
them was never split: refunds claimed by whichever record imported them first, orders that
went to the other, tips reversed on one side and refunded on the other. Re-keying makes that
attribution <em>stable</em> — it stops moving — but it does not make it <em>right</em>.</p>
<p>Of that remainder, 155 days and $4,567.53 are days those records had no sales imported at
all, which is the fourth problem above and is deliberately left visible. The other 268 days
are real trading days on which the two records disagree about who owns what.</p>
<p><strong>The shared-location records are now the clean part of the book.</strong> Three days
between all twenty of them: NGBK and NGBR at $299.42 each on 2026-08-06, which is the Square
tender-versus-order-total gap described below and not an attribution fault, and NGDA at $50.00,
an auto-gratuity booked as a service charge. Before the backfill those same records carried
423 days and $18,508.39.</p>
<p><strong>The other 119 days have not moved across any run of this analysis.</strong> Four
separate rebuilds — different databases, different preparation, one with the duplicates
deactivated and one without — all land on 119 days and $1,730.61, with the same five
restaurants accounting for almost all of it:</p>
</div>
<divclass="scroll">
<table>
<thead><tr><th>Client</th><thclass="n">Days</th><thclass="n">Variance</th><th>What it is</th></tr></thead>
<tbody>
<tr><tdclass="mono">NG4S</td><tdclass="n">10</td><tdclass="n">$1,066.61</td><td>refunds arriving for a record with no sales imported — the fourth problem</td></tr>
<tr><tdclass="mono">NGMV</td><tdclass="n">5</td><tdclass="n">$259.38</td><td>late May, undiagnosed</td></tr>
<tr><tdclass="mono">NGEB</td><tdclass="n">4</td><tdclass="n">$199.09</td><td>ezCater fee treatment — an open question</td></tr>
<tr><tdclass="mono">N-30012</td><tdclass="n">2</td><tdclass="n">$30.31</td><td>late May, undiagnosed</td></tr>
<trclass="total"><tdclass="dim">everyone else</td><tdclass="n dim">91</td><tdclass="n dim">$2.40</td><tdclass="dim">till rounding — pennies a day</td></tr>
</tbody>
</table>
</div>
<divclass="measure">
<p>Sixteen of the 122 are days a record had no sales imported at all, worth $1,227.65 — the
fourth problem, still deliberately visible. The clusters on NGMV, NGPS and NGEB are
unexplained and worth a look, though at under $650 across sixteen days they are no longer
urgent.</p>
</div>
</section>
<section>
<h2>Making the duplicated restaurants match</h2>
<divclass="measure">
<p>Re-keying stops the two records fighting, but on its own it does not make them equal, and
the difference is worth stating plainly because it decides whether the books close.</p>
<p><strong>Orders were always duplicated; refunds never were.</strong> A sales order's
identifier has always carried its client, so each of the two records built its own order
history from the start. Refunds, payouts and cash-drawer shifts did not, so only ONE record
holds each of them — whichever imported it last. The migration freezes that ownership rather
than evening it out. The record left without them shows returns from its own orders and no
refunds to set against them, and is out of balance by exactly the amount its twin is holding.</p>
<p>On 2026-05-11 both NGBK and NGBR held the same 221 orders. NGBK had no refunds; NGBR had
two, worth $2,232.29; and NGBK's books were out by $2,232.29 to the cent. Across the whole
database NGBK held <strong>158,535 orders and five refunds</strong>.</p>
</div>
<divclass="callout">
<spanclass="h">The fix is to ask Square again, not to manufacture copies</span>
<p>With client-scoped keys in place, every record now creates its own copy of whatever it
reads. So replaying the window from Square is all that is needed: each record imports the same
refunds independently and the two histories converge, without any code inventing a duplicate
and having to be trusted about it. <code>backfill-history</code> does exactly that for a date
range, and after it every one of the ten pairs held matching order and refund counts.</p>
<p>It closed <strong>420 of the 423 days</strong> the shared records were carrying, and
$17,859.55 of the $18,508.39. It is also what recovered the zero-regression guarantee above.</p>
</div>
<divclass="callout warn">
<spanclass="h">What retiring the duplicate records would be worth</span>
<p>An earlier measurement of the same window, taken with one record of each pair deactivated
and a live Square import run afterwards, left <strong>279 days and $7,790.54</strong> instead
of 542 and $20,239.00. Most of that difference is the twenty shared records: with the
duplicates retired their share fell from $18,508.39 to $6,059.93.</p>
<p>That is not an argument that the configuration is wrong — two live records is a deliberate
choice, and the re-key is what makes it safe. It is a number to weigh: leaving both active
costs roughly <strong>$12,000 of unexplained variance across 260 client-days</strong> per
ninety days, carried on ten restaurants, until the historical attribution behind them is
redistributed. The two figures are not perfectly isolated — that earlier run also included a
live import, which backfilled data this one does not have — so treat it as the right order of
magnitude rather than an exact price.</p>
<spanclass="h">One capped read, found by doing this</span>
<p>The refunds import asked Square for a location's refunds and read the first page of the
answer — no cursor, no date range. Square pages at a hundred, so a location with more than a
hundred refunds silently returned a hundred, and the response looked complete. That is why the
twins each held almost exactly 100 refunds, and why an earlier import added exactly 1,000
across ten locations. Following the cursor is a few lines; the reason it went unnoticed for so
long is that a capped list is indistinguishable from a short one.</p>
</div>
<divclass="measure">
<p><strong>This turned out to be a better answer than retiring the duplicate records.</strong>
An earlier measurement that deactivated one record of each pair left 279 days and $7,790.54.
Backfilling instead, with both records live, leaves <strong>122 days and $2,379.45</strong> —
and it needs no business decision about which restaurant's history to abandon.</p>
</div>
</section>
@@ -704,7 +753,7 @@
<footer>
<span>Measured 2026-08-15 against <spanclass="mono">integreat-prod-restore</span>, restored fresh from backup point 209608347 — production as of 2026-08-14 22:52. Nothing in production was read or written. Branch <spanclass="mono">worktree-sales-summary-balance</span>.</span>
<span>A day counts as out of balance when money taken minus money earned is half a penny or more. "Material" means ten cents or more, the threshold below which the residual is till rounding. Of the 542 remaining days, 452 are material — but 171 are days with no sales imported rather than arithmetic faults, and 423 of the 542 sit on the twenty records that share a Square location.</span>
<span>A day counts as out of balance when money taken minus money earned is half a penny or more. "Material" means ten cents or more, the threshold below which the residual is till rounding. Of the 122 remaining days only 32 are material, and just 3 of them sit on the twenty records that share a Square location.</span>
<span>Both the baseline and the result are live captures taken straight after their own recompute, never historical reads — see the note on <code>as-of</code> above.</span>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.