← Commit history

0.9.279: Wiki #71 second cause, measured on ConfRoomROG with KiCad's own parser: one malformed symbol makes KiCad refuse a whole .kicad_sym (Symbol Editor lists the library EMPTY) while the bridge's structural reader called it clean. New handlers/kicad_parse_check.py runs kicad-cli sym export svg (read-only) as KiCad's verdict and inventory. kicad_install_symbol and kicad_install_library refuse a file KiCad refuses before writing (kicad_refuses_symbol / kicad_refuses_library); kicad_adom_library_status, kicad_lint_library and the kicad_show_library error carry kicadParser; kicad_adom_library_heal mode:prune drops the symbols KiCad refuses (dryRun names them, original kept as .pruned.bak). Lint's checkmark now says whether KiCad was consulted. Also measured: KiCad's library index is process-wide; a reopened editor frame keeps the old symbol set until kicad.exe fully restarts.

John Lauer ·9f85125985 ·1mo ago ·parent bad5c5b
2 files changed +64−10
handlers/open_symbol_editor.py+42−9
@@ -202,18 +202,51 @@ def _stale_explanation(kicad_info: dict, name: str) -> dict:                       "registered file. Re-run kicad_install_symbol and the part lands where "                       "KiCad reads; kicad_adom_library_status shows both paths."),         }+    # wiki #71 (2026-09-03, ConfRoomROG): the paths agreed and the symbol was in+    # the file, and KiCad still showed the library EMPTY, because ONE malformed+    # symbol makes KiCad's parser refuse the whole file. Our reader does not see+    # that. Ask KiCad before blaming navigation.+    try:+        from handlers import kicad_parse_check as _kpc+        _v = _kpc.verdict_file(kicad_info, rep.get("registeredPath")) if rep.get("registeredPath") else {}+    except Exception:  # pylint: disable=broad-except+        _v = {}+    if _v.get("available") and not _v.get("ok"):+        return {+            "errorCode": "library_refused_by_kicad",+            "registeredPath": rep.get("registeredPath"),+            "kicadParser": _v,+            "error": (f"'{name}' is in the file KiCad reads, but KiCad's parser REFUSES that file "+                      f"({_v.get('error')}), so the Symbol Editor lists the Adom library empty "+                      f"(title: {title})"),+            "_hint": ("One malformed symbol hides the whole library. kicad_adom_library_heal "+                      "{\"mode\":\"prune\",\"dryRun\":true} names the culprit(s) with KiCad's reason; "+                      "without dryRun it rebuilds the file from the symbols KiCad accepts (original kept "+                      "as .pruned.bak). Then reopen the editor."),+        }+    if _v.get("available") and _v.get("ok") and name.lower() not in {n.lower() for n in _v.get("symbols") or []}:+        return {+            "errorCode": "symbol_not_loaded_by_kicad",+            "registeredPath": rep.get("registeredPath"),+            "kicadParser": _v,+            "error": (f"KiCad's parser loads {len(_v.get('symbols') or [])} symbol(s) from the registered file "+                      f"and '{name}' is not one of them, although the bridge's reader finds it there "+                      f"(title: {title})"),+            "_hint": "Compare kicadParser.symbols with kicad_adom_library_status.symbols; report the file if they differ.",+        }     return {         "error": (f"'{name}' is in the Adom library KiCad reads ({rep.get('registeredPath') or 'registered path'}), "-                  f"but the open Symbol Editor did not load it in the background "+                  f"KiCad's parser accepts that file"+                  + (f" and lists '{name}'" if _v.get("ok") else "")+                  + f", but the open Symbol Editor did not load it in the background "                   f"(title: {title})"),-        "_hint": ("The file and the table agree, so this is not a path problem. What is NOT "-                  "known is why the editor did not load it: the bridge has no measurement "-                  "that separates 'the editor has not indexed this file yet' from 'the "-                  "background navigation missed'. kicad_rescan_libraries force:true restarts "-                  "KiCad (reported by one user as NOT sufficient on 10.0 for symbols, wiki #71); "-                  "kicad_screenshot_all shows what the tree actually lists. If you can "-                  "reproduce with force:true failing while paths agree, report it - that is "-                  "the unmeasured case."),+        "kicadParser": _v or None,+        "_hint": ("Path, table and KiCad's parser all agree, so the remaining cause is KiCad's "+                  "PROCESS-WIDE library index: measured on ConfRoomROG (wiki #71), an editor frame "+                  "reopened while kicad.exe stayed alive kept listing the OLD symbol set; only a "+                  "full close of KiCad and a cold reopen re-read the file. kicad_rescan_libraries "+                  "force:true does that restart (refused when a human launched KiCad). "+                  "kicad_screenshot_all shows what the tree actually lists."),     }  
server.py+22−1
@@ -207,13 +207,34 @@ def _handle_adom_library_status(kicad_info: dict, args: dict) -> dict:                                "registeredPath from 0.9.274.")     except Exception:         pass+    # wiki #71 (2026-09-03): the count above is the BRIDGE's reader. Ask KiCad+    # too: kicad-cli refused a library our reader called clean, and KiCad then+    # shows the whole library empty. kicadParser is KiCad's own inventory.+    try:+        from handlers import kicad_parse_check as _kpc+        reg = result.get("registeredPath")+        if reg:+            v = _kpc.verdict_file(kicad_info, reg)+            result["kicadParser"] = v+            if v.get("available") and not v.get("ok"):+                result["_hint"] = ("KICAD REFUSES THIS LIBRARY: kicad-cli says '%s'. The Symbol Editor will "+                                   "list the Adom library EMPTY no matter how many symbols the bridge counts "+                                   "(registeredSymbols=%s). One malformed symbol does this to the whole file. "+                                   "kicad_adom_library_heal {\"mode\":\"prune\",\"dryRun\":true} names the "+                                   "culprit(s); without dryRun it rebuilds the file from the symbols KiCad accepts."+                                   % (v.get("error"), result.get("registeredSymbols")))+            elif v.get("available") and v.get("ok") and result.get("registeredSymbols") not in (None, len(v.get("symbols") or [])):+                result["_hint"] = ("KiCad loads %d symbol(s) from the registered file; the bridge's reader counts %s. "+                                   "Trust kicadParser.symbols." % (len(v.get("symbols") or []), result.get("registeredSymbols")))+    except Exception:+        pass     return {"success": True, **result}    def _handle_adom_library_heal(kicad_info: dict, args: dict) -> dict:     """kicad_adom_library_heal - reconcile a split Adom library (wiki #71).-    Human-chosen mode: merge (default) or repoint. dryRun:true previews."""+    Human-chosen mode: merge (default), repoint, or prune (drop symbols KiCad refuses). dryRun:true previews."""     return heal_split(kicad_info, mode=(args.get("mode") or "merge"), dry_run=bool(args.get("dryRun")))  def _handle_list_versions(kicad_info: dict, args: dict) -> dict: