Rust Phase 4 native KiCad netlist slice

Status: implemented and ready for focused review. This slice promotes the native in-process version-E-oriented netlist projection and KiCad version-E S-expression writer. It does not promote a JSON, TypeSpec, WASM, or stable Cargo interchange API.

Boundary

build_kicad_netlist consumes the existing SchematicBundleIndex and an optional typed ProjectView. It materializes resolved design nets, terminals, components, component units, embedded library parts and pins, and per-sheet title metadata. emit_kicad_netlist writes that model directly to KiCad's version-E S-expression format through a bounded pretty emitter.

This slice intentionally governs the semantic subset consumed by the version-E writer. It does not yet promote net-class aliases, graphical IDs, bus flags, terminal endpoint records, libraries, or design source/date/tool metadata as complete native model fields. The Rust structs are native compiler state. The example gate serializes them only as test evidence. Any future browser, downstream JSON, or public interchange operation must first receive a TypeSpec-owned contract and generated projections; this implementation must not become an accidental hand-maintained transport contract.

Semantic decisions

Resource and complexity policy

The scalar compiler's net and terminal ceilings are tightened to the caller's netlist ceilings before compilation. Net, terminal, component-row, component-candidate, field, unit, unit-pin, library-part, library-pin, sheet, retained-string, and output-byte allowances are independent. Component rows are rejected when a new group would cross the ceiling; candidates and pins are rejected before insertion. Title-block children and comments are counted from the structural index before model allocation. Recursive variable expansion has separate per-result and aggregate-work ceilings. Wildcard matching likewise has a caller-owned aggregate work ceiling across all nets and patterns.

Source parsing and model construction are linear apart from ordered map/set operations and natural pin sorting. Wildcard matching uses an iterative active-state simulation with O(pattern length) work memory and predictable O(pattern length times net-name length) time per attempted pattern. It never uses recursive or exponential wildcard backtracking. Version-E output is appended directly and checked before every write; an output-limit failure returns an error and publishes no partial string.

Evidence

kicad_netlist.rs owns synthetic model, writer, wildcard, reachability, title-block, and one-over/one-under resource evidence. Rack L3_020 builds the native example once and compares the governed version-E projection with Python on four governed real projects: Yoshi Mainboard, Taillight, Speedy Processing Module, and Jumperless V5r7. The same gate parses both emitted version-E documents and compares their governed semantic trees. The four-project gate is mandatory corpus evidence and does not silently skip unavailable inputs.

Deferred work

This slice does not replace the native kicad_cruncher command, expose a public package API, reproduce every CLI option, or approve browser packaging. Those remain later native-first slices. Exact KiCad CLI-oracle expansion may add cases, but should reuse this model and direct writer rather than introduce a parallel JSON-shaped compiler.