| Contract (loading & API shape) | board_model loading, instantiation, required API, and enums | ✅ |
| API behavior | setup() initial state is correct | ✅ |
| Acceptance spawn and early movement | ✅ |
| get_cell ASCII mapping and out-of-bounds handling | ✅ |
| place_belt placement rules | ✅ |
| rotate_cell rotation rules | ✅ |
| spawn_item rules and RNG non-consumption | ✅ |
| peek_next_kind is stable and matches the spawn | ✅ |
| Movement | Straight belts move one cell per tick | ✅ |
| Adjacent pair advances in the same tick | ✅ |
| Three items in a loop all advance | ✅ |
| Full loop stalls then all items miss | ✅ |
| Collision / stalls | Merge to same empty cell chooses the lowest id | ✅ |
| Head-on swap is blocked | ✅ |
| Blocked item becomes a miss after five ticks | ✅ |
| Stuck counter resets after movement | ✅ |
| Exit & scoring | Matching exit scores and removes the item | ✅ |
| Wrong exit becomes a miss | ✅ |
| Two items can enter the same exit | ✅ |
| Off-board movement becomes a miss | ✅ |
Exit departure frees the previous cell for a follower in the same tick Details: items=[(-999, -999), (0, 0)] delivered=[0] | ❌ |
| Splitter | Splitter alternates right-left-right | ✅ |
| Splitter toggles are independent per splitter | ✅ |
| Blocked splitter does not toggle | ✅ |
| Splitter toggles on exit and off-board departure | ✅ |
| Splitter "right" is relative to entry direction | ✅ |
| Spawn & misses | Spawn schedule is t=1,4,7... | ✅ |
| Blocked spawn becomes a miss and consumes RNG | ✅ |
| Blocked spawn still consumes the id | ✅ |
| At t=120, future ticks freeze the state | ✅ |
| Determinism | Same seed and same operation sequence produce identical results | ✅ |
| Spawn color sequence matches RandomNumberGenerator | ✅ |
| Win path | Standard map simple controller reaches the win threshold | ✅ |
| View behavior | Displayed labels have no missing glyphs | ✅ |
| Tick advances at 0.5s interval | ✅ |
| Mouse click places a belt | ✅ |