Skip to content

fix(intent): settlement allocation follows a corrected payment (#6818) - #6846

Merged
delchev merged 1 commit into
masterfrom
fix/settlement-payment-updated
Aug 19, 2026
Merged

fix(intent): settlement allocation follows a corrected payment (#6818)#6846
delchev merged 1 commit into
masterfrom
fix/settlement-payment-updated

Conversation

@delchev

@delchev delchev commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Closes #6818.

The gap

settlements: bound the payment's bare create topic and nothing else. A payment is rarely final the moment it is typed in: one booked for the wrong amount is corrected the next day, one entered from a bank statement is completed once the counter-party is identified, one captured as a draft is amended before anyone treats it as money. In every one of those cases the allocation - and with it the invoice's settled figure - kept describing an amount the payment no longer carried, and nothing said so.

The fix

The spread handler is emitted once per bound payment event (create and update) from a new settlementListeners glue collection:

  • settlements still drives the one-per-settlement <Name>OnInvoice delegate. The two templates share the settlements collection today, so a second collection is what lets them fan out differently off one shared descriptor - rollupEntry copies it per class name + topic suffix, exactly as roll-ups and expansions already do.
  • The create handler keeps its established class name (<Name>OnPayment), so an existing project regenerates without churn; the correction one is <Name>OnPaymentUpdated.

The allocation was already a recompute of the payment's unallocated balance (pot less what is already allocated through the junction), which is what makes an extra delivery a no-op. It now converges in the other direction too: a payment corrected below what it already covers releases the excess through the junction repository - newest allocation first, reducing rather than removing the last row it touches - so the allocations sum to the payment again and the paid roll-up follows them down. Without that half, the fix would only have covered corrections that went up, which is not what "corrected the next day" means.

-transitioned is deliberately not bound here: that vocabulary gap is #6810, filed separately as the issue notes.

Verification

  • IntentEngineIT (50 tests) + IntentEmissionCoverageIT - 51/51 green. settlement_generates_on_payment_listener_and_on_invoice_delegate now also asserts the second listener, its -updated destination, the release call and that the release orders by the junction key descending through the repository.
  • The two generated listeners were rendered from the template and compiled with javac against the real api-modules-java + data-store-java jars - settlements have no compile-level coverage in any IT today (pre-existing), so the API use (delete/update/orderByDesc) was proven directly rather than assumed.
  • mvn formatter:validate clean; mvn -P release ... install (javadoc) clean on both touched Java modules.

Docs

🤖 Generated with Claude Code

`settlements:` bound only the payment's bare create topic, so a payment
booked for the wrong amount and corrected the next day - or created
incomplete and completed later - was never re-allocated: the invoice kept
the settled figure of an amount the payment no longer carried, or the
payment was never allocated at all.

The spread handler is now emitted once per bound payment event, from a new
`settlementListeners` glue collection. `settlements` still drives the
one-per-settlement `<Name>OnInvoice` delegate; a second collection is what
lets the two templates fan out differently off one shared descriptor
(`rollupEntry` copies it per class name + topic suffix, exactly as roll-ups
and expansions already do). The create handler keeps its established class
name, so an existing project regenerates without churn; the correction one
is `<Name>OnPaymentUpdated`.

The allocation was already written as a recompute of the payment's
UNALLOCATED balance, which is what makes an extra delivery a no-op. It now
converges in the other direction too: a payment corrected below what it
already covers releases the excess through the junction repository, newest
allocation first, so the allocations sum to the payment again and the paid
roll-up follows them down.

`-transitioned` is deliberately not bound here - that vocabulary gap is

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

settlements: binds only the payment's create topic - corrections and later confirmations never re-run allocation

1 participant