0.2.33: exited positions (secondary-sale edge case)

A member who sold/transferred their stake showed a phantom -100% loss
($0 ending balance, no distribution through the fund). Now:
- entity_access.exited_on (migration e1f2a3b4c5d6), set/cleared from the
  Partners tab (writer-only, inline date picker, audited)
- LP portal card shows a quiet "Exited <date>" badge, keeps documents,
  hides balance/gain
- portfolio summary excludes exited positions ("Excludes N exited")
- fund committed totals (rollup + Partners tab) skip exited members so
  seller + buyer are not double-counted

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jonathan Kirkwood
2026-07-03 08:54:19 -05:00
co-authored by Claude Opus 4.8
parent 4215d4478f
commit a639ba14cf
14 changed files with 355 additions and 17 deletions
+7
View File
@@ -86,6 +86,7 @@ export interface Partner {
latest_value_cents: number | null;
latest_as_of: string | null;
statements_count: number;
exited_on: string | null;
}
export interface AccessGrant {
@@ -160,6 +161,7 @@ export interface CapitalAccount {
ending_balance_cents: number;
document_id: number | null;
created_at: string;
exited_on: string | null;
}
export interface Entity {
@@ -313,6 +315,11 @@ export const api = {
`/api/entities/${entityId}/partners`,
{ method: "DELETE" },
),
setPartnerExited: (entityId: number, userId: number, exitedOn: string | null) =>
request<Partner>(`/api/entities/${entityId}/partners/${userId}/exited`, {
method: "PUT",
body: JSON.stringify({ exited_on: exitedOn }),
}),
createEntity: (data: Partial<Entity>) =>
request<Entity>("/api/entities", { method: "POST", body: JSON.stringify(data) }),
updateEntity: (id: number, data: Partial<Entity>) =>