docs: document direct edit solver and API contracts
This commit is contained in:
96
.trellis/spec/backend/direct-edit-api.md
Normal file
96
.trellis/spec/backend/direct-edit-api.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# Direct Edit Solver And API
|
||||||
|
|
||||||
|
## 1. Scope / Trigger
|
||||||
|
|
||||||
|
This contract covers the pure direct-edit resolver and the workbench endpoints
|
||||||
|
that preview, persist, checkpoint, and rebase `native-road-edits/v2` documents.
|
||||||
|
It is required because the feature crosses compiler, storage, and HTTP layers.
|
||||||
|
|
||||||
|
## 2. Signatures
|
||||||
|
|
||||||
|
```js
|
||||||
|
resolveDirectEditConstraints(model, editDocument, context)
|
||||||
|
// -> { roadProfiles, junctionPlans, constraintStates, handles, diagnostics }
|
||||||
|
|
||||||
|
GET /api/edit-state
|
||||||
|
POST /api/edit-preview
|
||||||
|
POST /api/edits
|
||||||
|
POST /api/revisions
|
||||||
|
POST /api/revisions/:id/rebase
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Contracts
|
||||||
|
|
||||||
|
- The resolver is deterministic and must not import `fs`, `path`, `http`, or
|
||||||
|
write files. It accepts a baseline model, an optional validated v2 document,
|
||||||
|
and `{ revisionId, compilerGeometryVersion, previewSeq }` context.
|
||||||
|
- `GET /api/edit-state` returns the active document, `documentVersion`, active
|
||||||
|
revision, constraint states, diagnostics, and `road-edit-handles/v1` manifest.
|
||||||
|
- `POST /api/edit-preview` accepts `document` (or replacement `constraints`
|
||||||
|
and `operations`) and optional integer `previewSeq`. It returns the same
|
||||||
|
manifest/state data plus compiled layers, echoes `previewSeq`, and never
|
||||||
|
changes active files. Work over the 300ms budget sets `degraded: true`.
|
||||||
|
- `POST /api/edits` requires integer `expectedDocumentVersion` and either a
|
||||||
|
complete `document` or replacement arrays. Saves through a staging file and
|
||||||
|
rename, increments `documentVersion`, and returns the active revision.
|
||||||
|
- A version mismatch returns HTTP 409 with `{ ok: false, error, current }` and
|
||||||
|
leaves the active document byte-identical.
|
||||||
|
- `POST /api/revisions` requires a non-empty `label`; it creates an immutable
|
||||||
|
checkpoint and returns its manifest plus current edit state.
|
||||||
|
- `POST /api/revisions/:id/rebase` is read-only and returns status counts plus
|
||||||
|
per-constraint details. `pending`, `conflicted`, and `stale` constraints do
|
||||||
|
not enter geometry solving.
|
||||||
|
|
||||||
|
## 4. Validation & Error Matrix
|
||||||
|
|
||||||
|
| Condition | Required behavior |
|
||||||
|
| --- | --- |
|
||||||
|
| Missing or invalid v2 document fields | Reject with a field-specific 400 error |
|
||||||
|
| Missing `expectedDocumentVersion` | Reject with 400; do not write |
|
||||||
|
| Expected version differs from active version | Return 409 and current version; do not write |
|
||||||
|
| Empty checkpoint label | Reject with 400; no revision is created |
|
||||||
|
| Missing active workspace for preview | Reject with 400; no files are created |
|
||||||
|
| Solver replay anchor cannot resolve | Mark `stale` or `conflicted` with diagnostic; never silently apply |
|
||||||
|
| Compiler geometry version differs | Mark all replayable constraints `recheck` without changing values |
|
||||||
|
| Invariant violation (lane width, crossing boundaries, self-intersection, connector bounds) | Return a blocking diagnostic; do not clamp or silently repair |
|
||||||
|
|
||||||
|
## 5. Good / Base / Bad Cases
|
||||||
|
|
||||||
|
- Good: preview the same document later saved with the same active baseline;
|
||||||
|
compiled layers and solver diagnostics agree, while tracked file bytes and
|
||||||
|
mtimes remain unchanged.
|
||||||
|
- Base: an empty v2 document yields byte-for-byte baseline geometry and an
|
||||||
|
empty constraint-state list.
|
||||||
|
- Bad: two tabs save version `N`; the second save with `N` receives 409 and
|
||||||
|
cannot overwrite the first tab's document.
|
||||||
|
|
||||||
|
## 6. Tests Required
|
||||||
|
|
||||||
|
- Unit: resolver purity, empty-document identity, five replay statuses, handle
|
||||||
|
manifest fields, and blocking invariant diagnostics.
|
||||||
|
- Integration: preview file bytes/mtimes unchanged, `previewSeq` echoed,
|
||||||
|
preview layers matching formal compilation, and `degraded` represented as a
|
||||||
|
boolean.
|
||||||
|
- Persistence: atomic save, version-409 no-write path, checkpoint parent and
|
||||||
|
digest integrity, and rebase counts/details.
|
||||||
|
|
||||||
|
## 7. Wrong vs Correct
|
||||||
|
|
||||||
|
### Wrong
|
||||||
|
|
||||||
|
```js
|
||||||
|
fs.writeFileSync(activeEdits, JSON.stringify(draft));
|
||||||
|
```
|
||||||
|
|
||||||
|
This permits half-written documents and allows a stale browser tab to overwrite
|
||||||
|
newer edits.
|
||||||
|
|
||||||
|
### Correct
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (expectedDocumentVersion !== current.documentVersion) throw conflict409();
|
||||||
|
saveEditDocument(activeEdits, { ...draft, documentVersion: current.documentVersion });
|
||||||
|
```
|
||||||
|
|
||||||
|
The service checks the version before the atomic version-bumping write, while
|
||||||
|
the pure resolver remains reusable by preview and formal compilation.
|
||||||
@@ -3,3 +3,4 @@
|
|||||||
## Revision Storage
|
## Revision Storage
|
||||||
|
|
||||||
- [Road Revision Storage](./road-revision-storage.md) -- immutable workbench revision layout, validation, and recovery contract.
|
- [Road Revision Storage](./road-revision-storage.md) -- immutable workbench revision layout, validation, and recovery contract.
|
||||||
|
- [Direct Edit Solver And API](./direct-edit-api.md) -- pure constraint solving, preview/save endpoints, version protection, and rebase behavior.
|
||||||
|
|||||||
@@ -80,3 +80,63 @@ diagnostics, and wired road profiles and junction plans into geometry compilatio
|
|||||||
### Next Steps
|
### Next Steps
|
||||||
|
|
||||||
- Implement exact/recheck/pending/conflicted/stale replay matching (step 4).
|
- Implement exact/recheck/pending/conflicted/stale replay matching (step 4).
|
||||||
|
|
||||||
|
## Session 4: Direct-edit replay matching
|
||||||
|
|
||||||
|
**Date**: 2026-08-27
|
||||||
|
**Task**: Continue `direct-edit-solver-api`, step 4
|
||||||
|
**Git Commit**: `735ce69`
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Added exact-anchor replay classification, snapshot candidate fallback, stale
|
||||||
|
lane-boundary handling, and compiler-geometry `recheck` propagation.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- [OK] npm test; npm run format:check; npm run test:client; npm run test:client:unit; npm run build
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
|
||||||
|
- Add the read-only edit-state and edit-preview endpoints (step 5).
|
||||||
|
|
||||||
|
## Session 5: Read-only edit APIs
|
||||||
|
|
||||||
|
**Date**: 2026-08-27
|
||||||
|
**Task**: Continue `direct-edit-solver-api`, step 5
|
||||||
|
**Git Commit**: `41c314f`
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Added `GET /api/edit-state` and `POST /api/edit-preview`. Preview compiles from
|
||||||
|
the draft document without writing active files and returns sequence, degraded
|
||||||
|
status, diagnostics, handles, and derived layers.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- [OK] npm test; npm run format:check; npm run test:client; npm run test:client:unit; npm run build
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
|
||||||
|
- Implement edit/revision/rebase writes with expected-version protection (step 6).
|
||||||
|
|
||||||
|
## Session 6: Edit persistence and rebase APIs
|
||||||
|
|
||||||
|
**Date**: 2026-08-27
|
||||||
|
**Task**: Complete `direct-edit-solver-api`, step 6
|
||||||
|
**Git Commit**: `f3f763f`
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Added atomic active-document saves with expected-version 409 protection,
|
||||||
|
revision checkpoint creation, and read-only revision rebase status summaries.
|
||||||
|
Existing state/session responses now expose active revision and document version.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- [OK] npm test; npm run format:check; npm run test:client; npm run test:client:unit; npm run build
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
|
||||||
|
- Run the solver-api quality review, then archive the child task before starting
|
||||||
|
the map-editor child task.
|
||||||
|
|||||||
Reference in New Issue
Block a user