M0–M3 gap backlog: T1–T9 (bundled libs, MCP tools, validators, drop-import)#2
Conversation
SPEC §17 step 8 — top-level SPEC.md symlink to the canonical spec. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…afana preset (T3) SPEC §8.8 + §12. Architecture overview, an OTel Collector config (OTLP → spanmetrics → Prometheus) and an importable Grafana dashboard, grounded in the real agent.hook.* span contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… (T4) The 5 SPEC §A.3 slash commands missing from .claude/commands/. The first three wrap existing tools (kc_snapshot_*, kc_diff); the two add-* commands are synthesis prompts over the existing schematic kc_* tools. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s (T5) SPEC §7.3. Decoupling (KC020), power-rail source (KC021), length-match membership (KC030), diff-pair declaration (KC031), controlled-impedance achievability (KC040, IPC-2141A estimate), analog/digital partition isolation (KC050). 19 unit tests; KC001-011 numbering reconciliation documented. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kc_decoupling_check / kc_partition_check / kc_impedance_check (reuse the
KC020/050/040 validators); kc_diffpair_declare / kc_length_match_set
(reuse ui_* mutation logic, persist via /replace); kc_bom_get (KCIR
grouping); kc_export_step (kiconnector /tools/step); kc_session_fork
(new kiserver /project/{id}/session/fork writing an agent-readable
session manifest). Registry 28 -> 36. 11 tool tests + 2 route tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…y candidates (T7)
FR-040/041/042. Replaces the M1 shape-only heuristic: real distributor
stock/price/lifecycle/datasheet via the shared aggregator (fails closed
per FP#5), plus symbol + footprint candidates from a new kiserver
GET /project/{id}/library/search over the existing LibraryIndex.
5 mpn tests + 3 route tests; existing mpn tests made hermetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kiserver POST /project/{id}/library/import writes the dropped file into
a project-local imported-libs/ (symbols) or <nick>.pretty/ (footprints),
idempotently registers the matching sym-lib-table/fp-lib-table row, and
strips path traversal from the filename. Client useLibraryImport hook +
LibraryImportDropZone infer the kind from the extension and surface the
result/error. 6 route tests + 5 client tests.
Also fixes a pre-existing BomView.tsx TS6133 (unused lastRequestId from
an earlier web edit) by wiring it in as the intended stale-response
guard on the async bom-price load.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lands the bundled symbol/footprint mirror SPEC §9.5/§12/D6/FR-040 require.
libs/ ships a curated, pinned subset of the official KiCad libraries — the
five whole symbol libs the examples reference (Device, power, Connector,
Regulator_Switching, RF_Module) plus the exact footprints they place — all
fetched from KiCad GitLab at tag 9.0.0 and SHA-256-pinned in MANIFEST.toml by
scripts/populate_libs.py (--pin re-fetches+repins; default verifies and
self-heals missing files per D6). sym-lib-table/fp-lib-table register them via
${KICLAUDE_BUNDLED_LIBS}; LICENSE.md carries the CC-BY-SA-4.0 + KiCad Library
Exception attribution.
kiserver GET /project/{id}/library/search now resolves the project's own libs
AND the bundled mirror (bundled_libs_dir() + _merge_hits), so a project with an
empty sym-lib-table still resolves the standard KiCad parts offline. Empirical
gate: Device:R and Connector:USB_C_* resolve through the route (9 tests).
Fixes the examples' fictional/wrong library references to real KiCad 9.0.0
parts (the mirror cannot honestly contain libraries KiCad does not ship):
- blinky: MCU_Espressif: -> RF_Module:ESP32-S3-WROOM-1
- esp32_c6_rf: ESP32-C6-WROOM-1 -> ESP32-C6-MINI-1; fabricated
Package_BGA:DDR3L_BGA-16_4x4_P0.8mm -> real BGA-16_1.92x1.92mm_Layout4x4_P0.5mm
(Value MT41K256M16-DDR3L -> BGA-16, that DRAM is FBGA-96); U.FL ->
Connector_Coaxial:U.FL_Molex_MCRF_73412-0110_Vertical
- buck_subsystem: Regulator_Switching:TPS562201 -> pin-identical real TPS562202
(+ matching TI datasheet URL)
Golden round-trip (M0-Q-02) + snapshot re-verified byte-identical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviewer's GuideImplements the remaining M0–M3 backlog items T1–T9: adds design‑intent validators and high‑speed MCP tools, wires full MPN resolution through a new library search route and bundled KiCad 9.0.0 library mirror, introduces STEP export and session‑fork tooling, adds drop‑to‑import for libraries and new slash commands, and updates docs/observability and examples to match the real bundled libraries. Sequence diagram for kc_mpn_resolve with distributors and library searchsequenceDiagram
actor Claude
participant MCP as MCP_kc_mpn_resolve
participant Dist as DistributorAggregator
participant KS as Kiserver
participant LI as LibraryIndex
Claude->>MCP: kc_mpn_resolve{ mpn, manufacturer, footprint, project_id }
MCP->>MCP: _shape_rejection(mpn)
alt [invalid MPN shape]
MCP-->>Claude: envelope{ ok:true, found:false, reason, stock:null, symbol_candidates:[] }
else [valid MPN]
MCP->>Dist: price(mpn, qty=1)
Dist-->>MCP: pricing
MCP->>Dist: aclose()
opt [project_id present]
MCP->>KS: GET /project/{id}/library/search?query=mpn
KS->>LI: LibraryIndex.search(query)
LI-->>KS: hits[]
KS-->>MCP: { hits: [...] }
MCP->>MCP: _library_candidates(hits)
end
MCP->>MCP: _confidence(..., found, has_candidates)
MCP-->>Claude: envelope{ ok:true, found, stock, symbol_candidates, footprint_candidates, confidence }
end
Sequence diagram for FR-043 library drop-to-import flowsequenceDiagram
actor User
participant Browser as LibraryImportDropZone/useLibraryImport
participant GW as Gateway_server
participant KS as Kiserver
participant FS as Project_filesystem
User->>Browser: Drop .kicad_sym / .kicad_mod
Browser->>Browser: kindForFile(filename)
Browser->>GW: POST /api/server/project/{id}/library/import
GW->>KS: POST /project/{id}/library/import
alt [kind == symbol]
KS->>FS: write imported-libs/<name>.kicad_sym
KS->>FS: _append_lib_table_row(sym-lib-table,...)
else [kind == footprint]
KS->>FS: write imported.pretty/<name>.kicad_mod
KS->>FS: _append_lib_table_row(fp-lib-table,...)
end
KS-->>GW: { ok:true, nickname, lib_id_prefix, uri }
GW-->>Browser: same JSON
Browser-->>User: Show "Imported <nickname> (<lib_id_prefix>)"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Code Review
This pull request introduces several major features, including a pinned KiCad library mirror for offline part resolution, drag-and-drop library imports (FR-043), structured BOM retrieval, session branching, and high-speed design-intent validators (KC020-KC050) with corresponding MCP tools. Feedback on the changes focuses on critical performance and robustness improvements: offloading synchronous file and database operations in FastAPI endpoints to standard synchronous functions to avoid blocking the asyncio event loop, enhancing the decoupling and ground partition checks to prevent false negatives, adding thread safety to library table modifications, and implementing defensive checks to prevent crashes from malformed data or negative impedance calculations.
| unbypassed = [ | ||
| pn | ||
| for pn in sorted(power_nets) | ||
| if not any(c == "cap" for (_, c) in net_members.get(pn, [])) | ||
| ] |
There was a problem hiding this comment.
The current decoupling check only verifies if any capacitor is connected to the power net. However, a bypass capacitor must be connected between the power rail and ground to be effective. If a capacitor is connected in series or between two non-ground nets, it is not a bypass capacitor. We should verify that the capacitor also connects to a ground net (e.g., containing 'GND' or 'VSS').
unbypassed = []
for pn in sorted(power_nets):
has_bypass = False
for (other_ref, cls) in net_members.get(pn, []):
if cls == "cap":
other_nets = fp_nets.get(other_ref, set())
if any("GND" in gn.upper() or "VSS" in gn.upper() for gn in other_nets):
has_bypass = True
break
if not has_bypass:
unbypassed.append(pn)| if len(bridges) > 1: | ||
| findings.append( | ||
| { | ||
| "code": "KC050", | ||
| "severity": "error", | ||
| "message": ( | ||
| f"Partition violation: {agnd} and {dgnd} are tied by " | ||
| f"{len(bridges)} components ({', '.join(bridges)}); a split-" | ||
| "ground design needs exactly one bridge (single-point tie)." | ||
| ), | ||
| "target_uuid": None, | ||
| } | ||
| ) |
There was a problem hiding this comment.
The current ground partition check only flags if there are multiple bridges (len(bridges) > 1). However, if there are zero bridges (len(bridges) == 0), the analog and digital grounds are completely isolated, which is also a severe partition violation that causes reference drift and noise. We should flag both cases.
if len(bridges) == 0:
findings.append(
{
"code": "KC050",
"severity": "error",
"message": (
f"Partition violation: {agnd} and {dgnd} are completely isolated; "
"a split-ground design needs exactly one bridge (single-point tie) "
"to prevent reference drift."
),
"target_uuid": None,
}
)
elif len(bridges) > 1:
findings.append(
{
"code": "KC050",
"severity": "error",
"message": (
f"Partition violation: {agnd} and {dgnd} are tied by "
f"{len(bridges)} components ({', '.join(bridges)}); a split-"
"ground design needs exactly one bridge (single-point tie)."
),
"target_uuid": None,
}
)There was a problem hiding this comment.
Hey - I've found 7 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="services/mcp/src/kc_mcp/tools/mpn.py" line_range="78-86" />
<code_context>
+ # distributor or fails closed).
+ found = False
+ stock: dict[str, Any] = {"quotes": []}
+ aggregator = sourcing._factory()
+ try:
+ part = await aggregator.price(raw_mpn, qty=1)
+ found = bool(getattr(part, "quotes", None))
+ stock = _pricing_to_payload(part)
+ except Exception as e:
+ stock = {"quotes": [], "error": f"distributor lookup failed: {e}"}
+ finally:
+ with contextlib.suppress(Exception):
+ await aggregator.aclose()
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Handle potential failures in creating the distributor aggregator explicitly.
If `sourcing._factory()` raises (e.g., due to misconfiguration), `aggregator` is never assigned and the `finally` block will raise when trying to `await aggregator.aclose()`, masking the real error. Consider initializing `aggregator: sourcing.Aggregator | None = None` before the `try` and only calling `aclose()` when it’s not `None` to avoid this secondary exception.
</issue_to_address>
### Comment 2
<location path="client/src/components/schematic/LibraryImport.tsx" line_range="24-27" />
<code_context>
+
+type ImportState = "idle" | "importing" | "done" | "error";
+
+function kindForFile(name: string): "symbol" | "footprint" | null {
+ if (name.endsWith(".kicad_sym")) return "symbol";
+ if (name.endsWith(".kicad_mod")) return "footprint";
+ return null;
+}
+
</code_context>
<issue_to_address>
**nitpick (bug_risk):** Normalize filename case when inferring library kind from extension.
These checks are case-sensitive, so files like `CUSTOM.KICAD_SYM` or `Foo.KiCad_Mod` will be treated as unsupported. Consider lowercasing `name` before the `.endsWith` checks to accept extensions in any case.
</issue_to_address>
### Comment 3
<location path="services/mcp/tests/test_validate_kc.py" line_range="88-93" />
<code_context>
+ assert len(kc) == 1 and kc[0]["severity"] == "error"
+
+
+def test_kc021_rail_with_regulator_clears() -> None:
+ proj = _project(
+ nets=[{"name": "+3V3"}, {"name": "GND"}],
+ footprints=[_fp("VR1", "+3V3", "GND"), _fp("C1", "+3V3", "GND")],
+ )
+ assert _codes(_run_validators(proj), "KC021") == []
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a KC021 test for rails driven by ICs (not only regulators/PWR_FLAG)
KC021 considers a net driven if any member is classified as `"ic"`, `"reg"`, or `"active"` by `_refdes_class`. Current tests cover the regulator (`VR1`), PWR_FLAG, and a pure-passive rail, but not a rail driven only by an IC. Please add a case (e.g. `U1` on `+3V3` with only passives otherwise) to assert that an IC-powered rail is treated as driven and to guard against regressions in `_refdes_class`/`has_active`.
```suggestion
def test_kc021_rail_with_regulator_clears() -> None:
proj = _project(
nets=[{"name": "+3V3"}, {"name": "GND"}],
footprints=[_fp("VR1", "+3V3", "GND"), _fp("C1", "+3V3", "GND")],
)
assert _codes(_run_validators(proj), "KC021") == []
def test_kc021_rail_driven_by_ic_clears() -> None:
proj = _project(
nets=[{"name": "+3V3"}, {"name": "GND"}],
footprints=[_fp("U1", "+3V3", "GND"), _fp("C1", "+3V3", "GND")],
)
assert _codes(_run_validators(proj), "KC021") == []
```
</issue_to_address>
### Comment 4
<location path="services/mcp/tests/test_validate_kc.py" line_range="175-176" />
<code_context>
+}
+
+
+def _imp_project(width: float, target: float, stackup: dict[str, Any] | None = _STACKUP):
+ return _project(
+ nets=[{"name": "CLK", "class": "Sig", "target_impedance_ohm": target}],
+ net_classes=[{"name": "Sig", "track_width_mm": width}],
</code_context>
<issue_to_address>
**suggestion (testing):** Consider a KC040 test where the net class exists but has no width, to pin the `unknown`/warning path
Current KC040 tests cover normal, off-target, and missing-stackup cases, plus `_microstrip_z0` monotonicity. There’s also a path where `_net_class_width` returns `None` (net class present but no `track_width_*`), which yields a “missing geometry” warning. Please add a test that creates a project with a net class lacking width to lock in and document this behaviour.
</issue_to_address>
### Comment 5
<location path="services/mcp/tests/test_highspeed_tools.py" line_range="122-128" />
<code_context>
+ assert any(f["code"] == "KC050" for f in out["violations"])
+
+
+async def test_impedance_check_returns_per_net_result(mock) -> None: # type: ignore[no-untyped-def]
+ out = _payload(await kc_impedance_check.handler({"project_id": "p1"}))
+ assert out["ok"] is True
+ clk = next(r for r in out["results"] if r["net"] == "CLK")
+ assert clk["target_ohm"] == 50.0
+ assert clk["achieved_ohm"] is not None
+ assert clk["status"] in {"ok", "warning", "error"}
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a kc_impedance_check test for the `status='unknown'` / missing-geometry case
`kc_impedance_check` has an explicit `status: "unknown"` branch when Er/height or width are missing. Please add a test that adjusts the mock project (e.g. clears `stackup.layers` or removes `track_width_mm`) and asserts a result with `achieved_ohm is None` and `status == "unknown"` to cover this degradation path.
Suggested implementation:
```python
async def test_partition_check_flags_double_ground_bridge(mock) -> None: # type: ignore[no-untyped-def]
out = _payload(await kc_partition_check.handler({"project_id": "p1"}))
assert out["ok"] is True
assert any(f["code"] == "KC050" for f in out["violations"])
async def test_impedance_check_marks_missing_geometry_as_unknown(mock) -> None: # type: ignore[no-untyped-def]
# Remove stackup geometry so impedance calculation for CLK degrades to "unknown"
project = mock.project
original_layers = project.get("stackup", {}).get("layers")
if "stackup" in project:
project["stackup"]["layers"] = []
try:
out = _payload(await kc_impedance_check.handler({"project_id": "p1"}))
assert out["ok"] is True
clk = next(r for r in out["results"] if r["net"] == "CLK")
assert clk["achieved_ohm"] is None
assert clk["status"] == "unknown"
finally:
# Restore original geometry so other tests see the default project
if "stackup" in project:
project["stackup"]["layers"] = original_layers
A self-contained `httpx.MockTransport` stands in for kiserver +
```
If `mock.project` is structured differently (e.g. stackup stored under another key, or `layers` is not a direct child of `stackup`), adjust the `project["stackup"]["layers"]` access accordingly to ensure the geometry removal actually triggers the `"unknown"` status path in `kc_impedance_check`.
</issue_to_address>
### Comment 6
<location path="services/mcp/tests/test_mpn_resolve.py" line_range="72-77" />
<code_context>
+ assert "required" in out["error"]
+
+
+async def test_shape_rejection_is_not_found() -> None:
+ out = _payload(await kc_mpn_resolve.handler({"mpn": "!!!"}))
+ assert out["ok"] is True
+ assert out["found"] is False
+ assert out["reason"] == "not_an_mpn_shape"
+ assert out["confidence"] == 0.0
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Extend shape-rejection coverage to exercise the `missing_digit_or_letter` path
The current test input (`"!!!"`) only hits the `not_an_mpn_shape` path because it doesn’t match `_MPN_SHAPE_RE` at all. Please add a second case that matches the regex but lacks either a digit or a letter (e.g. `"ABCDEF"` or `"123456"`) and assert that it returns the `missing_digit_or_letter` reason, so that branch remains covered and stable.
```suggestion
async def test_shape_rejection_is_not_found() -> None:
# Case 1: does not match the MPN shape at all
out = _payload(await kc_mpn_resolve.handler({"mpn": "!!!"}))
assert out["ok"] is True
assert out["found"] is False
assert out["reason"] == "not_an_mpn_shape"
assert out["confidence"] == 0.0
# Case 2: matches the MPN shape but is missing a digit or a letter
out_missing = _payload(await kc_mpn_resolve.handler({"mpn": "ABCDEF"}))
assert out_missing["ok"] is True
assert out_missing["found"] is False
assert out_missing["reason"] == "missing_digit_or_letter"
assert out_missing["confidence"] == 0.0
```
</issue_to_address>
### Comment 7
<location path=".claude/commands/snapshot.md" line_range="10-3" />
<code_context>
+ - mcp__kiclaude__kc_snapshot_create
+---
+
+# /snapshot — pin a revertable checkpoint
+
+A snapshot is a cheap "save point" before a risky edit (a big
</code_context>
<issue_to_address>
**nitpick (typo):** Consider correcting "revertable" to "revertible" (or "reversible") in the snapshot docs.
"Revertable" appears in both the heading and description and is a nonstandard spelling. Consider using "revertible snapshot" / "revertible checkpoint" (or "reversible") to avoid it reading like a typo in user-facing docs.
Suggested implementation:
```
description: Create a named, revertible snapshot of the current KCIR project state via kc_snapshot_create, so a later /revert can roll back to exactly this point. Read-only with respect to the .kicad_* files — snapshots live in the content-addressed store, not the board.
```
```
# /snapshot — pin a revertible checkpoint
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| aggregator = sourcing._factory() | ||
| try: | ||
| part = await aggregator.price(raw_mpn, qty=1) | ||
| found = bool(getattr(part, "quotes", None)) | ||
| stock = _pricing_to_payload(part) | ||
| except Exception as e: | ||
| stock = {"quotes": [], "error": f"distributor lookup failed: {e}"} | ||
| finally: | ||
| with contextlib.suppress(Exception): |
There was a problem hiding this comment.
issue (bug_risk): Handle potential failures in creating the distributor aggregator explicitly.
If sourcing._factory() raises (e.g., due to misconfiguration), aggregator is never assigned and the finally block will raise when trying to await aggregator.aclose(), masking the real error. Consider initializing aggregator: sourcing.Aggregator | None = None before the try and only calling aclose() when it’s not None to avoid this secondary exception.
| function kindForFile(name: string): "symbol" | "footprint" | null { | ||
| if (name.endsWith(".kicad_sym")) return "symbol"; | ||
| if (name.endsWith(".kicad_mod")) return "footprint"; | ||
| return null; |
There was a problem hiding this comment.
nitpick (bug_risk): Normalize filename case when inferring library kind from extension.
These checks are case-sensitive, so files like CUSTOM.KICAD_SYM or Foo.KiCad_Mod will be treated as unsupported. Consider lowercasing name before the .endsWith checks to accept extensions in any case.
| def _imp_project(width: float, target: float, stackup: dict[str, Any] | None = _STACKUP): | ||
| return _project( |
There was a problem hiding this comment.
suggestion (testing): Consider a KC040 test where the net class exists but has no width, to pin the unknown/warning path
Current KC040 tests cover normal, off-target, and missing-stackup cases, plus _microstrip_z0 monotonicity. There’s also a path where _net_class_width returns None (net class present but no track_width_*), which yields a “missing geometry” warning. Please add a test that creates a project with a net class lacking width to lock in and document this behaviour.
| async def test_impedance_check_returns_per_net_result(mock) -> None: # type: ignore[no-untyped-def] | ||
| out = _payload(await kc_impedance_check.handler({"project_id": "p1"})) | ||
| assert out["ok"] is True | ||
| clk = next(r for r in out["results"] if r["net"] == "CLK") | ||
| assert clk["target_ohm"] == 50.0 | ||
| assert clk["achieved_ohm"] is not None | ||
| assert clk["status"] in {"ok", "warning", "error"} |
There was a problem hiding this comment.
suggestion (testing): Add a kc_impedance_check test for the status='unknown' / missing-geometry case
kc_impedance_check has an explicit status: "unknown" branch when Er/height or width are missing. Please add a test that adjusts the mock project (e.g. clears stackup.layers or removes track_width_mm) and asserts a result with achieved_ohm is None and status == "unknown" to cover this degradation path.
Suggested implementation:
async def test_partition_check_flags_double_ground_bridge(mock) -> None: # type: ignore[no-untyped-def]
out = _payload(await kc_partition_check.handler({"project_id": "p1"}))
assert out["ok"] is True
assert any(f["code"] == "KC050" for f in out["violations"])
async def test_impedance_check_marks_missing_geometry_as_unknown(mock) -> None: # type: ignore[no-untyped-def]
# Remove stackup geometry so impedance calculation for CLK degrades to "unknown"
project = mock.project
original_layers = project.get("stackup", {}).get("layers")
if "stackup" in project:
project["stackup"]["layers"] = []
try:
out = _payload(await kc_impedance_check.handler({"project_id": "p1"}))
assert out["ok"] is True
clk = next(r for r in out["results"] if r["net"] == "CLK")
assert clk["achieved_ohm"] is None
assert clk["status"] == "unknown"
finally:
# Restore original geometry so other tests see the default project
if "stackup" in project:
project["stackup"]["layers"] = original_layers
A self-contained `httpx.MockTransport` stands in for kiserver +If mock.project is structured differently (e.g. stackup stored under another key, or layers is not a direct child of stackup), adjust the project["stackup"]["layers"] access accordingly to ensure the geometry removal actually triggers the "unknown" status path in kc_impedance_check.
| @@ -0,0 +1,34 @@ | |||
| --- | |||
| name: snapshot | |||
| description: Create a named, revertable snapshot of the current KCIR project state via kc_snapshot_create, so a later /revert can roll back to exactly this point. Read-only with respect to the .kicad_* files — snapshots live in the content-addressed store, not the board. | |||
There was a problem hiding this comment.
nitpick (typo): Consider correcting "revertable" to "revertible" (or "reversible") in the snapshot docs.
"Revertable" appears in both the heading and description and is a nonstandard spelling. Consider using "revertible snapshot" / "revertible checkpoint" (or "reversible") to avoid it reading like a typo in user-facing docs.
Suggested implementation:
description: Create a named, revertible snapshot of the current KCIR project state via kc_snapshot_create, so a later /revert can roll back to exactly this point. Read-only with respect to the .kicad_* files — snapshots live in the content-addressed store, not the board.
# /snapshot — pin a revertible checkpoint
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Closes the outstanding M0–M3 gaps from the codebase audit (
Todo.md). Worked top-to-bottom as the Sequential execution backlog; each item is its own commit with tests.Done (T1–T9)
SPEC.mdroot redirectdocs/specs/SPEC-01-kiclaude.mddocs/architecture/+docs/observability/agent.hook.*span contract)/snapshot/revert/board-diff/add-led/add-usb-ckc_mpn_resolve(full)library/searchroutePOST /library/import+useLibraryImport/LibraryImportDropZone; 6 route + 5 client testslibs/mirror9.0.0subset (SHA-256 inMANIFEST.toml,populate_libs.py), merged intolibrary/search(FR-040)Notable in T9 (please review)
The bundled mirror can't honestly contain libraries KiCad doesn't ship, so the examples' fictional/wrong refs were corrected to real KiCad 9.0.0 parts:
MCU_Espressif:→RF_Module:ESP32-S3-WROOM-1ESP32-C6-WROOM-1→ESP32-C6-MINI-1; fabricatedPackage_BGA:DDR3L_BGA-16_4x4_P0.8mm→ realBGA-16_1.92x1.92mm_Layout4x4_P0.5mm(ValueMT41K256M16-DDR3L→BGA-16, since that DRAM is FBGA-96);RF_Connectors:U.FL_Molex_73412-0110→Connector_Coaxial:U.FL_Molex_MCRF_73412-0110_VerticalRegulator_Switching:TPS562201→ pin-identical realTPS562202(+ datasheet URL)Not in this PR (recorded, not stubbed)
occt-import-js(~20 MB wasm); SPEC §11 defers to M4.simpleXOR ≤ 0.01: empirically ruled out across 6 attempts (docs/plans/2026-05-24-m2-r-05d-edge-aligned-offset.md); needs a multi-weekClipperOffsetport.Verification
ruffclean ✓Known gaps
library/searchroute is symbol-only) — coverage gap for whoever addskc_footprint_search.🤖 Generated with Claude Code
Summary by Sourcery
Complete the remaining M0–M3 backlog items by wiring high-speed design validators, sourcing and STEP export tools, library search/import infrastructure, bundled KiCad libraries, and related docs and commands into the agent stack.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests: