diff --git a/periscope/dependency/simple_project/eval_golden.json b/periscope/dependency/simple_project/eval_golden.json index 3411c0a..2e9c55a 100644 --- a/periscope/dependency/simple_project/eval_golden.json +++ b/periscope/dependency/simple_project/eval_golden.json @@ -10,8 +10,6 @@ "PE-USBC-002|J1|/USBC.CC1", "PE-USBC-003|J1|", "PE-USBC-004|J1|", - "PE-USBC-005|J1|", - "PE-ETH-001|PCB|", - "PE-POE-001|PCB|" + "PE-USBC-005|J1|" ] } diff --git a/periscope/src/backend/periscopex/finding_engine.py b/periscope/src/backend/periscopex/finding_engine.py index ca3f689..771ba36 100644 --- a/periscope/src/backend/periscopex/finding_engine.py +++ b/periscope/src/backend/periscopex/finding_engine.py @@ -219,7 +219,7 @@ def _seed() -> None: _add("PE-ETH-004", "RECOMMENDED", "REVIEW", domain="shared", requirement="Bob Smith 75 Ω is typical for GbE; often inside MagJack.") _add("PE-POE-001", "TYPICAL", "INFO", domain="shared", - requirement="PoE certifier runs only with PoE evidence; bare RJ45 is N/A.") + requirement="PoE certifier runs only with PoE evidence; skip a bare RJ45.") _add("PE-POE-002", "TYPICAL", "INFO", domain="shared", requirement="PoE class/type from 802.3af/at/bt or Class n — never invented.") _add("PE-POE-003", "MANDATORY", "RULE", domain="shared", diff --git a/periscope/src/backend/periscopex/interface_class_check.py b/periscope/src/backend/periscopex/interface_class_check.py index 1d44c5b..3c8ebdd 100644 --- a/periscope/src/backend/periscopex/interface_class_check.py +++ b/periscope/src/backend/periscopex/interface_class_check.py @@ -67,7 +67,11 @@ _OHM_SUFFIX = re.compile(r"^(\d*\.?\d+)([RKMG])$", re.I) def check_interface_classes(graph: DesignGraph) -> list[Finding]: - """USB-C, Ethernet, and PoE class + connection integrity.""" + """Certify class + connection integrity for connectors actually on this graph. + + USB-C, RJ45/Ethernet, PoE (only with PoE evidence) are the method — not a + catalog. No connector → no that certifier. No invented DDR/PoE/USB3/I/Z. + """ out: list[Finding] = [] out.extend(_check_usb_c(graph)) out.extend(_check_ethernet(graph)) @@ -79,9 +83,9 @@ def format_interface_class_context(graph: DesignGraph) -> str: """Plain FACT block for AI review — not the verification engine.""" lines = [ "### Interface class (deterministic certifiers — do not invent)", - "USB-C: CC1/CC2, Rp/Rd 5.1 kΩ, VBUS/GND, SuperSpeed only if class is USB3.", - "Ethernet: 10/100 vs GbE; magnetics required for GbE. Bob Smith is recommended.", - "PoE: only with PoE evidence. Never invent PoE on a bare RJ45. No Z/I/mm.", + "USB-C / RJ45 / PoE only if that connector is on THIS graph. " + "PoE only with PoE evidence — never because RJ45 exists. " + "No DDR3 unless a DDR device is present. No invented Z/I/mm.", ] findings = check_interface_classes(graph) if not findings: @@ -98,8 +102,7 @@ def format_interface_class_context(graph: DesignGraph) -> str: def _check_usb_c(graph: DesignGraph) -> list[Finding]: connectors = [c for c in graph.components.values() if _is_usb_c(c)] if not connectors: - return [_na("PCB", "PE-USBC-001", "USB-C", - "No USB-C receptacle in the netlist (footprint/value/MPN/nets).")] + return [] out: list[Finding] = [] for comp in sorted(connectors, key=lambda c: c.reference): out.extend(_usb_c_one(graph, comp)) @@ -248,8 +251,7 @@ def _usb_c_ss_finding( def _check_ethernet(graph: DesignGraph) -> list[Finding]: jacks = [c for c in graph.components.values() if _is_ethernet_jack(c)] if not jacks: - return [_na("PCB", "PE-ETH-001", "Ethernet", - "No RJ45 / Ethernet jack in the netlist.")] + return [] out: list[Finding] = [] for comp in sorted(jacks, key=lambda c: c.reference): out.extend(_eth_one(graph, comp)) @@ -377,15 +379,11 @@ def _eth_bob_smith_finding( def _check_poe(graph: DesignGraph) -> list[Finding]: jacks = [c for c in graph.components.values() if _is_ethernet_jack(c)] if not jacks: - return [_na("PCB", "PE-POE-001", "PoE", - "No RJ45 — PoE is N/A (not invented).")] + return [] out: list[Finding] = [] for comp in sorted(jacks, key=lambda c: c.reference): ev = _poe_blob(graph, comp) if not ev: - out.append(_na(comp.reference, "PE-POE-001", "PoE", - f"{comp.reference} is RJ45 without PoE evidence — " - "PoE not certified (bare jack is not PoE).")) continue out.extend(_poe_one(graph, comp, ev)) return out @@ -722,15 +720,6 @@ def _nets_equal(a: str, b: str) -> bool: return _leaf(a).upper() == _leaf(b).upper() -def _na(designator: str, rule_id: str, kind: str, facts: str) -> Finding: - return _info( - designator, rule_id, - f"{kind} N/A — no candidate to certify.", - facts, - f"{kind} certifier runs always; absence is N/A, not ERROR.", - ) - - def _info( designator: str, rule_id: str, finding: str, facts: str, requirement: str, *, mpn: str = "", net: str | None = None, pins: list[str] | None = None, diff --git a/periscope/src/backend/periscopex/pcb_review.py b/periscope/src/backend/periscopex/pcb_review.py index 122903c..f1446ae 100644 --- a/periscope/src/backend/periscopex/pcb_review.py +++ b/periscope/src/backend/periscopex/pcb_review.py @@ -36,11 +36,13 @@ notes. Do not claim the via count or size is missing if that block lists them. Do not claim antenna keepout geometry is missing if keepout zones are listed. - Kelvin/sense pins, crystal keepout — only if named in the pintable/layout_rules. - Creepage/clearance only if the extraction or IEC number is in context. -- Interface class: USB-C CC/Rd/VBUS, Ethernet 10/100 vs GbE magnetics, \ -PoE only with evidence. Deterministic certifiers already ran; explain \ -those FACTS. Never invent PoE on a bare RJ45 or SuperSpeed on USB2 Type-C. \ -Never invent millimetres, Z, or I. Do not assume USB 500 mA — PE-PWR \ -skips when the datasheet has no I_load/Imax/I_abs. +- Interface class: only connectors on THIS board. USB-C CC/Rd/VBUS if a \ +USB-C receptacle exists; Ethernet 10/100 vs GbE if RJ45 exists; PoE only \ +with PoE evidence (never because RJ45 exists); DDR only if a DDR device \ +is present. Deterministic certifiers already ran; explain those FACTS. \ +Never invent a missing interface, PoE on a bare RJ45, or SuperSpeed on \ +USB2 Type-C. Never invent millimetres, Z, or I. Do not assume USB 500 mA \ +— PE-PWR skips when the datasheet has no I_load/Imax/I_abs. ### Evidence Cite numbers from "Parsed board geometry". Say insufficient evidence ONLY \ diff --git a/periscope/src/backend/periscopex/review_parse.py b/periscope/src/backend/periscopex/review_parse.py index afb155a..a9fea77 100644 --- a/periscope/src/backend/periscopex/review_parse.py +++ b/periscope/src/backend/periscopex/review_parse.py @@ -40,10 +40,11 @@ datasheet's recommended values. - Required external components named by the datasheet (bootstrap, \ compensation, feedback divider, sense resistor). - Unused / no-connect pins. -- Dedicated interface class (USB-C CC1/CC2 Rp/Rd 5.1 kΩ VBUS/GND; Ethernet \ -10/100 vs GbE magnetics; PoE only with evidence). Deterministic certifiers \ -own those FACTS. Do not invent PoE on a bare RJ45, SuperSpeed on USB 2.0 \ -Type-C, or geometry/Z/I. Do not assume USB 500 mA. +- Dedicated interface class only for connectors on THIS netlist (USB-C \ +CC1/CC2 Rp/Rd 5.1 kΩ VBUS/GND; Ethernet 10/100 vs GbE magnetics; PoE only \ +with evidence; DDR only if a DDR part exists). Deterministic certifiers \ +own those FACTS. Do not invent a missing interface, PoE on a bare RJ45, \ +SuperSpeed on USB 2.0 Type-C, or geometry/Z/I. Do not assume USB 500 mA. Then work the areas one at a time. For EACH area, don't just confirm a \ part is present — ask what specific failure mode would make it wrong \ diff --git a/periscope/src/docs/interface-class-certifiers.md b/periscope/src/docs/interface-class-certifiers.md index fbe50ce..cf9d39f 100644 --- a/periscope/src/docs/interface-class-certifiers.md +++ b/periscope/src/docs/interface-class-certifiers.md @@ -1,34 +1,24 @@ # Certifier di classe (interfacce) -Michele 2026-09-21: per USB-C, Ethernet (10/100 vs GbE), PoE, DDR3 e analoghe, check dedicati (deterministici + IA). Certificare **classe** e **integrità delle connessioni**. FEM termico: no, per ora. +Michele 2026-09-21: USB-C, RJ45/Ethernet, PoE, DDR3 sono **il metodo**, non un catalogo. Se **questa** scheda ha il connettore/bus, certifica classe + integrità delle connessioni. Se non c’è, non emettere quel certifier. HubAudio: J2 USB-C USB2 16P, J1 PoE 10/100 MagJack, niente DDR → niente finding DDR. RJ45 nudo ≠ PoE. FEM: no. I vs larghezza: solo con I datasheet (skip se manca). ## Cosa non è -Non è un unico check SI generico. Non è il DRC KiCad. Non è “via ampacity IPC” (traccia vs corrente è un altro motore). +Non è un unico check SI generico. Non è il DRC KiCad. Non è “via ampacity IPC”. Non è un elenco di bus immaginari. ## Formato finding -Classe dichiarata o inferita (FACT/REQUIREMENT da BOM, net, footprint, sheet). Se manca evidenza: INSUFFICIENT_EVIDENCE, niente geometria/Z/I inventati. Via ≠ pad ≠ track. +Classe dichiarata o inferita (FACT/REQUIREMENT da BOM, net, footprint, sheet). Se manca evidenza **sull’interfaccia presente**: INSUFFICIENT_EVIDENCE, niente geometria/Z/I inventati. Via ≠ pad ≠ track. Assenza di connettore → silenzio, non N/A. -## Prima fetta (shipped 2.61.0, skip-I 2.61.1) +## Presente su questa scheda (2.61.2) -| ID | Cosa certifica | -| --- | --- | -| PE-USBC-001 | Classe USB-C USB2 vs USB3 (BOM/footprint/MPN/net) | -| PE-USBC-002 | CC1 e CC2 connessi, non NC | -| PE-USBC-003 | Rd 5.1 kΩ ±10% verso GND, o Rp 56/22/10 kΩ verso VBUS; IC CC → INSUFFICIENT | -| PE-USBC-004 | VBUS e GND | -| PE-USBC-005 | Coppie SuperSpeed **solo** se la classe è USB3; USB2 = N/A | -| PE-ETH-001 | Classe 10/100 vs GbE | -| PE-ETH-002 | Coppie TX/RX (10/100) o quattro MDI (GbE) | -| PE-ETH-003 | Magnetics se GbE; N/A se non GbE | -| PE-ETH-004 | Bob Smith 75 Ω (RECOMMENDED; spesso nel MagJack) | -| PE-POE-001 | Evidenza PoE, altrimenti N/A (RJ45 nudo ≠ PoE) | -| PE-POE-002 | Classe/tipo 802.3af/at/bt se citati; altrimenti INSUFFICIENT | -| PE-POE-003 | Isolamento/magnetics solo con evidenza PoE | +| ID | Quando gira | Cosa certifica | +| --- | --- | --- | +| PE-USBC-001…005 | c’è un receptacle USB-C | classe USB2/USB3, CC1/CC2, Rd/Rp 5.1 kΩ, VBUS/GND, SuperSpeed solo se USB3 | +| PE-ETH-001…004 | c’è un RJ45 | 10/100 vs GbE, coppie TX/RX o 4 MDI, magnetics se GbE, Bob Smith REVIEW | +| PE-POE-001…003 | evidenza PoE sul jack | classe/tipo se citati; isolamento/magnetics; **skip** se RJ45 nudo | +| PE-DDR-* | solo se c’è un dispositivo DDR | non inventato su HubAudio (nessun DDR in BOM) | -Motore: `periscopex/interface_class_check.py` (grafo, non geometria). Schema `MODE=run` e PCB `MODE=pcb`. L’IA spiega i FACT, non certifica. Nessun I inventato (niente USB 500 mA): la corrente vs larghezza è PE-PWR, e **skip** se il datasheet non riporta I_load/Imax/I_abs. +Motore: `periscopex/interface_class_check.py` (grafo, non geometria). Schema `MODE=run` e PCB `MODE=pcb`. L’IA spiega i FACT, non certifica. Nessun I inventato: PE-PWR **skip** se il datasheet non riporta I_load/Imax/I_abs. -## Dopo - -DDR3 (indirizzo/comando vs DQ, lunghezze, VTT/VREF). Altre periferiche con lo stesso schema. +HubAudio (parti vere): J2 `USB_C_Receptacle_USB2.0_16P` → USB-C USB2 (SS N/A); J1 ARJP11A PoE 10/100 MagJack → Ethernet 10/100 + PoE; J3/J4 fibra, J5 SMA, jack audio → non inventare bus. Niente DDR. diff --git a/periscope/src/docs/piano-pcb-review.md b/periscope/src/docs/piano-pcb-review.md index 8ad89d4..0ba033d 100644 --- a/periscope/src/docs/piano-pcb-review.md +++ b/periscope/src/docs/piano-pcb-review.md @@ -76,7 +76,7 @@ Mutex vs analisi e vs placement. SSE `pcb_*`. IDs `PCB-{ref}-{001}`. KiCad `/net | PE-STCH-001 | pour GND + segnale senza via GND nel bbox | | PE-USBC-001…005 | classe USB-C + CC + Rd/Rp + VBUS/GND + SuperSpeed se USB3 | | PE-ETH-001…004 | 10/100 vs GbE; magnetics se GbE; Bob Smith REVIEW | -| PE-POE-001…003 | PoE solo con evidenza; isolamento/magnetics; RJ45 nudo = N/A | +| PE-POE-001…003 | PoE **solo** con evidenza sul jack; RJ45 nudo = skip (non N/A) | | Creepage | **skip** senza numero datasheet/IEC | | Crystal keepout | PE-PLC-004 se kind=keepout | @@ -125,7 +125,7 @@ Pintable skill **1.13.0** (`net_class` required on SI kinds). Older extracts wit | Gap | Why it stays out | | --- | --- | -| DDR3 class certifier | After USB-C / Ethernet / PoE first slice (2.61.0) | +| DDR class certifier | Only if a DDR device is on the graph. HubAudio has none — do not invent PE-DDR | | Thermal FEM / energy | PE-THM-002 is Tj=Ta+P·θJA with measured copper/vias; no spreading/FEM | | CPWG / OpenEMS | Field-solver export excluded from the ImpedenceFinder vendor snapshot | | ImpedenceFinder license | Upstream has **no LICENSE** (UNKNOWN). Not invented in-tree. See `vendor/impedancefinder/SOURCE.md` | diff --git a/periscope/src/frontend/content/changelog.md b/periscope/src/frontend/content/changelog.md index 09905e2..96b8006 100644 --- a/periscope/src/frontend/content/changelog.md +++ b/periscope/src/frontend/content/changelog.md @@ -2,6 +2,13 @@ What's new in Periscope. +## 2.61.2 — 2026-09-21 — Certifiers only for connectors on this board + +USB-C / RJ45 / PoE / DDR3 are the method, not a catalog. If this graph has a USB-C receptacle, run USB-C questions. If it has RJ45, run Ethernet. PoE only with PoE evidence — never because RJ45 exists. No connector → no that certifier (not N/A). HubAudio has USB-C USB2 + PoE 10/100 MagJack and no DDR: no DDR findings. Skip-I (2.61.1) unchanged. No FEM, no via IPC, no invented I/Z/PoE/SuperSpeed. + +- [Fixed] Absent USB-C / RJ45 / PoE no longer emit INFO N/A. +- [Fixed] Bare RJ45 is Ethernet only; PoE is skipped without PoE evidence. + ## 2.61.1 — 2026-09-21 — Skip trace-width vs current without datasheet I PE-PWR-001 (and PE-VIA-001) run only when the datasheet reports I_load / Imax / I_abs. Missing that number is a skip — not INFO INSUFFICIENT, not a typical USB 500 mA, not Iout_max-as-load. USB-C / Ethernet / PoE class certifiers still have no current/ampacity check. No via IPC table. No FEM. diff --git a/periscope/src/frontend/package.json b/periscope/src/frontend/package.json index 0473c8f..e1be359 100644 --- a/periscope/src/frontend/package.json +++ b/periscope/src/frontend/package.json @@ -1,6 +1,6 @@ { "name": "periscope-web", - "version": "2.61.1", + "version": "2.61.2", "private": true, "scripts": { "sync-version": "node scripts/sync-version.mjs", diff --git a/tests/test_eval_report.py b/tests/test_eval_report.py index 0ef734b..3b149b9 100644 --- a/tests/test_eval_report.py +++ b/tests/test_eval_report.py @@ -2,7 +2,7 @@ Favor: perfect golden match; citation rate ignores deterministic findings; simple_project graph still has U1/U2/U3, the two I2C pull-up keys, -and USB-C class certifiers on J1 (Ethernet/PoE N/A). +and USB-C class certifiers on J1 (no Ethernet/PoE — simple_project has no RJ45). Against: extra finding drops precision; missing golden key drops recall; Unverified quotes are citation misses, not hits. """ @@ -88,9 +88,9 @@ def test_simple_project_eval_matches_committed_golden(): assert scores.graph_ok, scores.graph_errors assert scores.precision == 1.0 assert scores.recall == 1.0 - assert scores.finding_count == 10 + assert scores.finding_count == 8 assert scores.by_status["WARNING"] == 2 - assert scores.by_status["INFO"] == 8 + assert scores.by_status["INFO"] == 6 def test_simple_project_eval_rejects_truncated_graph(tmp_path: Path): diff --git a/tests/test_interface_class_check.py b/tests/test_interface_class_check.py index 816350d..05060ba 100644 --- a/tests/test_interface_class_check.py +++ b/tests/test_interface_class_check.py @@ -128,7 +128,8 @@ def _usbc_device_graph(*, ss: bool = False, usb2_value: bool = True) -> DesignGr return DesignGraph(components=comps, nets=nets) -def test_no_connector_is_na_not_error(): +def test_no_connector_emits_nothing(): + """No USB-C / no RJ45 / no PoE evidence → do not emit that certifier.""" g = DesignGraph( components={ "U1": _comp("U1", ctype=ComponentType.IC, value="MCU", pins={"1": "GND"}), @@ -136,16 +137,8 @@ def test_no_connector_is_na_not_error(): nets={"GND": _net("GND", NetType.GROUND, ("U1", "1"))}, ) findings = check_interface_classes(g) - for f in findings: - complete_finding(f) - assert _by_rule(findings, "PE-USBC-001") - assert _by_rule(findings, "PE-ETH-001") - assert _by_rule(findings, "PE-POE-001") - assert all(f.status != "ERROR" for f in findings) - assert all(f.finding_class == "INFO" for f in findings) - assert "N/A" in _by_rule(findings, "PE-USBC-001")[0].finding - assert "N/A" in _by_rule(findings, "PE-ETH-001")[0].finding - assert "N/A" in _by_rule(findings, "PE-POE-001")[0].finding + assert findings == [] + assert not any((f.rule_id or "").startswith("PE-DDR") for f in findings) def test_usbc_rd_vbus_gnd_certified(): @@ -166,6 +159,7 @@ def test_usbc_rd_vbus_gnd_certified(): assert ss.finding_class == "INFO" assert "N/A" in ss.finding or "USB2" in ss.finding assert all(f.status != "ERROR" for f in findings if f.designator == "J2") + assert not any((f.rule_id or "").startswith(("PE-ETH", "PE-POE", "PE-DDR")) for f in findings) def test_usbc_missing_cc2_is_error(): @@ -429,13 +423,11 @@ def test_bare_rj45_does_not_invent_poe(): findings = check_interface_classes(g) for f in findings: complete_finding(f) - poe = _by_rule(findings, "PE-POE-001", "J1")[0] - assert poe.status != "ERROR" - assert poe.finding_class == "INFO" - assert "N/A" in poe.finding - assert not _by_rule(findings, "PE-POE-003", "J1") or _by_rule( - findings, "PE-POE-003", "J1", - )[0].status != "ERROR" + assert _by_rule(findings, "PE-ETH-001", "J1") + assert not any((f.rule_id or "").startswith("PE-POE") for f in findings) + assert not any((f.rule_id or "").startswith("PE-USBC") for f in findings) + assert not any((f.rule_id or "").startswith("PE-DDR") for f in findings) + assert all(f.status != "ERROR" for f in findings if (f.rule_id or "").startswith("PE-ETH")) def test_poe_with_evidence_requires_magnetics_isolation(): @@ -494,10 +486,9 @@ def test_simple_project_usbc_not_false_error(): ss = _by_rule(findings, "PE-USBC-005", "J1")[0] assert ss.status != "ERROR" assert ss.evidence_status == "INSUFFICIENT" or "N/A" in ss.finding - assert _by_rule(findings, "PE-ETH-001")[0].status != "ERROR" - assert "N/A" in _by_rule(findings, "PE-ETH-001")[0].finding - assert _by_rule(findings, "PE-POE-001")[0].status != "ERROR" - assert "N/A" in _by_rule(findings, "PE-POE-001")[0].finding + assert not any((f.rule_id or "").startswith("PE-ETH") for f in findings) + assert not any((f.rule_id or "").startswith("PE-POE") for f in findings) + assert not any((f.rule_id or "").startswith("PE-DDR") for f in findings) def test_hubaudio_like_usbc_usb2_and_poe_magjack(): @@ -538,6 +529,17 @@ def test_hubaudio_like_usbc_usb2_and_poe_magjack(): for f in findings if (f.rule_id or "").startswith(("PE-USBC", "PE-ETH", "PE-POE")) ) + assert not any((f.rule_id or "").startswith("PE-DDR") for f in findings) + + +def test_hubaudio_bom_has_usbc_and_poe_rj45_not_ddr(): + """HubAudio actual parts: J2 USB-C USB2 16P, J1 PoE 10/100 MagJack, no DDR.""" + from tests.paths import REPO_ROOT + bom = (REPO_ROOT / "tests" / "fixtures" / "hubaudio_kicad_bom.csv").read_text() + assert "USB_C_Receptacle_USB2.0_16P" in bom + assert "RJ45" in bom and "PoE" in bom + assert "DDR3" not in bom and "DDR2" not in bom and "DDR4" not in bom + assert "USB3" not in bom def test_rule_catalog_shared_not_si(): @@ -551,16 +553,14 @@ def test_rule_catalog_shared_not_si(): assert rec.domain == "shared" -def test_run_pcb_checks_includes_interface_class(): +def test_run_pcb_checks_skips_absent_interfaces(): findings = run_pcb_checks(DesignGraph(), {}, None) ids = {f.rule_id for f in findings} - assert "PE-USBC-001" in ids - assert "PE-ETH-001" in ids - assert "PE-POE-001" in ids - if_f = [f for f in findings if (f.rule_id or "").startswith(("PE-USBC", "PE-ETH", "PE-POE"))] - assert if_f - assert all(f.status != "ERROR" for f in if_f) - assert all((f.finding_id or "").startswith("PCB-") for f in if_f) + assert "PE-USBC-001" not in ids + assert "PE-ETH-001" not in ids + assert "PE-POE-001" not in ids + if_f = [f for f in findings if (f.rule_id or "").startswith(("PE-USBC", "PE-ETH", "PE-POE", "PE-DDR"))] + assert if_f == [] def test_merge_drops_duplicate_pcb_interface_findings(): diff --git a/tests/test_placement_check.py b/tests/test_placement_check.py index c79ec0d..bcc636e 100644 --- a/tests/test_placement_check.py +++ b/tests/test_placement_check.py @@ -48,7 +48,7 @@ def test_simple_project_without_pcb_has_no_ps_plc(): def test_simple_project_eval_has_no_placement_keys(): scores = eval_simple_project(SIMPLE) - assert scores.finding_count == 10 + assert scores.finding_count == 8 assert scores.precision == 1.0 assert scores.recall == 1.0 assert not any(k.startswith("PE-PLC-") for k in scores.extra_keys) diff --git a/tests/test_si_check.py b/tests/test_si_check.py index 87b304b..de2b1fc 100644 --- a/tests/test_si_check.py +++ b/tests/test_si_check.py @@ -54,7 +54,7 @@ def test_simple_project_without_pcb_has_no_ps_si_001(): def test_simple_project_eval_has_no_si_keys(): scores = eval_simple_project(SIMPLE) - assert scores.finding_count == 10 + assert scores.finding_count == 8 assert scores.precision == 1.0 assert scores.recall == 1.0 assert not any( diff --git a/tests/test_validation_concurrency.py b/tests/test_validation_concurrency.py index eebaad3..8d41b4e 100644 --- a/tests/test_validation_concurrency.py +++ b/tests/test_validation_concurrency.py @@ -160,9 +160,9 @@ async def test_concurrency_bounded_by_knob_and_charging_isolated(workspace, monk assert review_n == len(IC_MPNS) # all 5 reviewed if_ids = { f.get("rule_id") for f in report["findings"] - if (f.get("rule_id") or "").startswith(("PE-USBC", "PE-ETH", "PE-POE")) + if (f.get("rule_id") or "").startswith(("PE-USBC", "PE-ETH", "PE-POE", "PE-DDR")) } - assert "PE-USBC-001" in if_ids # N/A certifier, not a 6th IC review + assert not if_ids # five ICs, no USB-C/RJ45/DDR — do not invent those certifiers @pytest.mark.asyncio