Lifecycle is where an admitted thesis becomes a tracked object. It is still not broker execution.
Core lifecycle objects describe state and outcomes. Execution adapters may later place real orders, but broker order ids are not part of the core lifecycle contract.
Admission
LifecycleEngine.admit() turns an allowed SignalIntent and PermissionDecision into PositionIntent.
It validates:
- decision belongs to the signal intent
- decision cycle matches intent cycle
- rejected and deferred decisions do not admit
- admitted mode is explicit: live, paper, shadow, replay, or backtest
Admission emits a LifecycleTransition from PROPOSED to ADMITTED.
PositionIntent
PositionIntent carries:
- position intent id
- signal intent id
- thesis id
- source hypothesis id
- underlying id
- direction
- mode
- horizon
- admission timestamp
- invalidation context
- target context
- expression request
- permission decision id
- evidence summary
- cycle id
- lifecycle version
It is still instrument-neutral enough for expression adapters to choose spot, perp, future, or options.
Expression Opening
LifecycleEngine.open_expression() consumes a PositionIntent and ExpressionResult.
It enforces:
- matching position intent id
- matching mode
- one open per expression id
- cycle-scoped exposure ids
- failed expression transitions
- missing entry reference fallback with quality tracking
Successful opening emits ADMITTED -> OPEN.
Mark Observations
Marks are not lifecycle state transitions. They produce MarkRecord.
This distinction is important:
- state transitions belong in append-only lifecycle state logs
- marks are observations used for MFE, MAE, latest mark, and outcome construction
mark_exposure() is idempotent by event id and rejects same-timestamp or stale marks unless they are true redeliveries.
Close Events
CloseEvent closes an open exposure.
It includes:
- event id
- exposure id
- reference timestamp
- close price
- close reason
- source
Closing emits OPEN -> CLOSED and returns OutcomeRecord.
OutcomeRecord
OutcomeRecord carries:
- outcome id
- position intent id
- exposure id
- expression id
- opened and closed timestamps
- entry price
- close price
- actual move percent
- max favorable excursion
- max adverse excursion
- duration seconds
- path label
- economic label
- close reason
- source hypothesis id
- source pattern hit ids
Path Label Versus Economic Label
AtlantisV2 preserves a critical legacy lesson:
path label = how the trade exited
economic label = whether it made money
An expired or time-stop trade can still be profitable. That must count as economic profit for learning and research, even though it is not a path winner.
The first legacy parity fixture verifies this against:
/Users/home/dev/atlantis/process/execution/lifecycle/outcome_record.py
Idempotency
Lifecycle handles event redelivery:
- duplicate mark event id returns duplicate mark result
- duplicate close event id returns duplicate close result
- stale non-duplicate events are rejected
- same-timestamp non-duplicate observations are rejected
This follows the event model invariant that duplicate delivery should not change the result.
What Is Still Adapter Work
Lifecycle does not:
- choose an option contract
- submit a broker order
- reconcile a venue fill
- price a real options structure
- write to a database table
Those are adapter or runtime responsibilities.