portfolio-ledger · git:20261023.ef2f2f6 · 2026-10-23 · sha256 658761f85ab77c42

portfolio-ledger git:20261023.ef2f2f6A

Immutable. This exact content never changes and is served at /api/v1/blob/658761f85ab77c42.

---
name: portfolio-ledger
description: Read positions, exposure, and P&L from the append-only ledger with restart reconciliation and JSONL export, owned by JOURNAL with RISK reading.
bots:
  - bot-09-journal
  - bot-02-risk
gates:
  - G-2
required_tools:
  - portfolio.ledger_read
  - portfolio.exposure
  - portfolio.pnl
required_data: []
permissions:
  max_side_effect: read
  network: true
  filesystem: var
fixtures:
  - tests/fixtures/replay/smoke
---

# Portfolio Ledger

## L1 - Summary

The ledger is the desk's memory: every event appended once, hash-chained, never edited. JOURNAL owns reads for reports and reconciliation; RISK reads exposure and P&L for limit decisions. After any restart, reconcile from the chain before trusting a single number.

```
append-only events -> hash chain verifies -> exposure and P&L read -> reports and limits
restart -> reconcile from chain -> then read
```

## L2 - Method

1. S1 - Read through the tools: use `portfolio.ledger_read` for event history, `portfolio.exposure` for current exposure, and `portfolio.pnl` for realised and unrealised P&L. Never read the sqlite file directly when a tool exists.
2. S2 - Reconcile after restart: verify the hash chain (`seq` without gaps, every `prev_hash` matching) before serving numbers. A chain that does not verify stops reads until repaired from the last good snapshot.
3. S3 - Speak event types: the ledger carries the snake_case event kinds (order, fill, halt, kill, approval, journal_note, escalation). Filter by kind and ticket; never invent a kind.
4. S4 - Export as JSONL: snapshots and exports go to versioned JSONL views for reports and audits. Exports are derived views; the chain stays the single truth.
5. S5 - Separate writing from reading: seats write ledger events only through `journal.append` and `desk.event_emit` with kinds `journal_note` or `escalation`. Every other event type is appended by library code only.

## Failure modes

| Symptom | Cause | Action |
|---|---|---|
| Chain gap or hash mismatch | Crash mid-append or file tampering | Stop reads; reconcile from the last good snapshot; report to RISK |
| Direct sqlite reads in code | Bypassed tooling | Route through the portfolio tools; direct reads skip freshness and audit |
| Invented event kind | Typo or new-kind wish | Use the enumerated kinds; new kinds arrive via reviewed schema change |
| Seat writing non-journal events | Authority confusion | Refuse; only the adapter, engine, supervisor, or CLI append those kinds |

## References

- Tools: `portfolio.ledger_read`, `portfolio.exposure`, `portfolio.pnl` (ledger reads)
- Event vocabulary: ledger event kinds (`journal_note`, `escalation`, order and fill rows)
- Gate G-2: ledger rows back every receipted claim
- Companion skills: `desk-folders-and-journal` (layout plus append-only rule), `daily-report` (report rendering)