Rust Phase 2 Footprint Plotter-IR Slice

Decision

The footprint bytes-to-plotter proof now promotes standalone-footprint metadata, graphical properties, fp_text, fp_text_box, lines, three-point arcs, circles, rectangles, and polygons. Patterned line and arc strokes are decomposed into thick segments using the Python path's dash rules. Standard circle, oval, rectangle, round-rectangle, and trapezoid pads emit pad flashes; through-hole and NPTH pads also emit circular or slotted drill operations. Custom-pad gr_poly primitives and zero-radius chamfered roundrect pads emit the shared custom flash. It emits a strict TypeSpec-owned subset of the established kicad.plotter_ir.a0 document. The Phase 5 text extension closes the current standalone Python producer surface; non-polygon custom primitives, symbols, and embedded PCB footprints remain separate work.

Architecture

Contract And WASM Boundary

TypeSpec owns the request, result metadata, exact point/quad shapes, fill vocabulary, and shared tagged operation union. The pad variants carry layer lists and resolved mask margins; shared circle and segment variants carry optional drill roles and NPTH size hints. Generated Rust, Python, and TypeScript types stay deterministic. Browser callers pass KiCad and request bytes separately to plotFootprintIr. The operation returns result JSON and plotter-IR JSON as separate byte arrays, avoiding base64 and preserving a resource-limit diagnostic envelope.

Shared Circle and ThickSegment payloads have three mutually exclusive semantic states: graphic, plated drill, and NPTH drill. TypeSpec restricts the role vocabulary; generated Python decoding and the Rust contract boundary run mandatory cross-field validation. A graphic requires layer and forbids drill fields; a drill requires role plus non-empty layers; NPTH additionally requires mask and pad-size hints. Operation counts and pad-flash layer lists are validated at the same boundary. Custom-pad polygon widths are optional, but a non-empty width list must contain exactly one value per polygon.

Every numeric document field declared as a JavaScript-safe integer is bounded to ±9,007,199,254,740,991 in JSON Schema. Native conversion and the generated Rust and Python transport types enforce the same range so an out-of-range integer cannot silently lose precision in JavaScript.

Standalone text operations carry their exact layer and the cache-free state emitted by Python's footprint_to_ir. The semantic boundary requires canonical document/record identity, one footprint record, sequential operation indices, and forbids board-only cache and marker fields on footprint text.

Parity Evidence

Rack L1_026 makes Python, generated Python types, native Rust, and the host adapter consume shared vectors and requires the exact same document. An interleaved input proves canonical grouping, and the corpus covers patterned line/arc decomposition plus every promoted operation and fill. A standard-pad vector covers every promoted flash shape, inherited and clamped mask margins, rotated drill offsets, slots, and suppressed NPTH copper flashes. A custom-pad vector proves local polygon coordinates, per-polygon widths, anchor metadata, ignored non-polygon primitives, and exact chamfered roundrect polygon construction. A Phase 5 vector proves property ordering/skip rules, Reference/Value and local property-variable substitution, font/color/alignment mapping, hidden text, bordered text-box wrapping, and text-before-geometry order. Documents validate against both the strict generated slice schema and the established plotter-IR schema. Rack L0_046 owns real Node-hosted WASM execution and Rust quality; L0_049 owns generated-language cleanliness. The Phase 5 extension passed independent core, parity, and contract reviews and is closed in the parity ledger.

Pattern decomposition is fail-closed. The fixed safety-step cap and any zero-progress pattern produce a resource-limit diagnostic and no output document; neither segment nor arc conversion may return truncated geometry.

Retained Work

Promote symbol body/pin text next. The companion symbol-body slice now reuses this operation vocabulary. Standalone footprint text deliberately matches the cache-free Python producer; board-nested outline-cache placement remains owned by the embedded-footprint slice. Embedded PCB footprints will reuse the shared operations but require their own placement and record parity. The Phase 2 boundary review remains gated on that wider proof. Performance tuning remains profile-driven.