Skip to content

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-mid until the execution adapter exists; fills arrive as price_kind=live-fill with 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_pnl populated when an actual price is known, else ref_price=null + flag exit-price-not-recorded. A partial exit (exit qty < open qty) keeps the position open, records remaining_qty, and sets flag partial-exit-qty<N>-of<M>. A full exit (exit qty == open qty) sets status: 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

  1. Append-only. Same discipline as the journals; corrections are new lines.
  2. Marks are not fills. Every round-content price is a mid-candidate quote. A record is a fill only when price_kind says so and cites a fill receipt. This is the wall between the paper pilot and stage-8 execution.
  3. Entry data is a hard prerequisite for live money. A position whose open record lacks event_date/fill receipt cannot be the basis for a live order's position sizing.
  4. Conflicts are recorded, not resolved silently. Where sources disagree (currently two known cases), all values go in with flags; the owner's correct record settles them.
  5. 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