4.1 KiB
4.1 KiB
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
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-statereturns the active document,documentVersion, active revision, constraint states, diagnostics, androad-edit-handles/v1manifest.POST /api/edit-previewacceptsdocument(or replacementconstraintsandoperations) and optional integerpreviewSeq. It returns the same manifest/state data plus compiled layers, echoespreviewSeq, and never changes active files. Work over the 300ms budget setsdegraded: true.POST /api/editsrequires integerexpectedDocumentVersionand either a completedocumentor replacement arrays. Saves through a staging file and rename, incrementsdocumentVersion, 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/revisionsrequires a non-emptylabel; it creates an immutable checkpoint and returns its manifest plus current edit state.POST /api/revisions/:id/rebaseis read-only and returns status counts plus per-constraint details.pending,conflicted, andstaleconstraints 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 withNreceives 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,
previewSeqechoed, preview layers matching formal compilation, anddegradedrepresented 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
fs.writeFileSync(activeEdits, JSON.stringify(draft));
This permits half-written documents and allows a stale browser tab to overwrite newer edits.
Correct
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.