Tasks · 002-trade-ledger

Append-only trade ledger

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

Status Draft Spec 002-trade-ledger Design design Branch 002-trade-ledger Created Read time

11 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

Confirm scaffold — no unique setup; the Maven/Quarkus scaffold and extensions are owned by the umbrella (001). Verify the ledger package compiles against it. pom.xml

3 · Phase 2 — Foundational

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

Reference the shared modelTradeEvent, PriceTick, Side are owned by 001; do not redefine them, import from the model package. src/main/java/io/spectastic/portfolio/model/

4 · Phase 3a — US1 · Append and sequence

Tests (write & fail first)

Test append yields gap-free 1..N — assert N appends return sequence 1..N, no gaps, no reordering, and no prior event mutated. src/test/java/io/spectastic/portfolio/LedgerTest.java

Implementation

Implement append + AtomicLong sequenceincrementAndGet then add to the hot tail; reject nothing, mutate nothing. src/main/java/io/spectastic/portfolio/ledger/TradeLedger.java
Add idempotent-append guard — an optional client event key checked against a seen-key Set so a re-delivery appends once, not twice. src/main/java/io/spectastic/portfolio/ledger/TradeLedger.java

Closes FR-001, FR-005, SC-001.

5 · Phase 3b — US2 · Complete replay under unlimited history

Tests (write & fail first)

Test full and ranged replay — a full replay returns every event in sequence order across the tier boundary; a ranged replay [a,b] returns exactly that window. src/test/java/io/spectastic/portfolio/LedgerTest.java

Implementation

Implement full/ranged replay across the tier seam — read the tail in sequence order behind a boundary-spanning signature so the durable store slots in later unchanged. src/main/java/io/spectastic/portfolio/ledger/TradeLedger.java

Closes FR-002, FR-003.

6 · Phase 3c — US3 · Snapshot to bound cold-start

Tests (write & fail first)

Test restore-then-replay equals full replay — snapshot at N, restore, replay N+1..M, assert state bit-identical to full replay [0,M]. src/test/java/io/spectastic/portfolio/LedgerTest.java

Implementation

Implement Snapshot deep-copy + restore — capture { seq, foldId, opaqueState } as a deep copy; restore installs state and resumes replay at seq+1. src/main/java/io/spectastic/portfolio/ledger/Snapshot.java

Closes FR-004, SC-002.

7 · Phase 4 — Polish

Wrap append in a Micrometer timer — time the fold/append step; expose at Prometheus /q/metrics. src/main/java/io/spectastic/portfolio/ledger/TradeLedger.java
Benchmark append against the SLOs — JMH microbenchmark vs append p99 < 5 µs and ≥ 1e6/s; record the number (resolves the §3 spike / R-2). src/test/java/io/spectastic/portfolio/LedgerBench.java
Enforce diff-aware jacoco — patch ≥ 90% on touched ledger domain; a change never lowers touched-line coverage. pom.xml

Verifies NFR-001, NFR-002, NFR-003, NFR-004.

8 · Dependencies

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

9 · Change log

  1. Initial task breakdown. TDD per story: US1 append + gap-free sequence + idempotent guard, US2 full/ranged replay across the tier seam, US3 snapshot + restore==replay; polish for the append timer, SLO benchmark, and diff-aware coverage.