Gate interface certifiers to connectors on this board (2.61.2).
USB-C/RJ45/PoE/DDR3 are the method, not a catalog. No connector means no finding. Bare RJ45 is Ethernet only; PoE needs PoE evidence. HubAudio has USB-C and PoE MagJack, not DDR. Skip-I unchanged.
This commit is contained in:
@@ -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|"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user