diff --git a/MIGRATION.md b/MIGRATION.md index 3fb545f..c2a4b16 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -421,6 +421,10 @@ may add explicit probes. Empty discovery is an error unless Validation returns normally on success and otherwise raises an `ExceptionGroup` of contextual `ToolContractError`s. +Run this validation during Tool development, testing, or application startup. +It is the comprehensive semantic preflight for custom Tools; those checks are +intentionally not repeated for every offer evaluation in the routing hot path. + Positional routing bounds (`p`, `pos`, `position`, `x`, and `y`) now require a nearly Manhattan input-port direction. Arbitrarily angled ports remain valid for non-positional/extension routing. @@ -449,9 +453,12 @@ import it from user code. `trace_into()` uses the same primitive-offer route selection and now searches bounded route topologies with up to four bend roles. This preserves the common straight, bend, S-like, U-like, and dogleg cases while allowing routes that -need an additional bounded bend pair. Among legal bounded candidates, -`trace_into()` selects the lowest total primitive-offer cost; bend count and -step count are used only to break exact cost ties. +need an additional bounded bend pair. Bend-family requests search one-bend +routes before three-bend routes; other families search zero-to-two-bend routes +before four-bend routes. The first band with a legal route wins. Within that +band, candidates are ordered by total primitive-offer cost, adapter count, step +count, and deterministic discovery order. The route `strategy` affects only +that final discovery-order tie-break. Explicit-length `jog()` routes may also be satisfied by composing a straight primitive before or after an omitted-length native S primitive. `uturn()` routes diff --git a/README.md b/README.md index 71c37f0..7060cd7 100644 --- a/README.md +++ b/README.md @@ -275,8 +275,6 @@ my_pattern.ref(_make_my_subpattern(), offset=..., ...) ``` -## TODO +## Development -* PolyCollection & arrow-based read/write -* Bus-to-bus connections? -* tuple / string layer auto-translation +Project-level planned work is tracked in [TODO.md](TODO.md). diff --git a/masque/builder/__init__.py b/masque/builder/__init__.py index a4389f6..de1a0d1 100644 --- a/masque/builder/__init__.py +++ b/masque/builder/__init__.py @@ -31,6 +31,11 @@ geometry into the Pattern and Library. `masque.builder.planner` is an internal planner implementation rather than a stable public API. +Custom Tool authors should run `validate_tool_contract()` as a development or +application-startup preflight. It performs the comprehensive semantic checks +that are intentionally not repeated during route selection, keeping the normal +routing path focused on search rather than contract verification. + The practical layering is: - user code drives `Pather` and chooses Tools per port or by default, - Tools describe local legal motion primitives without touching Pather state, diff --git a/masque/builder/pather.py b/masque/builder/pather.py index 15e0c59..85acca9 100644 --- a/masque/builder/pather.py +++ b/masque/builder/pather.py @@ -1064,11 +1064,14 @@ class Pather(PortList): The current baseline searches bounded primitive-offer routes with up to four bend roles, including straight, single-bend, S-like, U-like, and - dogleg topologies. The lowest-cost legal bounded candidate is selected; - bend count, step count, and search order are tie-breakers only. `strategy` - controls straight-first vs turn-first search order within those ties. - Custom planning options may be supplied through `tool_options`; they are - forwarded only to primitive offer generation. + dogleg topologies. Bend-family requests try one-bend routes before + three-bend routes; other families try zero-to-two-bend routes before + four-bend routes. The first band with a legal candidate wins. Within a + band, candidates are ordered by total cost, adapter count, step count, + and deterministic discovery order. `strategy` controls straight-first + vs turn-first discovery order and therefore only the final tie-break. + Custom planning options may be supplied through `tool_options`; they + are forwarded only to primitive offer generation. If `plug_destination` is `True`, the destination port is consumed by the final step. If `thru` is provided, that port is renamed to the source name after the route is complete.