Not a bug — the block is still load-bearing and should stay. The comment is now misleading, and this repo is where the idiom originated, so it is worth getting right.
src/game.eigs:342:
# Physics — no observation needed, pure numeric mutation
unobserved:
game.current_angle is game.current_angle + CURRENT_ROTATE_RATE * SIM_DT
That framing was accurate when this landed (872c45f, 2026-04-17, "Wrap physics in unobserved blocks — zero-allocation game tick"). Upstream's tree-walking eval.c gated the dict in-place fast path on the block — eval.c:487, AST_DOT_ASSIGN — so game.current_angle is ... really did skip an allocation.
Upstream NaN-boxing B-3a (2026-05-22) then added dict_set_cached_immediate for DMG's register-write hot path: same in-place mutation, no g_unobserved_depth check. The win became unconditional and the gate went away. So of this block's 21 assignments, the 14 dict/index targets now get nothing from it — they are never observed (bookkeeping is gated on the named env path) and are mutated in place regardless.
The block still earns its place through the other half — the 7 named locals, which are exactly what unobserved: helps:
turn is player_turn_rate of game
thrust is player_thrust of game
cx is (cos of game.current_angle) * CURRENT_SPEED * SIM_DT
cy is (sin of game.current_angle) * CURRENT_SPEED * SIM_DT
drag is player_drag of game
drain_rate is 1.0
Plus every function it calls: g_unobserved_depth is global, not lexical, so player_thrust, player_drag and friends all run unobserved too and their internal named assignments are skipped as well. That is likely the larger share.
Why file it
This block is the ancestor of upstream's README example, which distilled it down to only the dict half and shipped that as the headline unobserved demo for two months (EigenScript#655, fixed in EigenScript#658). A reader coming here to see the idiom "in production" reads a comment that points at the inert half. The next person to copy this pattern copies the dead part.
Fix
Reword to credit the named locals and the called functions rather than the dict writes. Something like:
# Physics — the named locals below (turn/thrust/cx/cy/drag/drain_rate) and
# every function called from here run without observer bookkeeping. The
# game.* field writes are along for the ride: dict fields are never observed
# and are mutated in place regardless (upstream dict_set_cached_immediate),
# so the block is not what makes those cheap.
Verified against upstream main: eigenscript --lint src/game.eigs reports no W020 — the new upstream lint for provably-inert blocks correctly leaves this one alone, because it is not inert. Only the comment needs changing.
Not a bug — the block is still load-bearing and should stay. The comment is now misleading, and this repo is where the idiom originated, so it is worth getting right.
src/game.eigs:342:That framing was accurate when this landed (872c45f, 2026-04-17, "Wrap physics in unobserved blocks — zero-allocation game tick"). Upstream's tree-walking
eval.cgated the dict in-place fast path on the block —eval.c:487,AST_DOT_ASSIGN— sogame.current_angle is ...really did skip an allocation.Upstream NaN-boxing B-3a (2026-05-22) then added
dict_set_cached_immediatefor DMG's register-write hot path: same in-place mutation, nog_unobserved_depthcheck. The win became unconditional and the gate went away. So of this block's 21 assignments, the 14 dict/index targets now get nothing from it — they are never observed (bookkeeping is gated on the named env path) and are mutated in place regardless.The block still earns its place through the other half — the 7 named locals, which are exactly what
unobserved:helps:Plus every function it calls:
g_unobserved_depthis global, not lexical, soplayer_thrust,player_dragand friends all run unobserved too and their internal named assignments are skipped as well. That is likely the larger share.Why file it
This block is the ancestor of upstream's README example, which distilled it down to only the dict half and shipped that as the headline
unobserveddemo for two months (EigenScript#655, fixed in EigenScript#658). A reader coming here to see the idiom "in production" reads a comment that points at the inert half. The next person to copy this pattern copies the dead part.Fix
Reword to credit the named locals and the called functions rather than the dict writes. Something like:
Verified against upstream
main:eigenscript --lint src/game.eigsreports no W020 — the new upstream lint for provably-inert blocks correctly leaves this one alone, because it is not inert. Only the comment needs changing.