# Multi-session horizon — the Instance is a sequence of carried Sessions

**Status:** Accepted (owner, 2026-07-16 — implemented/extracted; kestrel-5zl.16). Extends ADR-0012 (the wake-driven Simulator) — this is the
"named later child" that ADR-0012 §Consequences deferred. Honours CONTEXT.md's *Instance* /
*Session* / *Blotter* vocabulary verbatim; proposes the new terms **SessionCarry**,
**carry-mark**, **InstanceRunId**, **session-ordinal (relative-day) coordinate**, **timescale
band**, and **InstanceBlotter**.

## Context

The runtime grades one intraday session. `runSimSession` / `runDaySession` /
`runSimulateSession` each drive **one** `SessionCore` over **one** bus with **one** `settle()`
into **one** Blotter. Every axis of the P0 platform benchmark that is not a day trade — swing,
position, multi-day options income, crypto — is blocked on a horizon longer than one session
(benchmark-matrix-design §4.2, §4.3; generality-audit §6). Five intraday assumptions gate it:
a single `session_date` on META, same-day-16:00 tau, settle-to-intrinsic at end-of-bus,
`atClockET` re-anchoring only to `session_date`, and the date-blind fence tripping at ~11.57
relative days (`\b\d{10,}\b` against a monotonic `sinceOpenMs`).

**The composition model is already decided — this ADR ratifies and specifies it, it does not
re-open it.** CONTEXT.md ("Instances, sessions, blotters") states: *an Instance's execution
divides into **Sessions** (one per market session), each yielding a **Blotter**; its history is
that ordered sequence*, and *a Session owns exactly **one Bus** and yields exactly **one
Blotter**.* ADR-0012 §Consequences ("Phase-1 scope is one Session, stated plainly") names
overnight carry, cross-Session standing-Plan re-arm, and *Blotter-sequence → Instance history* as
a later child. So the "one bus spanning days" alternative the audit weighed against is **already
foreclosed by the domain model**: the Session is the atom, the Bus is per-session, and a
multi-day horizon is an *ordered sequence of single-session buses with carried state*. This ADR
specifies what carries and how the sequence stays deterministic, date-blind, and fail-closed.

## Decision

### 1. Composition — an Instance runs an ordered sequence of Sessions; a typed **SessionCarry** crosses each boundary

A multi-day sim is **N single-session runs**, each a fresh `SessionCore` over its own bus,
finalised to its own Blotter, chained by a **SessionCarry** — the one typed object handed from
Session *k*'s finalize to Session *k+1*'s open. No bus spans days; no `SessionCore` is reused
across a boundary (each keeps its single `settle()` and single Blotter — zero churn to the
single-session contract). What the SessionCarry carries, and its fail-closed rules:

- **Positions** — carried at their **carry-mark** (Decision 3), never force-settled to intrinsic.
  Session *k+1* opens with this inventory as its starting book and the carry-mark as its basis.
- **Cash / realised P&L** — carries as a running Instance figure. The **`R` budget re-anchors per
  session** (the Session/day is the independent risk unit — m9i.3; generality-audit §6): a session
  gets a fresh `R` allotment, but capital already committed in carried positions persists and is
  visible against it.
- **Standing document** — the agent's authored book (View/Wake/Plan) carries and is **re-armed
  fresh at each Session open**, minting **new Plan-instance ids per session** (one Plan instance =
  one Session, per CONTEXT/ADR-0012). Consequence, fail-closed: a Plan's `ttl` / `within` window
  **re-anchors to session open and does not silently span sessions**. Carried *inventory* rides
  its TP/EXIT inside the new session's re-armed Plans; an agent that wants a Plan to persist
  re-authors/supersedes it — the runtime never invents cross-session Plan lifetime.
- **Pending wake frontier** — carries across the boundary. `inMinutes` offsets already span any
  horizon natively (`+1440` reaches tomorrow); `atClockET` targets re-anchor to the *target
  session's* date (Decision 3 / b3l router).
- **Journal / agent memory** — carries as Instance-level author context (JOURNAL), so the agent
  reasons across days. It is **author metadata, never an engine input** (a57.11), so it cannot
  perturb determinism.

