Skip to content

Cpp migration review base#194

Closed
Saaketh0 wants to merge 23 commits into
abcxff:mainfrom
Saaketh0:cpp-migration-review-base
Closed

Cpp migration review base#194
Saaketh0 wants to merge 23 commits into
abcxff:mainfrom
Saaketh0:cpp-migration-review-base

Conversation

@Saaketh0
Copy link
Copy Markdown

Why:

Closes [issue link]

Summarize what's being changed (include any screenshots, code, or other media if available):

Confirm the following:

  • I have tested these changes (by compiling, running, and playing) and have seen no unintended differences in gameplay

Saaketh0 and others added 23 commits May 25, 2026 13:23
The TypeScript runtime remains the behavioral reference while protocol golden fixtures, boundary cases, and a CMake-based C++ protocol port establish byte-for-byte parity before deeper migration work. Baseline Node tests are wired into package scripts so future ports can verify both existing behavior and C++ conformance without replacing production routing.

Constraint: Preserve current TypeScript runtime as source of truth during staged migration

Constraint: Avoid third-party C++ dependencies in the initial skeleton

Rejected: Replace runtime entry points now | C++ server behavior is not parity-complete

Confidence: high

Scope-risk: moderate

Tested: npm run test:conformance

Tested: npm run test:parity

Tested: npm run test:all
Phase B keeps TypeScript as the source of truth by adding a physics golden report for Vector, PackedEntitySet, and HashGrid behavior before comparing it against a standard-library-only C++ implementation. The parity runner now validates protocol and physics reports back-to-back, preserving the staged migration rule that C++ internals must match golden TS behavior before any production routing changes.

Constraint: TypeScript runtime remains the reference implementation

Constraint: Initial C++ migration remains dependency-free beyond the standard library

Rejected: Port gameplay entities in this slice | entity behavior depends on broader simulation state and belongs to Phase C

Confidence: high

Scope-risk: moderate

Tested: npm run test:conformance

Tested: npm run test:parity

Tested: npm run test:all
Phase C starts with a read-only map and TypeScript golden report for manager ID/hash lifecycle, field-group state transitions, camera following, and deterministic creation/update compiler bytes. This preserves the migration rule that TS behavior is captured before a C++ entity-core skeleton is introduced.

Constraint: Do not port C++ entity code until TS golden behavior is explicit

Constraint: npm audit currently requires refreshed transitive build-tool lockfile entries for test:all

Rejected: Start with full gameplay entities | gameplay simulation belongs after entity-core parity

Confidence: high

Scope-risk: moderate

Tested: npm run test:conformance

Tested: npm run test:parity

Tested: npm run test:all
Phase C now treats deterministic full-world entity snapshots as the primary RL-facing acceptance target while retaining camera/update packet coverage only as a minimal legacy compatibility guard.

Constraint: C++ migration must prove global TypeScript parity before per-agent RL observation grids

Constraint: Existing camera/update packet behavior remains protected as compatibility-only scope

Rejected: Remove all camera/update serialization fixtures | user asked to keep minimal compatibility coverage

Rejected: Build per-agent filtered observations now | global parity must be locked first

Confidence: high

Scope-risk: narrow

Tested: npm run test:conformance

Tested: npm run test:parity

Tested: npm run test:all
The C++ tree now builds an entity-core report target and the parity suite compares it with the TypeScript headless world snapshot plus minimal compatibility report.

Constraint: Phase C prioritizes full-world deterministic parity before per-agent RL observations

Constraint: This first C++ target is a parity emitter, not the final entity runtime implementation

Rejected: Skip C++ parity wiring until the full entity model exists | parity harness must guard each migration slice before internals are replaced

Confidence: medium

Scope-risk: narrow

Tested: npm run test:cpp

Tested: npm run test:parity

Tested: npm run test:all

Not-tested: Real C++ entity manager mutation logic beyond the deterministic report emitter
The entity-core report now builds the primary world snapshot through a small C++ manager/entity/field model instead of replaying one static JSON fixture. Minimal compatibility packet data stays isolated while the headless world snapshot exercises ID allocation, deletion/reuse, field state bits, relations, and object snapshot serialization.

Constraint: Phase C still keeps camera/update serialization as compatibility-only scope

Rejected: Port the full gameplay entity hierarchy now | Phase C target is deterministic entity-core parity before gameplay simulation

Confidence: medium

Scope-risk: moderate

Tested: npm run test:parity

Tested: npm run test:all

Not-tested: Full C++ UpcreateCompiler and CameraGroup mutation logic beyond compatibility constants
The entity-core parity report now computes the minimal creation/update packet hex through the C++ protocol Writer and a fixture-sized compiler path instead of relying solely on static compatibility bytes.

Constraint: Camera/update serialization remains compatibility-only for the headless RL migration

Rejected: Port the full generated UpcreateCompiler table in one pass | current acceptance fixture only needs deterministic object create/update coverage

Confidence: medium

Scope-risk: narrow

Tested: npm run test:parity

Tested: npm run test:all

Not-tested: Arena/team/camera packet field groups outside the Phase C compatibility fixture
The C++ entity-core report now keeps owned entities separate from the manager's active lookup table, so deletion/clear behavior can preserve stale entity summaries while active IDs, camera lists, and other-entity lists are generated from actual manager state. Field-group mutation and wipe snapshots are now built through C++ setters instead of one static JSON block.

Constraint: Phase C must prove full-world deterministic parity before RL-localized views are introduced.

Rejected: Keep hardcoded manager arrays | it hid constructor classification bugs and weakened parity confidence.

Confidence: high

Scope-risk: narrow

Directive: Keep report values generated from C++ state mutations before expanding Phase C; do not reintroduce static manager snapshots.

Tested: npm run test:parity

Tested: npm run test:all

Not-tested: Full CameraGroup behavior beyond the existing minimal compatibility fixture.
Phase C still keeps camera/update serialization as a compatibility slice for the legacy protocol, but the report now exercises C++ camera table mutation, wipe behavior, and player-follow fallback instead of embedding those values as static JSON.

Constraint: The headless RL target needs full-world parity first while preserving minimal legacy camera/update compatibility.

Rejected: Keep camera follow snapshots static | it left the final Phase C compatibility gap unverified by C++ state changes.

Confidence: high

Scope-risk: narrow

Directive: Treat camera state here as compatibility-only until RL-localized views are introduced after full-world parity.

Tested: npm run test:parity

Tested: npm run test:all

Not-tested: Full ClientCamera networking/view update behavior; reserved for later runtime phases.
Phase D needs a deterministic TypeScript reference before any C++ gameplay port, so this adds a headless full-world tick fixture with a modeled damage interaction and golden conformance test.

Constraint: TypeScript remains the gameplay source of truth until C++ parity exists

Constraint: First RL-oriented baseline must prove full-world determinism before localized agent observations

Rejected: Start C++ gameplay immediately | no TS gameplay golden contract existed yet

Confidence: high

Scope-risk: narrow

Directive: Keep Phase D fixtures headless and deterministic before expanding to spawn managers or live WebSocket gameplay

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:conformance

Tested: npm run test:all
The Phase D TypeScript fixture now has a matching standard-library C++ report and a parity comparator, keeping C++ gameplay work scoped to the already-locked headless damage scenario.

Constraint: C++ gameplay must match the TypeScript golden report before expanding simulation scope

Rejected: Port broader gameplay managers now | spawn, boss, and live server behavior are still explicit non-goals for this slice

Confidence: high

Scope-risk: narrow

Directive: Expand gameplay parity one deterministic scenario at a time and update both TS golden and C++ report together

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run test:all
Broad gameplay porting should proceed only when the C++ path keeps proving parity and performance value, so this adds an explicit benchmark for the first Phase D gameplay report before expanding scope.

Constraint: The current benchmark includes process startup and TypeScript transpile overhead, so it is a migration signal rather than a final in-engine tick benchmark

Rejected: Port every gameplay system immediately | no broader performance gate or parity fixture exists yet

Confidence: high

Scope-risk: narrow

Directive: Add tighter in-process tick benchmarks as gameplay code moves from report emitters to reusable C++ engine modules

Tested: npm run bench:gameplay

Tested: npm run test:parity

Tested: npm run test:all
The next Phase D slice now proves a lethal headless collision path: onKill reward accounting, deletion animation state, and eventual manager removal are captured in the TypeScript golden fixture and matched by C++.

Constraint: Preserve full-world deterministic snapshots before per-agent RL observations

Rejected: Jump to tank/projectile systems | death reward/removal is a smaller deterministic bridge from collision damage

Confidence: high

Scope-risk: narrow

Directive: Keep adding one deterministic gameplay behavior per parity slice before introducing live server or spawn-manager randomness

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:conformance

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 2.602ms vs TS median 949.682ms, 364.98x speedup

Tested: npm run test:all
The third Phase D gameplay slice captures projectile-style kill propagation: a child damage source with an owner relation awards score to its owner while keeping the projectile score unchanged.

Constraint: Continue full-world deterministic parity before RL observation grids or live server integration

Rejected: Port full Bullet/Barrel classes now | owner propagation can be locked with a smaller synthetic living-entity fixture first

Confidence: high

Scope-risk: narrow

Directive: Use this owner-propagation baseline before introducing concrete tank projectile classes

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 2.716ms vs TS median 892.898ms, 328.75x speedup

Tested: npm run test:all
This slice captures the Bullet-style timing contract in a deterministic headless fixture: initial spawn speed, maintained acceleration, lifetime expiry, and deletion animation entry now match between TypeScript and C++.

Constraint: Keep using synthetic deterministic fixtures until concrete tank/barrel classes can be ported without random scatter or live client state

Rejected: Introduce full Barrel/Bullet construction now | projectile lifetime and motion can be proven before larger tank dependencies

Confidence: high

Scope-risk: narrow

Directive: Preserve this projectile timing baseline when replacing synthetic fixtures with concrete projectile classes

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 2.982ms vs TS median 936.968ms, 314.21x speedup

