Skip to content

feat(money): #778 — finance correctness: rounding policy, #773 journal, TDS flag, chargeback parity, overage audit (PR-C)#824

Merged
teetangh merged 19 commits into
feature/enterprisefrom
feat/778-finance-correctness
Jun 10, 2026
Merged

feat(money): #778 — finance correctness: rounding policy, #773 journal, TDS flag, chargeback parity, overage audit (PR-C)#824
teetangh merged 19 commits into
feature/enterprisefrom
feat/778-finance-correctness

Conversation

@teetangh

Copy link
Copy Markdown
Contributor

Summary

PR-C of the production-grade stack (stacked on #823 / PR-B). With the schema frozen by PR-A+B, this PR makes the runtime finance-correct: one rounding policy proven to the paise, the last partially-journaled flow closed, the TDS regime consolidated behind a launch flag, refunds and chargebacks at full statutory parity, an end-to-end overage architecture audit with its findings fixed, the reconcile suite completed, and money-cron failures actually paging someone.

Closes #773. Closes #750. Closes #751. Closes #775. Part of #778 (§C, §E, §G), #738 (Items A/B), #709 (alerting slice), #715/#716 (overage/refund correctness slices).

What changed

One rounding/residual policy (#778 §C)

splitByBps()/prorate() encode the policy — floor every share, residual to exactly one named party (OWNER within a collaborator pool, PLATFORM_FEE across funding/tax splits). The §C-2 bug is fixed at its source: calculateRevenueSplit's round-per-collaborator could overshoot the pool and push the owner's remainder negative; it now floors with a Σbps>10000 refusal. GST's headline levy keeps nearest-rounding by documented exemption (flooring a levy under-collects tax; its CGST/SGST halves already floor+remainder). The §C-1 negative-plug regression test the #812 fix never got now pins the balanced posting. The new reconcile SPLIT_SUM_MISMATCH proves the policy end-to-end on every earnings-bearing payment.

#773 — the booking journal is complete

Multi-collaborator payments now post one balanced booking:<paymentId> transaction (funding debits by leg source → PLATFORM_FEE + per-party CONSULTANT_PAYABLE + per-org ORG_PAYABLE + GST_PAYABLE credits), with settled collaborators' earnings rows storing the share net of the host-org cut so cache equals journal exactly. A posting failure rolls the earnings creation back. The hourly sync-payment-earnings repair script — which minted full-share collaborator rows with no journal — now delegates to the same function. Seeds post the journal atomically with each earnings row. earningsPaymentsWithoutBookingTxn is promoted from an info metric to a threshold-zero reconcile finding: the platform can never silently run partially journaled again.

TDS consolidation + statutory parity (#778 §E, #738 A/B)

  • TDS_ENGINE env flag, default LEGACY (the conservative ₹50K-gated 194-O hybrid shipping today); 194O drops the gate for pure Section 194-O semantics — one env flip at launch once the CA confirms in writing. The 194J calculator is marked deprecated.
  • Every TDS reversal now also emits a TdsAdjustment row (the Form 140/144 filing artifact) alongside the negative TDSRecord — closing the long-standing "TdsAdjustment unwired" gap.
  • Chargeback parity: dispute LOST now reverses withholding for paid-out earnings (the shared cap prevents double-reversal after a prior refund), mints the Sec 34 credit note idempotently on CreditNote.disputeId, and emits GstTcsAdjustment where TCS was collected. The refund cascade emits the same TCS adjustment (inert until Sec 52 collection ships).
  • Law-aware TdsRate rows seeded: IT1961 sections through 2026-03-31, IT2025 §393 Sl. 8(v) from 2026-04-01, paymentCode deliberately null pending the CBDT notification.
  • X-Payout-Idempotency (mandatory at RazorpayX since 2025-03-15) verified already sent with deterministic keys.

Overage architecture audit (user-requested) — verdicts and fixes

Full trace of config → computeOverage → breaker → CHARGE_MEMBER/CHARGE_ORG/BLOCK → settlement → refund propagation → timeout/sweep. Fixed: a capture-vs-reversal race that could credit the org with money belonging to a refunded member (the CHARGED transition now gates the ORG_PAYABLE posting; the raced case self-reports for manual refund); refunding a CHARGE_MEMBER side-payment now debits ORG_PAYABLE instead of billing the platform via the plug; OverageEvent.currency mirrored the booking instead of hardcoding INR; config combos that meant unbounded liability (CHARGE_* with no circuit-breaker ceiling) or dead knobs are rejected at create and at piecemeal PATCH; sweep write-offs stamp an auditable reason. The locked settlement decision is documented at the handler: a member side-payment's ORG_PAYABLE credit is realized at org payout — no invoice-netting, no wallet credit — and the standing relief credit on that account is documented as expected, not drift. #751 ships alongside: overlapping coveredPlanTypes on the same contract is a 409 naming the conflicts unless forceOverlap: true.

Found, documented, deliberately not fixed here (needs a #715-style price-basis decision): SUBSCRIPTION lazy-debit discards recordBookingUtilization's result, so a cap-crossing at slot-allocation never creates an OverageEvent — a silent under-charge that OVERAGE_COUNT_DRIFT already detects. Flagged 🟡 in the programs band.

Reconcile completion (#778 §G) and ops (#709)

New findings: SPLIT_SUM_MISMATCH, OVERAGE_SETTLEMENT_MISMATCH (exact semantics from the audit, including the legitimate leg-net cases under #786), EARNINGS_WITHOUT_BOOKING_TXN (threshold 0), plus PR-A/B's MONEY_VALUE_WITHIN_SAFE_RANGE and ASSIGNMENT_PERIOD_OVERLAP. The payout poller keeps pre-completion gateway reversed as FAILED — that is the correct accounting (no PAYOUT txn was ever posted; webhooks own post-COMPLETED reversals) — but now records the distinction in failureReason. All 15 money workflows' failure stubs now page #ops-alerts through one env-gated script that no-ops loudly when the secret is absent.

Docs (updated in-PR)

booking-to-earnings reflects the completed journal + netting model; the programs band carries the lazy-debit gap; the compliance band and docs/compliance/05 flip the refund/chargeback adjustment matrix to wired and record the TDS_ENGINE flag; the stale 16-char Rule 46(b) divergence is marked resolved (#807's GST_DOC_NUMBER_MAX_LEN).

Verification

  • npx tsc --noEmit: 0 errors. npm test: 92 suites, 1187 tests green (+16 over the PR-B baseline: rounding-policy floors, negative-plug posting, multi-party journal, overage webhook race/redelivery, calculator hardening, overlap guard). Lint: clean (one pre-existing eqeqeq warning untouched).
  • Deferred runtime gate (Supabase unreachable; recorded on all three PRs): db push → triggers → seed → reconcile-ledgers ok:true with the new invariants → Verify invoice PDF generation after dropping the react-pdf reconciler hack #707 invoice-PDF smoke (%PDF magic bytes via next build && next start) → one live money round-trip. Run before merging the stack into feature/enterprise.

Known follow-ups (non-blocking, for the merge-time review)

🤖 Generated with Claude Code

teetangh and others added 15 commits June 10, 2026 08:07
…erce at the boundary (#781 §A)

Payment/Refund/Dispute/ConsultantEarnings/ConsultantPayout/DiscountCode/
ReferralCredit.currency and the four plan priceCurrency columns move from
free String to the Currency enum (@default(INR)); WalletTopUp gains an
explicit currency; paRouteProvider becomes the PayoutRailProvider enum.
A typo'd currency on a money row is now unrepresentable.

Gateways still speak free-form ISO codes (incl. display currencies), so
the gateway-facing payment-core types stay string and every row-write
passes through toCurrencyEnum() — throws (dead-letters, not 500-loops)
on a code we can't book. Plan create/update Zod schemas validate the
enum at the request edge (400, not 500). The shipped
LEDGER_ACCOUNT_NON_INR reconcile invariant remains the runtime backstop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
§B — money history is delete-proof:
- onDelete Cascade→Restrict on the 9 financial-history FKs
  (Organization/Consultant Earnings+Payouts, Refund, Dispute, TDSRecord);
  the two SetNulls that survive are documented in-schema (abandoned
  side-charge sweep; invoice re-rollup link).
- deletedAt on Organization/Payment/ConsultantProfile. Org DELETE becomes
  three-way: live obligations 409 (wind-down doctrine), settled history
  soft-deletes (DEACTIVATED + deletedAt + contact-PII scrub — name/GSTIN/
  PAN stay for the invoice trail; status tuples already gate every
  surface), money-untouched shells still hard-delete. Consultant DELETE
  gets the same split (earnings/payouts/TDS ⇒ soft-delete, slots removed
  so nothing is bookable). DPDP erasure now stamps deletedAt — statutory
  retention beats erasure under the legal-obligation exemption.
- deleteExpiredPayments documented as deliberately-safe (PENDING rows
  predate any Restrict FK).

§C — rates can no longer disagree on units:
- tdsRate/tdsRateApplied/TDSRecord.tdsRate Float→integer bps. This kills
  a real pre-existing bug: the 194-O engine stored fractions (0.001)
  while the legacy engine stored percent (10) in the same column type.
- FX snapshots Float→Decimal(18,6), converted to number at the client
  boundary (dn()) so Prisma.Decimal never crosses the RSC boundary.
- 26Q export emits tdsRatePercent derived from bps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#781 §B)

deletedAt: null scoping on the browse/detail/booking reads: explore
metadata+curated+reviews, home rails, public consultant list route,
plan list/detail surfaces (nullable consultantProfile handled via
OR-null so ownerless plans stay listed), and checkout's four
calculateAmountAndValidate branches reject a soft-deleted owner exactly
like plan-not-found. Org surfaces need no scoping — DEACTIVATED status
tuples already gate them. Money/admin/self reads deliberately keep
seeing soft-deleted rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… decrement-in-place (Closes #786)

Funding legs are now append-only, matching the journal's discipline:
a refund on an unbilled accrual appends a negative
INVOICE_ACCRUAL_REVERSAL / OVERAGE_INVOICE_ACCRUAL_REVERSAL sibling
instead of mutating the original. One reversal per source keeps
@@unique([paymentId, source]) intact (the P2002 #786 reported);
subsequent partials net into the existing reversal leg.

Side benefits over decrement-in-place: each partial refund's
proportional split (and each Sec 34 credit note) now computes against
the immutable original split, killing the attribution drift the
remainder-absorption was papering over; and the funding history stays
readable from the legs.

Readers updated: invoice rollup sums original+reversal so it bills the
net (fully-refunded-before-billing bookings are stamped but excluded
from the issued document); checkPaymentLegsSumToAmount becomes
pair-aware — originals must still sum to Payment.amount exactly, and
every reversal must be negative and never exceed its sibling. The enum
addition lands inside the schema freeze — post-freeze it would have
been a migration. Regression tests pin append-once-then-net.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…781 §D, #784, #753)

§D residue (schema lands in the freeze; automations stay deferred):
- CreditNote: IRN/e-invoice cluster mirroring OrganizationInvoice
  (CRN/DBN must reach the IRP for in-scope taxpayers; ≥₹10cr AATO adds a
  30-day window), docType enum, and disputeId @unique so the #738-B
  chargeback credit-note path (PR-C) mints idempotently.
- TdsRate lookup table, law-aware: the Income-tax Act 2025 renumbered
  TDS sections (194-O → §393 Sl.8(v)), re-keyed challans to payment
  codes 1001–1092, and renamed forms 26Q/27Q→140/144 from 2026-04-01 —
  a (lawCode, section, effectiveFrom)-keyed table is the only shape
  that survives that; rows are append-only.
- ConsultantProfile: Sec-197 certificate validity window + the cert's
  own rateBps (the engine stops re-purposing the consultant default).
- DataBreach: principal-notification leg — DPDP's 72-hour duty is dual
  (Board AND affected principals); reportedAt alone proved one leg.
- ProgramAssignment overlap guard (app-level; exclusion constraints
  aren't Prisma-expressible) + ASSIGNMENT_PERIOD_OVERLAP reconcile
  detector + regression test.

§D indexes: [organizationId, status, createdAt] on earnings;
[programAssignmentId, chargeStatus, createdAt] on OverageEvent; the
covered single/two-field subsets dropped.

Trims (user decision 2026-06-10): PROJECT/RETAINER/RESELLER marked
most-likely-never in every reserving comment (the ProgramType enum
never carried them — the comments claimed otherwise); dead
minimumCreditsPerPeriod dropped (#753's money-meter half shipped as
consumedPaise; nothing ever read the commitment-minimum); the
TaxJurisdiction enum stays documented-reserved (#769).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cisions

Payment-legs and refunds docs describe the #786 reversal-sibling model
(append-only funding legs, pair-aware sum invariant); the money
overview records the Currency-enum row rule with the toCurrencyEnum
gateway boundary; the compliance band marks the DPDP breach gap as
schema-closed (principal-notification leg now on DataBreach, cron still
Board-only) and documents the bps + law-aware TdsRate readiness for the
Form 140/144 generator, with CBDT payment codes deliberately
unhardcoded pending the final notification.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lass

1:1 wrappers (Consultation/Subscription) carry request/feedback/
cancellation because the wrapper IS the relationship; group events are
1:N and delegate per-attendee state to Appointment. Asymmetry is
intentional — the comment exists so it stops resurfacing as a gap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#784)

The two models were field-identical except the plan FK and role enum.
Merged: collaboratorType discriminator, nullable webinarPlanId/classPlanId
(XOR app-enforced via assertCollaboratorPlanXor — Postgres CHECKs aren't
Prisma-expressible), unified CollaboratorRole (union of both enums; the
per-type role subsets now live in the zod invite schemas, turning the
old Prisma-runtime-500 on an invalid role into a 400), per-plan-type
@@unique pairs (NULLs are distinct, so each bites only its own type).

service.ts collapses every webinar/class branch through planScope/
planWhere; public signatures unchanged; revenue-split math untouched.
Pre-MVP is the cheap time for this — post-freeze it would have been a
data-shuffling migration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l to a named party (#778 §C)

splitByBps/prorate in lib/payments/utils/money.ts encode THE policy:
floor every share; the leftover paise go to exactly one designated party
(OWNER within a collaborator pool, PLATFORM_FEE across funding/tax
splits) so splits always sum to the total. calculateRevenueSplit's
Math.round-per-collaborator — which could overshoot the pool and push
the owner's remainder NEGATIVE (#778 §C-2) — becomes floor + a Σbps >
10000 refusal. GST's headline levy keeps nearest-rounding by documented
exemption (flooring a LEVY under-collects tax; the CGST/SGST halves
already floor+remainder).

Adds the §C-1 regression the #812 fix never got: a negative platform
plug (earnings allocated off originalAmount exceeding the post-credit
funding) must POST a balanced txn with a PLATFORM_FEE credit — the
pre-#812 silent skip was unrepairable EARNINGS_LEDGER_DRIFT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xn (Closes #773)

The last partially-journaled money flow closes. createEarningsFromPayment
resolves every collaborator's HOST-org settlement up front, then posts a
single balanced booking:<paymentId> txn: funding debits by leg source
(#786 reversal sources explicitly filtered — they can't exist at
booking), Dr DISCOUNT for the platform-funded gap, then Cr PLATFORM_FEE
(primary fee + settled collaborators' fee slices), Cr CONSULTANT_PAYABLE
per party — a settled collaborator's earnings row now stores the share
NET of the host-org cut, so the cache equals the journal credit exactly —
Cr ORG_PAYABLE per host org, Cr GST_PAYABLE. A posting failure rolls the
earnings creation back (#812 discipline). The same-org collision P2002
catch became unsafe under in-txn posting and is replaced by deterministic
upfront detection (v1 outcome preserved).

The hourly sync-payment-earnings repair script now DELEGATES to
createEarningsFromPayment instead of minting its own full-share
collaborator rows with no journal — every multi-party payment it synced
was born as ledger drift. Seeds post the booking journal per earnings
row (atomic with the row), so a fresh seed reconciles clean; seed fee
math switched round→floor so the seeded journal balances to the paise.

Part of #778 §C-2/§G.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t artifacts (#778 §E, #738 A/B)

TDS_ENGINE env flag (default LEGACY): LEGACY keeps the conservative
₹50K-gated 194-O hybrid that ships today; 194O drops the gate for pure
Section 194-O semantics — one env flip at launch once the CA confirms in
writing. The 194J percent calculator is marked deprecated; the engine of
record stays lib/compliance/tds.ts.

Every TDS reversal now ALSO emits a TdsAdjustment row — the filing
artifact the Form 140/144 export will read — alongside the negative
TDSRecord that remains the YTD/dedup source (#778 §D, closes the
'TdsAdjustment unwired' gap). Statutory TdsRate rows seeded law-aware:
IT1961 194-O/194J through 2026-03-31, IT2025 §393 Sl.8(v) from
2026-04-01 with paymentCode deliberately null pending the CBDT
notification.

Chargeback parity (#738-B): the dispute LOST/CHARGE_REFUNDED branch now
reverses withholding for paid-out earnings via the shared
recordTdsReversal (its cap prevents double-reversal after a prior app
refund), mints the Sec 34 credit note idempotently on
CreditNote.disputeId (mintRefundCreditNote generalized to either
trigger), and emits GstTcsAdjustment when TCS collection stamped the
payment. Refund parity (#738-A): the cascade emits the same TCS
adjustment — inert until Sec 52 collection ships.

Also fixed from the overage audit: refunding a CHARGE_MEMBER
side-payment now debits ORG_PAYABLE (pulling back the org's relief
credit) instead of billing the platform via the plug.

X-Payout-Idempotency verified already-sent with deterministic keys
(mandatory at RazorpayX since 2025-03-15) — no change needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, coverage-overlap 409 (#775 #782 #751)

Full config→compute→breaker→charge→settle→refund→sweep trace (verdicts
in docs + the PR description). Real defects fixed:

- Capture-vs-reversal race: the CHARGE_MEMBER webhook posted the
  ORG_PAYABLE credit BEFORE the CHARGED transition — a booking refunded
  after order-mint left the org holding the member's money. The
  transition now gates the posting; a 0-row transition records an
  OVERAGE system error ('refund the side-payment') instead of crediting
  the org.
- OverageEvent.currency hardcoded INR while the side-Payment carried the
  booking currency — events now mirror it (and the timeout notification
  stops lying).
- Config guards: CHARGE_* without a positive circuit-breaker ceiling is
  unbounded liability — rejected at create AND at piecemeal PATCH
  (merged current+patch state re-checked); dead knobs (surcharge with
  BLOCK, any overage knob with unlimited coverage) rejected; NaN inputs
  normalized in the calculator.
- #751: creating a program whose coveredPlanTypes intersect another
  ACTIVE program on the same contract is now a 409
  (PROGRAM_COVERAGE_OVERLAP, names the conflicts) unless
  forceOverlap:true — overlapping coverage made checkout's program
  resolution ambiguous.
- Sweep write-offs now stamp chargeFailureReason for auditability.

The locked settlement decision is documented at the handler: a member
side-payment's ORG_PAYABLE credit is realized at org payout — no
invoice-netting, no wallet credit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hreshold zero, poller honesty (Closes #750; #778 §G)

- SPLIT_SUM_MISMATCH: per earnings-bearing payment, Σ platform fee +
  consultant shares + org shares must equal Payment.originalAmount to
  the paise — proves the floor+residual policy end-to-end under the #773
  netting model.
- OVERAGE_SETTLEMENT_MISMATCH: a CHARGED member overage must have a
  SUCCEEDED side-payment, a matching overage:<sidePaymentId> txn whose
  amounts agree, and settledAt; PENDING/FAILED events must have no txn.
  The capture-raced-reversal case self-reports via system error and is
  deliberately not double-flagged.
- earningsPaymentsWithoutBookingTxn promoted from info metric to a
  finding over RECONCILE_UNJOURNALED_MAX (default 0 — the platform must
  never silently run partially journaled again; pre-#773 seeded DBs trip
  it until reseeded, by design).
- #750 residue: resolveActiveAssignment orders by periodEnd desc
  (boundary instants matched two cycles arbitrarily); the TDS-reversal
  original lookup and the dunning-block probe get deterministic orders.
- Payout poller: pre-completion gateway 'reversed' stays FAILED — that
  is correct accounting (no PAYOUT txn was ever posted; webhooks own the
  post-COMPLETED reversal path) — but the distinction is now recorded in
  failureReason instead of silently collapsed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every money workflow's 'Notify on failure' stub (15 of them) now calls
the shared scripts/ci/notify-ops-failure.sh — a Slack webhook post with
the run URL, env-gated on SLACK_OPS_WEBHOOK_URL and a visible ::warning
no-op when the secret isn't provisioned (forks/previews don't fail).
The full #709 schedule-stagger audit stays in #709.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rrectness landing

booking-to-earnings drops the multi-collaborator deferral (#773 closed;
posting shape + the netting model + the standing ORG_PAYABLE
overage-relief credit documented); the programs band gains the
SUBSCRIPTION lazy-debit silent-under-charge gap found by the overage
audit (needs a #715-style price-basis decision); the compliance band and
docs/compliance/05 flip the refund/chargeback adjustment matrix to
wired (TdsAdjustment + GstTcsAdjustment + dispute parity), record the
TDS_ENGINE flag, and resolve the stale 16-char Rule 46(b) divergence
(#807 enforced via GST_DOC_NUMBER_MAX_LEN).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1dd47ec9-d322-4c37-a0c7-11f704e7c3a2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/778-finance-correctness

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive financial correctness and statutory compliance updates, including floored overage and revenue split calculations, inline balanced journal postings for multi-collaborator bookings, and fully wired tax adjustments (TDS, GST, and TCS) for refunds and lost chargebacks. It also adds robust validation guards for program overage configurations and expands ledger reconciliation checks to prevent financial drift. Feedback on these changes highlights a potential shell-scripting issue in the CI notification script where raw string interpolation could produce malformed JSON, and a performance concern in the ledger reconciler where a massive IN clause query could hit PostgreSQL parameter limits.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread scripts/ci/notify-ops-failure.sh Outdated
Comment thread scripts/reconcile/reconcile-ledgers.ts
teetangh and others added 4 commits June 10, 2026 11:52
…ists; deletedAt optional-chained

- ASSIGNMENT_PERIOD_OVERLAP compared only against the previous row — one
  long cycle overlapping several later short ones flagged just the first.
  Track the group's max periodEnd instead.
- tdsRateAppliedBps used truthiness, so a legitimate Sec 197 zero-rate
  certificate stored null instead of 0 bps; != null preserves it.
- checkout's consultation/subscription deletedAt checks use optional
  chaining for consistency with the webinar/class branches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	lib/payments/payouts/payout-service.ts
…bind-param cap

- notify-ops-failure.sh builds its JSON via jq (printf interpolation
  produced malformed payloads for job names with quotes).
- The SPLIT_SUM org-earnings sum drops its giant IN list (org-filtered
  groupBy + map join); the gross lookup and the overage-txn key probe —
  the same class the review flagged once — chunk their id lists at 5k
  to stay under Postgres's 65,535 bind-parameter cap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@teetangh teetangh changed the base branch from feat/781-schema-freeze to feature/enterprise June 10, 2026 06:29
@teetangh teetangh merged commit d64f13c into feature/enterprise Jun 10, 2026
1 check passed
@teetangh teetangh deleted the feat/778-finance-correctness branch June 10, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant