docs: design required mxpic_router stack

This commit is contained in:
2026-05-31 23:32:25 +08:00
parent ce7f6e95c4
commit 78f38d3be7
@@ -0,0 +1,143 @@
# Required mxpic_router Stack Design
Date: 2026-05-31
## Goal
Unify layout preview and GDS generation behind the same Nazca/mxpic_router
pipeline. `mxpic_router` is no longer an optional routed-only helper. It is a
required runtime package for `mxpic_EDA`, and both repositories should be
released together as a matched pair.
## Current Problem
`Build Layout` currently has two backend preview paths:
- No `bundles.*.links`: `server.py` calls `create_layout_svg_from_gds`, which
directly places PDK GDS with gdstk.
- With `bundles.*.links`: `server.py` calls `create_routed_layout_svg`, which
delegates to `mxpic_router`, builds Nazca GDS, then converts that GDS to SVG.
This duplicates layout semantics. Placement-only cells and routed cells can
drift because they are built by different engines. Maintenance is harder
because every future layout feature must be considered in two paths.
## Decision
Use one canonical build path for both preview SVG and project GDS:
`saved YAML -> mxpic_router -> Nazca GDS -> gdstk SVG conversion when needed`
`mxpic_router` and its required build stack are hard dependencies. The Flask
server should verify the whole stack before startup, fail early if anything is
missing, and give an actionable message.
## Dependency Gate
Add `backend/router_dependency.py` as the single backend module responsible for
router dependency validation.
Responsibilities:
- Add the sibling checkout path `../mxpic_router` to `sys.path` when it exists,
preserving the current local-development pattern.
- Import `mxpic_router.build_project_gds`.
- Import `nazca`, because router output is built as Nazca cells.
- Import `gdstk`, because preview SVG still converts router-generated GDS with
`gdstk.read_gds(...).top_level()[0].write_svg(...)`.
- Probe the route backend by importing
`mxpic_router.builder._import_mxpic_forge_route` and calling it. This uses the
same `mxpic_forge`/`mxpic.Route` lookup that actual router builds use.
- Return a small structured result for startup logging and tests.
- Raise a clear `RuntimeError` when the stack is incomplete.
Server startup should call this check before `app.run`. In script mode, startup
should exit before Flask launches if the dependency gate fails.
## Build Layout Flow
`Build Layout` should always use the router-backed preview path:
`frontend/canvas.html handleBuildLayout` -> POST `/api/save-layout` ->
`backend/server.py save_layout` writes `<cell>.yml` and route sidecar ->
`create_routed_layout_svg(...)` -> `mxpic_router.build_project_gds(...)` with
`target_cell_name=<cell>` -> temporary `.gds` -> `gdstk.write_svg(...)` ->
saved `<cell>.svg`.
There should be no `layout_has_links` branch in `save_layout`. A no-link layout
is still a valid router input; the router builds placed instances and exports
the requested top cell without drawing routes.
`layout_preview.py` can remain in the tree only if it is still useful as a
manual diagnostic module. It should not be used by production preview requests.
## Build GDS Flow
`Build GDS` should always delegate to `mxpic_router`.
`backend/gds_builder.py build_project_gds` should:
- Load saved project YAML files only if needed for validation/error messages.
- Call `_build_with_mxpic_router(...)` as the canonical builder.
- Remove silent fallback to `_build_with_gdstk` and `_build_with_nazca`.
- Raise a clear error if the required router stack is unavailable, though this
should normally be caught at server startup.
The old fallback functions may be removed if tests and imports no longer need
them. If kept temporarily, they must be clearly marked as unused diagnostics
and not reachable from the production API.
## Error Handling
Dependency failures should be early and explicit:
- Missing `mxpic_router`: tell the operator to install or place the matched
sibling checkout.
- Missing `nazca`: tell the operator the router runtime cannot build GDS.
- Missing `gdstk`: tell the operator previews cannot convert GDS to SVG.
- Missing route backend: tell the operator routing primitives are unavailable.
Request-time failures should remain JSON API errors, but normal deployment
should fail at startup before users can reach these routes.
## Testing
Update static/backend tests to assert the new contract:
- `server.py` imports and calls the router dependency gate before startup.
- `/api/save-layout` calls `create_routed_layout_svg` unconditionally for
previews.
- `/api/save-layout` no longer branches on `layout_has_links` to choose
between gdstk and router preview builders.
- `gds_builder.py` delegates to `_build_with_mxpic_router` without gdstk/Nazca
production fallback.
- The router dependency module checks `mxpic_router`, `nazca`, `gdstk`, and the
route backend.
- `GDS_SVG_GENERATION_LOGIC.md` documents the unified path.
Add a runtime smoke test for the local development environment when the required
router stack is installed: a no-link saved YAML cell should generate SVG through
`create_routed_layout_svg`. If CI does not install Nazca/router dependencies,
keep that test explicitly skipped unless the dependency gate passes.
## Release Policy
`mxpic_EDA` and `mxpic_router` should be released simultaneously.
Recommended lightweight policy:
- Update deployment notes to state that both repositories must be deployed as a
matched pair.
- Keep a visible compatibility note in `README.md` or deployment docs.
- Version compatibility checks are out of scope until both repositories expose
explicit version constants; until then, deployment docs carry the matched-pair
release requirement.
## Non-Goals
- Do not redesign the frontend YAML format in this change.
- Do not vendor/copy `mxpic_router` source into `mxpic_EDA`.
- Do not replace gdstk SVG conversion in this change; it remains the converter
after router-generated GDS.
- Do not add fallback behavior that hides a missing or incompatible router
stack.