diff --git a/docs/agent-log.md b/docs/agent-log.md index 1c6f8f7..cc764dc 100644 --- a/docs/agent-log.md +++ b/docs/agent-log.md @@ -4,6 +4,18 @@ What agents have done, newest first. Add an entry for every piece of work: the d note or request it was for, what changed, the files touched, the tests run, and anything left open or not verified. Keep each entry short; the git history has the details. +## 2026-10-29: new belts stood still until reload; golden test after t45 (Claude) + +- Owner bug: in a world started after a long session, belts built after loading never moved + (save and reload fixed them). The 6-tick power rebuild throttle (`nextPowerBuild`) survived + the tick reset of a new or loaded world, so rebuilds waited for the old tick count. Now a wait + longer than 6 ticks counts as stale. Not caused by t45; tests had hidden it with `nextPowerBuild=0`. +- t45 animates belts from the tick (`transportClock`), so `t_gpu_golden.py` now pins `tick` + (1000 for pixel = old R.frame, 300 for smooth = old 5 s clock); all goldens match exactly again. +- Files: sim/machine-tick, test/{t_basics.js,t_gpu_golden.py}, this log. +- Tests: new t_basics check failed before the fix; all headless suites, t_stalls.py, + t_gpu_golden.py and play.py pass. + ## 2026-10-29: t103 blow carried liquids without the Flask (Codex) - Removed only blow-side Flask gates, including Shift's HUD list; corrected the Flask hint. diff --git a/src/sim/machine-tick.js b/src/sim/machine-tick.js index 6be4e53..c10feab 100644 --- a/src/sim/machine-tick.js +++ b/src/sim/machine-tick.js @@ -47,7 +47,8 @@ function fanBlow(mm, sat) { function machinesTick() { procBlocksTick(); rackTick(); - if (powerDirty && tick >= nextPowerBuild) { rebuildPower(); nextPowerBuild = tick + 6; } + // A new or loaded world restarts the tick count, so a wait longer than 6 ticks is stale. + if (powerDirty && (tick >= nextPowerBuild || nextPowerBuild > tick + 6)) { rebuildPower(); nextPowerBuild = tick + 6; } if (brokenMachines.length) { const ids = brokenMachines; brokenMachines = []; for (const id of ids) if (machines[id]) removeMachine(id, false, true); diff --git a/test/t_basics.js b/test/t_basics.js index 0a4c59b..88b6b42 100644 --- a/test/t_basics.js +++ b/test/t_basics.js @@ -157,4 +157,10 @@ check('a save holding solid rock loads it as rubble with the same total', run(`( deserializeWorld(s.meta, s.buffers); return bag[BASALT] === 0 && bag[RBAS] === 1000 && bag[CLAY] === 0 && bag[LCLAY] === 200 && bag[MSLAG] === 7 && bagTotal === 1207; })()`)); +// A belt built in a new world joins the network even after a long earlier session (owner bug, +// 2026-10-29: new belts stood still until the world was saved and loaded again). +flatWorld(run, 256, 224, 208); +run('RS = 7; nextPowerBuild = 500000; weather.next = 1e15; for (let bx = 12; bx < 40; bx++) placeBlock(BP_BELT, 1, bx, 32, true); setCell(127 * W + 60, SAND, 20, 0);'); +ticks(run, 60); +check('a belt built after a tick reset carries its grains', run('mat[127 * W + 60] !== SAND && Array.from({ length: 100 }, (_, k) => mat[127 * W + 61 + k]).includes(SAND)')); done(); diff --git a/test/t_gpu_golden.py b/test/t_gpu_golden.py index b946d97..abccaf6 100644 --- a/test/t_gpu_golden.py +++ b/test/t_gpu_golden.py @@ -39,7 +39,8 @@ with launch(viewport={'width': 640, 'height': 480}) as (_, pg, url): SET.look=look;SET.zoom=zoom;SET.lighting='full';SET.lightEvery=1;SET.glow='low'; SM.t0=0; SM.surf=-1; performance.now=()=>5000;resizeRender();bot.x=CAM[0]-bot.w/2;bot.y=CAM[1]-bot.h/2; - snapCamera();R.frame=1000;drawWorld(); + // belts animate from the tick: pixel look by tick (was R.frame), smooth by tick/60 s (was the 5 s clock) + snapCamera();R.frame=1000;tick=look==='smooth'?300:1000;drawWorld(); }""",[look,zoom]) raw=pg.evaluate("""() => { const c=document.createElement('canvas');c.width=384;c.height=288;