# C4 — Cycle granularity **Guarantee.** The clock is data-driven: one input record = one cycle, advanced in global timestamp order, with a monotonic `cycle_id`. Ties (same timestamp, multiple sources) break by source declaration order. **Forbids.** A fixed time-grid clock; nondeterministic tie ordering. **Why.** The market *is* an irregular event sequence; a grid is arbitrary and either wastes empty cycles or clumps ticks. Backtest and live differ only in the origin of records, not the cycle semantics. Tie determinism preserves C1. ## Current state `Harness::run` (`crates/aura-engine/src/harness.rs`) increments `cycle_id` once per popped record and each cycle picks the smallest `(timestamp, source index)`; the source-index tie-break is the source *declaration* order. Ingestion sources are supplied to the production run path by role name, not list position (#275). `SourceSpec` carries `role: Option` — the bound `Role`'s name, load-bearing for source binding only, with every other flat-graph name staying a non-load-bearing debug symbol (C23). `Harness::run_bound` resolves a keyed supply against those roles via `bind_sources`, emitting sources in `SourceSpec` declaration order, so the tie-break is independent of how the caller orders the supply. A mis-bound feed is a named `SourceBindError` (`MissingFeed` / `ExtraFeed` / `DuplicateFeed` / `UnnamedSource`) at start time, not a silently wrong run. The raw-index `run(Vec)` primitive (positional, C23) is unchanged: `SourceSpec::raw` carries `role: None` and every hand-built graph keeps `role: None`; a raw-index arity mismatch stays an engine-wiring panic, while a keyed role mismatch is a user data-binding `Result`. ## See also - [C1](c01-determinism.md) — tie determinism is a precondition of the per-run bit-identity. - [C3](c03-single-merge.md) — the single ingestion merge is the clock's source stream. - [C23](c23-graph-compilation.md) — the raw-index compilation primitive; names non-load-bearing except the binding role. - [C5](c05-freshness-gating.md) — `cycle_id` advances every cycle, but recompute is gated. > History: [c04-cycle-granularity.history.md](c04-cycle-granularity.history.md)