ODS architecture and data flow#
ODS supplies owned training batches from accepted simulation trajectories through a bounded shared cache. The broader data pipeline gives live and stored numeric trajectories one causal sampling interface. Task execution, learning and evaluation remain application responsibilities.
Runtime structure#
Solid arrows show data flow; dotted arrows show application control. The three
BatchSource implementations are alternatives, not an automatic mixed replay.
flowchart TB
Producer["Expert producer"] --> Engine["OnlineDataEngine<br/>Shared CPU cache, locked copy and quotas"]
Engine --> Source["BatchSource<br/>Owned causal batches"]
Stored["Resident tensors / LeRobot files"] --> Source
Source --> Learner["Learner<br/>Direct sampling or SequenceDataset"]
Learner --> Eval["Independent student evaluation"]
Host["Application owner<br/>Plan, optional flow control and shutdown"]
Host -.-> Engine
Host -.-> Learner
The engine is not a separate training service. Its owner creates the producer process and shared storage. The producer runs vectorized environments; P is not a requirement for P separate OS processes. Sampling executes in the calling consumer and retains selection, copy and quota debit under the shared lock. Feature conversion can run on the owned copy after releasing that lock.
Applications own optional recording and independent student evaluation. Live training does not automatically persist every sample. The evaluator loads checkpoints and measures student rollouts; it has no implemented feedback edge that requests targeted collection from the producer.
Module ownership#
Layer |
Public owner and responsibility |
|---|---|
Production and shared state |
|
Language metadata |
|
Planning |
|
Owner-side flow control |
|
Contract and schema |
|
Live/resident adaptation |
|
Numeric SDK loading |
|
Iteration |
|
Shared numerical sampling |
|
Application |
|
Schema validation cannot infer action meaning from a vector width. Observation timing, action semantics, order, step duration and any feature conversion must describe the data truthfully. A schema fingerprint identifies the declaration, not the callable implementation or numerical dataset content. Engine-local origin IDs also do not establish portable dataset content identity.
Online and offline execution#
Live: the owner starts the engine and waits for initial fill. The worker
accepts task rollouts and publishes complete episodes. OnlineDataSource
delegates to the engine’s locked sampler and returns canonical owned contexts.
The host schedules further fills and training, optionally through
ODSFlowController; shutdown belongs to the engine creator.
Refill publishes batches of rows incrementally: readable rows can temporarily
belong to different generations. A generation filter is explicit;
wait_for_generation() reports completion of the entire requested fill.
Stored: the caller constructs a TensorDataSource or loads numeric LeRobot
data through the official SDK. The reader validates its declared schema,
mapping, temporal data and resident allowance. Subsequent contexts come from
resident CPU tensors, not per-minibatch disk streaming. Loading creates no
simulation producer and supplies no implicit refill or epoch policy.
Both paths return contexts of length H + F - 1, with the current frame at
H - 1. Real context frames use valid; only real current/future targets use
loss_mask. Padding, episode/continuity boundaries and declared segment and
generation filters keep the pre-action observation/action pairing causal.
Exact source comparisons freeze recorded values/schema and align selected frame IDs, sequence specification, transforms/RNG and quota/filter state. A refreshing online run and a fixed offline corpus can still select different data and learn differently. Shared APIs alone do not establish identical sample traces or a training-efficiency advantage.
Control and protection boundaries#
configure_ods()is a static planner. It does not run calibration, mutate a live engine, choose a learning-safe profile or invoke the optimizer. The application can explicitly selectODSFlowControllerto enforce the plan’s refill threshold and batch-start pacing with bounded waits. The controller is creator-process/thread only and does not start or stop the engine.request_refill()is owner-only and coalesces an outstanding request.wait_for_generation()waits for a complete fill. Optional bounded lifecycle logging must be drained during production and waits.A returned chunk costs one source selection. Duplicate draws count separately; copy failure spends nothing and downstream failure does not refund delivery. Live replacement retires unused allowance. Each source owns its ledger; there is no distributed global quota across independent sources/runs.
DataUnavailableErrormeans no eligible window exists;DataBudgetExhaustedErrormeans eligible data cannot fund the requested batch. The opt-in controller retries only these transient live errors up to its deadline while draining events and checking health. Worker/read failures propagate. Dataset iteration adds no hidden retry, refill or budget reset.Model/optimizer/RNG recovery belongs to the application. The demo recreates a live cache with a new run ID; exact replay-cache or protected offline-ledger recovery is not implemented.
See configuration for rate/cache formulas and runtime checks, and the Dataset/source design for implementation detail. Image/video sequence decoding, out-of-core loading, DAgger, feedback-driven collection, RLinf integration and general replay aggregation remain outside the implemented scope.