Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Decisions

2026-07-12-portfolio-position-dedup

Decisioncanonicalverified 2026-07-12

DECISION.2026-07-12.PORTFOLIO-POSITION-DEDUP

Decision

Portfolio position ids are stable across re-uploads of the same holding statement — the id is ${holdingId}, not ${holdingId}__${docId}. Re-uploading the same MF CAS or NPS statement overwrites the prior position rather than adding a second one.

Why

The recompute audit found that every re-upload of an MF CAS produced a new portfolio_positions/{holdingId__docId} row, causing the engine to double-count NAV — a user who uploaded the same CAS twice saw their portfolio value inflated by 2x. Contributing factors:

  • Positions carry no natural key beyond holdingId + docId.
  • The latest-upload-wins promise in the mapper comment was aspirational.
  • Firestore's write-if-not-exists semantics don't apply — every document confirm ran set().

Impact

  • portfolio-position-mapper.ts:120 — position id changed.
  • Test updated: two-doc dedup case now expects equal position ids.
  • Engine: no change; the engine sums by holding_id, which was always correct — only the underlying position table was wrong.
  • V2 will introduce per-lot position ids (${holdingId}__${lotId}) when the FIFO lot ledger lands; that changes this id scheme again.

Status

Active. Landed as part of the Phase 4 recompute-correctness sweep.

Sources

  • Phase 4 recompute-correctness commit (Phase 4 sweep).
  • apps/functions/src/portfolio/portfolio-position-mapper.ts.
  • Related entity: pillar-portfolio.

Every project of mine is written down like this.

Read the résumé