Tasks · 005-tax-lots

FIFO/LIFO tax lot tracking

Ordered, parallelizable work. Tests precede implementation. Drive through with /spectastic.implement — one task per invocation.

Status Draft Spec 005-tax-lots Design design Branch 005-tax-lots Created Read time

16 tasks across five phases. Setup → Foundational → User stories (US1·US2·US3) → Polish. Tasks marked [P] can run in parallel — different files, no dependency. Tests for a story MUST be written and failing before its implementation tasks start.

1 · Execution strategy

Implement US1 end-to-end. Ship. Iterate to US2 and US3 only after US1 is verified.

Setup → Foundational → US1 → US2 → US3 → Polish. Each story closes its conformance before the next opens.

One team on each user story after Foundational. Coordinate at shared seams (data model, API contracts) via the spec, not Slack.

2 · Phase 1 — Setup

Create the tax module skeleton src/main/java/io/spectastic/portfolio/tax/
Confirm Quarkus extensions and jacoco — verify quarkus-micrometer-registry-prometheus, quarkus-smallrye-openapi, and the jacoco plugin are already wired by 001. pom.xml

3 · Phase 2 — Foundational

Shared infrastructure no story can ship without. Sequential where order matters.

Reference the shared model owned by 001 — consume TradeEvent, PriceTick, and PRICE_SCALE; define no umbrella types here. src/main/java/io/spectastic/portfolio/model/
Define Lot and ReliefPolicy — the immutable lot record and the FIFO|LIFO enum. src/main/java/io/spectastic/portfolio/tax/Lot.java

4 · Phase 3a — US1 · Open lots on buys

Tests (write & fail first)

Test: buys open acquisition-ordered lots — one lot per buy, quantities sum to the long position. src/test/java/io/spectastic/portfolio/TaxLotBookTest.java

Implementation

Push a lot per buy onto the dequeArrayDeque<Lot> per (account, instrument) in acquisition order. src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java

Closes FR-001.

5 · Phase 3b — US2 · Relieve by FIFO or LIFO on a sell

Tests (write & fail first)

Test: the SC-001 worked example — buy 100@10 then 100@12, sell 150; FIFO relieved basis 1600 leaving 50@12, LIFO 1700 leaving 50@10, each exact. src/test/java/io/spectastic/portfolio/TaxLotBookTest.java

Implementation

Relieve by policy with an in-place split — FIFO from the head, LIFO from the tail; reduce the boundary lot's qtyOpen; realized gain qty·(sellPrice − lotBasis) in long arithmetic. src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java
Open a short lot on oversell — a sell exceeding open long lots closes them and opens a SHORT lot for the residual. src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java

Closes FR-002, FR-003, SC-001.

6 · Phase 3c — US3 · Auditable realized gain

Tests (write & fail first)

Test: a record per relief sums to cumulative gain — each RealizedGainRecord names lot, policy, proceeds, basis, gain; summing reproduces cumulative realized gain. src/test/java/io/spectastic/portfolio/TaxLotBookTest.java
Test: unrealized on tick reconciles to replay — per-lot unrealized gain folds on PriceTick; incremental equals a full replay to the cent. src/test/java/io/spectastic/portfolio/TaxLotBookTest.java

Implementation

Emit an immutable RealizedGainRecord — lot sequence, applied policy, proceeds, relieved basis, gain, holding period. src/main/java/io/spectastic/portfolio/tax/RealizedGainRecord.java
Fold unrealized gain and reconcile — per-lot unrealized on ticks; snapshot deep-copy, restore-then-replay-tail equals full replay. src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java

Closes FR-004, FR-005, SC-002.

7 · Phase 4 — Polish

Assert the bounded open-lot set — 0 lots when flat, open lots ≤ open buys. src/test/java/io/spectastic/portfolio/TaxLotBookTest.java
Add the Micrometer relief timer and JMH check — fold timer at /q/metrics; JMH microbench confirms relief p99 < 40 µs at 1000 lots. src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java
Wire diff-aware jacoco coverage — patch target on changed lines; a change never lowers coverage of what it touches. pom.xml

Closes NFR-001, NFR-002, NFR-003.

8 · Dependencies

Setup           → Foundational
Foundational    → US1, US2, US3   (independent after this point)
US1, US2, US3   → Polish

7 · Add HIFO relief policy (applied change 2026-07-22-hifo-relief)

Folded from the applied proposal's §6 (the archive is frozen).

Add a HIFO worked-example test — buy 100@10, 100@14, 100@12; sell 150 → relieved basis 2000, leaving 50@12 and 100@10; assert HIFO differs from FIFO and LIFO, to the cent src/test/java/io/spectastic/portfolio/TaxLotBookTest.java
Add HIFO to the policy enum src/main/java/io/spectastic/portfolio/tax/ReliefPolicy.java
Generalise lot selection — relief picks the policy-preferred lot (FIFO first, LIFO last, HIFO highest basis) and relieves/splits it in place src/main/java/io/spectastic/portfolio/tax/TaxLotBook.java

10 · Change log

  1. Initial task breakdown. TDD per story: US1 acquisition-ordered lot opens (T-100/T-110), US2 FIFO/LIFO relief with the SC-001 worked example as the headline test plus short-lot oversell (T-200/T-210/T-211), US3 immutable audit records and unrealized-on-tick reconcile-to-replay (T-300/T-301/T-310/T-311). Polish: bounded-lot assertion, Micrometer relief timer with JMH envelope check, diff-aware jacoco.