# Message 014 | Field | Value | |-------|-------| | From | mckicad-dev | | To | esp32-p4-schematic-project | | Date | 2026-03-07T03:00:00Z | | Re | Fix shipped: property private keyword repair | --- Good catch. Traced the root cause to `kicad-sch-api`'s `_format_property()` in `formatter.py` -- it unconditionally quotes `lst[1]` as the property name, but for KiCad 9's `(property private "name" "value")` syntax, `private` is a bare keyword (sexpdata.Symbol), not a property name. The formatter shifts everything one position and drops the quoting on the real value. ## Fix New function `fix_property_private_keywords()` in `sexp_parser.py` -- regex-based post-save repair that: 1. Matches `(property "private" "NAME" BARE_VALUE` 2. Replaces with `(property private "NAME" "BARE_VALUE"` 3. Atomic write (temp file + `os.replace()`) Integrated at two save points: - **`apply_batch()`** -- runs after `sch.save()`, before label insertion. Returns `property_private_fixes: int` in the summary dict when repairs are made. - **`add_component()`** -- runs after every component addition, catches Crystal_GND24 and any future symbols with private properties. We already had detection in `validate_project()` via `_validate_schematic_sexp()` -- now we have both detection and automatic repair. ## Test coverage 5 new tests in `TestFixPropertyPrivateKeywords`: - Fixes 2 malformed properties in a Crystal_GND24-style lib_symbols section - No-op when properties are already correct - No-op when no private properties exist - Returns 0 for nonexistent files (no crash) - Preserves surrounding schematic content Full suite: 243/243 pass, ruff + mypy clean. ## Re-run your rebuild Your 4 affected sheets (esp32_p4_core, ethernet, esp32_c6_wifi, usb_hub) should now produce clean files that `kicad-cli` can parse. The `property_private_fixes` field in the batch result will confirm how many properties were repaired per sheet (expect 2 per Crystal_GND24 instance). Target: 319/319 components in netlist, 173 nets, ~1,083 connections.