Skip to content

fix(engine): a lane activation never writes the node's top-level slot - #195

Merged
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/lane-never-writes-top-level
Nov 11, 2026
Merged

M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/lane-never-writes-top-level

Conversation

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Stacked on fix/gather-current-pass-lanes: merge that first. This branch contains its commit until then.

Summary

Inside a scatter lane, an activation must write only nodes.<id>.lanes.<lane>, never the node's top-level nodes.<id>. Four paths broke that. This fixes them and keeps the gather counting correctly.

Root cause per path

  • Boundary cancel (engine/build/activation/gates.rs): wrote items_update(&node.id, &[], None) whether or not the activation was in a lane. It also returned a plain Update, so the static edge scheduled the successor outside the lane, where it wrote its own top-level slot.
  • Cancel during retry or backoff (activation.rs): the same write and the same static-edge leak.
  • Reenter (outcome.rs): wrote items_update_with_meta(&node.id, …) and re-activated with Command::goto([node.id]), a bare id. So the re-entered activation lost its _lane envelope and ran outside the lane. Cancel while waiting to re-enter had the same write.
  • Related reads: gate and approval read polls, and a gate its from spawn's tickets, from the top-level slot. Inside a lane, max_polls never bounded them, and gate { from: [spawn] } never found the lane's tickets.

Fix

  • engine::state::cancelled_result: in a lane it writes the lane slot with status "cancelled" and goes to END. Outside a lane the behaviour is unchanged.
  • Reenter in a lane writes its notes to the lane slot as "pending", and re-activates through a Send carrying the same lane envelope, including the scatter step from the stacked fix.
  • gather skips "pending" and "cancelled" slots when counting arrivals.
  • NodeContext::slot returns the lane slot when present, otherwise the top-level slot. Gate and approval read through it.
  • Non-lane activations are unchanged.

Validation

On a Linux build host, merged onto main 8b22179:

  • cargo test --workspace --all-features --locked: 2866 passed, 0 failed, 35 ignored (no new ignores).
  • Red control: tests/lane_top_level_writes_tests.rs on its base (the stacked fix alone) fails all three tests. Boundary cancel and retry cancel fail with "lane body node … has a top-level slot". The re-entering gate fails with "graph exceeded the recursion limit of 200 steps", because its re-activation left the lane. All three pass with this change.
  • clippy -D warnings, fmt, cargo +1.88.0 check --all-features, rustdoc -D warnings.

Tests

tests/lane_top_level_writes_tests.rs (mock feature):

  • (a) cancel at a node boundary inside a lane;
  • (b) cancel during retry (backoff_ms: 0) and during backoff (backoff_ms: 40) inside a lane;
  • (c) a gate re-entering inside a lane, in tickets and from forms. It asserts no top-level writes at any checkpoint, that the gather never releases while a lane is pending, and that results come in lane order.

Found while writing #46's fuzz targets.

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.
Four paths in a scatter lane wrote `nodes.<id>` instead of the lane's
slot: a cancel seen at the node boundary, a cancel during retry or
backoff, a cancel while waiting to re-enter, and a Reenter (a gate or
approval polling), which also re-activated with a bare id and so left
its lane. A cancelled lane also kept routing down its static edge, so
its successor ran outside the lane.

A cancelled lane now marks its lane slot "cancelled" and stops; a
re-entering lane writes "pending" notes to its lane slot and re-activates
with its own lane envelope. The gather counts neither as arrived, and
gate and approval read their poll count from the lane's slot.
@M3gA-Mind

Copy link
Copy Markdown
Collaborator Author

Stacked on #194 (its first commit is #194's). Please merge #194 first.

@coderabbitai

coderabbitai Bot commented Nov 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

This review includes 17 billable files and costs up to $4.25.

Or wait 4 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3a64db20-b2fb-47e4-9b01-20141a9f1032
Commits

Reviewing files that changed from the base of the PR and between 8b22179 and f7f71f3.

