5.8 KiB
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.pycallscreate_layout_svg_from_gds, which directly places PDK GDS with gdstk. - With
bundles.*.links:server.pycallscreate_routed_layout_svg, which delegates tomxpic_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_routertosys.pathwhen 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 withgdstk.read_gds(...).top_level()[0].write_svg(...). - Probe the route backend by importing
mxpic_router.builder._import_mxpic_forge_routeand calling it. This uses the samemxpic_forge/mxpic.Routelookup that actual router builds use. - Return a small structured result for startup logging and tests.
- Raise a clear
RuntimeErrorwhen 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_gdstkand_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.pyimports and calls the router dependency gate before startup./api/save-layoutcallscreate_routed_layout_svgunconditionally for previews./api/save-layoutno longer branches onlayout_has_linksto choose between gdstk and router preview builders.gds_builder.pydelegates to_build_with_mxpic_routerwithout gdstk/Nazca production fallback.- The router dependency module checks
mxpic_router,nazca,gdstk, and the route backend. GDS_SVG_GENERATION_LOGIC.mddocuments 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.mdor 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_routersource intomxpic_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.