Skip to content

feat(billing): add service fee domain library - #5262

Open
jeanduplessis wants to merge 4 commits into
transaction-service-fee-1-schemafrom
transaction-service-fee-2-library
Open

feat(billing): add service fee domain library#5262
jeanduplessis wants to merge 4 commits into
transaction-service-fee-1-schemafrom
transaction-service-fee-2-library

Conversation

@jeanduplessis

@jeanduplessis jeanduplessis commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the service-fee domain library without connecting it to live payment paths.

Why this change is needed

The fee lifecycle has more states than a Stripe line item: eligibility, exemption, expected versus charged fee, settlement, fail-open misses, refunds, and disputes. Landing these rules as an unused library isolates the financial model from the later wiring changes and makes its behavior reviewable before any customer can be charged.

How this is addressed

  • Add aggregate fee calculation with minor-unit rounding and explicit eligible-line classification.
  • Add durable assessment creation, enrichment, settlement, refund, dispute, and organization-exemption helpers.
  • Add Checkout and invoice attachment helpers with idempotency and fail-open behavior.
  • Add alerting and reconciliation boundaries for misses and rate deviations.
  • Pin the Stripe API version so provider line-shape assumptions do not drift underneath the implementation.

Stack: #5236#5262 (this PR) → #5263#5264#5265#5266.

Human Verification

No new product or browser verification was performed while publishing this PR. This slice is intentionally unused; its behavior is covered by focused automated tests in the diff.

Reviewer Notes

Human Reviewer Flags

  • This is deliberately a large but inert domain-library slice. No payment path imports it yet.
  • The assessment is one row per commercial event, enriched as Stripe emits Checkout, Invoice, PaymentIntent, Charge, refund, and dispute events.
  • Positive fees fail open: the underlying purchase proceeds and the missed expected fee remains auditable.
  • Checkout promotions may reduce the collected fee below the initially expected fee, so those amounts are intentionally separate.

Code Reviewer Agent

Code Reviewer Notes
  • Review arithmetic and state transitions before integration concerns; later PRs mainly connect these APIs to existing flows.
  • Refund allocation is cumulative to avoid rounding drift across partial refunds.
  • Disputes have separate reversible counters rather than reusing monotonic refund fields.
  • The Stripe client API version is pinned to protect line and tax behavior assumptions.

Comment thread apps/web/src/lib/service-fees/checkout.ts Outdated
Comment thread apps/web/src/lib/service-fees/invoice-created.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • apps/web/src/lib/service-fees/checkout.ts
  • apps/web/src/lib/service-fees/checkout.test.ts
  • apps/web/src/lib/service-fees/invoice-created.ts
  • apps/web/src/lib/service-fees/invoice-created.test.ts
Previous Review Summaries (3 snapshots, latest commit 1e58993)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 1e58993)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The double-failure fallback in checkout.ts still persists a pending + zero-expected-fee assessment that no transition or settlement path can resolve.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/service-fees/checkout.ts 1124 safePrepareDecision fallback emits outcome: 'pending' with expectedFeeMinor: 0; markMissed rejects it and settleServiceFeeAssessment throws pending_settlement on every settlement retry, permanently wedging the assessment

SUGGESTION

File Line Issue
apps/web/src/lib/service-fees/invoice-created.ts 266 Catch-all alert hardcodes flow: 'personal_kilo_pass', mislabeling organization Kilo Pass invoices in Slack alerts
Files Reviewed (3 files)
  • .plans/service-fees/SPEC.md
  • .plans/service-fees/VALIDATION.md
  • docs/adr/0004-stripe-service-fee-assessment.md

Fix these issues in Kilo Cloud

Previous review (commit ce00251)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The double-failure fallback in checkout.ts still persists a pending + zero-expected-fee assessment that no transition or settlement path can resolve.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/service-fees/checkout.ts 1124 safePrepareDecision fallback emits outcome: 'pending' with expectedFeeMinor: 0; markMissed rejects it and settleServiceFeeAssessment throws pending_settlement on every settlement retry, permanently wedging the assessment

SUGGESTION

