-
DevPilot authored
Booking the accruals against the live books exposed a real defect, and it cost one duplicate entry before it was caught. Nine rows in sa_players carry a membership NUMBER in member_id (101, 1015, 897000) instead of a member row id. The accrual run reached the first of them, the foreign key on accounts_receivable.member_id refused the insert, and the exception escaped the loop that records claims in posting_accruals. That loop runs AFTER the journal entry is posted, so the entry stood at the full batch total with only the claims written before the failure. The next run read the remaining documents as never accrued and posted a SECOND entry for them — and would have posted one more every night, because the failure is deterministic. AccrualService::batch now treats a claim it cannot write as something to report, not something to throw: the entry is already posted, so abandoning the rest of the batch is the one response guaranteed to corrupt the ledger. A member id that does not resolve costs the receivable, never the claim — posting_accruals is the system of record and already tracks obligations for non-members. Member existence is resolved once per batch, not once per claim. Phase_112_003 repairs what the two runs left: the duplicate is reversed rather than deleted so the correction stays visible, its claims move to the entry that actually posted their money, and the 110 claims plus 32 receivables that were never written are backfilled against it. It verifies the entry and its claims agree before finishing, and does nothing at all unless production matches the exact broken shape. Why the clone missed it: the verification harness built tables with CREATE TABLE ... LIKE, which silently drops foreign keys — so the constraint that breaks production did not exist in the clone, and the run came back green. The harness now copies DDL via SHOW CREATE TABLE and asserts the foreign key count matches the source (409/409). Verified against a clone of the actual broken production state: net movement for sa_subscription_accrual is 104,769.00 not 184,938.00, all 135 claims equal their entry to the cent, 1,316 claims total 835,167.93, trial balance diff 0.00, and both the repair and the fixed runner post nothing on a second pass. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
87c22aca