# 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 `.yml` and route sidecar -> `create_routed_layout_svg(...)` -> `mxpic_router.build_project_gds(...)` with `target_cell_name=` -> temporary `.gds` -> `gdstk.write_svg(...)` -> saved `.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.