mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* feat(relay): split step-5 shadow compare and dry-run logs per cell The 24 h per-cell shadow gate needs per-cell sticky-compare counts, per-cell unexplained counts, and dry-run `full` refusals while the map showed room. Both summary lines gain additive per-cell fields; existing fields are unchanged. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count a cell-mismatch on both cells and bound per-cell maps by the fleet - countByCell (was cells) counts a compare on every cell it involves: the database's cell, every seat's cell when there is no row, and both cells for a cell-mismatch. Drop the 64-cell cap and cellsOverflow. - Add ReservePlacer.free and use it for the dry-run free share. - Rename the room bound to RESERVE_DRY_RUN_ROOM_BOUND. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count a duplicate-seat compare on every seat cell An unexplained duplicate seat counted only on the database's cell, so a cell whose stale feed kept a second seat could pass its own step-5 check. Count it once on every seat cell, the same as a cell-mismatch. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count explained cell-mismatch and duplicate-seat on the database cell only Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): key per-cell counts on prototype-free records Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): explain a duplicate seat left by a just-superseded half-open control When the database names the newest seat exactly, every other seat has a strictly lower epoch, and the newest seat joined within the cell's silence close (timeout + one ping interval + the map lag bound), the older seat is a half-open control awaiting its 75 s pong-silence close, not a fault. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): bound the superseded duplicate-seat rule on the move's age A same-epoch rejoin resets joinedAt, so a stale older seat could stay explained forever; the director-clock sighting of the epoch moves only when the epoch rises. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): leave a superseded duplicate seat unexplained without an epoch sighting Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): explain a superseded duplicate seat only from a prior sighting compare() recorded the epoch before classifying, so a first-ever sighting (restart or eviction) read as a fresh move. Classify first and take the move's age from the record that existed before this compare. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): also bound a superseded duplicate seat on its join age A long-ago lower-epoch sighting dates the move to this compare, so the current seat's join age bounds it too. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count an ageless superseded duplicate seat as its own class A superseded-shaped duplicate-seat with no prior sighting of the host (the first compare since a restart) has no move age, so it is now `superseded-unknown-age` (explained: false) rather than a plain duplicate. The count line also carries `uptimeMs`, so the gate can discount that class in an instance's first 100 s. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): limit superseded-unknown-age to an instance's first 100 s Flushes are lazy, so a window has no upper bound and an uptime field on the count line cannot date it. The compare now records when it started and emits superseded-unknown-age only within the superseded close bound of that; later, a missing sighting means another instance served the host or the sighting was evicted, so it is a plain unexplained duplicate-seat. Drops the uptimeMs field. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * docs(relay): say where a missing sighting comes from after the first 100 s Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f