You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
conveyor-engine: a queue-coupled discrete conveyor's slat contents are not integral, contra conveyors.md 6.4 rule 1 #950
A queue-coupled DISCRETE conveyor admits fractional volume, so its slat contents and exits are not integral. docs/design/conveyors.md §6.4 rule 1 says they must be. One of the two is wrong, and deciding which changes numerics.
The spec claim
docs/design/conveyors.md §6.4 rule 1 (~line 702-707), of a DISCRETE conveyor:
Un-inserted carry is never taken from upstream -- an inflow's reported rate reflects only its inserted units, so conservation and the capacity bound both hold exactly. Slat contents therefore stay integral, and exits arrive as integral lumps. Conveyor-driven inflow bypasses quantization entirely (never blocked -- §4.3; it is already integral when the upstream is discrete, which the queue-fed case mandates).
The bolded parenthetical is load-bearing: coupled admission skips quantization because the incoming volume is assumed already integral. As implemented, it isn't.
Why the assumption fails
A queue-coupled conveyor MUST be discrete (XMILE 3.7.2, enforced as a compile error; conveyors.md §11). But nothing on the coupled admission path quantizes:
src/simlin-engine/src/conveyor.rsadmission_budget (~line 1072-1087) returns cap_room.min(limit_vol) -- a continuous volume, no floor.
src/simlin-engine/src/conveyor.rsconsume_inflow_budget (~line 1097-1101) does self.in_carry += vol for the discrete case. Nothing rounds vol to whole units.
The coupled volume enters via phase_b's conv_inflows (the conveyor-driven inflow path), which by rule 1's own words "bypasses quantization entirely".
The queue's serve is not integral under the XMILE defaults: src/simlin-engine/src/xmile/variables.rsconveyor_to_datamodel defaults one_at_a_time = true, batch_integrity = false (line ~320). With batch_integrity = false, QueueState::take_for_conveyor (src/simlin-engine/src/queue.rs ~line 197) splits its front cohort fractionally to fill exactly the room the belt reports.
So the belt receives a fractional volume and inserts it unquantized.
Empirical demonstration
test/conveyors/queue_coupled_conveyor.xmile (added by #924): discrete belt, len 1, dt 0.5, capacity 2 + STEP(20, 2), queue fed by arrivals = TIME + 1, queue has an <overflow/>.
Belt contents run 0.5, 1.25, 1.75, 2.5, 3.25 -- nothing integral. Exits are likewise fractional. Per §6.4 rule 1 they should all be whole units.
This is not a backend-parity bug: the wasm belt pass (src/simlin-engine/src/wasmgen/belt.rs) mirrors the VM bit-for-bit and #924's corpus gate pins that agreement. Both backends share the divergence from the spec.
Why this needs a decision, not just a patch
Two resolutions, and picking the wrong one silently changes numerics:
The spec's parenthetical is wrong. Perhaps Stella really does admit fractional coupled volumes when batch_integrity = false. Then §6.4 rule 1's "slat contents therefore stay integral" sentence and its parenthetical need correcting. The repo's standing rule is Stella-over-spec (docs/design/conveyors.md preamble: a Stella disagreement is a spec bug to fix, not a delta to document). This needs fact-finding against Stella, not a guess.
The VM under-quantizes. If Stella keeps coupled admission integral, then admission_budget should floor its result (and/or take_for_conveyor should never split a batch below a whole unit when the destination is discrete). BOTH backends must move in the same commit -- conveyor.rs and wasmgen/belt.rs -- exactly as engine: <leak_integers/> is silently ignored on an exponential-leak conveyor #942 requires for its own VM quirk.
Urgency: the corpus is about to freeze the possibly-wrong answer
test/conveyors/queue_coupled_conveyor.xmile is now an integration-corpus fixture (simulate_special_path in src/simlin-engine/tests/integration/simulate.rs) with the VM as its oracle. That makes the current, possibly-wrong VM behavior the permanent corpus answer. Whichever way this resolves, that fixture's expected trajectory changes and its checked-in-by-implication values must be re-derived. Resolve this before the fixture's numbers calcify.
A queue-coupled DISCRETE conveyor admits fractional volume, so its slat contents and exits are not integral.
docs/design/conveyors.md§6.4 rule 1 says they must be. One of the two is wrong, and deciding which changes numerics.The spec claim
docs/design/conveyors.md§6.4 rule 1 (~line 702-707), of a DISCRETE conveyor:The bolded parenthetical is load-bearing: coupled admission skips quantization because the incoming volume is assumed already integral. As implemented, it isn't.
Why the assumption fails
A queue-coupled conveyor MUST be discrete (XMILE 3.7.2, enforced as a compile error; conveyors.md §11). But nothing on the coupled admission path quantizes:
src/simlin-engine/src/conveyor.rsadmission_budget(~line 1072-1087) returnscap_room.min(limit_vol)-- a continuous volume, nofloor.src/simlin-engine/src/conveyor.rsconsume_inflow_budget(~line 1097-1101) doesself.in_carry += volfor the discrete case. Nothing roundsvolto whole units.phase_b'sconv_inflows(the conveyor-driven inflow path), which by rule 1's own words "bypasses quantization entirely".src/simlin-engine/src/xmile/variables.rsconveyor_to_datamodeldefaultsone_at_a_time = true,batch_integrity = false(line ~320). Withbatch_integrity = false,QueueState::take_for_conveyor(src/simlin-engine/src/queue.rs~line 197) splits its front cohort fractionally to fill exactly the room the belt reports.So the belt receives a fractional volume and inserts it unquantized.
Empirical demonstration
test/conveyors/queue_coupled_conveyor.xmile(added by #924): discrete belt,len 1,dt 0.5, capacity2 + STEP(20, 2), queue fed byarrivals = TIME + 1, queue has an<overflow/>.Belt contents run
0.5, 1.25, 1.75, 2.5, 3.25-- nothing integral. Exits are likewise fractional. Per §6.4 rule 1 they should all be whole units.This is not a backend-parity bug: the wasm belt pass (
src/simlin-engine/src/wasmgen/belt.rs) mirrors the VM bit-for-bit and #924's corpus gate pins that agreement. Both backends share the divergence from the spec.Why this needs a decision, not just a patch
Two resolutions, and picking the wrong one silently changes numerics:
The spec's parenthetical is wrong. Perhaps Stella really does admit fractional coupled volumes when
batch_integrity = false. Then §6.4 rule 1's "slat contents therefore stay integral" sentence and its parenthetical need correcting. The repo's standing rule is Stella-over-spec (docs/design/conveyors.mdpreamble: a Stella disagreement is a spec bug to fix, not a delta to document). This needs fact-finding against Stella, not a guess.The VM under-quantizes. If Stella keeps coupled admission integral, then
admission_budgetshouldfloorits result (and/ortake_for_conveyorshould never split a batch below a whole unit when the destination is discrete). BOTH backends must move in the same commit --conveyor.rsandwasmgen/belt.rs-- exactly as engine: <leak_integers/> is silently ignored on an exponential-leak conveyor #942 requires for its own VM quirk.Urgency: the corpus is about to freeze the possibly-wrong answer
test/conveyors/queue_coupled_conveyor.xmileis now an integration-corpus fixture (simulate_special_pathinsrc/simlin-engine/tests/integration/simulate.rs) with the VM as its oracle. That makes the current, possibly-wrong VM behavior the permanent corpus answer. Whichever way this resolves, that fixture's expected trajectory changes and its checked-in-by-implication values must be re-derived. Resolve this before the fixture's numbers calcify.Components affected
src/simlin-engine/src/conveyor.rs(admission_budget,consume_inflow_budget)src/simlin-engine/src/queue.rs(take_for_conveyor)src/simlin-engine/src/wasmgen/belt.rs(must move in lockstep)docs/design/conveyors.md§6.4 rule 1test/conveyors/queue_coupled_conveyor.xmile+src/simlin-engine/tests/integration/simulate.rsRelated
<leak_integers/>silently ignored on an exponential belt; another VM quirk the wasm lowering deliberately mirrors, whose fix must also move both backends together.Identified during review of #924 on branch
conveyor-engine.