New term **SessionCarry**: the typed hand-off object `{ positions@carry-mark, cash, standing
document, pending wake frontier, journal }`. It is the *only* channel between sessions — anything
not on it does not survive a boundary (fail-closed by omission).

### 2. Overnight physics — mark across the gap, settle expiry, refuse or receipt the rest

- **Gaps (next open ≠ prior close).** Positions re-mark at each session's **opening carry-mark**
  = that session's first admissible print (bounded by the same T-5 author cutoff, no look-ahead).
  The overnight gap P&L is realised into the new session's mark; the carry-mark handed *out* of a
  session is its **session-close mark**. Close-mark → next open-mark is exactly the gap.
- **Options expiry mid-sequence.** Settle is **polymorphic by instrument** (Decision 3): an
  expiry-terminal instrument (a weekly option that expires on day 5 of `EQOPT-SWING-INCOME`)
  **settles to intrinsic at its expiry session's close** via the *existing* 0DTE settle path —
  expiry is a genuine terminal settle for that leg — and does **not** carry past expiry.
  Assignment/roll of a held short option (position → underlier conversion) is P1, tracked
  separately.
- **Corporate actions.** Deferred (P2) and **fail-closed until modelled**: a tape carrying a
  corporate-action event kind (split, dividend, symbol change) is **refused loudly** ("corporate
  actions not modelled"), never silently mis-marked. First-wave benchmark cells are chosen to
  avoid them (benchmark-matrix-design §2).
- **Financing / borrow.** Deferred (P2). Every cross-session boundary stamps an explicit
  **"financing not modelled" receipt** so a multi-day grade is honest about the omission.
  Long-only cash cells (crypto, long equity — the first-wave multi-day cells) do not need it;
  short/margin tapes are **refused until financing is modelled** (this also keeps the
  never-naked / bounded-risk non-negotiable intact, since unbounded shorts stay out).

### 3. Determinism + identity — the Instance is a pure function of its ordered Sessions

- **Settle becomes carry-aware but stays a per-session `settle()`.** A **carry-mark** settle
  (mark held inventory to the session-close spot, `pnl = (mark − basis)·qty·multiplier`, position
  survives) sits beside the existing **intrinsic** settle (expiry-terminal, position dies). Which
  one runs is a property of the instrument, not a new session mode. RUNTIME §6 already anticipates
  this ("physical-style instruments mark at last").
- **Identity chains.** Per-session **SimRunId** = `sha256(graded bus)` is unchanged. New
  **InstanceRunId** = `sha256` of the *ordered* per-session SimRunIds (a hash of ordered hashes) —
  the Instance identity is a pure function of its Sessions **and their order**. The grid's tape
  axis extends to an **ordered sequence of session tapes** (a *sequence cell*); an existing
  single-session cell is the length-1 degenerate case.
- **Replay.** The SessionCarry into session *k+1* is a **pure function of session *k*'s graded
  bus**, so the whole sequence replays byte-identically: same tapes + same agent turns ⇒
  byte-identical per-session buses ⇒ identical SimRunIds ⇒ identical InstanceRunId. No wall clock,
  no RNG crosses a boundary (RUNTIME §0).
- **The date-blind fence generalises by *coordinate*, not by widening the threshold.** The
  cross-session author coordinate is the pair **`(session-ordinal d{N}, session-relative
  sinceOpenMs)`** — a relative day index (`d0, d1, d2, …`, pinning no calendar date) plus a
  `sinceOpenMs` that **resets at each session's own open**. Because `sinceOpenMs` never
  accumulates past one session (≤ 8 digits for a full RTH day), it **structurally cannot reach the
  10-digit epoch signature** no matter how many weeks the horizon spans. The fence pattern stays
  `\b\d{10,}\b` — **unchanged and un-weakened**; the ~11.57-day limit disappears because the
  horizon is no longer expressed as a single monotonic millisecond count. This is the principled
  fix the bead demanded, not a threshold-widening hack.

### 4. Crypto 24/7 — a UTC-day session by convention (design-only, split out as future work, P2)

Crypto has no RTH boundary, so the *same* sequence-of-Sessions carry model applies with the
**session boundary redefined as UTC midnight**: a crypto "session" is one UTC calendar day, the
tape is continuous (no pre/open/close phases), and the carry-mark is taken at the **daily UTC
close (00:00Z)**. Long-only / no-short / cash-only is enforced at the runtime (a crypto SELL
floors at zero position — benchmark-matrix-design §4.3). This is **future work**, split into its
own child bead — it needs a non-RTH phase model and a UTC clock beside the ET clock, both larger
than the equity/option critical path and not gating it.

### 5. Wake cadence scales with the horizon via a per-cell **timescale band**

The intraday defaults (30-min spacing, minutes-scale staleness backstop, structural close ramp)
are wrong for a position trader who wakes *daily*. The wake floor is parameterised by a
**timescale band** — `scalp | day | swing | position` (benchmark-matrix-design Axis A) — declared
**per cell** and applied as the session's default staleness backstop, `MIN_WAKE_SPACING`, and
`MAX_WAKES`; a per-session override is allowed. A `position` cell gets an hours-to-a-day backstop
and a daily-mark cadence; a `scalp` cell keeps seconds-scale spacing. The staleness backstop stays
non-removable while holding inventory (fail-closed), only its *magnitude* scales with the band.

### 6. Grade — per-session Blotters plus a sequence-level **InstanceBlotter**

Each Session still projects to **one Blotter** from its own bus (unchanged, ADR-0011). New
**InstanceBlotter**: a pure aggregation over the *ordered* per-session Blotters — chained carried
P&L, an Instance-level EV / max-drawdown, and the **benchmark-relative alpha hook**
(`alpha = Instance EV − buy-and-hold baseline over the full horizon`, benchmark-matrix-design §4.1).
`buildGrid` extends so a **sequence cell**'s independent evidence unit is the whole InstanceBlotter
(a swing "run" is the N-day sequence, not one day); `CellAggregate`'s per-axis `Dist` and the
no-omnibus discipline are unchanged. A single-session cell is the length-1 InstanceBlotter — the
degenerate case, so existing grids are untouched.

## Consequences

- **The single-session contract is preserved, not rewritten.** `SessionCore`, its one `settle()`,
  and its one Blotter are unchanged; the Instance runner is a *new* orchestration layer above them
  threading SessionCarry. This is why the lift is bounded — the sequence runner + carry +
  carry-mark + relative-day coordinate is the whole P0 critical path.
- **Fail-closed is structural at the new seam.** Corporate-action tapes, short/margin tapes
  without financing, and any state not on the SessionCarry are refused or dropped loudly — never
  silently mis-modelled. A cross-session `ttl` never silently persists.
- **Determinism holds across the horizon** because the carry is a pure function of the prior
  session's graded bus and the date-blind coordinate cannot manufacture an epoch integer.
- **Crypto, financing, corporate actions, assignment/roll, and the sequence-level grade are
  deferrable** (P1/P2) behind the equity/option carry critical path — the first swing and
  option-income cells need only P0 + the timescale band.
- **New modules (indicative):** `src/session/instance.ts` (the sequence runner + SessionCarry),
  a carry-mark branch in `src/fill/engine.ts` settle, a session-ordinal coordinate in
  `src/session/day.ts`'s author projection, `InstanceRunId` in `src/session/run-identity.ts`, and
  an `InstanceBlotter` aggregation in `src/session/grid.ts`. Consolidate onto the extracted
  date-blind fence once kestrel-7dv.2 lands (do not fork it).

## Alternatives considered

- **One bus spanning days** (the audit's foil). Rejected — it contradicts CONTEXT.md ("a Session
  owns exactly one Bus") and ADR-0012's Session atom, forces the date-blind fence to swallow
  multi-week millisecond counts (the widening hack), and re-marks nothing at the overnight gap.
  The sequence-of-Sessions model is both the smaller lift and the one the domain already mandates.
- **Cross-session Plan instances / spanning `ttl`.** Rejected — breaks the "one Plan instance =
  one Session" identity and makes lifecycle non-deterministic across a boundary. Re-arm fresh per
  session; carried inventory rides the re-armed Plans.
