fix(runtime,verify): single-owner simulation delivery (ARN-236) - #400
fix(runtime,verify): single-owner simulation delivery (ARN-236)#400rita-aga wants to merge 2 commits into
Conversation
ADR-0177: SimScheduler::tick enqueues only; drain_ready owns consumption. Terminal tick flushes due batches; callback rejection fails the run. DST proves exactly-once delayed delivery.
Grok independent review — PR #400 (ARN-236 / ADR-0177)Scope: Single-owner simulation delivery — What was done well
FindingsImportant (should fix / watch)
Suggestions (nice to have)
Plan alignmentMatches ADR-0177 readiness gates: single owner, deterministic drain order, terminal flush, callback failure visibility, joint driver migration. DST compliance (BTreeMap/BinaryHeap/VecDeque, no wall clock) holds. VerdictSolid structural fix to simulation delivery ownership with strong tests on exactly-once drain, terminal flush, and callback budget failure. Residuals are API footguns and budget calibration, not a return of silent message loss on the migrated paths. Verdict: PASS |
|
@greptile review |
ARENA SHIPPABLE · Grok · 2026-07-14 11:57 PDTPR: #400 Checklist
Summarysingle-owner sim delivery |
Rename used loop variable, document has_violations vs execution_errors, and mark ADR-0177 Accepted with the implementation.
|
@greptile review |
1 similar comment
|
@greptile review |
|
Greptile P2s already landed: loop var is |
Summary
Implements ADR-0177 for ARN-236: simulation no longer has competing delayed-message ownership paths.
Studied
origin/codex/arn-236-simulation-delayed-delivery(PR #387 used ADR-0171; this PR renumbers to 0177 to avoid concurrent ADR collisions).Contract
SimScheduler::tickadvances logical time and enqueues due messages only (no clone return).drain_ready(budget)is the sole ownership transfer; cycle-fairBTreeMapactor order + FIFO per mailbox.reaction_budget_per_tick), and fallible — rejection fails the run.Tests (RED→GREEN)
Local verification
CI on this PR: Compile & Lint, Tests, DST matrix — green.
Residual
Greptile Summary
This PR implements ADR-0177, eliminating the competing delayed-message ownership paths in the simulation layer.
SimScheduler::ticknow only enqueues due messages into per-actor mailboxes;drain_ready(budget)is the single ownership-transfer point, using cycle-fairBTreeMapiteration and FIFO-per-mailbox order. The terminal tick flushes all remaining ready messages across budgeted batches, and integration-callback reactions share one budget counter per tick across those batches.core.rs:tick()returnsvoid; newdrain_ready,has_ready_messages, andwith_mailbox_budgetAPI added with pre-assertions and deterministic actor ordering.sim_actor_system.rs: refactored into sub-modules (callbacks,invariant_eval,random_budget,recording); addsrandom_in_flight_actionstracking,execution_errorsfield, and shared-budget drain loop;SimActorResult::all_invariants_heldnow also requiresexecution_errors.is_empty().temper-verify/simulation.rs: parallel refactor using the samedrain_ready/ in-flight pattern with terminal-tick flush; addsmessage_batch_budgettoSimConfig.Confidence Score: 5/5
The changes are fully self-contained to the deterministic simulation layer with no production runtime paths affected; the new drain and budget logic is correctly implemented and exercised by targeted tests.
The single-owner contract is cleanly enforced: tick() is write-only to mailboxes and drain_ready() is the exclusive consumer, removing the previous dual-path hazard. The cycle-fair BTreeMap draining, in-flight reservation accounting, shared reaction budget on terminal ticks, and callback-error invalidation all check out. The test suite covers each new behavior including exactly-once delivery across 16 seeds, terminal multi-batch flush, and shared-budget exhaustion. No logic errors were found in the changed code.
No files require special attention beyond the already-noted ADR status field left as Proposed.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[outer tick loop] --> B["scheduler.send(actor, action) + reserve in_flight"] B --> C["scheduler.tick() — advance time, enqueue due msgs to mailboxes"] C --> D["process dropped_log — release in_flight for drops"] D --> E["reactions = 0, begin drain loop"] E --> F["drain_ready(message_batch_budget) — cycle-fair BTreeMap pop_front"] F --> G{messages returned?} G -->|yes| H["release in_flight per msg, apply_action, schedule callbacks"] H --> I["deliver_integration_callbacks(&mut reactions) — shared budget across all batches"] I --> J{callback error?} J -->|yes| K["break simulation — execution_errors recorded"] J -->|no| L{terminal tick AND has_ready_messages?} G -->|none| L L -->|yes, flush remaining| F L -->|no| M[next tick] M --> A%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[outer tick loop] --> B["scheduler.send(actor, action) + reserve in_flight"] B --> C["scheduler.tick() — advance time, enqueue due msgs to mailboxes"] C --> D["process dropped_log — release in_flight for drops"] D --> E["reactions = 0, begin drain loop"] E --> F["drain_ready(message_batch_budget) — cycle-fair BTreeMap pop_front"] F --> G{messages returned?} G -->|yes| H["release in_flight per msg, apply_action, schedule callbacks"] H --> I["deliver_integration_callbacks(&mut reactions) — shared budget across all batches"] I --> J{callback error?} J -->|yes| K["break simulation — execution_errors recorded"] J -->|no| L{terminal tick AND has_ready_messages?} G -->|none| L L -->|yes, flush remaining| F L -->|no| M[next tick] M --> AReviews (3): Last reviewed commit: "fix(runtime): address review on simulati..." | Re-trigger Greptile
Context used: