Skip to content

fix(ledger): book advance attribution at purchase time#4767

Draft
GAlexIHU wants to merge 1 commit into
mainfrom
codex/credit-purchase-attribution-timing
Draft

fix(ledger): book advance attribution at purchase time#4767
GAlexIHU wants to merge 1 commit into
mainfrom
codex/credit-purchase-attribution-timing

Conversation

@GAlexIHU

@GAlexIHU GAlexIHU commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep subscription and schedule definitions ledger-neutral; this changes only the materialized credit-purchase initiation path
  • determine and book existing advance attribution at purchase time
  • keep only the non-attributed remainder as issuance at the grant's future effective_at
  • align the ledger timing with the immediate lineage backfill so a subsequent committed purchase sees the already-settled advance

Behavior

  • a future-effective 100-credit purchase against 40 of existing advance books 40 of attribution immediately and 60 of issuance at effective_at
  • the future 60 does not appear in the current spendable balance
  • two sequential 60-credit purchases against 100 of advance attribute 60 + 40, with only the remaining 20 issued in the future
  • promotional purchase coverage verifies that grant realization and lineage use the same purchase-time ledger transaction group

Invoice-settled purchases keep their existing trigger at invoice draft creation. This PR does not add payment control or recurring subscription grants.

Cancellation / void limitation

The existing void path operates on currently issued future-balance-overage value for the source charge. Before a future grant reaches effective_at, its scheduled remainder has no spendable balance slice to void, and the purchase-time advance attribution is not such a slice. As a result, future-effective grants remain non-voidable before effective_at; this PR does not add cancellation of scheduled ledger entries or claim to solve that lifecycle. Void behavior for remaining issued value after effective_at is unchanged.

Tests

  • nix develop --impure .#ci -c env POSTGRES_HOST=127.0.0.1 go vet -tags=dynamic ./openmeter/ledger/chargeadapter ./openmeter/billing/charges/creditpurchase/service
  • nix develop --impure .#ci -c env POSTGRES_HOST=127.0.0.1 go test -tags=dynamic -v ./openmeter/ledger/chargeadapter ./openmeter/billing/charges/creditpurchase/service
  • nix develop --impure .#ci -c env POSTGRES_HOST=127.0.0.1 go test -tags=dynamic -v ./test/credits

All database-backed tests ran against PostgreSQL; none were skipped.

Greptile Summary

This PR books existing advance attribution when a credit purchase is materialized. The main changes are:

  • Advance attribution and accrued-cost translation move to purchase time.
  • Remaining credit issuance stays at the grant effective time.
  • Tests cover future-effective grants, sequential purchases, and promotional lineage timing.

Confidence Score: 4/5

Past-effective promotional purchases need a ledger-ordering fix before merging.

  • Future-effective purchases consume advance at the intended time.
  • Past-effective purchases can place authorization and settlement before the newly moved attribution.
  • The added tests do not cover this timing order.

openmeter/ledger/chargeadapter/creditpurchase.go

Important Files Changed

Filename Overview
openmeter/ledger/chargeadapter/creditpurchase.go Splits attribution and issuance timestamps, but past-effective promotional purchases can record settlement before attribution.
openmeter/ledger/chargeadapter/creditpurchase_test.go Adds database-backed coverage for future-effective grants and sequential advance consumption.
openmeter/billing/charges/creditpurchase/service/promotional_test.go Verifies that promotional realization and lineage use the purchase-time transaction group.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant C as Purchase caller
    participant H as Credit purchase handler
    participant L as Ledger
    C->>H: Materialize past-effective promotional purchase
    H->>L: Authorize and settle at effectiveAt
    H->>L: Attribute advance at purchasedAt
    Note over L: Settlement appears before attribution in ledger history
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant C as Purchase caller
    participant H as Credit purchase handler
    participant L as Ledger
    C->>H: Materialize past-effective promotional purchase
    H->>L: Authorize and settle at effectiveAt
    H->>L: Attribute advance at purchasedAt
    Note over L: Settlement appears before attribution in ledger history
Loading

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
openmeter/ledger/chargeadapter/creditpurchase.go:242
**Past-Effective Settlement Precedes Attribution**

When a promotional purchase is materialized after its `effectiveAt`, this attribution is booked at the current time while authorization and settlement remain booked at the earlier effective time. An as-of query between those times therefore shows the purchase settled before its receivable attribution exists, producing invalid ledger history for a supported past-effective charge.

Reviews (1): Last reviewed commit: "fix(ledger): book advance attribution at..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9464c898-0582-4cf9-a6a1-5426b3301962

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 codex/credit-purchase-attribution-timing

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.

❤️ Share

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

@GAlexIHU GAlexIHU added the release-note/bug-fix Release note: Bug Fixes label Jul 21, 2026
for _, attribution := range advanceAttributions {
templates = append(templates, transactions.AttributeCustomerAdvanceReceivableCostBasisTemplate{
At: bookedAt,
At: purchasedAt,

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.

P1 Past-Effective Settlement Precedes Attribution

When a promotional purchase is materialized after its effectiveAt, this attribution is booked at the current time while authorization and settlement remain booked at the earlier effective time. An as-of query between those times therefore shows the purchase settled before its receivable attribution exists, producing invalid ledger history for a supported past-effective charge.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openmeter/ledger/chargeadapter/creditpurchase.go
Line: 242

Comment:
**Past-Effective Settlement Precedes Attribution**

When a promotional purchase is materialized after its `effectiveAt`, this attribution is booked at the current time while authorization and settlement remain booked at the earlier effective time. An as-of query between those times therefore shows the purchase settled before its receivable attribution exists, producing invalid ledger history for a supported past-effective charge.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/bug-fix Release note: Bug Fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant