Continuous futures

The strategy sees one logical adjusted series while the venue fills dated contracts at raw prices. Marketfeed elects every roll, serves the root’s roll schedule and serves the spliced, adjusted composite; the engine consumes the two as one pinned pair and translates orders (GLE-270, GLE-323).

A run names the root in one of two forms (GLE-325, owner Decision 4): the bare root fut:XCME:ES, adjusted with Panama, or the composite fut:XCME:ES:cont:adj=<panama|ratio|none> with the method on the symbol (bare :cont is panama). Both take the price grid from the adapter’s instrument metadata for the root and route through one dispatch (continuousPlan in engine/continuous_dispatch.go); the engine keeps no symbol registry. The grammar refuses, before any spawn and with its own text for each: :cont anywhere but directly after the root, a repeated adj=, an unknown adj= value (want adj=panama, adj=ratio or adj=none; the values are case-sensitive), ofs= (back months are viewer-only), any other qualifier such as straddle=, and an @ suffix. An @ES-style alias, the retired registry’s symbol, is no continuous form since ER5 (GLE-327): the recognition that refused it with the replacement named for one release (ER3) is gone, so it takes the plain path and the adapter judges it like any other symbol. A run can hold several continuous series, each of a different root, beside any plain series (GLE-424); a run that names one root twice (two intervals, or the root beside one of its composites) is refused before any spawn, since both would trade one chain of contracts. A run with a continuous series takes the BARS schema, and each continuous series time bars. Every series runs through the same run phases (GLE-423, GLE-424): the data client, its gates and the fetch, where a continuous series’ gates are its served roll schedule and its clock’s session and its fetch builds its served composite; one strategy phase, which Inits the strategy with each continuous series’ logical symbol and the simulator with every series’ contracts beside the plain symbols (engine/contrun.go, engine/contmix.go, with the pieces shared with the composite driver in engine/contseries.go); the run report and BENCH line. A relative spec in the root (fut:XCME:ES+1), an intraday grid, and a session together with the epoch clock are refused by the guard that follows (continuousGuard, engine/contguard.go). The run id is run-<slugified symbol>-<interval>: run-fut-xcme-es-1d, run-fut-xcme-es-cont-adj-ratio-1d.

The consumption pipeline is engine/continuous (ParseServedSchedule in compschedule.go, BuildComposite in composite.go) with engine/adjust for the manifest; engine/resolver translates orders, fills and roll legs by the served constants. continuous_composite.go fetches the schedule and the composite and builds the run, continuous_run.go orchestrates it, and continuous_servedloop.go executes it, rolling at each served cut. Panama, ratio and none methods, bracket retranslation, and partial-roll primitives are implemented. There is no other construction: ER5 (GLE-327) deleted the per-contract path (each held contract fetched on its own and adjusted locally by engine/contadjust over the served schedule), the former local election (continuous.Build, engine/roll, engine/symbols) and the registry’s roll block, so an adapter that serves no schedule or no composite fails the run and nothing re-elects locally. The parity gate that compared the two constructions before the deletion (ER4, GLE-326; E4) left its record in testdata/parity-composite/summary.txt.

At a roll the driver cancels/replaces working contract orders at equivalent adjusted levels and transfers the position at the served cut (see Roll execution at the cut). continuous_orderbook.go tracks orders and bracket generations so stale lifecycle events cannot clear a new bracket. The six-checkpoint failure state records which cancel, close, open, advance and resubmit steps completed in RollPartialFailure; automatic recovery at the next live startup remains future work.

With --results-dir, continuous runs persist manifest.yaml and the dual raw/adjusted audit.jsonl; degradation produces degradation.json when applicable. Manifests reconstruct series adjustments and pin the schedule followed; the audit records fills and rolls. Invariant 5 checks active-contract mapping and invariant 6 checks manifest integrity. Live refuse-to-start gates exist, and continuous live mode does not exist: --mode live on a bare root or a :cont composite is refused before any spawn, with a message that names the symbol and says live continuous futures runs are refused (owner decision 2026-10-04, GLE-228 Decision 7; marketfeed does not stream a composite, so trade a dated contract live). Should it ever be built it must follow the served schedule too.

