§2 · One anchor, integer ticks, immutable tempo

A session defines its time with three numbers and one instant. Tempo must not change during a session. Every time value in the protocol is a tick; bars are a presentation form and belong in the user interface, not on the wire.

Field Meaning
anchorEpochMs Physical instant of tick 0. Immutable.
bpm Quarter notes per minute. Immutable.
beatsPerBar Default 4. Immutable.
ppq Ticks per quarter note. The value is 960.
ticksPerBar Derived: ppq × beatsPerBar — 3840 in 4/4.

This is what a fractional bar position does not give: loop length is always an integer. Sixteen bars is 61 440 ticks whether the tempo is 118 or 120, so comparison, hashing and equality are exact in every implementation.

N14 · the first thing an implementer gets wrong

A tick must be derived using floored division — toward negative infinity — not truncation toward zero and not rounding. The remainder used for a material position must be non-negative. Both differ from the native operators of several languages:

// JavaScript BigInt: both wrong for this purpose
(-7n) / 2n   // -3n   — truncates toward zero, want -4n
(-7n) % 2n   // -1n   — negative remainder, want 1n

Done correctly:

// Floored division
let t = q / 60000n;
if (q < 0n && q % 60000n !== 0n) {
  t -= 1n;
}

A tick may be negative, because a session may be announced before its anchor. That is not an edge case; it is how a set is scheduled.