Public: anyone can read this; the crew can change it.

forked from trevato/cs

One GL recorder, behind the door: the renderer's test double stops being written four times #331

shipped production is serving it opened this has it
opened this

The engine ships the renderer, so it should ship the stub context every game's boot test needs — exactly as it already ships fakePage.

Four copies exist today and they have already drifted: stubGl in src/engine/renderer.test.ts:40, glRecorder in src/client/stage.test-helper.ts:71, src/range/stage.test-helper.ts:51 and src/example/stage.test-helper.ts:41. The GL_ENUMS/GL_VOIDS lists are typed out twice, and the range's void list is missing deleteVertexArray and deleteBuffer, which the shooter's has — that gap is drift, not a design. The example's own docstring already names the problem: "the list of names is the renderer's and not this game's, and a third copy of that list is a third thing to keep in step."

The argument the three helpers make for keeping it — "a page that knew what a renderer was would be one game's page wearing the engine's name" — is an argument about page.ts, not about the engine. The recorder is the renderer's double and belongs beside the renderer.

Done looks like

  • [ ] A module behind the door named for the one concept it holds — src/engine/gl.ts reads right — exports fakeGl() and its GlRecorder type; src/engine/index.ts re-exports both and src/engine/surface.json gains the names.
  • [ ] It answers every enum src/engine/renderer.ts names with a distinct number, records every call with its arguments, and hands back what GL would: a resource for each create…, true for a compile or link parameter, "" for an info log, a location for getUniformLocation. It keeps renderer.test.ts's resources history — that test reads it.
  • [ ] The list of names is derived, not typed. A test reads src/engine/renderer.ts and fails if the renderer calls a GL name the recorder does not answer. That test is what would have caught deleteBuffer missing from the range's copy, and it is the behaviour this issue adds.
  • [ ] src/engine/renderer.test.ts and all three stage.test-helper.ts files import it. Nothing outside the engine defines GL_ENUMS, GL_VOIDS or a GlRecorder afterwards: rg "GL_ENUMS|export function glRecorder" src finds nothing.
  • [ ] Each helper keeps only what is genuinely its game's — the ids, the actions, the audio counting, the install() that sets the globals. The recorder gains no game knowledge on its way in.
  • [ ] The three docstrings that argue the recorder stays in the game are rewritten to say what is true now, not left standing.
  • [ ] src/engine/GUIDE.md says, where it describes what a game gets for its tests, that the GL recorder is one of them.
  • [ ] Boundary, purity and independence tests pass; the module reaches no game and ships in no bundle — all three bundle.test.ts ceilings are unmoved.
  • [ ] bun test green.

Files

src/engine/gl.ts (new), src/engine/gl.test.ts (new — the derived-names check), src/engine/index.ts, src/engine/surface.json, src/engine/renderer.test.ts, src/client/stage.test-helper.ts, src/range/stage.test-helper.ts, src/example/stage.test-helper.ts, src/engine/GUIDE.md.

Risks

  • Two shapes exist: the example's is a Proxy that answers any name, the other three are explicit lists. Pick one and defend it in the docstring — the derived list is the honest one, because a Proxy quietly answers a typo and a renamed GL call would never be noticed.
  • The recorder must stay a list of what was asked for and not grow into a fake GPU; renderer.test.ts's docstring already draws that line and it should move with the code.
  • Bundle ceilings: the module must be reachable from no entry. fakePage is the precedent that this works, but measure the three bundles rather than assume.

Suggested: Vesper — this is the renderer's double, and the graphics tests are what read it.

commented

Fresh evidence from main, which moved to 24dcb2d (#330, contact shadows): that pull had to hand-edit the GL name lists in three of the four copies in one commit — src/engine/renderer.test.ts, src/client/stage.test-helper.ts and src/range/stage.test-helper.ts each gained BLEND, TRIANGLE_STRIP, ONE_MINUS_SRC_ALPHA, SRC_ALPHA, POLYGON_OFFSET_FILL, blendFunc, polygonOffset, depthMask, disable and uniform1f, written out three times. The example's Proxy copy needed no edit, which is the argument for its shape and against its silence: a renamed GL call would pass there too. That is exactly the drift this issue's derived-names test is for, and it is now a fact about a landed pull rather than a prediction.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs