docs: S2 contract — AP-155's static sphere-as-cylinder emission, both sites pinned
Both static publication paths emit an authored Setup Sphere as a base-anchored Cylinder (r, 2r) while the live path emits a Sphere for the same data — different narrow-phase dispatch and a route-dependent collision difference for the same object. The fix mirrors FromSetup's step-3 emission at both sites; the contract's first test is the route-independence property asserted shape-for-shape, and the dispatch test picks geometry where cap-hit and curve-hit verdicts differ so the sphere verdict is observable, not inferred. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2edfc70467
commit
ce0bfce1cf
1 changed files with 72 additions and 0 deletions
72
docs/research/2026-08-07-s2-static-sphere-contract.md
Normal file
72
docs/research/2026-08-07-s2-static-sphere-contract.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# S2 contract (Campaign S) — AP-155: static publication must emit authored Spheres as Spheres
|
||||
|
||||
**Date:** 2026-08-07 (overnight). **Scoped by:** the session lead.
|
||||
**Implementer:** one Sonnet agent. **Review:** dual Opus.
|
||||
|
||||
## The divergence (AP-155, narrowed to its surviving half)
|
||||
|
||||
Both static publication paths emit an authored Setup `Sphere` as a
|
||||
height-capped **Cylinder**:
|
||||
|
||||
- `src/AcDream.App/Streaming/LandblockPhysicsPublisher.cs` (~1018–1036)
|
||||
- `src/AcDream.Content/LandblockPhysicsContentBuilder.cs` (~672–690)
|
||||
|
||||
Identical code in both: `ShadowShape.Cylinder(radius = r*scale,
|
||||
cylHeight = 2r, base = origin*scale - r*ẑ rotated)`. The LIVE path
|
||||
(`ShadowShapeBuilder.FromSetup`, step 3) emits `ShadowShape.Sphere` for the
|
||||
same authored data. Consequences: (a) narrow-phase dispatch differs
|
||||
(CCylSphere tests vs CSphere tests — a mover meets a flat cap where retail
|
||||
meets a curved surface), and (b) the SAME object collides differently
|
||||
depending on whether it arrived as a landblock static or a live spawn —
|
||||
the route-dependence Campaign S's plan calls out. Retail's
|
||||
`CPhysicsObj::FindObjCollisions` dispatches Spheres to
|
||||
`CSphere::intersects_sphere` — there is no cylinder substitution anywhere
|
||||
in retail for this branch.
|
||||
|
||||
## The fix
|
||||
|
||||
Replace both emissions with `ShadowShape.Sphere`, mirroring
|
||||
`FromSetup` step 3's emission EXACTLY — same origin/scale composition, same
|
||||
guards (`Radius <= 0` skip stays). Read FromSetup first and copy its
|
||||
semantics rather than inventing; if FromSetup's sphere emission differs from
|
||||
what a plain mirror would produce here (e.g. BoundsCenter handling), STOP
|
||||
and report the difference instead of choosing.
|
||||
|
||||
Then check the ripple: `BuildFloodSpheres`' sphere branch (uncapped) now
|
||||
sees these as Spheres — flood behaviour matches the live path, which is the
|
||||
point. `RetailSphereCap` applies to the Cylinder branch only (AP-156's
|
||||
retirement of the 10-cap on non-cyl branches) — verify with a test, not by
|
||||
reading alone.
|
||||
|
||||
## Tests
|
||||
|
||||
1. Parity: for a representative Setup with authored Spheres, the static
|
||||
publication's registered shapes are shape-for-shape identical (type,
|
||||
local position, radius, scale) to `FromSetup`'s output for the same
|
||||
inputs. This is the route-independence property, asserted directly.
|
||||
2. Dispatch: a mover resolve against a statically-published sphere object
|
||||
takes the Sphere narrow phase (assert via outcome on a diagonal approach
|
||||
that distinguishes cap-hit from curve-hit: pick geometry where cylinder
|
||||
and sphere verdicts differ, assert the sphere verdict).
|
||||
3. Sabotage: restore the Cylinder emission at ONE site; tests 1 and 2 both
|
||||
redden; restore.
|
||||
4. Existing static publication and content-builder suites stay green.
|
||||
|
||||
## Measurement (report, not gate)
|
||||
|
||||
Count, over installed landblocks already swept by existing content tests
|
||||
(reuse their enumeration), how many static entities carry sphere-only
|
||||
Setups — the affected population. Three example object ids.
|
||||
|
||||
## Scope — OUT
|
||||
|
||||
Register/ISSUES edits (session lead). `ShadowShapeBuilder`,
|
||||
`ShadowObjectRegistry` internals. The live path. Anything about
|
||||
SortingSphere (AP-157 is measured and deferred).
|
||||
|
||||
## Acceptance
|
||||
|
||||
Full suite `dotnet test AcDream.slnx -c Release -m:1` green, totals
|
||||
reported; sabotage reported verbatim; nothing committed. Only
|
||||
`C:\Users\erikn\source\repos\acdream`, absolute paths, no subagents;
|
||||
contradictions → STOP and report.
|
||||
Loading…
Add table
Add a link
Reference in a new issue