Skip to content

ENG-50: implement confirmation effects (commitReservation, prorateAccrual, updatePaymentSchedule)#115

Merged
Connorbelez merged 3 commits intomainfrom
Connorbelez/eng50-commit-reservation
Mar 18, 2026
Merged

ENG-50: implement confirmation effects (commitReservation, prorateAccrual, updatePaymentSchedule)#115
Connorbelez merged 3 commits intomainfrom
Connorbelez/eng50-commit-reservation

Conversation

@Connorbelez
Copy link
Copy Markdown
Owner

@Connorbelez Connorbelez commented Mar 18, 2026

Implements the three deal-closing confirmation effects that fire when a deal
transitions to confirmed (fundsTransfer.onDone → confirmed):

  • commitReservation: commits the pending ledger reservation for the deal
  • prorateAccrualBetweenOwners: calculates and writes seller/buyer prorate
    credit entries based on closing date relative to payment schedule
  • updatePaymentSchedule: creates a dealReroute record to redirect future
    dispersals from seller to buyer for the transferred share

Adds schema tables (prorateEntries, dealReroutes) and supporting CRUD modules
(mortgages/queries, obligations/queries, prorateEntries/, dealReroutes/).
Replaces placeholder registry entries with real effect handlers.

Tests: 9 pass, 6 skipped (convex-test action ctx limitation).

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

Summary by CodeRabbit

Release Notes

  • New Features

    • Added payment rerouting capability for ownership transfers during deal closing, enabling funds to flow from seller to buyer for transferred shares.
    • Implemented interest accrual proration calculations to split ownership costs fairly between seller and buyer based on closing dates.
    • Added financial reservation commitment functionality for deal confirmation.
  • Tests

    • Comprehensive test coverage for deal closing operations, including edge cases and idempotency verification.
  • Documentation

    • Added implementation gap analysis and acceptance criteria documentation.

…rual, updatePaymentSchedule)

Implements the three deal-closing confirmation effects that fire when a deal
transitions to confirmed (fundsTransfer.onDone → confirmed):

- commitReservation: commits the pending ledger reservation for the deal
- prorateAccrualBetweenOwners: calculates and writes seller/buyer prorate
  credit entries based on closing date relative to payment schedule
- updatePaymentSchedule: creates a dealReroute record to redirect future
  dispersals from seller to buyer for the transferred share

