docs: record the direct-edit client and side conventions
Three of this task's defects were cross-layer wiring rather than logic, so they belong in the spec where the next session will read them, not only in the task's research notes. Frontend: a new client spec covering layer ownership (baseline is never written, preview hides rather than overwrites), why a handle carries only its id, why a handle's position must derive from the clamped value, the ban on computing inside a setState updater, and why per-pointermove React state is the wrong owner of per-frame feedback. Backend: the left/right convention now states the three places that must agree and why a sign convention can be wrong on both sides of the wire at once; a table of the four profile fields the geometry stage actually reads, so nobody builds UI for interval-scoped editing again before the compiler honours it; and the save-is-not-applying contract, including that compileFresh must be installed by every path that sets session.area. Also records that an identity test cannot catch an ignored editsFile, and that a regression test is only trustworthy once it has been seen to fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -94,3 +94,56 @@ saveEditDocument(activeEdits, { ...draft, documentVersion: current.documentVersi
|
||||
|
||||
The service checks the version before the atomic version-bumping write, while
|
||||
the pure resolver remains reusable by preview and formal compilation.
|
||||
|
||||
## 8. Left and right
|
||||
|
||||
`left` is `heading - 90`. Three places agree and must keep agreeing:
|
||||
|
||||
- `offsetLine()` (`native-road.js`) offsets a positive value counter-clockwise
|
||||
from the direction of travel, i.e. toward geographic left.
|
||||
- `centerlineShift = (edgeOffsets.left - edgeOffsets.right) / 2`, so widening the
|
||||
left edge moves the centerline left.
|
||||
- Sidewalks use `heading + (side === 'left' ? -90 : 90)`.
|
||||
|
||||
The handle manifest reports `axisAzimuth = tangent + 90` for both sides, which is
|
||||
therefore *right*. Handle placement must offset the left handle by `tangent - 90`.
|
||||
|
||||
**Regression**: `makeRoadHandles()` once placed the left handle at `tangent + 90`,
|
||||
drawing it over the right kerb, so dragging the visually-left handle moved the
|
||||
right edge. Assert sides by geography (a north-heading road's left handle is west
|
||||
of its centerline), never by axis sign — a sign convention can be wrong on both
|
||||
sides of the wire at once and still look self-consistent.
|
||||
|
||||
## 9. What the geometry stage actually reads
|
||||
|
||||
`compileGeometry()` honours only four profile fields:
|
||||
|
||||
| Field | Read at |
|
||||
| --- | --- |
|
||||
| `edgeOffsets.left/right` | `native-road.js` centerline shift |
|
||||
| `widthMeters` | road width |
|
||||
| `sidewalkWidths.left/right` | `sidewalkRing()` |
|
||||
| `laneDividerOffsets` | lane separator placement |
|
||||
|
||||
`profile.interval` and `profile.transitions` are written by the solver and read by
|
||||
nothing: every direct edit currently applies to the whole road. Do not add UI for
|
||||
interval-scoped editing until that changes — see
|
||||
`research/interval-not-applied.md` in the map-editor task.
|
||||
|
||||
## 10. Saving is not applying
|
||||
|
||||
`POST /api/edits` writes the v2 document only. `/api/state` serves the outputs of
|
||||
the last compile, so a save without a recompile leaves a refresh showing pre-edit
|
||||
geometry — indistinguishable from a failed save.
|
||||
|
||||
`compileInput()` is the only caller that passes `editsFile`, and
|
||||
`session.context.compileFresh` must be installed by **every** path that sets
|
||||
`session.area`, including `/api/import`. It was originally wired only when the
|
||||
server started with an area on the command line, so every UI-imported session
|
||||
answered `请先导入 OSM 文件` to `/api/compile`.
|
||||
|
||||
An identity test cannot catch a `editsFile` regression: an ignored document and an
|
||||
empty one produce identical output. Assert that a **non-empty** document changes
|
||||
the compiled output. Wiring gaps between two handlers need an HTTP-level test, and
|
||||
a regression test is only trustworthy once you have watched it fail without the
|
||||
fix.
|
||||
|
||||
Reference in New Issue
Block a user