Summary¶
round-state.json — the retired canonical book — was shown orphaned 2026-09-06 → 09-17 and
renamed to round-state.RETIRED-2026-09-17.json (decision log 2026-09-17:cron-prompt-book-source-apply).
Since then the book survives only in per-round round-content-<date>.json prose + JSON, which
carries marks but no entry fills, no entry dates, no greeks/heat — framework hole #1.
This concept defines the position ledger: an append-only JSONL accumulator
(hermes-pilot/ledger/position-ledger.jsonl) in the pattern of the
journal schemas. It is the prerequisite for
(a) computable risk-heat gates, (b) exit-path attestation on long-vol, and
(c) real execution (the stage-8 adapter cannot submit orders without something that records fills).
Schema v0 (frozen in meaning; v1 additive only)¶
One JSON object per line, one event record per position event.
{"v":0, "position_id":"<slug>", "record_type":"open|mark|exit|resolve|correct",
"event_date":"YYYY-MM-DD|null",
"backfilled_at":"2026-09-19|null",
"structure":"long-straddle|put-debit-vertical|call-credit-vertical|...",
"qty":"int|null",
"legs":[{"sym":"TSLA","occ":"261016C00365000|ymd+cp+strike","cp":"C","strike":365,
"qty":1, "ref_price":16.075, "price_source":"mid|fill|receipt"}],
"ref_price":"decimal|null (per-share net debit/credit; mid-marks are NOT fills)",
"price_kind":"paper-mid|paper-fill|live-fill",
"status":"open|closed|expired-unfilled|closed-on-entry",
"regime_label_at_event":"calm-contango-vrp+|null",
"source_refs":["hermes-pilot/round-content-2026-09-16.md"],
"flags":["entry-fill-not-recorded|qty-source-conflict|exit-disposition-conflict|..."],
"gates_snapshot":{"ev_rn":null,"ev_phys":null,"sizing":"..."},
"note":"..."}
regime_label_at_event — the day's regime label from 96-journal/regime.jsonl (the last record whose date equals the event_date; duplicates: latest wins). null when the regime file is absent or unreadable (fail-closed for opens, stamped as null for exits).
transition — bool, true when the day's regime record has transition: true. Additive field (v0→v1).
data_missing — bool, true when the day's regime record has data_missing: true. Additive field (v0→v1).
remaining_qty — int, the quantity still open after a partial exit. Present only on partial-exit exit records (where status remains open). Additive field (v0→v1).
correct records reuse the journal convention: {"record_type":"correct","corrects":"<record-key>", ...}, where a record key is <position_id>:<record_type>:<event_date> — the three fields that identify an event uniquely (defined 2026-09-20; the schema allowed correct records without saying what they point at). A correction carries the corrected fields plus note, and restates flags as they stand after it.
Existing fields never change meaning; new fields are additive and carry v.
Event types¶
- open — a position entered.
event_date= fill date when known.price_kind=paper-miduntil the execution adapter exists; fills arrive asprice_kind=live-fillwith a receipt ref. - mark — optional daily per-round mark (legs + greeks/heat snapshot). Phase-2 work: the daily round appends one mark record per open position. v0 backfill writes only open/exit/resolve.
- exit — position closed or partially closed;
realized_pnlpopulated when an actual price is known, elseref_price=null+ flagexit-price-not-recorded. A partial exit (exit qty < open qty) keeps the positionopen, recordsremaining_qty, and sets flagpartial-exit-qty<N>-of<M>. A full exit (exit qty == open qty) setsstatus: closed. An exit qty larger than the open qty is an error. - resolve — expiration/never-filled outcome (
status=expired-unfilled). - correct — append-only correction; never edit prior lines.
Rules¶
- Append-only. Same discipline as the journals; corrections are new lines.
- Marks are not fills. Every round-content price is a mid-candidate quote. A record is a
fill only when
price_kindsays so and cites a fill receipt. This is the wall between the paper pilot and stage-8 execution. - Entry data is a hard prerequisite for live money. A position whose
openrecord lacksevent_date/fill receipt cannot be the basis for a live order's position sizing. - Conflicts are recorded, not resolved silently. Where sources disagree (currently two
known cases), all values go in with flags; the owner's
correctrecord settles them. - Ledger location:
hermes-pilot/ledger/position-ledger.jsonl(pilot-side, like trades-*.json). The wiki holds the schema, not the data.
Who writes it (2026-09-23)¶
hermes-pilot/ledger_sync.py derives events from each round's round-content-<date>.json: TRADE → an open record, EXIT → an exit record, everything else ignored. No model writes the ledger. A position is matched to an existing entry by its leg signature (symbol, expiry, cp, strike, direction), never by name or a re-derived id — re-deriving would mint a new id for an existing position and orphan its exit. Ids are minted only for genuinely new positions. Round prices are marks: recorded as paper-mid and flagged not-a-fill, per the rule above. The script is idempotent per (position_id, record_type, event_date).
It refuses rounds dated before 2026-09-18, when prompt v2.5 defined HOLD/TRADE/EXIT. Earlier rounds used the words loosely — the 09-16 morning round marked already-held straddles TRADE — so deriving from them would invent entries. Override only after checking a round by hand (--allow-pre-v25).
The round calls it as OUTPUT step 2c from prompt v2.9 (applied 2026-09-23), so the ledger no longer depends on anyone remembering — which is exactly how it missed the 2026-09-22 exits.
Backfill (2026-09-19, agent-built, subject to owner review)¶
hermes-pilot/backfill_ledger.py seeded the ledger from surviving artifacts:
| position | status | evidence quality |
|---|---|---|
| spy-765-straddle-260918 | closed (exit 9/14) | entry date NOT recorded (pre-9/4); exit price NOT recorded |
| nvda-2275-straddle-260918 | closed 9/14 | disposition CONFLICT (9/14 report says HOLD; cron prompt says hard-exited) |
| tlt-82-straddle-260918 | closed 9/14 | same conflict |
| spy-780-785c-credit-260911 | expired-unfilled 9/11 | clean |
| tsla-365-straddle-261016 | open | entry fill/date NOT recorded (gap 9/14→9/16) |
| eix-55-straddle-261016 (2) | open | same |
| pcg-14-straddle-261016 (2) | open | same |
| nvda-220-straddle-261002 | open | same |
| spy-740-765p-debit-261016 | open, entered 2026-09-16 (paper, post-FOMC) | qty CONFLICT: report 5 lots vs trades-2026-09-16-evening.json qty 1 |
The four gap opens carry entry-fill-not-recorded. Owner correction records (or the artifacts
that predate them) can close them; until then hole #1 is partially closed — the ledger exists,
the entry history is flagged-incomplete.
Links¶
- Journal schemas — accumulator conventions
- Hermes pilot reconciliation — hole #1 provenance
- Automation architecture — stage 9 (journal) / stage 8 boundary