feat: pending/cleared two-phase + available balance (#7) #18

Open
agent-int wants to merge 1 commit from feat/issue-7-pending-cleared into main
Collaborator

Pending / cleared two-phase + available balance

Fifth and final server item of the P1 double-entry tier (#7): two-phase settlement
(TigerBeetle two-phase / Modern Treasury pending/posted).

A transaction now carries a pending flag (default false = settled). The available balance
excludes pending transactions; the existing currentBalance (ledger balance) still includes
everything. A settle operation flips a pending transaction to settled.

Terminology: pending/settled is a TRANSACTION-level settlement status, distinct from the
split-level cleared_in_event_id (reconciliation against a bank statement) and from
postedBy/committed_at — documented in the domain type.

Purely additive — ledger-balance behavior unchanged

currentBalance, running-balance, statements, and content_hash/idempotency are untouched;
pending is a separate axis surfaced via a new available-balance query.

Surfaces

  • Migration 0012: ALTER TABLE transactions ADD COLUMN pending INTEGER NOT NULL DEFAULT 0.
  • Domain: DoubleEntryTransaction.pending.
  • Store: insert/hydrate pending; transactionsByAccountSettled; Commands.availableBalance
    (settled-only); settleTransaction (flips pending→0, notFound guard).
  • gRPC: pending on post + detail + register; new SettleTransaction (write) +
    GetAvailableBalance (read) RPCs.
  • Client: pending on post + view models; settleTransaction, availableBalance.
  • MCP: optional pending on propose/commit_post_transaction; settle_transaction (write) +
    get_available_balance (read) tools.
  • Tests: store (PendingTransactionTests), gRPC (PendingTransactionRPCTests), MCP.

Correction/edit preserves settlement status (effective-date lesson applied)

The correction reversal (Correction.swift) and the superseding replacement
(Commands.txnEdit) both carry the original's pending, so availableBalance nets to zero
correctly across an edit of a pending transaction — covered by a regression test.

⚠️ Migration version — cross-branch coordination

Numbered version 12 (main at 8; v9=attachments #15, v10=effective-date #16, v11=budgets #17 on
their still-open branches). Per-recorded-version migrator → gap-safe. When merging the migration
PRs, order the Schema.migrations array by version and set the count assertion accordingly.

Scope

Completes the #7 P1 server tier (5/5 items). Note (like effective-date's app path): the gRPC/app
edit path preserves pending only via the store correction machinery; wiring an explicit pending
override onto the gRPC EditTransaction is a documented follow-up. Does not close #7.

## Pending / cleared two-phase + available balance Fifth and final server item of the **P1 double-entry tier** (#7): two-phase settlement (TigerBeetle two-phase / Modern Treasury pending/posted). A transaction now carries a `pending` flag (default false = settled). The **available balance** excludes pending transactions; the existing `currentBalance` (ledger balance) still includes everything. A `settle` operation flips a pending transaction to settled. Terminology: `pending`/settled is a TRANSACTION-level settlement status, distinct from the split-level `cleared_in_event_id` (reconciliation against a bank statement) and from `postedBy`/`committed_at` — documented in the domain type. ### Purely additive — ledger-balance behavior unchanged `currentBalance`, running-balance, statements, and `content_hash`/idempotency are untouched; pending is a separate axis surfaced via a new available-balance query. ### Surfaces - **Migration 0012**: `ALTER TABLE transactions ADD COLUMN pending INTEGER NOT NULL DEFAULT 0`. - **Domain**: `DoubleEntryTransaction.pending`. - **Store**: insert/hydrate `pending`; `transactionsByAccountSettled`; `Commands.availableBalance` (settled-only); `settleTransaction` (flips pending→0, notFound guard). - **gRPC**: `pending` on post + detail + register; new `SettleTransaction` (write) + `GetAvailableBalance` (read) RPCs. - **Client**: `pending` on post + view models; `settleTransaction`, `availableBalance`. - **MCP**: optional `pending` on propose/commit_post_transaction; `settle_transaction` (write) + `get_available_balance` (read) tools. - **Tests**: store (`PendingTransactionTests`), gRPC (`PendingTransactionRPCTests`), MCP. ### Correction/edit preserves settlement status (effective-date lesson applied) The correction **reversal** (`Correction.swift`) and the superseding **replacement** (`Commands.txnEdit`) both carry the original's `pending`, so `availableBalance` nets to zero correctly across an edit of a pending transaction — covered by a regression test. ### ⚠️ Migration version — cross-branch coordination Numbered **version 12** (main at 8; v9=attachments #15, v10=effective-date #16, v11=budgets #17 on their still-open branches). Per-recorded-version migrator → gap-safe. When merging the migration PRs, order the `Schema.migrations` array by version and set the count assertion accordingly. ### Scope Completes the #7 P1 server tier (5/5 items). Note (like effective-date's app path): the gRPC/app edit path preserves pending only via the store correction machinery; wiring an explicit pending override onto the gRPC `EditTransaction` is a documented follow-up. Does not close #7.
feat: pending/cleared two-phase + available balance (#7)
Some checks failed
ci / macos (pull_request) Successful in 3m59s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
fee0079a4c
Add two-phase settlement (TigerBeetle two-phase / Modern Treasury
pending/posted). A transaction carries a `pending` flag (default false =
settled). The available balance excludes pending transactions; the existing
currentBalance (ledger balance) still includes everything. A settle operation
flips a pending transaction to settled. `pending` is a transaction-level
settlement status, distinct from the split-level reconciliation `cleared` and
from postedBy/committed_at.

Purely additive: currentBalance, running-balance, statements, and
content_hash/idempotency are untouched.

- migration 0012 (pending column, default 0 = settled)
- Domain: DoubleEntryTransaction.pending
- Store: insert/hydrate pending; transactionsByAccountSettled;
  Commands.availableBalance (settled-only); settleTransaction
- gRPC: pending on post + detail + register; SettleTransaction (write) +
  GetAvailableBalance (read) RPCs
- Client: pending on post + view models; settleTransaction; availableBalance
- MCP: optional pending on propose/commit_post_transaction; settle_transaction
  + get_available_balance tools
- Tests at the store, gRPC, and MCP layers

Correction/edit preserves settlement status: the reversal (Correction.swift)
and the superseding replacement (Commands.txnEdit) both carry the original's
pending, so availableBalance nets to zero across an edit of a pending
transaction (regression test).

Migration numbered version 12 (main at 8; v9/v10/v11 reserved by the parallel
unmerged attachments/#15, effective-date/#16, budgets/#17 branches); the
migrator applies per-recorded-version so the gap is safe. Completes the P1
double-entry server tier (#7).
nic force-pushed feat/issue-7-pending-cleared from fee0079a4c
Some checks failed
ci / macos (pull_request) Successful in 3m59s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
to edf0b4f31a
Some checks failed
ci / macos (pull_request) Successful in 4m15s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
2026-06-30 22:44:32 -07:00
Compare
Some checks failed
ci / macos (pull_request) Successful in 4m15s
ci / linux (pull_request) Has been cancelled
ci / proto (pull_request) Has been cancelled
ci / purity (pull_request) Has been cancelled
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin "feat/issue-7-pending-cleared:feat/issue-7-pending-cleared"
git switch "feat/issue-7-pending-cleared"

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch "main"
git merge --no-ff "feat/issue-7-pending-cleared"
git switch "feat/issue-7-pending-cleared"
git rebase "main"
git switch "main"
git merge --ff-only "feat/issue-7-pending-cleared"
git switch "feat/issue-7-pending-cleared"
git rebase "main"
git switch "main"
git merge --no-ff "feat/issue-7-pending-cleared"
git switch "main"
git merge --squash "feat/issue-7-pending-cleared"
git switch "main"
git merge --ff-only "feat/issue-7-pending-cleared"
git switch "main"
git merge "feat/issue-7-pending-cleared"
git push origin "main"
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nic/commons!18
No description provided.