File Line Issue
apps/web/src/lib/service-fees/invoice-created.ts 266 Catch-all alert hardcodes flow: 'personal_kilo_pass', mislabeling organization Kilo Pass invoices in Slack alerts
Files Reviewed (10 files)
  • apps/web/src/lib/service-fees/assessments.ts (+ test)
  • apps/web/src/lib/service-fees/checkout.ts (+ test) - 1 issue
  • apps/web/src/lib/service-fees/drizzle-store.ts (+ test)
  • apps/web/src/lib/service-fees/invoice-created.ts (+ test) - 1 issue
  • apps/web/src/lib/service-fees/organization-exemptions.ts (+ test)
  • apps/web/src/lib/service-fees/types.ts
  • packages/db/src/schema.ts (+ test)
  • packages/db/src/migrations/0213_service_fee_assessments.sql
  • packages/db/src/migrations/meta/0213_snapshot.json
  • packages/db/src/migrations/meta/_journal.json

Fix these issues in Kilo Cloud

Previous review (commit 842d6ec)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The inert service-fee domain library is carefully built (minor-unit BigInt rounding, idempotent upserts, optimistic-concurrency guards, fail-open misses), but the double-failure fallback in checkout.ts persists a pending + zero-expected-fee assessment that no transition or settlement path can ever resolve.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/service-fees/checkout.ts 1125 safePrepareDecision fallback emits outcome: 'pending' with expectedFeeMinor: 0; markMissed rejects it and settleServiceFeeAssessment throws pending_settlement on every settlement retry, permanently wedging the assessment

SUGGESTION

File Line Issue
apps/web/src/lib/service-fees/invoice-created.ts 266 Catch-all alert hardcodes flow: 'personal_kilo_pass', mislabeling organization Kilo Pass invoices in Slack alerts
Files Reviewed (28 files)
  • apps/web/src/lib/service-fees/types.ts
  • apps/web/src/lib/service-fees/constants.ts
  • apps/web/src/lib/service-fees/calculation.ts (+ test)
  • apps/web/src/lib/service-fees/assessments.ts (+ test)
  • apps/web/src/lib/service-fees/checkout.ts (+ test) - 1 issue
  • apps/web/src/lib/service-fees/invoice-created.ts (+ test) - 1 issue
  • apps/web/src/lib/service-fees/settlement.ts (+ test)
  • apps/web/src/lib/service-fees/refunds.ts (+ test)
  • apps/web/src/lib/service-fees/disputes.ts (+ test)
  • apps/web/src/lib/service-fees/stripe-lines.ts (+ test)
  • apps/web/src/lib/service-fees/tax.ts (+ test)
  • apps/web/src/lib/service-fees/alerts.ts (+ test)
  • apps/web/src/lib/service-fees/organization-exemptions.ts (+ test)
  • apps/web/src/lib/service-fees/drizzle-store.ts (+ test)
  • apps/web/src/lib/service-fees/read-only.ts
  • apps/web/src/lib/stripe-client.ts

Custom-instruction checks: no .md documentation files in this PR (image-format rule N/A); kilocode-landing SEO rules N/A (no landing pages in this repo); no memory-leak vectors found (no global mutable state, caches, timers, or listeners introduced — only module-level immutable constants).

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 68.8K · Output: 16.7K · Cached: 506.5K

Review guidance: REVIEW.md from base branch transaction-service-fee-1-schema

@jeanduplessis
jeanduplessis force-pushed the transaction-service-fee-2-library branch 2 times, most recently from ce00251 to 1e58993 Compare August 18, 2026 19:08
Land the fee math, durable assessments, Checkout/invoice attach helpers,
and refund/dispute observers without wiring them into payment paths.
Pin the Stripe API version so line-shape assumptions stay stable.
@jeanduplessis
jeanduplessis force-pushed the transaction-service-fee-1-schema branch from e996029 to f5731b3 Compare August 19, 2026 14:23
@jeanduplessis
jeanduplessis force-pushed the transaction-service-fee-2-library branch from 1e58993 to 68aaf4a Compare August 19, 2026 14:23
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