Skip to content

Fix friend creation and direct expense ledger lifecycle - #40

Merged
AnganSamadder merged 5 commits into
mainfrom
fix/friend-ledger-lifecycle
Aug 26, 2026
Merged

Fix friend creation and direct expense ledger lifecycle#40
AnganSamadder merged 5 commits into
mainfrom
fix/friend-ledger-lifecycle

Conversation

@AnganSamadder

Copy link
Copy Markdown
Owner

Summary

  • make confirmed friendships the sole source for Friends UI and friend pickers
  • create the private direct-expense ledger atomically with the first saved expense
  • await friend and group cloud acknowledgements with rollback/account-switch safety
  • clarify friend, group-participant, and direct-ledger terminology
  • prepare TestFlight version 0.1.18 build 133

Verification

  • 79 focused iOS regression tests passed
  • 2,797 standard iOS tests passed with 0 failures and 0 warnings
  • 575 backend tests passed; bun run ci passed
  • TSan: 2,755 tests, 0 failures, no race reports
  • ASan: 2,797 tests, 0 failures, no memory reports
  • manual simulator: add friend via Return, Friends list visibility, direct target selection, and no ledger created on cancel
  • production read-only verification after requested repair: David and Alexios are confirmed friends; both legacy ledgers contain 0 expenses

Copilot AI lite review requested due to automatic review settings August 26, 2026 20:22
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
payback Ready Ready Preview Aug 26, 2026 10:05pm

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22e550cc22

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 915 to +917
if (!matchingFriend) {
if (
!createdDirectGroupForExpense &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Block name fallback for freshly created direct ledgers

When a first-expense request supplies an unregistered counterparty ID whose participant name matches exactly one confirmed friend, this new guard disables only the group-membership fallback; the name-based fallback at lines 925–933 still accepts the request. The mutation consequently creates a ledger and expense for an identity absent from account_friends, so every legacy fallback—not only this branch—must be excluded when createdDirectGroupForExpense is true.

AGENTS.md reference: apps/backend/convex/AGENTS.md:L36-L37

Useful? React with 👍 / 👎.

Comment on lines +773 to +778
const existingGroupByClientId = await ctx.db
.query("groups")
.withIndex("by_client_id", (q) => q.eq("id", args.group_id))
.unique();

if (!existingGroupByClientId && !existing && requestedContextKind === "direct") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reuse identity-equivalent direct ledgers before inserting

If another device creates the direct ledger after this client opens a transient Add Expense draft, or two devices save concurrently, each draft has a different UUID; therefore existingGroupByClientId is null and this branch inserts another direct ledger without checking the owner's existing ledgers for the same identity-equivalent counterparty. This leaves permanent duplicate ledgers and causes future direct expenses to reuse whichever duplicate happens to be returned first.

AGENTS.md reference: AGENTS.md:L69-L71

Useful? React with 👍 / 👎.

@AnganSamadder

Copy link
Copy Markdown
Owner Author

Retriggering CI for the unchanged tested head after the synchronize event did not create a GitHub Actions run.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8797b70a06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Confirmed friends plus explicit friends drafted in this creation flow.
private var allFriends: [GroupMember] {
let existing = store.friendMembers
let existing = store.confirmedFriends

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reuse known participant identities for typed friends

When someone already exists only as a group participant and the user types that same name under Add New Friend, switching allFriends to confirmedFriends prevents the existing identity from being found; the unchanged fallback then creates a fresh UUID, and addGroupAndSync persists it as a separate friend. This splits one person across balances, linking, and future groups. Keep the picker restricted to confirmed friends, but resolve typed additions through manualFriendCandidate(named:), as the standalone add-friend flow does.

AGENTS.md reference: apps/ios/PayBack/Sources/AGENTS.md:L17-L18

Useful? React with 👍 / 👎.

@AnganSamadder
AnganSamadder merged commit 05e221f into main Aug 26, 2026
25 of 29 checks passed
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