Files selected for processing: 17

  • CHANGELOG.md
  • crates/tinyflows/src/engine.rs
  • crates/tinyflows/src/engine/build/activation.rs
  • crates/tinyflows/src/engine/build/activation/gates.rs
  • crates/tinyflows/src/engine/build/activation/routing.rs
  • crates/tinyflows/src/engine/build/outcome.rs
  • crates/tinyflows/src/engine/state.rs
  • crates/tinyflows/src/lane_context_tests.rs
  • crates/tinyflows/src/nodes/control_flow/gather.rs
  • crates/tinyflows/src/nodes/control_flow/gather_tests.rs
  • crates/tinyflows/src/nodes/integration/approval.rs
  • crates/tinyflows/src/nodes/integration/gate.rs
  • crates/tinyflows/src/nodes/mod.rs
  • crates/tinyflows/src/validate/scatter.rs
  • crates/tinyflows/tests/lane_top_level_writes_tests.rs
  • crates/tinyflows/tests/loop_scatter_lanes_tests.rs
  • crates/tinyflows/tests/scatter_gather_e2e.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@tinysweeper

tinysweeper Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Verdict: Incomplete · Priority: none
Coverage: Reviewed 9 of 17 files; not reviewed (large PR): crates/tinyflows…, crates/tinyflows…, and 6 additional unreviewed files.
Pull request purpose (title): fix(engine): a lane…

Diagnostics and supporting details

Full summary

Pull request purpose (title): fix(engine): a lane activation never writes the node's top-level slot. Tiny Sweeper reviewed this change across 5 lane(s) and found 0 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

Unreviewed paths

  • crates/tinyflows/src/engine.rs
  • crates/tinyflows/src/engine/build/activation.rs
  • crates/tinyflows/src/engine/build/activation/gates.rs
  • crates/tinyflows/src/engine/build/activation/routing.rs
  • crates/tinyflows/src/nodes/integration/approval.rs
  • crates/tinyflows/src/nodes/integration/gate.rs
  • crates/tinyflows/src/validate/scatter.rs
  • crates/tinyflows/tests/scatter_gather_e2e.rs

Partial review reasons

  • critique: crates/tinyflows/src/engine.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/engine/build/activation.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/engine/build/activation/gates.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/engine/build/activation/routing.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/nodes/integration/approval.rs — not selected by the large-review budget
  • security: crates/tinyflows/src/nodes/integration/approval.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/nodes/integration/gate.rs — not selected by the large-review budget
  • security: crates/tinyflows/src/nodes/integration/gate.rs — not selected by the large-review budget
  • critique: crates/tinyflows/src/validate/scatter.rs — not selected by the large-review budget
  • security: crates/tinyflows/src/validate/scatter.rs — not selected by the large-review budget
  • critique: crates/tinyflows/tests/scatter_gather_e2e.rs — not selected by the large-review budget
  • security: crates/tinyflows/tests/scatter_gather_e2e.rs — not selected by the large-review budget

Review snapshot

Change surface Files Review signal Count
Production 11 Active findings 0
Tests 5 Noted findings 0
Documentation 1 Resolved findings 0
Configuration 0 Pending checks/questions 20

Completeness: Incomplete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

No active actionable findings.

Before merge

  • Complete the critique review for crates/tinyflows/src/engine/build/activation/routing.rs, crates/tinyflows/src/engine/build/activation/gates.rs, crates/tinyflows/src/validate/scatter.rs, crates/tinyflows/src/nodes/integration/gate.rs, crates/tinyflows/src/engine.rs, crates/tinyflows/src/engine/build/activation.rs, crates/tinyflows/tests/scatter_gather_e2e.rs, crates/tinyflows/src/nodes/integration/approval.rs.
  • Complete the security review for crates/tinyflows/src/validate/scatter.rs, crates/tinyflows/src/nodes/integration/gate.rs, crates/tinyflows/tests/scatter_gather_e2e.rs, crates/tinyflows/src/nodes/integration/approval.rs.
  • Review uncovered paths: crates/tinyflows/src/engine.rs, crates/tinyflows/src/engine/build/activation.rs, crates/tinyflows/src/engine/build/activation/gates.rs, crates/tinyflows/src/engine/build/activation/routing.rs, crates/tinyflows/src/nodes/integration/approval.rs, crates/tinyflows/src/nodes/integration/gate.rs, crates/tinyflows/src/validate/scatter.rs, crates/tinyflows/tests/scatter_gather_e2e.rs.