--symbol-registry and --served-roll-schedules are gone (ER3, GLE-325): algo run treats either as an unknown flag. The config keys symbol-registry and data.served-roll-schedules were refused for one release and are, since ER5 (GLE-327), unknown fields like any other: the config loads and a warning names the ignored key (unknown field global.symbol-registry ignored); delete them.

No run warns about roll knobs any more: there is no definition to carry one, and the intraday-roll flag is implicit in the served cut instants (GLE-228 Decision 9, done by GLE-270).

scripts/golden-roll-agreement.sh is the engine-side gate for this. On the live archive, a bare-root fut:XCME:ES run, a fut:XCME:ES:cont:adj=panama run (the bare root’s method, named) and a --cache off run of the bare root must pin the schedule the adapter serves, execute exactly its cuts inside the window (the audit ledger’s roll_dates against cmd/tools/rollsched’s dump of the schedule), and build manifests that differ only in the symbol’s name. (The manifest’s exdate is the incoming contract’s first bar, not the cut; the audit ledger records the cut.) make roll-agreement runs it.

Continuous run conventions

A continuous series runs through the same bar loop as every other series (GLE-421). Its frame (engine/contframe.go) owns the series’ contract mapping, adjustment and roll execution, and the loop calls it per bar in a fixed order: start the bar (the lifecycle trace marks it), fire the rolls due before it (the notice first, then both legs at the served cut), hand the simulator the bar’s original contract bar and deliver its events translated onto the logical symbol, push the account, record the adjusted bar and the raw mark, send the strategy the adjusted bar, and route the strategy’s orders: the logical symbol is translated onto the active contract, the active contract is taken as addressed, and any other symbol is rejected before it reaches the simulator. The end-of-data cancellation goes through the frame too.

The loop can carry several frames, and plain series beside them (GLE-422): every frame’s rolls fire on the loop’s clock, at the first bar of any series that closes after the cut, in the order of their cuts (series order on the same instant), so a roll is not held back until its own series’ next bar. Each venue event goes to the frame that owns it: a fill by its contract’s chain, a cancel by the order it came from, and anything else to the plain series’ delivery. The simulator’s clock never moves backwards (a roll’s synthetic bar sits at its cut, which can precede another series’ last bar), and a roll leg is exempt from the rule that admits an order submitted after another symbol’s bar only on a later bar of its own. With one series nothing of this changes the run.

