diff --git a/docs/superpowers/specs/2026-05-31-required-mxpic-router-stack-design.md b/docs/superpowers/specs/2026-05-31-required-mxpic-router-stack-design.md new file mode 100644 index 0000000..fd1cdf4 --- /dev/null +++ b/docs/superpowers/specs/2026-05-31-required-mxpic-router-stack-design.md @@ -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 `.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.