From a26d4be6668e373cb1a594c60ac7c22aed4ed0bb Mon Sep 17 00:00:00 2001 From: que01 Date: Thu, 27 Aug 2026 13:25:50 +0800 Subject: [PATCH] docs: document direct edit solver and API contracts --- .trellis/spec/backend/direct-edit-api.md | 96 ++++++++++++++++++++++++ .trellis/spec/backend/index.md | 1 + .trellis/workspace/dingkang/journal-1.md | 60 +++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 .trellis/spec/backend/direct-edit-api.md diff --git a/.trellis/spec/backend/direct-edit-api.md b/.trellis/spec/backend/direct-edit-api.md new file mode 100644 index 0000000..8ea4ff3 --- /dev/null +++ b/.trellis/spec/backend/direct-edit-api.md @@ -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. diff --git a/.trellis/spec/backend/index.md b/.trellis/spec/backend/index.md index 2f8b289..703246c 100644 --- a/.trellis/spec/backend/index.md +++ b/.trellis/spec/backend/index.md @@ -3,3 +3,4 @@ ## Revision Storage - [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. diff --git a/.trellis/workspace/dingkang/journal-1.md b/.trellis/workspace/dingkang/journal-1.md index e2f6d5b..d64b4ad 100644 --- a/.trellis/workspace/dingkang/journal-1.md +++ b/.trellis/workspace/dingkang/journal-1.md @@ -80,3 +80,63 @@ diagnostics, and wired road profiles and junction plans into geometry compilatio ### Next Steps - 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.