Agent review details

critique

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinyflows/src/engine/build/activation/routing.rs, crates/tinyflows/src/engine/build/activation/gates.rs, crates/tinyflows/src/validate/scatter.rs, crates/tinyflows/src/nodes/integration/gate.rs, crates/tinyflows/src/engine.rs, crates/tinyflows/src/engine/build/activation.rs, crates/tinyflows/tests/scatter_gather_e2e.rs, crates/tinyflows/src/nodes/integration/approval.rs
  • Lane summary: Reviewed 9 of 17 files — 8 not reviewed. Reviewed 9 files; 1 finding. 8 files were omitted: not selected by the large-review budget.

security

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinyflows/src/validate/scatter.rs, crates/tinyflows/src/nodes/integration/gate.rs, crates/tinyflows/tests/scatter_gather_e2e.rs, crates/tinyflows/src/nodes/integration/approval.rs
  • Lane summary: Reviewed 8 of 12 files — 4 not reviewed. Reviewed 8 files; 0 findings. 4 files were omitted: not selected by the large-review budget. 5 files were not security-reviewed: CHANGELOG.md (prose or tabular data), crates/tinyflows/src/engine/build/activation.rs (vendored or build output), crates/tinyflows/src/engine/build/activation/gates.rs (vendored or build output), crates/tinyflows/src/engine/build/activation/routing.rs (vendored or build output), crates/tinyflows/src/engine/build/outcome.rs (vendored or build output).

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This pull request fixes two bugs in the tinyflows engine: lane activations writing to the node's top-level slot instead of the lane slot (on cancel, retry/backoff cancel, and re-entry), and a gather inside a loop body counting stale lanes from a prior pass. The changes also add the `scatter_step` field to lane envelopes and lane slots for pass discrimination. Tests cover the fixed paths, and the code appears correct and well-reviewed. _The code index is behind this pull request (indexed at `96d24e943b51`), so retrieved context may be out of date._

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: No sensitive content in committed files. _The code index is behind this pull request (indexed at `96d24e943b51`), so retrieved context may be out of date._

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The description is accurate for this diff: every engine change it names (boundary cancel, retry/backoff cancel, lane-aware `Reenter`, `NodeContext::slot` reads in `gate`/`approval`, and the `pending`/`cancelled` skip in `gather`) is present, and the extra `_scatter`/`_scatter_step` stamping, `current_activation` filtering, `validate/scatter.rs` message and `loop_scatter_lanes_tests.rs` belong to the `fix/gather-current-pass-lanes` commit the body explicitly says this branch carries, including the `LaneContext::scatter_step` addition the CHANGELOG calls out as a breaking literal change. I found no code defect to report: the non-lane cancel path still produces the same `Update` and step stamp as before, the lane cancel/reenter paths stay inside the lane envelope, and the new stamping is written after node meta so a node cannot forge it. _The code index is behind this pull request (indexed at `96d24e943b51`), so retrieved context may be out of date._
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash, deepseek-v4-flash
  • Spend: $0.044802
  • Completion usage: incomplete; some provider completion costs are unavailable.
  • Tokens: 988530 input · 157906 output · 360320 cached · 781 embedding
  • Updated: 2026-11-11T12:01:18Z
Head State Pass summary
f7f71f3b7e05 incomplete 0 active finding(s), 0 resolved finding(s) (at 2026-11-11T12:01:18Z)

tinysweeper 0.1.2

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper could not complete coverage (8 unanswered item(s)), so this is not an approval.

Diagnostics

Total spend: $0.0448

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Nov 11, 2026
@M3gA-Mind
M3gA-Mind merged commit b6ce54a into tinyhumansai:main Nov 11, 2026
9 checks passed
M3gA-Mind added a commit to M3gA-Mind/tinyflows that referenced this pull request Nov 11, 2026
Resolves the CHANGELOG conflict with the engine fixes that landed on
main (tinyhumansai#192-tinyhumansai#195): both Unreleased entries are kept.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant