|
48 | 48 | - A logical region may have at most one ownership claim. |
49 | 49 | - Shard lifecycle is strictly `Created -> Active -> Draining -> Stopped`. |
50 | 50 | Rejected transitions leave the prior state unchanged. |
| 51 | +- The scheduler defaults to the existing one-shard inline path. Its multi-shard |
| 52 | + worker mode is crate-internal, explicitly selected, and not wired into the |
| 53 | + application. |
| 54 | +- A shadow tick visits each runnable shard exactly once in canonical `ShardId` |
| 55 | + order. Persistent workers receive owned, disjoint shard batches through |
| 56 | + capacity-one command/result channels; every shard is returned before the next |
| 57 | + tick, and worker completion order never changes output publication order. |
| 58 | +- Only `Active` shards accept new scheduler input. `Draining` shards continue |
| 59 | + ticking admitted work, reject new input, and cannot become `Stopped` until |
| 60 | + their tick work is quiescent. |
| 61 | +- A worker failure after dispatch permanently poisons that scheduler. A partial |
| 62 | + tick is fail-stop and must never be retried. |
| 63 | +- Cross-shard workers emit destination-only intents; only the scheduler may |
| 64 | + stamp their source, source-local sequence, and completed tick. Workers never |
| 65 | + access or send directly to another shard. |
| 66 | +- Accepted cross-shard envelopes produced in tick N apply exactly once as a |
| 67 | + separate prefix to the destination's tick N+1 execution. They never compete |
| 68 | + with the ordinary shard inbox. The prefix can enter `SimShard` only through |
| 69 | + an unforgeable scheduler-owned tick capability; sibling modules have no |
| 70 | + constructor or mid-tick mutation path. |
| 71 | +- Central admission is bounded (1,024 envelopes by default), nonblocking, and |
| 72 | + reject-newest after sorting by destination `ShardId`, source `ShardId`, then |
| 73 | + source-local FIFO sequence. Rejections return the intact owned envelope. |
| 74 | +- Boundary preparation is non-mutating. Tick overflow or pre-dispatch failure |
| 75 | + leaves ready envelopes queued; a successful tick commits exactly the |
| 76 | + prepared scheduler metadata identities, never floating-point payload |
| 77 | + equality. A draining destination cannot stop while an admitted envelope still |
| 78 | + targets it. |
| 79 | +- Before a multi-shard tick advances, every resident full `ChunkKey` |
| 80 | + (world/dimension/typed chunk position) must occur in exactly one registered |
| 81 | + shard container. The scan includes clean chunks, so aliases cannot become |
| 82 | + competing persist records on a later tick; conflicts leave tick, inbox, and |
| 83 | + dirty state unchanged. Spatial region membership is not enforced by this |
| 84 | + packet; unique out-of-region residency remains valid until that separate |
| 85 | + architecture step lands. |
| 86 | +- A successful scheduler tick transfers nonempty per-shard |
| 87 | + `ChunkOverlayRecord` batches in canonical `ShardId`/`ChunkPos` order only |
| 88 | + after every fallible worker and cross-shard phase succeeds. Each batch is |
| 89 | + capped at storage's `MAX_SAVE_BATCH` (4,096); a canonical overflow tail stays |
| 90 | + persist-dirty and is emitted by a later tick without blocking or loss. A |
| 91 | + deterministic per-map continuation cursor visits that tail before wrapping, |
| 92 | + so repeatedly re-dirtying lower chunk keys cannot starve it. |
| 93 | +- Persist output is collected from every registered lifecycle state, including |
| 94 | + a stopped shard with a deferred tail. Clearing a dirty mask transfers |
| 95 | + ownership only into the move-owned scheduler outcome; the simulation still |
| 96 | + holds no database handle and mutation-journal output remains a separate |
| 97 | + bounded seam. |
0 commit comments