Skip to content

GAME-RENDER-ADOPT-01.8: register the BAR game state with Game.Render RendererSelection behind the SVG surface (Refs FS-GG/.github#5180) - #53

Merged
EHotwagner merged 2 commits into
mainfrom
routine/5180-bar-render-adopt
Nov 1, 2026
Merged

EHotwagner merged 2 commits into
mainfrom
routine/5180-bar-render-adopt

Conversation

@EHotwagner

@EHotwagner EHotwagner commented Nov 1, 2026 •

Copy link
Copy Markdown

GAME-RENDER-ADOPT-01.6 source slice: the SC2 client's tactical game-state type is registered with the FS.GG.Game.Render RendererSelection registry, and the existing tactical map is the default (and only registered) Svg adapter behind it. Design, inventory and upstream gaps: docs/GAME-RENDER-ADOPT-01.6.md.

Refs #50
Refs FS-GG/.github#5179

What changes

  • src/SC2.Client.Rendering (new, pure, also compiled by Fable): TacticalView (last accepted TacticalObservation plus the target cursor) is the registered state type; board geometry, allegiance and fills have one definition; TacticalView.scene is the Scene projection the canvas backends will draw; TacticalRenderer.registry and report.
  • Tactical.fs: the existing marker code is the Svg adapter's Mount/Present/Dispose (same circle attributes, handlers and labels; the activation closure is lifted to activateUnit). Present rebuilds markers only for a new observation, so a cursor move never drops marker focus. A RendererDriver<TacticalView> runs the selection; globalThis.SC2Renderer.select(token) and .observe() are the hooks. The unit list, authority, guest and transport paths are unchanged.
  • Pixi and Babylon are not registered; selecting them is refused with the markers and the game state intact (SC2.Client#51).
  • Four byte-exact pinned FS.GG.Game main sources (RendererSelection.fsi/.fs, RendererDriver.fsi/.fs at d602c2d4) under src/SC2.Client.Rendering/Upstream/, because no published Game.Render carries them (0.17.0 is the newest). eng/game-render/pin.env and scripts/check-game-render-pin.py (run by verify.sh; --against-upstream compares to the commit) keep them unedited. Same bridge as FourD#56.
  • One new package, FS.GG.UI.Scene 0.31.0 (what FS.GG.Game main builds against; 0.32.x needs FSharp.Core >= 10.1.401, which the SDK pin forbids). Locked restore passes; package-provenance.json and scripts/verify-packages.sh record and check the archive hash.

Review round 1 (REQUEST_CHANGES at 9d2c0f7)

  • Blocking: the broker's stale observation (same sequence, no units, empty perspective) is accepted as a Current-to-Stale transition and keeps the prior units; unit test and Chromium journey use that real shape.
  • Decode: fractional or out-of-range uint32/int32 fields are refused (9 probes plus the exact limits).
  • Parity gate: both runtimes print a canonical digest of decoded values; the test shows the digest changes on a one-value divergence.
  • Held for #5181: decode strictness to match validateObservation, the 64-entity guest limit, generation and validity sequences, duplicate keys. Documented only: project-wide TreatWarningsAsErrors=false, and Handle.select returning true for any known token.

Not accepted by this PR (held remainder)

Done-when needs the published Game.Render and the FS.GG.Game#745 kit; switching to them, deleting Upstream/ and eng/game-render/, and the three-backend switch test are held. Live SC2 state needs SC2.Client#49; everything here is recorded or synthetic. This PR does not close #50.

Local gates (same commands as CI where the toolchain exists)

  • dotnet restore SC2Client.slnx --locked-mode: passes; dotnet build SC2Client.slnx Debug and Release: 0 warnings, 0 errors.
  • dotnet run --project tests/SC2.Client.Rendering.Tests: 29 checks, 0 failed. Emitted Fable (rendering-vectors.mjs): 29 checks, 0 failed; verify.sh requires equal counts. Mutation controls (snapshot units drawn, enemy fill changed, Pixi registered) each failed the expected checks.
  • npm --prefix src/SC2.Client.Browser test (includes tactical-ui-contract.mjs): passes. npm ... run build: passes.
  • Browser.Tests/renderer-selection.spec.js (real index.html DOM and emitted Tactical module in Chromium): 1 passed; a mutation that rebuilds markers on every present failed it.
  • bash scripts/verify-provenance.sh, verify-packages.sh, check-game-render-pin.py --against-upstream, node --test scripts/lib/qualified-product-retention.test.mjs: pass.
  • Not run locally: the rest of verify.sh and the existing Playwright suite (no Rust toolchain on this host, guests cannot be built); CI runs them.
  • No fixtures or release controls added; no clock-dependent inputs. The new spec re-binds the committed gateway observation vector's identity to its own observation frame with the product codecs at test time (the committed envelope carries a different frame basis than its observation), so no new fixture is committed.

🤖 Generated with Claude Code

… SVG default (Refs FS-GG/.github#5180)

Adds Broker.Browser.Render (portable F#: the BAR observable game-state type mapped from the
barc.browser.v1 Observation, a shared Scene projection, an Elmish client over RendererSelection with a
replay feed) and Broker.Browser.Render.Host (Fable-only: the retained SVG surface registered as the
default adapter). Pixi and Babylon are not registered; selecting them is refused with state intact.

FS.GG.Game's RendererSelection and SvgSurface are in no published package, so four byte-exact sources
are pinned at d602c2d4 (eng/game-render/pin.env, scripts/check-game-render-pin.py), as in FourD#56.
The existing client is unchanged. Decision record and inventory: docs/GAME-RENDER-ADOPT-01.8.md.

Refs FS-GG/.github#5179

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@EHotwagner

Copy link
Copy Markdown
Author

Root/fdev: independent review of 9d2c0f77 is REQUEST_CHANGES. Each finding is classified below.

Fix now:

  • Blocking: BarClient refuses the broker's real stale observation. It carries the same sequence, with no units or perspective (Gateway.fs:182-184, live path ~497-503). Accept an equal-sequence Current→Stale transition and retain the prior units. Test the real shape through BarClient.update and in the browser journey.
  • Decode: range-check and integer-check the uint32/int32 fields. Today definitionId -1 gives Some 0u on .NET and 4294967295 on Fable, and teamId 2.7 becomes 2.
  • Parity gate: compare a digest of decoded values from .NET and Fable, not only the check count.

Held for the live slice (FS-GG/.github#5181 scope):

  • decode strictness to match validateObservation (capturedAtUnixMs, session and perspective binding);
  • the 64-entity guest limit;
  • generation and validity sequences;
  • duplicate-key semantics.

Document only: the project-wide TreatWarningsAsErrors=false needed for the pinned files, and that Handle.select returns true for any known token.

The home decision (FSBarV2) is accepted. Refs FS-GG/.github#5180

…ers, gate on a decoded-value digest (Refs FS-GG/.github#5180)

- BarClient accepts the equal-sequence Current-to-Stale frame the broker sends (Gateway.fs envelope: last
  sequence, no units, empty perspective) and keeps the prior entities, so the veil shows.
- BarObservationJson refuses fractional or out-of-range uint32/int32 fields (definitionId, teamId), which
  .NET and Fable narrowed differently.
- The parity gate prints and compares a digest of every decoded value, not only the check count.

Refs FS-GG/.github#5179

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@EHotwagner

Copy link
Copy Markdown
Author

Root/fdev: the independent delta re-review APPROVED exact head ed0367ef.

  • Stale handling: the real broker stale shape is accepted, with units kept and the veil drawn, and the refusals for a repeat, a stale behind and Current-at-equal-after-stale are correct.
  • Decode: the integer range and whole-number checks agree on .NET and Fable.
  • Parity: the digest gate bites. A Fable-only unasserted change failed cmp.
  • Counts: 104 checks on both runtimes, 4 Chromium journeys.

Triage, declined: the doc line about stale lastSequence and the digest's non-coverage of BarScene.view are non-material. The live slice #5181 reworks the view.

Merging. FS-GG/.github#5180 continues: the published Game.Render and the #745 kit, which delete the pin bridge. Refs FS-GG/.github#5180

@EHotwagner
EHotwagner merged commit 10af773 into main Nov 1, 2026
3 of 4 checks passed
@EHotwagner
EHotwagner deleted the routine/5180-bar-render-adopt branch November 1, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant