Phase 1 / Forge / forge_3d orchestration: PhysicsWorld and ECS Transform synchronisation - #72
Draft
guysenpai wants to merge 18 commits into
Draft
Phase 1 / Forge / forge_3d orchestration: PhysicsWorld and ECS Transform synchronisation#72guysenpai wants to merge 18 commits into
guysenpai wants to merge 18 commits into
Conversation
Moves the eleven-step cycle of `engine-physics-solver.md` §1.7 out of the acceptance suite that held the only composition of it and into `forge_3d/world.zig`. The call sequence, the arguments and the arithmetic are the ones the eight committed witnesses were taken over: the reparenting changes who calls, never what is computed. Cycle ownership: - `PhysicsWorld` holds the shape store, the body store, the broadphase, the warm-start cache, the island partition and the per-tick scratches - `step()` reads as the cycle: nine stage methods in the frozen order, with the two code-free anchors (3 read-only, 5 bis empty) as comments where they run - each stage method begins with its own `enter()`, so a stage cannot be moved without its record moving — a recorder wired at the call site would be blind to the one mutation it exists to catch - `tests/solver_test.zig` keeps the name `World` as an alias, so the ten suites that drive a world all drive the same owner Step 10 bis is UNCONDITIONAL: - the harness gated it on a `sensors_on` flag defaulting to false, which for a production world means sensors silently do not work - `SensorState.update` takes a `*const BodyManager`, so the pass cannot alter a bit of body state and making it unconditional leaves every witness identical Telemetry: - `SolverStats.warm_start_injections` counts constraint POINTS injected, summed over substeps — not part of what §1.8.2 reports, and the only place the application half of warm start is observable - `applyWarmStartRange` returns the count it injected Tests: - `tests/world_test.zig`: the step order read as an order, the substep cadence with its paired one-substep negative, and step 10 bis on a world that was never told about sensors - the declared per-platform test floor re-derived from the suite: 1869 -> 1875
F1 — probe C claimed "a record moved away from its work is undetectable by any test here", which its own batch refutes: swapping two stage BODIES executes the work in the same order as swapping their CALLS, so on a consequential pair the physics guards fire identically. Measured, not deduced — probe C' on (build_constraints, island_partition) gives 3 failed, 35 crashed with the order test passing, i.e. probe D minus the order test. Both pairs are now named, the claim is bounded to the physically harmless case, and what the test guards ALONE is stated: the 10 / 10 bis adjacency, where probe A reports 1 failed of 561. F2 — `warm_start_injections` moves into a named `not_reported` sub-struct of `SolverStats`. §1.8.2's exclusion was carried by a doc comment, so it rested on whoever later maps the struct onto the reported telemetry surface; it is now carried by the type and visible at every read site. The counter stays where the injection happens. F3 — the order test is renamed to say what it measures: the nine CODED steps of an eleven-anchor cycle, not eleven steps.
The counter-factual refuted its own prediction and had to be read further: under the "tag before publishing" defect BOTH halves of the sleeping test fail, because the unpublished final velocity stays in the ECS and sync-in pushes it back as an activating write, waking the sleeper on 29 of 30 ticks. Closing that channel separates them — with Velocity removed the immobility half passes while the published pose is off by 1.88e-5 m, which is the value half doing the work the structural claim credits it with. Also records the review's 157-line correction with its instrument, so the figure and the recipe above it stop naming different byte strings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gate D's count was copied from Gate C and read "unchanged" while the true value had moved: Gate C bis added the moveKinematic test and journaled no count, so the comparison ran against a baseline one gate stale. Measured in a worktree at each of the four heads, the series is 561 / 564 / 570 / 571 / 571, and the missing Gate C bis line is added — leaving a gate without its count is the mechanism, not the arithmetic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brief
briefs/m1.1.15-physics-world-orchestration.mdDRAFT, opened at the first gate as
engine-development-workflow.md§4.4 requires:ci.ymlfires onpull_requestand not on a branch push, so a gate whose exit depends on a matrix cell is unreachable until the PR exists. Gate A's exit is exactly that — the eight committed determinism witnesses byte-identical on the twelve-cell matrix, and the four CHAIN witnesses are x86_64 artifacts that no local corner can verify.No
Witness-regen:trailer appears anywhere in this branch, and none will. A red witness here is a defect to isolate, not an act to declare.Summary
forge_3dhad every mechanism the arena needs and no owner for the tick that runs them. This milestone creates that owner:PhysicsWorldexecutes the eleven steps ofengine-physics-solver.md§1.7 in their frozen order, wires the pieces the body store cannot wire from inside, and connects the solver to the ECS in both directions.Gate progress
PhysicsWorldand the tickGate A — what landed
tests/solver_test.zig— where its only composition lived, driven by ten suites — intoforge_3d/world.zig. Call sequence, arguments and arithmetic unchanged: the reparenting changes who calls, never what is computed.step()reads as the cycle: nine stage methods in order, plus the two code-free anchors as comments where they would run (3 read-only, 5 bis the empty composite seam of §1.7.3). Each stage method opens with its ownenter(), which is what binds the recorded order to the executed one.sensors_onflag defaulting tofalse; in production that reads "sensors silently do not work".SensorState.updatetakes a*const BodyManager, so the pass cannot alter a bit of body state and the change is witness-neutral by construction.SolverStats.warm_start_injections— real injections, not loop turns. Documented as NOT part of what §1.8.2 reports; see the brief's Notes, and flagged there for your call.Gate A — measurements
Determinism instrument, all four local corners green (
{Debug, ReleaseSafe} × {f32, f64}, macOS aarch64): self-reproducible, the four discrete traces byte-identical to the committed witnesses, no divergence withinK = 60. The four chain witnesses readREPORTED, not gatedon this host because level 1 is intra-ISA — that is the matrix's half of the exit.Counter-factuals, four RUN, and the fourth is a residual rather than a confirmation:
1 failedof 561 — the order test, that adjacency's only guardexpected 16, found 4, plus 6 physics tests4 failed, 35 crashed— where order matters physically, dozens fireenter()Probe C is the honest limit: a record separated from its work is undetectable by any test here. What bounds it is structural — each
enter()is the first statement of the stage method carrying its name — and that is a smaller claim than "the order is verified", stated as such inworld.zigand in the test.Counts, with their denominators.
zig build test-forge-3dcollects 561 on this branch (560 pass, 1 skip) against 555 onmainate02d27b, measured in a worktree, both macOS aarch64:+6, the six blocks added intests/world_test.zig. Full suite 1875 collected. Thedead-testsdeclared floor was re-derived from the SUITE (1875), never from the closure's own arithmetic.One test assertion removed, declared in the brief's Recorded deviations:
expect(s.world.sensors_on)in the determinism scenario had no flag left to read. It is replaced by two assertions obtained by different mechanisms — the scenario's trigger asserted on the body's ROLE, and the unconditional pass asserted on the STATE it produces, intests/world_test.zig.Local gates
zig buildcleanzig build test— 1875 collected, 1856 pass, 19 skipzig build test-forge-3d— 561 collected, 560 pass, 1 skipzig fmt --checkgreen oversrc/ tests/ bench/ tools/ build.zigzig build lintgreen,dead-testsconservation reconciled at 1875zig build forge-determinismgreen on the four local corners