Repository navigation
feat(ledger): add spendable balances for FBO collection - #5270
Conversation
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes.
|
| Layer / File(s) | Summary |
|---|---|
Minimum-balance query and historical calculation openmeter/ledger/balance.go, openmeter/ledger/historical/..., openmeter/ledger/noop/noop.go, openmeter/ledger/README.md |
The ledger adds a minimum-balance query that requires AsOf and rejects filters that truncate posting history. The historical adapter calculates bucket minima across the boundary and later movements. Tests cover effective times, simultaneous postings, opening balances, and annotation exclusions. |
FBO source listing and spendable balances openmeter/ledger/fbo/service.go, openmeter/ledger/fbo/balance.go, openmeter/ledger/fbo/source_query.go, openmeter/ledger/fbo/sources*.go, openmeter/ledger/fbo/balance_test.go |
The FBO service validates source and balance queries, lists eligible sources, and reports positive spendable balances using minimum-balance buckets. Tests cover source-specific minima, future spending, and breakage boundaries. |
FBO consumption and breakage release openmeter/ledger/fbo/consume.go, openmeter/ledger/fbo/consume_test.go, openmeter/ledger/fbo/README.md |
The service validates consumption requests, selects credits, returns transaction inputs, releases matching breakage, and supports advances under the configured policy. Tests cover grouped transactions and rollback. |
Collector integration and transaction commits openmeter/ledger/collector/collect.go, openmeter/ledger/collector/service.go, openmeter/ledger/collector/README.md, openmeter/ledger/collector/*_test.go, openmeter/ledger/README.md |
The collector delegates accrued and receivable consumption to the FBO service and commits returned inputs under a generated group ID. Tests and documentation reflect FBO-owned source selection and breakage handling. |
Comment-writing guidance
| Layer / File(s) | Summary |
|---|---|
Comment guidance and example AGENTS.md |
The guidance asks contributors to use plain, concrete language in comments, retain useful explanations, and compare verbose and concise Go comment examples. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant Collector
participant FBOService
participant BreakageService
participant Ledger
Collector->>FBOService: Submit Consume request
FBOService->>FBOService: Select credits and resolve transaction inputs
FBOService->>BreakageService: Record releases for consumed sources
FBOService-->>Collector: Return transaction inputs
Collector->>Ledger: Commit inputs as a transaction group
Merge Risk: 
Minimal · up to 0d8ec
-
This update only adds documentation guidance for writing comments and does not change runtime behavior, so it carries no actionable merge risk.
Pre-merge checks: 
4
✨ Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
| // ListSources returns ordered eligible source slices at the historical boundary. | ||
| // It uses the current collection policy; it is not the future spendable-balance API. |
There was a problem hiding this comment.
Source reads hide transaction requirements
ListSources needs a caller-owned PostgreSQL transaction, but its public comment does not say so. It calls LockForPosting, which fails without a transaction and holds customer account locks until that transaction ends. Document this requirement and lock lifetime so callers do not treat it as an ordinary balance read.
| // ListSources returns ordered eligible source slices at the historical boundary. | |
| // It uses the current collection policy; it is not the future spendable-balance API. | |
| // ListSources returns ordered eligible source slices at the historical boundary. | |
| // It requires a caller-owned PostgreSQL transaction and holds the customer's FBO, | |
| // receivable, and accrued account locks until that transaction ends. | |
| // It uses the current collection policy; it is not the future spendable-balance API. |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openmeter/ledger/fbo/source_query.go
Line: 57-58
Comment:
**Source reads hide transaction requirements**
`ListSources` needs a caller-owned PostgreSQL transaction, but its public comment does not say so. It calls `LockForPosting`, which fails without a transaction and holds customer account locks until that transaction ends. Document this requirement and lock lifetime so callers do not treat it as an ordinary balance read.
```suggestion
// ListSources returns ordered eligible source slices at the historical boundary.
// It requires a caller-owned PostgreSQL transaction and holds the customer's FBO,
// receivable, and accrued account locks until that transaction ends.
// It uses the current collection policy; it is not the future spendable-balance API.
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| sources, err := s.listCustomerFBOSources(ctx, SourceQuery{ | ||
| CustomerID: request.CustomerID, | ||
| Currency: request.Currency, | ||
| Filters: request.Filters, | ||
| AsOf: request.SourceBalanceAsOf, | ||
| }) |
There was a problem hiding this comment.
Consume no longer reserves selected credit. If a caller makes two calls in one database transaction before posting their shared group, both read the same FBO balance. With 10 credits and two requests for 7, both return transactions consuming 7 instead of leaving only 3 for the second request.
CommitGroup does not check available balances, so posting these inputs leaves FBO at -4 and skips any required shortfall advance. Keep reservations across calls, or reject repeated consumption before posting.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openmeter/ledger/fbo/consume.go
Line: 217-222
Comment:
**Customer credit spent twice**
`Consume` no longer reserves selected credit. If a caller makes two calls in one database transaction before posting their shared group, both read the same FBO balance. With 10 credits and two requests for 7, both return transactions consuming 7 instead of leaving only 3 for the second request.
`CommitGroup` does not check available balances, so posting these inputs leaves FBO at -4 and skips any required shortfall advance. Keep reservations across calls, or reject repeated consumption before posting.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.609d2f4 to
0d8ece0
Compare
0d8ece0 to
c680681
Compare
c680681 to
14d457f
Compare
14d457f to
9188073
Compare
Collecting against a historical balance could reuse credit already allocated to later usage. Collection now uses each source's minimum balance from the selection time through recorded future postings, preserving those later allocations.
Move source selection, consumption transactions, breakage releases, and shortfall advances into
ledger/fbo.Consumehandles one collection request and returns resolved transaction inputs. The collector owns the database transaction, commits the group, and creates billing allocations.The ledger gains a generic minimum-balance query. FBO calculates minima per source before combining buckets and excludes future breakage because consumption releases it; breakage at or before the boundary remains effective. Ordinary account balances retain their historical meaning.
Validation on the rebased stack: PostgreSQL-backed minimum-balance, FBO, collector, and correction tests plus scoped Go lint passed. Coverage includes future spending and grants, simultaneous postings, independent source minima, and breakage boundaries.
Stack: #5252 → #5270 → #5294 → #5304. Depends on #5252; booking-time alignment follows in #5294.
The PR should not merge until repeated
Consumecalls cannot select the same unposted credit twice.Fix with agent prompt
Summary
Adds minimum-balance queries so collection preserves credit already assigned to later spending.
Diagram
Reviews (8) · Last reviewed commit: "feat(ledger): preserve future spending i..." · Reviewed by Greptile