A run plans any number of continuous roots beside plain series (GLE-424):

  • Orders route by their symbol. An order for a continuous series’ logical symbol, or for its active contract, goes to that series’ frame from any series’ bar, so a strategy can trade both legs of an ES/NQ spread on one bar. An order for a plain series’ symbol goes to the simulator as on a plain run. Any other symbol is refused by the series whose bar it was placed on.
  • A dated contract beside its own root is a second position. With fut:XCME:ES and fut:XCME:ES:M26 in one run, the continuous lot is held as ESM26 and rolls with the series, and the dated lot is held as fut:XCME:ES:M26 and never rolls. The strategy sees two symbols and the simulator two books.
  • A continuous series warms up and fills at bar resolution. Its warm-up (GLE-393) is the strategy’s lookback depth of adjusted bars before the start. They are read in the same served composite as the live bars: pinned to the first build’s snapshot token, generation and adjustment anchor, so warm-up and live bars share one adjusted frame. The rolls before the start fire silently: no roll notice, no roll legs and no audit record, since nothing is held yet. The run starts on the first live bar’s contract, and the simulator’s universe holds only the contracts the live part can trade. When the warm-up holds fewer bars than the lookback, the series records a warmup_shortfall degradation and runs with what it has, as a plain series does. When the feed refuses the earlier read, its build fails (a degraded or empty span there, say), or it does not reproduce the run’s own bars (adjusted bars and original contract bars alike, under the same snapshot), the series starts cold, and a warmup_shortfall record says why. A broken connection fails the run, as on a plain warm-up fetch. The run’s resolution is bar whatever --simulation-resolution asks, because a contract’s trade prints are not fetched.
  • Declarations work as on any run (GLE-392). Declared plain series (COT, FRED, dated contracts) reconcile as on a plain run. A declared continuous series, a bare root or a :cont composite, joins the run as a continuous series on any run, plain or continuous: it is gated on its served schedule, fetched as its served composite and driven by its own frame. It needs the pb data wire, and a root the run already holds is refused. A declaration naming a configured series is that series. Aligned series work on a continuous run, a continuous grid or source included (On a continuous run, GLE-394). Declared market events are still refused on a run with a continuous series.
  • A declared continuous series is reference-only unless tradeable. Its bars arrive and its rolls are kept, but the simulator’s universe holds only the contracts of the series the strategy may trade. An order on a reference-only series is denied. Naming it in TradeableSymbols, under universe-expansion=full, puts its contracts in the universe.
  • Each continuous series has its own artefacts (GLE-425). With one continuous series, the run’s directory holds manifest.yaml, audit.jsonl and degradation.json as before. With several, each series writes its manifest and ledger in <run>/continuous/<series>/ (the series symbol slugified: continuous/fut-xcme-es/manifest.yaml). The run’s one degradation.json stays at <run>/, each record naming its series (fut:XCME:NQ@1d). The result header’s series entries carry Continuous, Method and HeldRank for each continuous series. The run report prints a held-rank line per series that holds a deferred rank.
  • Performance pairs fills by identity (GLE-425). The recorder pairs each translated fill with its simulator metadata (order type, slippage) by the fill’s identity: client id, side, quantity, time and execution id, first in first out within one identity. It no longer pops one queue in order, so series whose deliveries interleave cannot trade each other’s slippage.
  • Warm-up shortfall records name their series on a run of several series, like the continuous records; lead-in clamp and aligned-view records name it in their note.

TestGLE424TwoRootsRollAtOneInstant, TestGLE424TwoRootsRollAtTheirOwnCuts and TestGLE424ContinuousBesideItsDatedContract (engine/gle424_several_roots_e2e_test.go) run each case through a subprocess adapter serving ES and NQ composites and a probe strategy.

These are the engine’s conventions since GLE-270 and GLE-323. They describe how the engine consumes marketfeed’s served roll schedule and :cont composite (wire reference: ROLL_SCHEDULE, the request pins and the composite Bar fields in the Protocol reference). How marketfeed elects, measures and adjusts is marketfeed’s documentation: the sections “How a roll works, end to end”, “The roll schedule (grammar v2)”, “The :cont composite product” and “Adjustment: panama, ratio, none” of docs/marketfeed.md in the marketfeed repository (GLE-274). Until ER5 (GLE-327) this section was “Continuous construction conventions”; the construction it once described left the engine with the local election, and what stays here is the engine’s side: what it checks, refuses, executes and records.

Who decides what

FactOwnerEngine behaviour
Which contract is held when (spans, cut instants)marketfeedfollows it; elects nothing
The seam pair at each cut (out_at_cut, in_at_cut)marketfeedfills the roll legs at it and stamps RawGap/RawRatio from it; does not re-measure it
The adjusted bars and each span’s cumulative constantmarketfeedtakes them as served; checks each bar’s constant against its span’s, and the holder’s against the identity; translates orders by them
Held rank (front or deferred)marketfeedfollows the served contracts at any disclosed rank and reports it (GLE-387); refuses an undisclosed rank
Price grid, adjustment methodthe adapter’s instrument metadata for the root; the method is the symbol’s adj= (panama when it names none)applies the grid; the method selects the composite requested (adj=)
Order translation, roll execution, roll costengineexecutes at the cut, pays slippage + commission

The instant law

A held span is the half-open interval [Start, End). A bar belongs to the span whose interval holds its close: Start < ts_close <= End. The cut instant T of a roll is the incoming span’s Start (the outgoing span’s End). So the outgoing contract’s last bar is the last one closing at or before T, and the incoming contract’s first bar is the first closing after T.

A bar straddles the cut when its bucket crosses T. An epoch composite (an intraday run, or any run under --continuous-clock epoch) is requested with straddle=incoming, so the feed rebuilds such a bucket from the incoming contract’s own tape, tags it with the incoming contract and names the outgoing one in seam_prior_contract; the engine notes the straddle when the incoming span’s first bar carries that field. A bucket whose outgoing side has no constituent (ES’s Sunday 22:00Z cut inside a UTC-day bucket, the outgoing contract’s Sunday session opening at the cut) is served as one bar tagged with the incoming contract, opening at the bucket’s nominal start, before the incoming span’s Start, with no prior contract. The engine therefore judges membership on the close alone and treats the open as a bucket label; stamping the fragment’s first constituent’s start as ts_open (MR2’s split-fragment law) is a marketfeed follow-up that would let a consumer judge both instants. Under GLE-274’s schedule the cut is the roll date’s first trading instant (ES: Sunday 22:00Z for a Monday roll date), so a trade-date session bar does not straddle: a daily continuous run reads session bars (GLE-324, D5 = E), the incoming contract’s first bar opens at the cut and closes after it, the outgoing contract’s last bar closes before it, and no straddle note or record arises. An epoch daily bar (--continuous-clock epoch) straddles only when the prior trade day’s session shares its UTC day.

A bucket that crosses the cut is routed by bar, not by instant (GLE-286). The roll executes at T before the bar reaches the simulator, so every fill on that bar is in the incoming contract at the incoming contract’s prices, including a resting order that fills at the bar’s open. A bar-resolution fill is stamped at the bar’s close, so the ledger stays in time order: the roll legs at T, then the bar’s fills. An OHLC bar cannot order its intra-bar events against the cut, and the simulator does not split a bar at the cut. Daily and weekly continuous runs read session bars, which never cross a cut, so this reaches intraday epoch runs and the --continuous-clock epoch option only. It takes two shapes:

  • One-sided. The outgoing contract does not trade in the bucket before the cut, so the bar holds only the incoming contract’s market from T on. Its open is the incoming contract’s first trade at T, and only the bucket’s ts_open label precedes the cut. Livestock on a 1h grid is served this way. LE’s J26→M26 cut at 2026-03-17T13:30Z (08:30 CDT) falls inside the 13:00Z bucket, which comes whole from M26. No straddle note or record arises, because the bar names no prior contract.
  • Two-sided. Both contracts trade in the bucket, which happens on a grid that crosses a cut inside trading hours. CL’s G26→H26 cut at 2026-01-14T23:00Z falls inside the 20:00Z bucket of a 4h grid. The feed rebuilds the bucket from the incoming contract’s own tape, so its open is the incoming contract’s price from before the cut, when the strategy still held the outgoing one. The engine notes the bar, and degradation.json records it, as bar straddles the cut CLG26->CLH26 at …: its bucket crosses the cut and the feed assigned it to the incoming contract CLH26 (straddle=incoming); routed by bar: the roll executes first, so every fill on the bar, even at its open, is in CLH26.

engine/gle286_intraday_straddle_test.go pins both shapes on a 1h grid with a cut at :30: the roll legs at the cut at the served pair, and an exit resting across the cut that fills in the incoming contract at the crossing bar’s open. Where the two-sided case matters, choose a grid whose buckets start at the roots’ cuts. On a 1h grid, every served cut since 2016 starts a bucket except livestock’s, which are one-sided. The 2026-10-03 census found that all 224 cuts off the whole hour are LE, HE and GF.

Served seams

The feed removes each seam from older history and serves the result: panama_snapshot_forward bars carry cumulative_adjustment (the additive offset, accumulated from in_at_cut - out_at_cut toward the anchor’s holder), ratio_snapshot_forward bars carry cumulative_price_ratio, and unadjusted bars carry the venue prices with both constants zero. The schedule discloses the same constant per span up to the anchor’s holder, which carries the identity (offset 0, factor 1); spans after the holder are served undisclosed. The engine takes the adjusted and raw prices as served and recomputes nothing. It refuses a bar whose constant differs from its span’s (CONSTANT_MISMATCH), a traded span with no constant (CONSTANTS_UNDISCLOSED), a holder not at the identity (HOLDER_NOT_IDENTITY), a constant that is not finite or a ratio that is not positive (CONSTANT_INVALID), and bars whose adjustment state does not match the run’s method (BAR_NOT_ADJUSTED, BAR_ADJUSTED_UNDER_NONE). Every boundary’s RawGap (and RawRatio under ratio) is stamped from the served pair under every method, so a needs_rolls strategy’s RollNotice reports the real raw seam even when the series is unadjusted. A seam pair that is not finite or is zero on both sides fails the run, as does a ratio seam whose pair has no finite positive quotient (RATIO_SEAM_INVALID).

A seam the feed built from a fallback price (degraded, with degraded_reason settle_window, last_common or temporal) refuses the run by default when it lies between two traded spans: its pair is a substitute, and one substituted seam moves every adjusted bar on the far side of it.

continuous: fut:XCME:CHF: SEAM_DEGRADED: the served seam CHFM14->CHFU14 at 2014-06-12T22:00:00Z is degraded (reason: temporal, cadence: 1m); its pair is a fallback, and one substituted seam moves every adjusted bar on the far side of it: pass --accept-degraded-seams to trade it anyway

--accept-degraded-seams (config key accept-degraded-seams) trades every such seam in the run as served: each is flagged in the manifest (SeamDegraded), noted on stderr (served seam CHFM14->CHFU14 at 2014-06-12T22:00:00Z is degraded (reason: temporal, cadence: 1m); accepted on request), recorded in degradation.json as degraded_roll_seam, and the manifest pin carries ;degraded-seams=accepted. A degraded seam into a span the window does not trade is not examined, and an adapter that serves no reason reads reason: unstated. A per-seam allowlist (--accept-degraded-seam <root>:<from>-><to>) is a follow-up to the run-wide flag. The run manifest’s underlyingsources carry the served state sched:<recipe>@g<N>@snap:<token>;rank=<F|B1|B2>[;seam=<policy>][;degraded-seams=accepted]: the snapshot token is part of the pin, so the pin moves on every nightly re-derive even when the constants do not, and any manifest diff tooling masks @snap: (as the retired parity gate did, ER4).

Roll execution at the cut

A roll fires on the first bar closing after T (the incoming contract’s first bar). In order, the driver:

  1. sends the strategy its RollNotice (when it observes rolls), before anything the roll executes reaches it;
  2. cancels every working order on the outgoing contract, invisibly to the strategy, before any replacement exists, so a fault mid-roll cannot leave exposure in both contracts;
  3. when the position is not flat, submits two market legs: one closing the outgoing position, and one opening it in the incoming contract carrying the position’s bracket children re-translated to the incoming contract;
  4. advances the simulator through two synthetic bars at T: an outgoing bar flat at out_at_cut, where the close leg fills, then an incoming bar flat at in_at_cut, where the open leg fills and the re-established bracket children are first evaluated;
  5. re-translates standalone working orders into the incoming contract. A stop that the incoming contract’s cut price is already through (a buy stop at or under it, a sell stop at or over it) cannot rest as a stop: the simulator refuses a stop on its triggering side, as the exchange would. It goes to the venue as the order it has become, which is what IBKR does with such a stop once its “will trigger immediately” warning is confirmed. A stop becomes a market order, filling at the first real incoming bar’s open; a stop-limit becomes its limit order, resting from that bar. The engine logs each one, and the strategy sees the fill under the stop’s client id. A first-touch stop (StopTouch) may rest through and is re-sent unchanged.

Both legs therefore fill at the cut instant at the served pair, each moved adversely by the run’s per-leg --slippage-ticks and charged commission: those are the modelled roll cost, and there is no separate roll-cost setting. Under Panama the two legs’ adjusted prices are equal, so the roll itself books no adjusted-frame P&L beyond its costs. The resolver translates each adjusted-frame order onto the active contract by that contract’s served constant, the one the build checked against the served bars; the engine holds no arithmetic of its own.

The asymmetry between steps 4 and 5 is deliberate. A bracket child activates on the open leg’s fill and is evaluated at the cut, so a child whose level the cut price has crossed fills there, and the strategy sees it. A standalone order is re-translated after the synthetic bars, so a Day order keeps its one-bar life for the first real incoming bar instead of spending it on a synthetic one. The cost: a standalone stop the cut price is already through fills at the first real bar’s open, not at the cut.

Held rank

marketfeed elects every roll on the front (the nearest-expiring contract) but may hold a contract behind it, and the served schedule discloses which: held_rank 0 is the front (F), 1 the contract after it (B1), 2 the one after that (B2). Eight roots hold a deferred rank by design, because their front month is illiquid or settles inside the month: SR1, SR3, ZQ, ALI, HRC, DA and CSC hold B1, and CB holds B2.

The engine follows the served contract identities whatever rank they hold (GLE-387): the composite’s bars are the held contract’s, bar.ActiveContract names it, orders on the logical symbol go to it, and each roll moves the position from the outgoing held contract to the incoming one at the served seam pair. Under B1 the outgoing contract at a roll is not expiring: it becomes the new front. On fut:XCME:SR3 the March 2019 roll moved the position from SR3H19 to SR3M19 at the two contracts’ 15 March settlements (97.57 and 97.595), while SR3Z18 was the front. A schedule from a producer that predates held_rank is refused (HELD_RANK_UNDISCLOSED: the composite consumer needs a schedule-v2 lineage).

A deferred run says so: the run report prints continuous: fut:XCME:SR3 holds B1 by its served schedule (the contract after the front), result.json carries HeldRank (F, B1, B2) for every continuous run, the HTML report’s header table shows it, and the manifest pin records ;rank=B1. make roll-agreement ROOT=fut:XCME:SR3 (or any root) checks that a run executes exactly the served schedule’s cuts and pins its rank; it passes on ES (F), SR3 and ZQ (B1) and CB (B2).

Known limits: the engine applies the root’s tick size to every contract, and CME quotes SR3 and ZQ in a coarser tick outside the nearest-expiring month, so slippage ticks on a deferred holding are priced at the root’s (finer) tick; the strategy does not yet receive the front contract’s name or the rank on OnRoll. Both are GLE-412.

strategies/demo/go/ratetrend is a worked example: a moving-average trend on continuous SR3 that logs the contract it holds, each roll into the next one, and the held contract’s implied rate from its raw close (the back-adjusted close is shifted by the roll gaps, so 100 - close would not be a rate any contract traded at). make run-ratetrend:

[ratetrend] INFO: ratetrend: 2019-03-18T20:15:44Z holds SR3M19 (was SR3H19)
[ratetrend] INFO: ratetrend: 2019-05-23T20:18:40Z SR3M19 raw=97.5950 rate=2.4050 fast=97.8131 slow=97.8041 pos=0 target=1
[ratetrend] INFO: ratetrend: fill ratetrend_1558642720000000000 buy 1 fut:XCME:SR3 @ 97.7975
[ratetrend] INFO: ratetrend: 2019-06-17T19:20:58Z holds SR3U19 (was SR3M19)

The fill is reported on the logical symbol at the adjusted price; the engine executed it in SR3M19, the contract after the front (SR3H19 had become the front at the March roll).

Where the schedule ends

The feed closes a schedule’s last span when it cannot continue the chain (an unmeasurable seam, or a lapsed front without a listed successor); only the true current front stays open. The composite carries no bar past a closed span, and a bar whose tagged span does not hold its close is refused (BAR_OUTSIDE_SPAN), as is one tagged with a span after the anchor’s holder (BAR_AFTER_HOLDER); the engine invents no roll. A run end beyond the feed’s newest bar is clamped to that bar plus one bar of the run interval and recorded (run_end_clamped); a start whose UTC day is not before the clamped end is EMPTY_WINDOW.