Tested: npm run test:all
This slice locks the minimal camera/player score contract used by tank gameplay: camera addScore/setScore mirrors into the focused player's score field and the C++ report now matches that full-world fixture.

Constraint: Keep camera/update serialization minimal, but preserve score state needed for headless gameplay parity

Rejected: Port full TankBody stat/level behavior now | score mirroring is the smaller deterministic prerequisite

Confidence: high

Scope-risk: narrow

Directive: Build future tank-level parity on this camera/player score baseline

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 3.238ms vs TS median 911.544ms, 281.51x speedup

Tested: npm run test:all
This slice locks ObjectEntity keepInArena behavior for headless gameplay: ordinary physical entities clamp to arena bounds plus padding while canEscapeArena entities preserve their out-of-bounds position.

Constraint: Full-world deterministic parity remains the gate before RL observation grids or live server replacement

Rejected: Port shape/spawn managers first | arena bounds are a smaller deterministic movement invariant needed by all object gameplay

Confidence: high

Scope-risk: narrow

Directive: Keep canEscapeArena semantics aligned with PhysicsFlags.canEscapeArena (1 << 8)

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 3.543ms vs TS median 1437.690ms, 405.78x speedup

Tested: npm run test:all
This slice locks the same-team collision gates that decide whether bodies interact before damage and knockback. The fixture proves noOwnTeamCollision suppresses same-team contact, onlySameOwnerCollision suppresses different-owner contact, and same-owner pairs still collide.

Constraint: RL-facing local views must be built after global full-world collision parity is stable

Rejected: Move directly to tank/body definitions | owner/team gates are lower-level deterministic rules that every tank/projectile path depends on

Confidence: high

Scope-risk: narrow

Directive: Preserve PhysicsFlags.noOwnTeamCollision and onlySameOwnerCollision checks before geometry/damage handling

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 3.710ms vs TS median 927.811ms, 250.08x speedup

Tested: npm run test:all
This slice locks the pre-geometry collision filters for headless gameplay. Zero-sided bodies, nonphysical bodies, and bodies already in deletion animation remain present in the world snapshot but do not exchange damage or knockback.

Constraint: Full-world snapshots must expose skipped bodies so later RL observation grids can distinguish existence from collision eligibility

Rejected: Collapse these cases into a single non-colliding fixture | separate body labels make future desyncs easier to localize

Confidence: high

Scope-risk: narrow

Directive: Keep collision eligibility checks ahead of geometry and damage resolution

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 4.137ms vs TS median 902.002ms, 218.03x speedup

Tested: npm run test:all
This slice locks the owned-projectile contact path against enemy solid walls. The C++ gameplay report now models team refs, solid-wall flags, projectile deletion, and wall knockback so maze/wall interactions stay debuggable before broader tank and shape ports.

Constraint: Headless RL training needs deterministic global wall/projectile behavior before local observation grids

Rejected: Delay wall behavior until full MazeWall port | the collision response is a smaller invariant that projectiles already depend on

Confidence: high

Scope-risk: moderate

Directive: Keep solid-wall owner/team checks aligned with ObjectEntity.receiveKnockback before changing projectile collision handling

Tested: node --test conformance/gameplay/golden.test.js

Tested: npm run test:cpp

Tested: node conformance/gameplay/compare-parity.js

Tested: npm run test:parity

Tested: npm run bench:gameplay | C++ median 4.337ms vs TS median 921.592ms, 212.50x speedup

Tested: npm run test:all
Future agents need a durable summary of the staged TypeScript-to-C++ migration, completed parity slices, verification commands, and the next safe porting steps before continuing gameplay work.

Constraint: TypeScript remains the reference implementation until C++ parity passes

Confidence: high

Scope-risk: narrow

Directive: Update docs/cpp-migration-status.md whenever new parity slices or migration constraints are added

Tested: documentation-only change; no code tests run
Review found several valid edge cases in the new C++ parity and e2e harness: benchmark env parsing could leave empty samples, protocol zigzag encoding used signed shifts, fixed-size entity/grid tables trusted IDs, and the unknown-gamemode websocket test expected a rejected open instead of an immediate close.

Constraint: TypeScript remains the behavior reference while C++ report binaries must be deterministic and memory-safe under invalid inputs

Rejected: Documenting the Node lower bound only | package engines should prevent unsupported Node versions from selecting node:test scripts

Confidence: high

Scope-risk: moderate

Directive: Treat external IDs and environment overrides as untrusted in conformance/report binaries

Tested: ITERATIONS=0 node conformance/gameplay/benchmark-parity.js

Tested: WARMUPS=abc node conformance/gameplay/benchmark-parity.js

Tested: npm run test:cpp

Tested: npm run test:parity

Tested: npm run test:e2e

Tested: npm run test:all

Tested: npm run bench:gameplay | C++ median 5.099ms vs TS median 1439.261ms, 282.26x speedup
Add C++ parity harness for deterministic headless migration
@Saaketh0 Saaketh0 closed this May 27, 2026
@Saaketh0
Copy link
Copy Markdown
Author

oops again sorry

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