Apply the finding engine to schematic and PCB reviews.

FACT, REQUIREMENT, and INFERENCE are separate fields; datasheet provenance
lives in the rule DB so Recommended cannot stay ERROR; LLM output is REVIEW.
Designer decisions persist across rescans. Schematic and PCB share one library
and the same finding object in the report UI.
This commit is contained in:
2026-09-20 08:38:59 +02:00
parent 8f4ebc645c
commit dc65e96a22
16 changed files with 797 additions and 211 deletions
+8 -1
View File
@@ -7,6 +7,7 @@ untouched. Does not write ``.kicad_pcb`` or packing coordinates.
from __future__ import annotations
import json
import logging
from datetime import datetime, timezone
from pathlib import Path
@@ -17,7 +18,7 @@ from backend.periscopex.cad_bridge import (
cad_index_from_graph,
write_cad_bridge,
)
from backend.periscopex.functional_groups import build_placement_plan
from backend.periscopex.finding_engine import apply_decisions
from backend.periscopex.graph import build_graph
from backend.periscopex.models import ComponentConstraints, DesignGraph, LayoutGraph, ValidationReport
from backend.periscopex.pcb_checks import assign_pcb_finding_ids, run_pcb_checks
@@ -227,6 +228,12 @@ async def run_pcb_pipeline(
_step(project_id, "write_report", "running")
assign_pcb_finding_ids(findings)
annotate_findings_cad(findings, cad_index_from_graph(graph))
dec_path = ws.local_path("decisions.json")
if dec_path.is_file():
try:
apply_decisions(findings, json.loads(dec_path.read_text()))
except Exception:
logger.exception("decisions.json apply failed")
summary: dict[str, int] = {"ERROR": 0, "WARNING": 0, "INFO": 0}
for f in findings:
summary[f.status] = summary.get(f.status, 0) + 1
+7
View File
@@ -21,6 +21,7 @@ from typing import Awaitable, Callable
log = logging.getLogger(__name__)
from backend.periscopex.finding_engine import apply_decisions
from backend.periscopex.models import (
ComponentConstraints,
ComponentType,
@@ -789,6 +790,12 @@ async def validate_design_async(
def _write_report(paused: bool = False) -> ValidationReport:
annotate_findings_cad(all_findings, graph.cad_index)
assign_finding_ids(all_findings)
dec_path = existing_path.with_name("decisions.json")
if dec_path.is_file():
try:
apply_decisions(all_findings, json.loads(dec_path.read_text()))
except Exception:
log.exception("decisions.json apply failed")
summary = {"total": len(all_findings), "ERROR": 0, "WARNING": 0, "INFO": 0}
for f in all_findings:
summary[f.status] = summary.get(f.status, 0) + 1