After route 2 I pinned a falsifiable bet: routes 4-7 reuse the seam route 2 built, so their marginal cost should be well under 400 production lines, and if route 4 also cost ~900 the bet was dead. Scoping estimates 1,500-2,500 lines plus ~1,700 lines of test re-modelling. Honouring the bet: no implementation pass until the scope is re-planned. The bet failed for an instructive reason. The seam generalises fine — the begin/prepare/submit chain has no local-player precondition, the classifier's remote branches are already retail-exact, and all remote physics state is already in Runtime. Route 2 was simply not a representative unit: one entity vs N, one disposition vs four, one execution path vs two (canonical SetPosition AND the interpolation queue), no teleport hook, no constrain phase, two duplicate authorities vs six. Picking the simplest route first and then calibrating everything against it was the error. Four findings that change the campaign plan, not just route 4: - Route 4's Create half is already done (C3b/C3c). The remaining work is steady-state remote Position plus deletions; the route title misleads. - AP-131 cannot be retired by route 4. Route 2 did not fix its FORCE_POSITION half, and its local ordinary-Apply half is owned by no route in the inventory. - #277's safety bound breaks: it argues about Creates, while a steady-state Position can carry a remote out of the collision window with no Create at all. Needs a Position-time service-window guard on both hosts; the graphical host has no such predicate today. - N3 (headless never calls RetryPending) stops being latent the moment route 4 makes headless remotes produce placement receipts. Also records three previously unfiled divergences found while scoping: the NPC airborne hard-snap that ignores the wire IsGrounded bit, ConstrainTo armed before the operation instead of after, and ConstrainTo never armed on the remote teleport branch. Route 4 fixes all three by construction, which makes it a behaviour change to every visible creature rather than a refactor. Allocation is NOT the blocker the inventory feared: the steady state classifies to Interpolate, which runs no SetPosition at all. Recommends splitting route 4 into 4a (near/interpolate + airborne no-op — the observable win, no park hazard) and 4b (teleport/far/cellless — where the parks, the service-window guard, N3 and #277 live). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.3 KiB
C4 route 4 — scoping, and a stop-and-re-plan (2026-08-03)
Scoped at HEAD e3b766d9, after route 2 shipped. This is not a contract. The
scoping says route 4 is materially larger than the budget it was given, so the
correct next action is a user decision, not an implementation pass.
The budget, and how it failed
After route 2 I pinned a falsifiable bet: routes 4-7 reuse the seam route 2 built, so their marginal cost should be far lower — well under 400 production lines. If route 4 also costs ~900, the bet is dead and that is the signal to stop and simplify.
Estimate: 1,500-2,500 lines of new/changed production code, plus ~1,700 lines of test re-modelling. The bet failed before implementation started.
But it failed for a reason worth stating precisely, because it changes what to do about it: the seam generalises fine. Route 2 was just not a representative unit.
| route 2 | route 4 | |
|---|---|---|
| entities | 1 (local player) | N (every visible remote) |
| dispositions | 1 (ForcePosition) | 4 (SetPosition / SetPositionSimple / Interpolate / NoPositionOperation) |
| execution paths | 1 | 2 (canonical SetPosition and the interpolation queue) |
| teleport hook | never | BeforePositionOperation |
| constrain phase | never | AfterPositionOperation |
| duplicate authorities to delete | 2 | 6 |
| outbound ack | owns it | none |
| frequency | ~never | 5-10 Hz x N |
I chose route 2 first because it was simplest to reason about, then used it to calibrate everything after it. That was the error: a one-entity, one-disposition, no-interpolation route is the floor, not the median.
What is genuinely reusable (the good news)
- The begin/prepare/submit/commit chain is entity-kind agnostic — no
local-player precondition anywhere in
TryBeginExclusiveAuthoredPlacement→TryPrepareAndSubmitAuthoredPlacement→SubmitPreparedPlacementCore. - The classifier's remote branches are retail-exact already (verified against
CPhysicsObj::MoveOrTeleport@0x00516330 on all five behaviours). - The placement receipt → presentation path is already entity-agnostic; C3c drives remote Creates through it today.
- All remote physics state already lives in Runtime (J5.5) —
RemoteMotion,EntityPhysicsHost, the interpolation queue. No assembly boundary to cross. RuntimeAcceptedPositionDriveControlleritself is ~15-20% liftable — the architecture, not the code. It is single-entity and ack-owning by construction (_pendingis one slot andRetainPendingthrows on a second).
Four findings that change the campaign plan, not just route 4
1. Route 4's Create half is already done. C3b/C3c landed
RuntimeRemoteFirstEntryState + RuntimeRemoteBodyDescription and flipped both
hosts' Creates onto the residence conductor. Route 4's remaining work is
steady-state remote Position plus the deletions. The route title is
misleading and will send an implementer hunting for a flip that already happened.
2. AP-131 cannot be retired by route 4. The row covers two halves: the
!HasAnims gate on SetPlacementFrame, and the FORCE_POSITION branch skipping
unset_parent. Route 2 did not fix the second — it consumes an
already-merged snapshot, so a ForcePosition still passes
installPlacementFrame: true, clearParent: true. Retiring AP-131 needs the
unconditional merge gone for every Position: remote (route 4), local
ForcePosition (a route-2 residual), and local ordinary-Apply — which no route
in the eight-route inventory owns. Either widen route 4 or move AP-131 to C5
with those two as prerequisites. Pinning "route 4 retires AP-131" pins something
route 4 alone cannot deliver.
3. #277's bound breaks. Its safety argument is that the collision window is strictly larger than ACE's Create-broadcast group, so the far set is empty. That is a statement about Creates. A steady-state Position can carry a remote out of the window with no Create at all — a creature wandering off, or the >=96 m far-snap branch by definition targeting something distant. Route 4 introduces a second producer of far parks the radius argument never covered. Needs a Position-time service-window guard on both hosts; headless has the predicate, the graphical host has none and one must be built.
4. N3 stops being latent. The route-2 round-2 finding — headless never calls
RetryPending after construction, so a declined Place would wedge the ordered
stream — was filed as latent because headless remotes produced no placement
receipts. Route 4 makes them produce receipts for the first time. Fix N3 in
route 4 or the headless stream wedges.
Three unfiled divergences found during scoping
Our production remote path diverges from the retail classifier on five behaviours; three have no register row:
- NPC airborne hard-snap (
LiveEntityNetworkUpdateController.cs:1819-1823) writesBody.Position/Orientationand never consultsupdate.IsGroundedat all — it branches on the client-trackedrmState.Airborne. Retail returns 0 and writes nothing (@0x0051636D). ConstrainToarmed before the operation, unconditionally (:1522-1529), so it arms on the airborne no-op retail skips and anchors to the pre-move position on the far branch. Retail arms it after a nonzeroMoveOrTeleport, anchored to the post-movem_position(@0x00454254-@0x00454272).ConstrainTonever armed on the remote teleport branch (the path returns at:1504, before:1522), where retail does re-arm afterteleport_hook'sUnConstrain.
Route 4 fixes all three by construction — which means route 4 is a behaviour change to every visible creature in the game, not a refactor.
Allocation: not the blocker anyone feared
The inventory's "frame-frequency routes are blocked on placement allocation"
warning was written pre-C2 and before anyone checked which branch remotes take.
The steady state — nearby, grounded, non-teleporting — classifies to
Interpolate, which runs no SetPosition at all. The 944 B/op cost applies
only to teleports, cellless first placements, and >=96 m remotes.
Arithmetic (assumptions, not a capture): 40 remotes x 7 Hz with ~10% on a
SetPosition branch ~= 26 KB/s. Pathological dense-town worst case ~= 264 KB/s,
about 2.4% of the Slice-G5 profile. Not a blocker — provided the near branch
stays out of SetPosition. The contract must forbid routing every remote
Position through it "for uniformity".
Unmeasured and worth measuring before pinning a budget: the legacy path's actual
cost (no gate covers PhysicsEngine.SetPosition), and the real near/far split in
live play.
Route 4's one big advantage: it is trivially observable
Route 2 cost five review rounds largely because nothing a user could do would trigger it. Route 4 is the opposite — every remote entity exercises it continuously. Six checks, all within two minutes of ordinary play with a second character:
- Near interpolate — second character walks/runs in a circle 5-15 m away. Smooth motion, no per-packet stepping.
- Airborne no-op — they jump, and jump off a ledge. Clean parabola, clean landing. Watch for invisible-but-solid, the #184 signature.
- Far-snap — they run >96 m and back. No freeze at the boundary, no wrong Z.
- Remote teleport — portal/recall out and back, plus an admin
@teleto. Arrive grounded, animating, immediately targetable. - The leash — route 4 moves
ConstrainTofrom before to after, stops arming it on the airborne no-op, starts arming it on teleport. #167 was a leash bug. - Creature blast radius — pull a drudge, let it chase, melee it, let it die.
Weight this gate heavily. All four route-2 states were green and three were defective; route 4 finally has a real oracle.
The decision
Route 4 is worth doing — it fixes three unfiled divergences affecting every creature, retires the largest duplicate-authority cluster in the codebase, and builds the seam route 5 needs (the classifier gives Projectile identical branches to Remote). But it is a 1,500-2,500 line behaviour change, not a wiring job, and it should not start on a budget everyone knows is wrong.
Options, in the order I would rank them:
A. Split route 4 into 4a and 4b. 4a = the interpolation/near path plus the airborne no-op (the steady state, highest visible value, no park hazard, no service-window work). 4b = teleport/far/cellless, which is where the parks, the service-window guard, N3 and #277 all live. Each gets its own contract, gate and review. Roughly halves the blast radius per commit and puts the observable win first.
B. Do route 4 whole against a corrected budget (~2,000 lines, 2-3 implementation passes, one adversarial review per pass). Honest, but it is a large single commit touching every visible creature.
C. Defer route 4; do routes 5-7 first. Rejected — route 5 needs the same seam, so this just moves the cost.
D. Stop the campaign here and simplify instead. The complexity concern that
prompted the budget is real, and RuntimeSetPositionState at 5,652 lines is the
obvious target. But route 4 is where three live divergences get fixed, so
stopping leaves known-wrong behaviour in the client.
Recommendation: A. It respects the budget's intent — keep each landing small enough to review — without abandoning work that fixes real bugs. It also front- loads the part with a clean live gate and defers the part with the known traps.