Adds schema tables (prorateEntries, dealReroutes) and supporting CRUD modules
(mortgages/queries, obligations/queries, prorateEntries/*, dealReroutes/*).
Replaces placeholder registry entries with real effect handlers.

Tests: 9 pass, 6 skipped (convex-test action ctx limitation).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear Bot commented Mar 18, 2026

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98b6eddb-06ca-445b-9028-0c5490fe0b91

📥 Commits

Reviewing files that changed from the base of the PR and between ad30a91 and 45f770f.

📒 Files selected for processing (4)
  • convex/engine/effects/dealClosingPayments.ts
  • convex/engine/effects/dealClosingProrate.ts
  • convex/mortgages/queries.ts
  • convex/obligations/queries.ts

📝 Walkthrough

Walkthrough

Implements three deal-closing confirmation effects (commitReservation, prorateAccrualBetweenOwners, updatePaymentSchedule) with supporting database schema, data access queries/mutations, and comprehensive test coverage. Updates effect registry to wire new implementations. Includes gap analysis documentation against PRD requirements.

Changes

Cohort / File(s) Summary
Effect Implementations
convex/engine/effects/dealClosing.ts, convex/engine/effects/dealClosingProrate.ts, convex/engine/effects/dealClosingPayments.ts
Three new internal action handlers for deal confirmation: commitReservation (reserves funds via ledger), prorateAccrualBetweenOwners (calculates and records accrual splits), and updatePaymentSchedule (creates payment reroutes). Each includes idempotency guards, error handling, and logging.
Effect Registry Update
convex/engine/effects/registry.ts
Replaces three placeholder entries with real effect handler references, wiring commitReservation, prorateAccrualBetweenOwners, and updatePaymentSchedule to their implementations.
Database Schema
convex/schema.ts
Adds two new tables: prorateEntries (records seller/buyer accrual splits with daily rates and period dates) and dealReroutes (tracks payment reroutes from seller to buyer post-closing with effective dates).
Data Access Layer
convex/dealReroutes/mutations.ts, convex/dealReroutes/queries.ts, convex/prorateEntries/mutations.ts, convex/prorateEntries/queries.ts, convex/mortgages/queries.ts, convex/obligations/queries.ts
New internal queries and mutations supporting effect operations: dealReroutes insert/getByDealId, prorateEntries batch insert/getByDealId, mortgage lookup, and obligation queries (getSettledBeforeDate, getFirstAfterDate) for proration calculations.
Test Coverage
convex/deals/__tests__/effects.test.ts
Comprehensive test suite (437 lines) covering all three effects with scenarios for missing data, idempotency, and calculation accuracy. Includes seed helpers, effect argument builders, and isolated tests for edge cases.
Documentation
specs/ENG-50/gap-analysis.md, specs/ENG-50/tasks.md
Gap analysis documenting PRD alignment and design rationale (reservation-based locking, principal vs. balance semantics, reroute auditability). Tasks checklist confirming implementation of all required queries, mutations, effects, and tests.

Sequence Diagram(s)

sequenceDiagram
    participant Event as Deal Confirmation Event
    participant Engine as Effect Engine
    participant DealDB as Deal DB
    participant MortDB as Mortgage DB
    participant ObligDB as Obligation DB
    participant Ledger as Ledger Service
    participant Log as Logger

    Event->>Engine: trigger dealClosing effects
    
    rect rgb(100, 150, 200, 0.5)
    Note over Engine,Log: commitReservation Effect
    Engine->>DealDB: fetch deal by ID
    DealDB-->>Engine: deal + reservationId
    alt reservationId missing
        Engine->>Log: graceful exit, no action
    else reservationId present
        Engine->>Ledger: commitReservation(reservationId, effectiveDate)
        Ledger-->>Engine: success / error
        Engine->>Log: log outcome
    end
    end

    rect rgb(150, 100, 200, 0.5)
    Note over Engine,Log: prorateAccrualBetweenOwners Effect
    Engine->>DealDB: fetch deal by ID
    DealDB-->>Engine: deal + closingDate
    alt deal missing
        Engine->>Log: throw DEAL_NOT_FOUND
    else closingDate missing
        Engine->>Log: graceful exit
    else idempotent check passes
        Engine->>ObligDB: getSettledBeforeDate(mortgageId)
        ObligDB-->>Engine: lastPaymentDate
        Engine->>ObligDB: getFirstAfterDate(mortgageId)
        ObligDB-->>Engine: nextPaymentDate
        Engine->>MortDB: fetch mortgage (interest, principal)
        MortDB-->>Engine: mortgage data
        Engine->>Engine: calculate dailyRate, sellerDays, buyerDays
        Engine->>DealDB: insertProrateEntries (seller + buyer splits)
        DealDB-->>Engine: entry IDs
        Engine->>Log: log proration summary
    end
    end

    rect rgb(200, 150, 100, 0.5)
    Note over Engine,Log: updatePaymentSchedule Effect
    Engine->>DealDB: fetch deal by ID
    DealDB-->>Engine: deal + closingDate
    alt deal missing
        Engine->>Log: throw DEAL_NOT_FOUND
    else closingDate missing
        Engine->>Log: graceful exit
    else idempotent check (no existing reroute)
        Engine->>DealDB: insertDealReroutes(dealId, fromOwner, toOwner, effectiveAfterDate)
        DealDB-->>Engine: reroute ID
        Engine->>Log: log creation success
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Connorbelez/tanstackTemplate#23: Main PR directly implements the three deal-closing confirmation effects and supporting infrastructure (queries, mutations, schema tables) that fulfill the requirements outlined in this issue.

Possibly related PRs

Poem

🐰 A deal closes, and proration chimes,
Seller and buyer split the daily times,
Reroutes dance through the payment stream,
Idempotent flows—a cashier's dream! ✨
From reservation vaults to accrual's grace,
The engine now runs—what a perfect place!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Connorbelez/eng50-commit-reservation
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link
Copy Markdown
Owner Author

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Connorbelez Connorbelez marked this pull request as ready for review March 18, 2026 03:12
Copilot AI review requested due to automatic review settings March 18, 2026 03:12
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Connorbelez has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copy link
Copy Markdown
Owner Author

@greptile review

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Connorbelez has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the three confirmation-time effects for deal closing (commit reservation, prorate accrual credits, and reroute future payment dispersals) plus the supporting storage and internal CRUD needed to persist and query the resulting records.

Changes:

  • Add new persistence tables for prorate credits and deal payment reroutes, plus internal CRUD modules.
  • Implement commitReservation, prorateAccrualBetweenOwners, and updatePaymentSchedule effects and wire them into the effects registry.
  • Add a Vitest suite covering error/idempotency paths for the new effects (with several happy-path tests currently skipped).

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
specs/ENG-50/tasks.md Task tracking checklist for ENG-50 implementation/testing.
specs/ENG-50/gap-analysis.md Documents PRD vs implementation deviations and follow-ups.
convex/schema.ts Adds prorateEntries + dealReroutes tables and indexes.
convex/prorateEntries/queries.ts Internal query to fetch prorate entries by deal for idempotency.
convex/prorateEntries/mutations.ts Internal mutation to atomically insert prorate entries.
convex/dealReroutes/queries.ts Internal query to fetch reroute record by deal for idempotency.
convex/dealReroutes/mutations.ts Internal mutation to insert a reroute record.
convex/obligations/queries.ts Internal queries to find last-settled and next obligation around closing date.
convex/mortgages/queries.ts Internal mortgage fetch helper for effects.
convex/engine/effects/dealClosingProrate.ts Implements prorate accrual effect writing prorateEntries.
convex/engine/effects/dealClosingPayments.ts Implements reroute effect writing dealReroutes.
convex/engine/effects/dealClosing.ts Adds commitReservation effect implementation.
convex/engine/effects/registry.ts Replaces placeholders with real effect handlers.
convex/deals/tests/effects.test.ts Adds unit tests for confirmation effects (some skipped due to harness limitations).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread convex/engine/effects/dealClosingPayments.ts
Comment thread convex/obligations/queries.ts Outdated
Comment thread convex/obligations/queries.ts Outdated
Comment thread convex/deals/__tests__/effects.test.ts
Comment thread convex/engine/effects/registry.ts
Comment thread convex/engine/effects/dealClosing.ts
Comment thread convex/engine/effects/dealClosingProrate.ts
Comment thread convex/engine/effects/dealClosingProrate.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@convex/engine/effects/dealClosingPayments.ts`:
- Around line 58-78: The catch block around the
ctx.runMutation(internal.dealReroutes.mutations.insert, ...) in
updatePaymentSchedule is swallowing failures; instead of just logging, re-throw
(or propagate) the error so the caller knows the reroute write failed. Update
the catch to log the error and then throw the caught error (or remove the
try/catch and let the exception bubble) so that a confirmed deal cannot be left
without the reroute side effect.
- Around line 37-47: The current idempotency pattern uses ctx.runQuery with
internal.dealReroutes.queries.getByDealId followed by a separate insert, which
allows races; make the check+insert atomic by moving dedupe into a single
mutation or enforcing a unique constraint. Replace the read-then-write flow
(ctx.runQuery + subsequent insert into internal.dealReroutes) with a single
atomic operation: either implement a createIfNotExists-style mutation on
internal.dealReroutes that checks dealId and returns existing row if present, or
add a unique constraint on dealId and catch the duplicate-key error on insert to
treat it as a no-op; apply the same change for the other occurrence around lines
59-67 (same symbols: ctx.runQuery, internal.dealReroutes.*) so concurrent
executions cannot create duplicate reroutes.

In `@convex/engine/effects/dealClosingProrate.ts`:
- Around line 175-195: The catch block after calling
ctx.runMutation(internal.prorateEntries.mutations.insertProrateEntries, {
entries }) only logs the error and returns, which hides failures; update the
catch in dealClosingProrate.ts to log the error (keeping the existing
console.error message referencing dealId) and then rethrow the caught error (or
throw a new Error with the original error message) so the caller can observe and
handle the prorate write failure for entries/sellerAmount/buyerAmount.
- Around line 47-57: The idempotency check using
ctx.runQuery(internal.prorateEntries.queries.getByDealId, { dealId }) is
currently outside the transaction that inserts prorate entries, allowing race
conditions; move this existence check into the same mutation/transaction that
performs the insert (or replace the logic with a conditional insert/upsert
within the transaction). Concretely, update the mutation that creates prorate
entries so it first queries getByDealId (or does a SELECT ... FOR UPDATE / an
atomic upsert) inside the same ctx.runMutation/transactional block that calls
the insert logic for dealId, and remove the standalone pre-check (also apply the
same change for the similar check at the second occurrence around lines
referenced 176-179). Ensure you use the same transaction context so only one
concurrent run can create entries for a given dealId.

In `@convex/mortgages/queries.ts`:
- Around line 8-17: getInternalMortgage currently throws
ConvexError("MORTGAGE_NOT_FOUND") when ctx.db.get(mortgageId) returns nothing,
but callers (e.g., the logic in dealClosingProrate.ts) expect a nullable result;
change the handler in getInternalMortgage to return null instead of throwing
when mortgage is falsy (mirroring getInternalDeal), remove the ConvexError
throw, and ensure any type annotations or callers rely on a nullable return
rather than catching an exception.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef73d027-9395-44b1-a95d-56f3bca0b0f7

📥 Commits

Reviewing files that changed from the base of the PR and between 129cead and ad30a91.

📒 Files selected for processing (14)
  • convex/dealReroutes/mutations.ts
  • convex/dealReroutes/queries.ts
  • convex/deals/__tests__/effects.test.ts
  • convex/engine/effects/dealClosing.ts
  • convex/engine/effects/dealClosingPayments.ts
  • convex/engine/effects/dealClosingProrate.ts
  • convex/engine/effects/registry.ts
  • convex/mortgages/queries.ts
  • convex/obligations/queries.ts
  • convex/prorateEntries/mutations.ts
  • convex/prorateEntries/queries.ts
  • convex/schema.ts
  • specs/ENG-50/gap-analysis.md
  • specs/ENG-50/tasks.md

Comment thread convex/engine/effects/dealClosingPayments.ts
Comment thread convex/engine/effects/dealClosingPayments.ts
Comment thread convex/engine/effects/dealClosingProrate.ts
Comment thread convex/engine/effects/dealClosingProrate.ts
Comment thread convex/mortgages/queries.ts
- mortgages/queries: return null instead of throwing (match caller pattern)
- obligations/queries: use index range constraints + .first() instead of
  collect+sort (avoids full-table scan)
- dealClosingPayments, dealClosingProrate: re-throw errors after logging
  so failures propagate to Convex scheduler for retry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Connorbelez Connorbelez merged commit 4a4d22e into main Mar 18, 2026
0 of 3 checks passed
Connorbelez added a commit that referenced this pull request Apr 20, 2026
…rual, updatePaymentSchedule) (#115)

Implements the three deal-closing confirmation effects that fire when a deal
transitions to confirmed (fundsTransfer.onDone → confirmed):

- commitReservation: commits the pending ledger reservation for the deal
- prorateAccrualBetweenOwners: calculates and writes seller/buyer prorate
  credit entries based on closing date relative to payment schedule
- updatePaymentSchedule: creates a dealReroute record to redirect future
  dispersals from seller to buyer for the transferred share

Adds schema tables (prorateEntries, dealReroutes) and supporting CRUD modules
(mortgages/queries, obligations/queries, prorateEntries/*, dealReroutes/*).
Replaces placeholder registry entries with real effect handlers.

Tests: 9 pass, 6 skipped (convex-test action ctx limitation).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * Implemented complete deal closing workflow with three core operations: reservation commitment to lock funds, automated interest proration calculation between seller and buyer, and payment routing configuration for transferred ownership shares.
  * Added comprehensive database support for tracking prorate entries and payment reroutes.

* **Tests**
  * Added extensive test coverage for deal closing effects including edge cases and idempotency validation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

2 participants