SIGN IN SIGN UP

gate: run the A4 live gate on CS2 — all four checks pass (#62)

The A4 chain routes every engine to JS dispatch through new code and deliberately changes
Damage.onPre semantics, so the 469 unit tests prove the refactor is faithful to itself but not that
the runtime still works. This runs it on the Docker CS2 server and records the result.

Two fixtures under tools/a4gate: a driver and a second plugin context. The second context is the
point — "Handled no longer truncates" is a claim about composition across uncoordinated plugins, and
two handlers in one closure would not have shown it.

All four pass. The damage result, which is the deliberate behaviour change:

  dmg#1 h1 Handled, zeroed  -> h2 RAN saw=0,  B RAN saw=0
  dmg#2 h1 Stop             -> neither ran
  dmg#3 h1 Continue         -> h2 RAN saw=42, B RAN saw=42

Block power preserved, Stop still truncates, and the non-truncation holds across the plugin
boundary. No panic, segfault, double-borrow or JS error across the run.

Three things shifted while running it, all recorded in the doc:

- Check 1 got smaller and sharper. All three lazy installs are already idempotent shim-side
  (s_usercmdHookInstalled, m_eventHookInstalled, AddListenerEntity guards Find), so "installs twice"
  is structurally impossible and only "never installs" was reachable. The discriminator is pre == post
  within one plugin: the post subscription reaches JS by a different path, so a doubled FireEvent hook
  would read 22/11. It read 11/11, and 13/13 after the reload.

- Bots DO generate usercmds. The plan asserted they don't and wrote UserCmd.onRun off as
  human-only; both plugins got ~20k dispatches. Only the movement field VALUES need a human client.

- Check 2 needed no bullets. S2_DAMAGE_SELFTEST fires three synthetic dispatches at fixed frames, so
  cycling the return value across them removes the rcon timing race the plan was worried about.

Two gotchas worth having written down, both of which cost time: a server command's console.log goes
to the rcon reply rather than the container log, and JS-initiated engine work cannot observe its own
listeners (the re-entrant dispatch is try_borrow_mut-skipped) — hence the delayed acceptInput in the
output test.

Still open: UserMessages.onPre payloads, and usercmd movement field values.
G
Gabriel Hirakawa committed
946cd6c322296ac9787df1384d5ce65e34a6f382
Parent: bf6c396
Committed by GitHub <noreply@github.com> on 8/1/2026, 6:14:12 AM