fix(intent): settlement allocation follows a corrected payment (#6818) - #6846
Merged
Conversation
`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>
delchev
force-pushed
the
fix/settlement-payment-updated
branch
from
August 19, 2026 17:47
1cf9fe8 to
b3d3c15
Compare
This was referenced Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
settlementListenersglue collection:settlementsstill drives the one-per-settlement<Name>OnInvoicedelegate. The two templates share thesettlementscollection today, so a second collection is what lets them fan out differently off one shared descriptor -rollupEntrycopies it per class name + topic suffix, exactly as roll-ups and expansions already do.<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 (
potless 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 thepaidroll-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.-transitionedis 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_delegatenow also asserts the second listener, its-updateddestination, the release call and that the release orders by the junction key descending through the repository.javacagainst the realapi-modules-java+data-store-javajars - 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:validateclean;mvn -P release ... install(javadoc) clean on both touched Java modules.Docs
README.md,CLAUDE.mdand the AI assistant guide (intent-assistant-guide.md) - including the two traps a new glue collection carries (aGlueGeneratorcase, andcopybeing a per-key allow-list).🤖 Generated with Claude Code