The served constants are relative to the holder of the anchor, and the anchor is the (clamped) run end. When the end falls in a span whose contract has no bar yet (past a cut), that holder would be an untraded contract, so the bars are fetched again anchored one nanosecond after the last served bar’s close, and the last traded contract carries the identity (noted as adjustment anchor moved ...). One boundary stays (ER1 panel): when the last traded bar closes exactly at its span’s end and the next contract has no bars, the moved anchor, one nanosecond after that close, lies in the next span, so the untraded incoming contract stays the holder and the identity contract. An explicit anchor cannot sit before the request end, and the end must lie after a bar’s close for that bar to be served, so no anchor at the close itself can be asked for. The run is still consistent: the last traded contract carries the constant of the seam into the untraded span, the manifest anchors on the untraded contract, and every bar’s constant equals its span’s relative to that holder.

A span the feed marks provisional (unsealed) is served and noted. A held contract with no bars inside its in-window span fails the run (SPAN_WITHOUT_BARS).

Fetch plan and caching

A continuous run makes two wire reads in the common case: a schedule probe anchored at the run end (the generation, the feed’s newest bar and the snapshot token of that state under that anchor), and one composite BARS fetch from the run’s first UTC day to the run end on the run’s clock (the session composite at 1d/1w, epoch buckets otherwise), pinned to the probe’s generation and token. The feed folds the method and the explicit anchor into the token, not the window, the cadence or the session, so bars and schedule anchored alike carry one token and the probe is the build’s schedule. A clamped or re-anchored end moves the anchor: the bars are then fetched without a token pin (a re-anchor adds a second BARS fetch) and the schedule is read once more, pinned to the bars’ token under that anchor. No dated contract is fetched on its own, there is no seven-day tail past a span and no pre-start roll decision to prime. The strategy’s warm-up (GLE-393) is one more read of the same composite from the warm-up start, under the first build’s snapshot pins; see “Continuous run conventions”.

A token-pinned composite fetch is served through the Level-1 series cache under the snapshot token and the explicit anchor (GLE-324): the token names the served state, so an entry serves one state’s bars only into a run pinned to that state, and an answer that comes back under another token than the one pinned is returned as served and not written. A clamped or re-anchored fetch pins no token and is read live, as is every schedule read (a few kilobytes; the generation and the token are its freshness signal). There is no Level-2 continuous cache: the build takes the served bars as they are, and the former cost of re-applying an adjustment to prove a cached build went with the adjustment.

degradation.json for schedule records

On a run of several series each record names its series in series (the series label, fut:XCME:NQ@1d); a single-series run’s records carry no series. A composite run’s degradation.json holds, in this order: served_roll_schedule notes (an adjustment anchor moved by a re-anchor, a bar straddling a cut, a served degradation flag restated, unsealed in-window spans); run_end_clamped (earliest the clamp limit, latest the configured end); degraded_roll_seam for each traded degraded seam, present only under --accept-degraded-seams since the run is refused otherwise; and the feed’s own degradation flags, filtered to the traded contracts and the run window, with their kinds verbatim (interior_gap, seam_session_gap, dead_month, missing_head_sessions, coverage_incomplete, seam_fallback, expiry_conflict, missing_expiration, and whatever else the feed serves), contract as the engine code (ESM26; empty for a root-wide flag), the flag’s detail as the note, and its interval as earliest/latest (plus one gap_spans entry when both bounds are set). The engine-side scans of the per-contract path (the adapter coverage record, interior_gap_engine, the engine’s own seam_session_gap and missing_head_sessions) were deleted with that path in ER5: the served flags replace them. These records use the same fields as coverage records; their complete is always false and means nothing for them: it is a coverage claim, and only coverage records make one.

The retired local election

The engine’s own roll election (continuous.Build, engine/roll) and local adjuster (engine/contadjust), which elected rolls and adjusted bars inside the engine until GLE-270 and GLE-323, were deleted in ER5 (GLE-327) together with engine/symbols, the registry’s roll block and the per-contract orchestration. The reference text that described them (session identity, warmup replay, the calendar backstop, roll placement within the day, seam measurement, the positions not adopted from mf-view and the open engine considerations of the July 2026 parity investigation) is in this file’s history at commit b209cc0.