The pinned contract plus the four review documents behind 6dc7ba51:
round 1 (retail FAIL 3 MAJOR / architecture FAIL 2 MAJOR) and round 2
(both PASS on the fixed diff).
Process findings worth carrying into the remaining routes:
1. The contract's 13 explicit "what must REMAIN true" invariants were the
fix for 4b-2's round-1 defect (a contract that said what must change but
not what must stay). They did NOT prevent a round-1 FAIL here. What the
round-1 MAJORs actually shared was a STRUCTURAL cause the invariant list
could not express: two parallel inline copies of the same routing tail.
An invariant list constrains behaviour; it cannot see duplication.
2. Both reviews independently found the same NPC synth-velocity defect
(retail R3 = architecture A2). Independent convergence on one finding is
the strongest signal this process produces — weight it accordingly.
3. The specified two-client gate could not have observed three of the four
MAJORs: it teleported a player character, and all three live on the NPC
arm. Caught by both reviewers before the gate ran, not after. Check that
a gate can structurally see the defect class it is gating.
4. A reviewer named a symbol that does not exist (RuntimeCollisionReportingState
.ForceEnd is a private helper, not the public entry point). The implementer
silently substituted the correct one (LeaveWorld) while reporting "no
disagreements with either review". Verify implementer claims against source
even when they report full agreement.
5. A new test asserted only what must NOT happen, so an emptied
ApplyWireAirborneLeftoverBookkeeping passed every test in the tree. Caught
in round 2 and closed with positive assertions, sabotage-verified. Negative
assertions alone cannot detect a deleted write.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
386 lines
22 KiB
Markdown
386 lines
22 KiB
Markdown
# C4 route 4b-3 — architecture / adversarial review (2026-08-04)
|
|
|
|
Reviewer lens: **adversary**. Retail conformance is a separate reviewer's
|
|
scope; this review asks only "does this break something, leak something,
|
|
deadlock something, or leave an entity in a bad state?"
|
|
|
|
Subject: the uncommitted working tree on `claude/acdream-physics-divergence-5aa784`
|
|
at base `3e002993` (`git diff HEAD` plus the three untracked non-contract
|
|
files). Contract:
|
|
[`2026-08-04-c4-route-4b-3-contract.md`](2026-08-04-c4-route-4b-3-contract.md).
|
|
|
|
## Verdict: **FAIL**
|
|
|
|
Two MAJOR findings. Both are behaviour REGRESSIONS against `3e002993` — not
|
|
pre-existing residuals — and both sit on code paths the contract's own
|
|
invariant list names as load-bearing (invariant 5, the arm-count partition;
|
|
invariant 6 / D3, "the hook's whole point is that no locomotion state
|
|
survives a teleport"). Both are invisible to the specified two-client
|
|
connected gate, because that gate teleports a *player* character and both
|
|
defects are on the NPC/creature arm.
|
|
|
|
Everything else I checked held. Build is green (0 warnings); focused suites
|
|
pass **Runtime 1,125 / 0 skips** and **App 4,078 / 3 skips** at Release with
|
|
`--no-build`.
|
|
|
|
---
|
|
|
|
## What I verified and found sound (do not churn)
|
|
|
|
- **Invariant 1 (`StoresAcceptedDestination`).** `ApplyAcceptedRemoteTeleport`
|
|
(`src/AcDream.Runtime/Session/RuntimeRemotePlacementDriveController.cs:820-848`)
|
|
is byte-for-byte the far arm's shape minus the `StopInterpolating` clear,
|
|
including the currency-guarded `StoreAcceptedDestinationPose`. The partition
|
|
is extended, not re-litigated.
|
|
- **Invariant 3 (no stranded entity).** The teleport arm reaches
|
|
`SubmitAndResolve` through the *same* `TryExecuteAcceptedRemotePosition`
|
|
the far arm uses; the `DeferredCell` arm still cancels synchronously with
|
|
`restoreCancelledPark: true`. No new park shape, no new withdrawal site.
|
|
- **Invariant 10.** `TickLostCellDeadlines` / `TryDequeueExpiredLostCell` /
|
|
`ArmLostFamilyDeadlines` still have zero production callers (4 references,
|
|
all inside `RuntimeSetPositionState.cs`; the rest are tests). The reaper
|
|
stays inert.
|
|
- **Invariant 11 (route 1 unchanged).** The shared builder got an *overload*,
|
|
not a third copy, and the route-1 overload forwards
|
|
`committedCellId: canonical.FullCellId` — its pre-slice value verbatim
|
|
(`RuntimeAcceptedPositionRouteRequests.cs:41-56`).
|
|
- **D1's plumbing is honest.** `PreMergeCommittedCellId = hadCanonical ? beforeCell : null`
|
|
is measured before `RefreshSnapshot`
|
|
(`RuntimeEntityObjectLifetime.cs:1725-1770`), never re-read, and `null`
|
|
("no prior canonical record") makes `TryBuild` decline rather than fabricate
|
|
a 0. `RuntimeRemoteTeleportClassificationTests` genuinely discriminates the
|
|
fix from the shipped dead predicate — the companion test fails under the
|
|
post-merge read. This is the strongest test in the diff.
|
|
- **The `_activePlacementOwners` deletion is legitimate** — see item 1 below.
|
|
- **Shadow suspend/restore across the hook.** `RemoteTeleportHook`'s
|
|
`ReportCollisionEnd` → `ShadowObjects.Suspend` removes the entity from
|
|
`_entityToCells`; the arm tails' `LiveEntityShadowPublisher.TryPublishRemote`
|
|
→ `ShadowPositionSynchronizer.Sync` → `RefreshPositionRows` un-suspends it
|
|
(`ShadowObjectRegistry.cs:1336-1393`). I specifically checked for a
|
|
pose-gate that could skip the restore on a zero-distance teleport: the
|
|
OnPosition-tail overload is **ungated** (`RuntimeRemotePhysicsUpdater.cs:1175-1191`);
|
|
only the per-tick loop gates. `TeleportRefused_…`'s
|
|
`Assert.Single(fixture.Shadows.AllEntriesForDebug(), …)` is a real proof of
|
|
this, because `AllEntriesForDebug` enumerates `_entityToCells`.
|
|
**No invisible-and-intangible entity on this path.**
|
|
- **Deletion completeness.** All eight wiring sites in the contract's
|
|
inventory are cut, including the two the handoff missed
|
|
(`SessionPlayerComposition`, `LiveSessionResetManifest`). Reset coverage is
|
|
genuinely preserved: `GraphicalSessionEventRoute.cs:152` calls
|
|
`_remotePlacementDrive.DetachRoute`.
|
|
- **Register bookkeeping.** AD-42, AP-136, AP-137, AP-138 all updated in the
|
|
diff; AP-138's Risk column does gain the teleport arm as a second producer,
|
|
and AP-137 is rewritten rather than deleted. (One factual defect in the
|
|
AP-137 rewrite — see A7.)
|
|
|
|
---
|
|
|
|
## MAJOR findings
|
|
|
|
### A1 (MAJOR) — the NPC arm silently stops arming `ConstrainTo` for every airborne-body packet; the code documents the opposite
|
|
|
|
**File:** `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:1290-1311`
|
|
(`ToConstraintArm`), consumed at `:2643`.
|
|
|
|
`ToConstraintArm` maps `RemoteContactArm.AirborneSnap` through its `_` arm to
|
|
`RuntimeRemoteAcceptedPositionArm.AirborneNoOperation` — the one value
|
|
`TryArmConstraintAfterOperation` never arms — and justifies it at `:1296-1297`
|
|
with:
|
|
|
|
> *"There is no Runtime analogue of `AirborneSnap` (a caller reaching it
|
|
> always returns before any arming call) … production never calls this with
|
|
> that arm."*
|
|
|
|
**That claim is false for the NPC arm.** After
|
|
`npcRouting = ApplyRemoteContactRouting(…)` at `:2600`, the only early return
|
|
is the currency guard at `:2619-2626`, which is gated on
|
|
`FarSnapPlacement or TeleportPlacement`. Control then falls out of the
|
|
`if (!snapSuppressedByStick || isTeleportRoute)` block straight into
|
|
`TryArmConstraintAfterOperation(ToConstraintArm(npcRouting.Arm), rmState)` at
|
|
`:2641-2644`. `AirborneSnap` is returned by
|
|
`ApplyRemoteContactRouting`'s free-flight carve-out at `:1123-1150` for **any**
|
|
non-teleport classification whenever `!remote.Body.InContact`.
|
|
|
|
**Concrete failure scenario.** A creature remote (guid not `0x50xxxxxx`) is
|
|
knocked off a ledge or jumps, so its canonical body has no contact plane
|
|
(`Body.InContact == false`). ACE broadcasts a wire-grounded `UpdatePosition`
|
|
(`IsGrounded: true`) at 5-10 Hz. The classifier returns `Interpolate`
|
|
(`playerDistance < 96 m`). Routing takes the airborne carve-out →
|
|
`AirborneSnap` → `ToConstraintArm` → `AirborneNoOperation` → **no arm**.
|
|
|
|
At `3e002993` the same packet armed: the post-operation site was passed the
|
|
ROUTE (`earlyRemoteRoute`), and `OwnsAfterOperationConstraint(Interpolate)` was
|
|
true with `ConstrainAfterRouting` true. So the arm count for this row goes
|
|
**1 → 0**, which is the "never zero times" half of contract invariant 5 and a
|
|
`yes` row of D4's partition table turning into a `no`. Retail's near branch
|
|
returns 1 @0x005163BE, so `HandleReceivedPosition` arms unconditionally
|
|
@0x00454272 — the divergence is in the wrong direction. The same 1→0 applies
|
|
to a far (`SetPositionSimple`) classification and to a null/`Rejected*`
|
|
classification whenever the NPC's body is out of contact.
|
|
|
|
Observable consequence: a creature that is knocked airborne on the **first**
|
|
accepted Position after spawn never sets `IsConstrained` at all, so the
|
|
`ConstraintManager` brake and `IsFullyConstrained()` (which gates
|
|
`jump_is_allowed`) stay dead for it; a creature already armed loses the
|
|
per-packet re-anchor (`ConstraintPosOffset` reset to 0) for the whole airborne
|
|
interval.
|
|
|
|
**Why no test caught it.** Proof obligation 3 asked for "a test that counts
|
|
arming calls per packet across the partition table's rows". What was delivered
|
|
(`RuntimeRemoteSteadyStatePositionTests.TryArmConstraintAfterOperation_MatchesTheCompletePartition`)
|
|
tests the Runtime *predicate* given an already-chosen arm value. Nothing tests
|
|
`ToConstraintArm`, and nothing counts arms per packet through `OnPosition`.
|
|
The mapping — the only new code in the arming path — is 100 % uncovered.
|
|
|
|
**Fix direction.** `AirborneSnap` is not `AirborneNoOperation`: retail's
|
|
airborne *no-op* is `arg4 == 0` (the WIRE contact bit, return 0), while
|
|
`AirborneSnap` is acdream's carve-out keyed on the BODY's contact for a packet
|
|
whose wire bit said grounded — retail returns nonzero for that packet and
|
|
arms. Either map `AirborneSnap` to an arming value, or (better) make
|
|
`ToConstraintArm` total with an explicit `AirborneSnap` case plus a
|
|
`_ => throw`, and add the missing end-to-end arm-count test across the D4 rows
|
|
including the body-airborne ones.
|
|
|
|
---
|
|
|
|
### A2 (MAJOR) — a teleported NPC gets a ~1,000 m/s synthesized `ServerVelocity` and an animation cycle planned from it
|
|
|
|
**File:** `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2526-2543`
|
|
(synthesis) and `:2683-2709` (consumption).
|
|
|
|
The NPC arm synthesizes a locomotion velocity for any packet that carries no
|
|
wire velocity:
|
|
|
|
```
|
|
serverVelocity = (worldPos - rmState.LastServerPos) / (float)elapsed; // :2532
|
|
… rmState.ServerVelocity = authoritativeVelocity; HasServerVelocity = true;
|
|
```
|
|
|
|
`rmState.LastServerPos` is only advanced at `:2681`, i.e. **after** routing, so
|
|
at `:2532` it still holds the pre-teleport position. For an admin teleport the
|
|
delta is the whole teleport distance over one packet interval — e.g. 192 m /
|
|
0.15 s ≈ 1,280 m/s. The tail then calls
|
|
`RemoteServerControlledVelocityCycle.Apply(update.Guid, ae, rmState, rmState.ServerVelocity)`
|
|
at `:2704-2709`, which runs `ServerControlledLocomotion.PlanFromVelocity` and
|
|
`Sequencer.SetCycle(style, plan.Motion, plan.SpeedMod)`.
|
|
|
|
At `3e002993` this was unreachable for a teleport: the `remotePlacementRequired`
|
|
block sat in the SHARED section, **above** the `IsPlayerGuid` split and above
|
|
the NPC synth-velocity code, and it always `return`ed. The diff deleted that
|
|
block and routed the teleport through the NPC tail instead, so the synthesis
|
|
now runs on every NPC teleport.
|
|
|
|
**Concrete failure scenario.** `@teleto` a drudge 200 m away while an acdream
|
|
client observes it. The teleport arm places it correctly, then the same packet
|
|
installs `ServerVelocity ≈ 1.3 km/s` and calls `SetCycle(Run, speedMod≈huge)`.
|
|
`RemoteServerControlledVelocityCycle.Apply`'s three guards do not help: the
|
|
body is grounded after the commit (`rm.Airborne == false`), the guid is not a
|
|
player guid, and `rm.MoveTo` was just set to `Invalid` **by the teleport hook's
|
|
own `CancelMoveTo`** — so the hook actively removes the last thing that would
|
|
have suppressed this. The creature stands at the destination playing a
|
|
run/sprint cycle at an absurd speed multiplier until the stale-velocity
|
|
watchdog fires (`ServerControlledVelocityStaleSeconds = 0.60`) or the next
|
|
packet's small delta replaces it.
|
|
|
|
This is directly contrary to `teleport_hook`'s purpose (@0x00514ED0 exists so
|
|
that *no* locomotion state survives a teleport) and is exactly the
|
|
"stands with correct animation" clause of the contract's live gate — which
|
|
cannot see it, because the gate teleports a player character and
|
|
`RemoteServerControlledVelocityCycle.Apply` early-returns for `0x50xxxxxx`
|
|
guids. The player-remote arm is accidentally immune because its own teleport
|
|
block returns at `:2185`, before the player synth-velocity at `:2432-2443`.
|
|
|
|
**Fix direction.** The teleport arm must suppress the synthesized velocity for
|
|
its own packet on the NPC arm too — either by advancing
|
|
`rmState.LastServerPos` to the destination before the synthesis, or (cleaner,
|
|
and symmetric with the player arm) by giving the NPC teleport its own tail
|
|
that skips the synth/cycle step. Whichever is chosen, add a test that asserts
|
|
the NPC sequencer's cycle is unchanged across a teleport packet; today nothing
|
|
in the tree looks at the animation layer for this arm.
|
|
|
|
---
|
|
|
|
## MINOR findings
|
|
|
|
### A3 (MINOR) — the stress test's teleport step now drives zero production code
|
|
|
|
**File:** `tests/AcDream.App.Tests/World/LiveEntityLifecycleStressTests.cs:710-730`.
|
|
|
|
The contract's deletion inventory says `LiveEntityLifecycleStressTests`
|
|
"constructs the controller and calls `TryApply` — its scenario must be
|
|
re-expressed against the canonical teleport arm, not dropped."
|
|
`BeginDeferredTeleport` is now four hand-written field assignments
|
|
(`_remote.Body.Position = destination; _remote.CellId = …;
|
|
Entity.SetPosition(…); Entity.ParentCellId = …`). It exercises no placement,
|
|
no hook, no routing. `RepeatedRetailRecallMotion_HiddenTeleportUnhide_…`
|
|
(`:252-296`) would pass identically if the entire teleport arm were deleted.
|
|
The Hidden/DeferredShadowRestore half of the scenario still discriminates, so
|
|
this is a coverage loss rather than a false pass — but the mid-teleport
|
|
Hidden/UnHide interaction the fixture exists for is no longer tested against
|
|
the mechanism that now performs the teleport.
|
|
|
|
### A4 (MINOR) — `TeleportRefused_…` does not discriminate the teleport arm from `UnroutedCatchUp`
|
|
|
|
**File:** `tests/AcDream.App.Tests/Physics/LiveEntityNetworkRemoteTeleportPresentationTests.cs:157-206`.
|
|
|
|
Every assertion in this test (`body.Position == destination + offset`,
|
|
`Entity.Position == body.Position`, `IsSpatiallyVisible`, one shadow entry at
|
|
`body.Position`) is also satisfied if the packet had classified `null` and
|
|
taken `UnroutedCatchUp` → `ApplyInterpolate`, because the body-to-target
|
|
distance is >192 m so AP-87's `bodyToTarget > 4 m` branch hard-places the body
|
|
at exactly the same wire pose and the same NPC tail then syncs entity and
|
|
shadow. The test *does* catch removal of the `store_position` fallback, so it
|
|
is not worthless, but the sibling commit test is the only one whose expected
|
|
value (`+ FootSphereCenterLift`) can only come from a canonical placement.
|
|
Adding one `Assert.Equal(0u, …)`-style discriminator (or asserting the hook
|
|
ran, as the routing-seam tests do) would close it.
|
|
|
|
### A5 (MINOR) — the landing block's new comment states something false
|
|
|
|
**File:** `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2266-2272`.
|
|
|
|
> *"A landing packet always classifies Interpolate (the teleport/cell-less arm
|
|
> dispatches earlier and returns before this block can be reached — D5)."*
|
|
|
|
The teleport half is true; "always classifies Interpolate" is not. The landing
|
|
block is reached for a wire-grounded, body-out-of-contact packet with ANY
|
|
non-teleport, non-airborne-no-op classification — including `SetPositionSimple`
|
|
(>= 96 m), `null` (login window), `RejectedAuthority`, and `RejectedData`. The
|
|
hard-coded `RuntimeRemoteAcceptedPositionArm.NearInterpolate` at `:2273` still
|
|
produces the correct arm count for all of those (every one of them is an
|
|
"arms" row), so this is a comment defect, not a behaviour defect — but process
|
|
rule 6 is explicit, and this is exactly the shape ("a comment asserting
|
|
behaviour the code no longer has") that six consecutive slices have shipped.
|
|
|
|
### A6 (MINOR) — new per-packet allocations on the remote hot path
|
|
|
|
**File:** `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2148-2153`,
|
|
`:2370-2374`, `:2609-2613`, and `:1080-1088`.
|
|
|
|
`runTeleportHook: () => RunRemoteTeleportHook(update.Guid, entity.Id, () => IsCurrentPositionOwner(entity))`
|
|
captures `update`, `entity` and `this`, so a display-class + delegate pair is
|
|
allocated for **every** remote accepted Position, not only for teleports (the
|
|
pre-slice tree allocated the inner lambda only when `remoteHardTeleport` was
|
|
true). Separately, `teleportStatus.ToString()` at `:1087` is evaluated at the
|
|
call site, so the probe's own `ProbeRemoteTeleportEnabled` self-guard does not
|
|
prevent the string allocation. Given Slice I's "0 B/resolve" discipline this
|
|
is worth a `Func<bool>` cached per controller, or hoisting the probe behind
|
|
`if (PhysicsDiagnostics.ProbeRemoteTeleportEnabled)` at the call site.
|
|
|
|
### A7 (MINOR) — D2's "unifies the player and NPC arms" is not delivered, and AP-137 now claims it was
|
|
|
|
**Files:** `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2186-2210`;
|
|
`docs/architecture/retail-divergence-register.md` (AP-137 row, the "**D2 — the
|
|
wire-airborne leftover shape**" sentence).
|
|
|
|
The retail return-0 shape is implemented only inside the `IsPlayerGuid` block.
|
|
On the NPC arm a wire-airborne packet with a null/`Rejected*` classification
|
|
still falls through the synth-velocity block into
|
|
`ApplyRemoteContactRouting`, which either hard-snaps the body (`AirborneSnap`,
|
|
if the body is also out of contact) or **enqueues/places** it
|
|
(`UnroutedCatchUp` → `ApplyInterpolate`, if the body is in contact) and then
|
|
syncs the render entity and publishes the collision shadow. That is not
|
|
"AP-135's two bookkeeping writes only, no body/queue/render write, no leash
|
|
arm, return". The register row's claim that this "unifies player and NPC
|
|
remotes on one behaviour" is therefore factually wrong as shipped, which is a
|
|
register-rule-1 problem in its own right. (This is NOT a regression against
|
|
`3e002993` — the NPC arm behaved this way before — so the fix can legitimately
|
|
be "scope the row to the player arm" rather than "implement the NPC half".)
|
|
|
|
### A8 (MINOR) — dead local
|
|
|
|
`src/AcDream.Runtime/Entities/RuntimeEntityObjectLifetime.cs:1727`:
|
|
`bool wasCellless = hadCanonical && beforeCell == 0u;` has no remaining reader
|
|
(only the comment at `:1759` mentions it). No compiler warning fires because
|
|
the initializer is not a constant. Delete it or the comment will outlive the
|
|
variable's meaning.
|
|
|
|
### A9 (MINOR) — proof obligation 1 is not stated anywhere in the tree
|
|
|
|
The contract requires the `ParkCollisionResidents`-overlap-throw
|
|
unreachability argument (with 4b-1's B2 caveat about
|
|
`HasOldPrefixPlacementDebt` being a stall rather than a throw) to be stated
|
|
"in the contract-conformance section of the implementation commit". The work
|
|
is uncommitted, so I cannot verify it; nothing in the diff carries the
|
|
statement. The underlying property does hold by reading — the teleport arm
|
|
adds packets to the same one-operation-per-key machinery and opens no new
|
|
operation shape — but the statement is still owed.
|
|
|
|
### A10 (MINOR, partly unverified) — the visibility-edge protection `_activePlacementOwners` provided has no replacement
|
|
|
|
I independently traced the deletion the implementer reported (item 1 of the
|
|
task). **Their conclusion is right, their stated reasoning is not.**
|
|
`_activePlacementOwners` was NOT write-never at `3e002993`: the writer chain
|
|
was `LiveEntityNetworkUpdateController` (`remotePlacementRequired` →
|
|
`_remoteTeleportController.BeginPlacement`) → `RemoteTeleportController.BeginPlacement`
|
|
→ `RemoteTeleportPlacementPresentation.Begin` →
|
|
`LiveEntityPresentationController.BeginAuthoritativePlacement`
|
|
(`RemoteShadowPlacementSynchronizer.cs:48` at HEAD). It becomes write-never
|
|
*because this slice deletes that chain*, which is exactly what the contract's
|
|
deletion-inventory row said. `git grep` over `src` + `tests` at HEAD confirms
|
|
no other production writer. So deleting the set and its four `IsPlacementActive`
|
|
gates changes nothing for any surviving path, and the four gates degenerating
|
|
to "always act" is correct.
|
|
|
|
What is not replaced is the *protection*: during the old multi-frame pending
|
|
placement, an intervening Hidden/UnHide edge was prevented from restoring a
|
|
shadow at an unresolved pose. The new teleport is synchronous inside
|
|
`OnPosition`, which mostly removes the window — but the canonical placement
|
|
publishes its receipt synchronously and the projection sink can raise a
|
|
visibility edge from inside it. I could not construct a reachable
|
|
Hidden/UnHide-during-placement path in the new design and am flagging this as
|
|
**unverified**, not as a defect.
|
|
|
|
---
|
|
|
|
## Judgment on the three reported items
|
|
|
|
**1. `_activePlacementOwners` deletion — sound, reasoning wrong.** See A10.
|
|
The set had a real production writer at HEAD; it is the slice's own deletions
|
|
that kill it. The four consumers' degeneration is behaviour-neutral for every
|
|
surviving path. Not a defect. The commit message should say "its only writer
|
|
is deleted by this commit", not "the predicate was permanently false".
|
|
|
|
**2. The two parallel `OnPosition` copies — a genuine structural hazard, and
|
|
it has already produced a defect.** This is not a stylistic complaint: A2 is
|
|
precisely the two copies disagreeing. The player copy's teleport block returns
|
|
at `:2185` before its synth-velocity at `:2432`; the NPC copy has no teleport
|
|
block at all and falls through its synth-velocity at `:2526` on the way to
|
|
routing. A1 is the second instance — the player copy cannot produce
|
|
`AirborneSnap` (its landing block returns first) while the NPC copy can, so
|
|
the shared `ToConstraintArm` was written against the player copy's reality and
|
|
is wrong for the NPC one. The implementer's own report that "a sabotage of the
|
|
wrong copy left both tests green" is the same signal. The duplication should
|
|
be collapsed, or at minimum every arm tail should be one shared helper that
|
|
both branches call; shipping a third slice against these two copies without
|
|
that is how the next one of these lands.
|
|
|
|
**3. Declining D7 (consolidating the post-placement currency guard into a
|
|
Runtime seam) — acceptable, and not the source of either MAJOR.** The guard is
|
|
now duplicated at three App call sites (`:2155-2161`, `:2393-2399`,
|
|
`:2619-2626`) instead of two. I checked all three: the predicate is
|
|
character-identical (`!IsCurrentPositionOwner(entity) || !ReferenceEquals(positionRecord.RemoteMotionRuntime, rmState)`),
|
|
and all three sit BEFORE their arming call, preserving the R5 invariant. The
|
|
widened arm predicate (`FarSnapPlacement or TeleportPlacement`) is applied
|
|
consistently at the two that need it; the teleport-specific site is
|
|
unconditional, which is strictly stronger. So the duplication is not itself a
|
|
correctness hazard today. It is, however, the same duplication-of-invariant
|
|
pattern as item 2, and a fourth copy (route 5's projectile arm) is next in the
|
|
queue — consolidating it is now overdue rather than optional.
|
|
|
|
---
|
|
|
|
## Gate status observed
|
|
|
|
- `dotnet build AcDream.slnx -c Release` → **succeeded, 0 warnings, 0 errors**.
|
|
- `dotnet test tests/AcDream.Runtime.Tests -c Release --no-build` →
|
|
**1,125 passed / 0 skipped / 0 failed**.
|
|
- `dotnet test tests/AcDream.App.Tests -c Release --no-build` →
|
|
**4,078 passed / 3 skipped / 0 failed**.
|
|
- Complete-solution Release suite: **not run by this reviewer** (the contract's
|
|
own gate; the new figure still has to be measured and recorded, not
|
|
inherited from 11,027).
|
|
- Two-client connected teleport gate: **not run**, and note the finding above
|
|
that neither MAJOR is observable through it as specified — A1 and A2 both
|
|
need a *creature* teleport (`@teleto` a drudge/mosswart into view), not a
|
|
second player character.
|