docs(openspec): propose planner-route-encoding change

Follow-up to the planner WS reconnect-loop incident. Proposes compactly
encoding the computed route in the Yjs session doc (single-source geometry
+ delta/varint polyline + run-length-encoded road metadata, dual-format
backward-compatible reads) to cut a ~305 KB / 77 km route to ~40–60 KB —
WITHOUT changing the routing-host "compute once, share via Yjs" model or
GPX export output.

Artifacts: proposal, design, specs (new planner-route-encoding
capability), tasks. Validates --strict. Ready for /opsx:apply.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-07-14 09:31:58 +02:00
parent 5debe5643e
commit d933cca451
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
5 changed files with 162 additions and 0 deletions

View file

@ -0,0 +1,48 @@
## ADDED Requirements
### Requirement: Compact single-source geometry encoding
The planner SHALL store a computed route's geometry once in the session document, as a compactly encoded polyline (fixed-precision delta encoding) rather than as stringified JSON floating-point coordinates, and SHALL derive any GeoJSON representation from it at read time. The encoding SHALL be lossless within the route's working precision (≈1 m).
#### Scenario: Geometry is not stored twice
- **WHEN** the routing host writes a computed route to the session document
- **THEN** the document contains a single encoded geometry value, not both a `geojson` LineString and a separate `coordinates` array
#### Scenario: Coordinates round-trip within precision
- **WHEN** a route's coordinates are encoded and then decoded
- **THEN** every decoded coordinate is within ~1 m of the original
### Requirement: Run-length-encoded road metadata
The planner SHALL store the per-coordinate road-metadata channels (surface, highway, maxspeed, smoothness, tracktype, cycleway, bikeroute) run-length encoded, and SHALL decode them back to the per-coordinate values readers expect.
#### Scenario: Uniform metadata collapses
- **WHEN** a long run of coordinates shares the same surface value
- **THEN** that run is stored as a single value+length pair, and decoding restores one value per coordinate
### Requirement: Backward-compatible reads
The planner SHALL read a session document written in either the legacy JSON format or the new compact encoding, transparently, with no migration step. A route written before this change SHALL render, export, and color correctly.
#### Scenario: Legacy document still works
- **WHEN** a session persisted in the legacy JSON format is loaded
- **THEN** its route geometry and road metadata decode correctly and the session behaves as before
#### Scenario: Legacy document re-encodes on recompute
- **WHEN** the routing host recomputes the route for a legacy-format session
- **THEN** the route is rewritten in the new compact encoding
### Requirement: Preserved compute-once model and outputs
The compact encoding SHALL NOT change how the route is computed or shared: the elected routing host computes the route once and writes it to the document for all participants to read, and clients SHALL NOT recompute to obtain geometry. GPX export output SHALL remain byte-compatible with the legacy encoding for the same route.
#### Scenario: One computation, shared to all
- **WHEN** multiple participants view a session
- **THEN** exactly one client (the routing host) computes the route and the others read the encoded result from the document
#### Scenario: GPX export unchanged
- **WHEN** the same route is exported to GPX under the legacy and the new encoding
- **THEN** the two GPX outputs are identical
### Requirement: Bounded document size
A computed route of a realistic length SHALL occupy substantially less of the per-session document budget than the legacy encoding, keeping typical routes well under the document size cap.
#### Scenario: A long route stays small
- **WHEN** a multi-waypoint route spanning tens of kilometres is stored
- **THEN** its serialized document size is a small fraction of the 5 MB cap (target ≈5× smaller than the legacy encoding)