`inire` is a single-package Python router with a small stable API at the package root and a larger semi-private implementation under `inire.geometry` and `inire.router`.
## Stable Surface
- The supported entrypoint is `route(problem, options=...)`.
- Stable public types live at the package root and include `RoutingProblem`, `RoutingOptions`, `NetSpec`, `Port`, `RoutingResult`, and `RoutingRunResult`.
- Deep imports such as `inire.router._router.PathFinder` and `inire.geometry.collision.RoutingWorld` are intentionally accessible for advanced workflows, but they are unstable.
## Current Module Layout
-`inire/model.py`: Immutable request and option dataclasses.
-`inire/results.py`: Immutable routing results plus the per-run `RouteMetrics` snapshot.
-`inire/geometry/static_obstacle_index.py` and `inire/geometry/dynamic_path_index.py`: Spatial-index management for static obstacles and routed paths, including dynamic per-object indices, per-net grid occupancy, congestion grid membership, and per-net dynamic envelopes.
-`inire/router/_search.py`, `_astar_moves.py`, `_astar_admission.py`, `_astar_types.py`: The state-lattice A* search loop and move admission pipeline.
-`inire/router/_router.py`: The negotiated-congestion driver and refinement orchestration.
-`inire/router/refiner.py`: Post-route path simplification for completed paths.
-`inire/router/cost.py` and `inire/router/danger_map.py`: Search scoring and obstacle-proximity biasing.
-`inire/utils/visualization.py`: Plotting and diagnostics helpers.
## Routing Stack
`route(problem, options=...)` builds a routing stack composed of:
1.`RoutingWorld` for collision state.
2.`DangerMap` for static-obstacle proximity costs.
3.`CostEvaluator` for move scoring and heuristic support.
4.`AStarContext` for caches and search configuration.
5.`PathFinder` for negotiated congestion, rip-up/reroute, and refinement.
The search state is a snapped Manhattan `(x, y, r)` port. From each state the router expands straight segments, 90-degree bends, and compact S-bends, then validates candidates against static geometry, dynamic congestion, and optional self-collision checks.
## Notes On Current Behavior
- Static obstacles and routed paths are treated as single-layer geometry; automatic crossings are not supported.
- The danger-map implementation uses sampled obstacle-boundary points and a KD-tree, not a dense distance-transform grid.
- The visibility subsystem keeps a lazy static corner index for default `tangent_corner` guidance and only builds the exact corner-to-corner graph on demand for `exact_corner` queries.
- Negotiated congestion now re-verifies every reached-target path at the end of each iteration against the final installed dynamic geometry, and it stops early if the conflict graph stalls for consecutive iterations.
- In the late all-reached low-edge regime, negotiated congestion reroutes only the current conflict set instead of all nets. The heaviest remaining late reroutes can be capped and carried forward by restoring their incumbent reached-target paths when more search would just churn before pair-local repair.
- After best-snapshot restoration, the router runs a bounded pair-local scratch reroute on final two-net reached-target conflict pairs. That repair phase clones static obstacles from the live collision world, treats all outside-pair geometry as fixed blockers, tries both pair orders, and only keeps the result if whole-set reverify improves.
- Final `RoutingResult` validity is determined by explicit post-route verification, not only by search-time pruning.
## Performance Visibility
`RoutingRunResult.metrics` includes both A* counters and index/cache/verification counters. The committed example-corpus baseline for those counters is tracked in `docs/performance.md` and `docs/performance_baseline.json`.