`/api/import` set `session.area` but never `session.context.compileFresh`, which
is only wired when the server starts with an area on the command line. Every
session imported through the browser therefore answered "请先导入 OSM 文件" to
`/api/compile`, even though the import had just succeeded.
This predates direct editing — it broke "保存并重新生成" for UI-imported
workspaces — but it surfaced now, because saving a direct edit recompiles and so
reported a failed regeneration after a save that had in fact succeeded.
Covered by a new HTTP-level test: import the fixture, then recompile twice. The
bug lived in the wiring between two handlers rather than in either one, so
nothing below the HTTP boundary could catch it. Verified by reverting the fix and
watching the test fail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds resolveDirectEditConstraints between compileRoadModel and
compileGeometry, per the parent design's data flow. The stage is an
identity transform until the individual constraint kinds land: it
returns empty road profiles, junction plans and handle manifest, so
compileGeometry's geometry code is untouched and output stays
byte-identical.
Constraint planning is separated from solving up front. Only `exact`
and `recheck` constraints may reach the solver; `disabled`,
`pending`, `conflicted` and `stale` are reported as unapplied with a
reason. SOLVED_KINDS starts empty and grows one entry per kind, so a
partially delivered solver reports what it skipped instead of
publishing half-solved geometry.
diagnostic() moves to src/compile/diagnostics.js so the solver can
share the compiler's diagnostic shape without depending on fs, which
would break the pure-function boundary that lets preview, the full
compile and the CLI export share one implementation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Planning: parent design.md becomes the single authoritative contract
(constraint model with 6 kinds, handle manifest, coordinate/unit
layering, preview sequencing, storage layout and lazy migration, area
config snapshot, API contract). Work is split into four independently
verifiable child tasks with per-step gates and rollback points.
Test infra: pin vitest 4.1.11, add test:client:unit for client pure
logic, extend prettier globs to root *.ts so vitest.config.ts is checked.
Add .gitignore: the repo had none, so inputs/, outputs/, workbench-data/
and the client build output were untracked rather than ignored.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>