State
Keep custom L3 state separate from runtime diagnostics and use the correct clock.
Use a dedicated key under context.l3State for your script's state. The getting-started guard uses requestGuard; policy stacks use their own chosen stack keys.
Separate runtime and custom fields
The runtime records fields such as enabled provider configuration, lastFrameAt, lastIntentAt, lastError, lastDecision, and a bounded decision list. Avoid replacing the entire state object with a custom payload that discards these diagnostics.
The current decision history retains the most recent 50 recorded decisions. It is not an unlimited audit log. L3-source bypasses and disabled evaluation do not necessarily produce a recorded intent decision.
Use market time for strategy rules
The quickstart records bar.date as lastMarketTime. Runtime frame/intent diagnostics and provider response timestamps use wall-clock time.
During historical replay, those clocks describe different things. Use market time for evidence freshness, cooldowns, and observation identity; use wall time to explain operational timing.
Initialize in each relevant hook
An intent can occur without a prior successful frame hook. Initialize the state needed by that check locally, as the quickstart does. Do not authorize an order merely because a missing initialization flag is falsy.
State helpers initialize in-memory objects. They do not guarantee persistence across restarts, a new historical run, or publication to an app. Source reload also does not automatically migrate custom state semantics.
Store compact evidence
Keep serializable timestamps, IDs, selected values, and reasons. Avoid storing provider clients, promises, functions, or complete session objects. Inspect output freshness before using a previously saved provider observation in a new decision.
Continue with model calls.