Repository navigation
fix(engine): a gather in a loop counts only the current pass's lanes - #194
Conversation
Lane slots are never cleared between loop passes, and the gather counted every slot under its predecessors against the scatter's lane_count, taken from the first lane_count anywhere in state. A pass with 3 lanes followed by one with 2 released [20, 21, 12], where 12 is the first pass's third lane. The scatter now stamps each lane envelope with its activation step, every lane slot records `_scatter` and `_scatter_step`, and the gather counts only slots from its own scatter's current activation, reading lane_count from that scatter. Slots from checkpoints written before this carry no stamp and count as before while no stamped slot exists. Also corrects the reason given for refusing a gather with no scatter: it releases empty and silently drops its predecessors' output.
|
Warning Review limit reached
This review includes 12 billable files and costs up to $3.00. Or wait 4 minutes for your next included review. View limit details
|
Tiny Sweeper reviewReviewed head: Verdict: Ready for maintainer review · Priority: none Diagnostics and supporting detailsFull summaryPull request purpose (title): fix(engine): a gather in a loop counts only the current pass's lanes. Tiny Sweeper completed its review; deterministic results follow. Review snapshot
Completeness: Complete Features
Tests
FindingsNo active actionable findings. Before mergeNone. Agent review detailscritique
security
tests
commits
description
Evidence and run details
|
Summary
A
gatherinside a loop body no longer collects lanes left over from an earlier pass. This also corrects the validator's stated reason for refusing a gather with no upstream scatter.Root cause
Lane slots (
nodes.<node>.lanes.<scatter>#<i>) are never cleared between loop passes; the reducer only adds keys. The gather counted every slot under its predecessors against the scatter'slane_count, and it took that count from the firstlane_countfound anywhere in state. So a pass with 3 lanes followed by a pass with 2 released[20, 21, 12], where12is pass 1's third lane: wrong results, silently.Fix
LaneContext::scatter_step). The step travels along the lane._scatterand_scatter_step. They are written after the node's own meta, so a node can't forge them._activation_step), and readslane_countfrom that same scatter.Counting on read rather than clearing on re-fire stays correct whatever writes a slot late. It also lets a pass with no lanes yet wait instead of releasing stale ones.
Compatibility
Slots and envelopes from checkpoints written by older binaries carry no stamp. Unstamped slots all count when no stamped slot exists, so an in-flight run resumed across the upgrade still completes. Once stamped slots exist, unstamped ones are treated as stale.
LaneContextgains a public field (scatter_step), so outside code that builds it as a struct literal must set it (CHANGELOG).Validation
On a Linux build host, merged onto main 8b22179:
cargo test --workspace --all-features --locked: 2863 passed, 0 failed, 35 ignored (no new ignores).tests/loop_scatter_lanes_tests.rscopied onto unmodified main fails withleft: [20, 21, 12] right: [20, 21]. It passes with this change.-D warnings, fmt,cargo +1.88.0 check --all-features, rustdoc-D warnings.Tests
tests/loop_scatter_lanes_tests.rs: a loop whose second pass is narrower gathers only[20, 21]. It also asserts the stale slot is still in state, so the test shows the slot being ignored, not removed.lane_context_tests: an old envelope decodes with no step; the step round-trips to the lane slot, and meta cannot forge it.Found while writing #46's fuzz targets.