USB-C A5/B5 are contacts, not EP. Datasheet pintable, KiCad .kicad_mod, and embedded PCB pads join by pin identity. Missing pintable skips; scalar pin_count is never an ERROR authority.
37 KiB
Albero delle analisi Periscope
Versione codice 2.63.1 (periscope/src/frontend/content/changelog.md). Letto in /Users/michelebigi/Development/periscope. Costituzione senza eccezioni: via ≠ pad ≠ traccia ≠ zona; niente I/Z/mm inventati; skip se manca evidenza. Non è DRC KiCad. DRC = KiCad. Questo documento mappa l’analisi, non implementa.
I test pytest stanno in tests/datasheet/, tests/library/, tests/schematic/, tests/pcb/, tests/af_ai/ (stessi file di 2.62.1, cartelle di mestiere). I path tests/test_*.py sotto i nodi restano i nomi file.
Due pipeline più una porta libreria (non è un esame):
- Libreria —
POST /api/library/datasheetsregistra un componente da PDF senzaMODE=run/MODE=pcb. - Schematico / review AI —
MODE=run,services/pipeline.py→validate_design_async(validation.py): estrazione datasheet, check deterministici, review IC DeepSeek. - Esame PCB —
MODE=pcb,services/pcb_pipeline.py→run_pcb_checks(pcb_checks.py, lista 2.62.1 invariata) + sezione additiva AF Board+AI (af_ai_hf.py) + review AI PCB (pcb_review.py/pcb_validation.py). Non auto-place.
I certifier USB-C / Ethernet / PoE girano su entrambe le pipeline (grafo, non geometria). DDR / CPU / FPGA / USB-PD sono la stessa qualità di finding ma partono da run_pcb_checks (grafo). Niente pezzo sul grafo → silenzio, non N/A.
Nodi analisi: 108 (99 PE-* + 1 LED senza rule_id + 8 processo estrazione/AI). Test pytest citati sotto i nodi: nomi reali da tests/.
Periscope 2.63.1
├── 0. Libreria (porta, non esame)
│ └── PDF + MPN → scheda (inbox IC / passivo / discreto) senza MODE=run/pcb
├── 1. Schematico / review AI (MODE=run)
│ ├── ingest (non è analisi: parser → grafo)
│ ├── estrazione datasheet
│ ├── check deterministici schema
│ ├── certifier di classe (condivisi con PCB)
│ └── review AI per-IC + post-pass
└── 2. Esame PCB (MODE=pcb)
├── ingest layout (non è DRC)
├── run_pcb_checks ← 2.62.1 invariato (SI + HF line inclusi)
│ ├── net / footprint
│ ├── placement vs layout_rules
│ ├── SI + linee HF (2.62.0 Fase A)
│ ├── DDR / CPU / FPGA (2.62.0)
│ ├── potenza / via / termico
│ ├── derating / timing / PI
│ ├── ESD / return / EMI / SPOF
│ ├── BOM ↔ PCB ↔ datasheet
│ └── resto Fase B (2.62.1)
├── AF Board + AI (additivo: flag → investigate_hf_hypotheses; non sostituisce SI/HF)
├── review AI PCB
└── tab antenna RF (non in run_pcb_checks)
1. Schematico / review AI (MODE=run)
Orchestrazione: pipeline.py stadi bom_parse → ic_extraction → simple_extraction → passive_extraction → graph_build → validation. Check deterministici: _run_deterministic_checks in validation.py. Finding ID schema PS-{ref}-{nnn} (non PCB-).
1.1 Ingest (prerequisito, non analisi)
Parser e grafo non emettono PE-*. Skip MPN: ic_mpn_skip_reason (silenzio onesto, niente MPN inventato).
- Test parser/grafo:
tests/test_bom_parser.py(test_parse_bom_uses_value_for_ic_when_mpn_column_empty,test_parse_bom_keeps_pnm_and_datasheet_url);tests/test_hubaudio_bom.py(tutti e 4);tests/test_netlist_parser.py(tutti e 3);tests/test_edif_parser.py(14);tests/test_kicad_parser.py(17);tests/test_kicad_project.py(19);tests/test_netlist_bundle.py(9);tests/test_functional_groups.py(8). - Test overlay parser:
tests/test_periscope_parsers_rewrite.py,tests/test_periscope_graph_rewrite.py,tests/test_periscope_models_rewrite.py.
1.2 Estrazione datasheet (processo)
Skip se manca PDF o lo skill non ha numero. Libreria library/extracted condivisa schema+PCB. PCB review non rilegge il PDF (pdf_path=None).
extract-pintable — skill skills/extract-pintable/
Modulo: services/datasheet_extract.py + llm/local_skill.py. Analizza: pin table, package, taxonomy IC.
- Skip se: niente PDF; IC già in libreria alla
model_versionminima. - Test:
tests/test_native_datasheet_extract.py(test_coerce_abs_max_matches_inherited,test_native_extract_has_no_anthropic_import);tests/test_pdf_ingest.py(6);tests/test_deepseek_provider.py(test_local_skills_load,test_extract_pdf_text_includes_page_markers,test_wroom_rejects_bare_soc_pin1_ant);tests/test_periscope_taxonomy_skills_src.py(test_pintable_skill_mentions_save_tool_and_wroom,test_skills_dir_is_src_and_local).
extract-specs — skill skills/extract-specs/
Analizza: specs discreti/connettori/cristalli; parametri fuori taxonomy → scartati.
- Skip se: niente PDF o tipo non in
SIMPLE_TYPES. - Test:
tests/test_pdf_ingest.py(test_coerce_abs_max_keeps_valid_drops_junk);tests/test_layout_rules.py(5 —layout_rulesnumerici, niente mm inventati).
extract-pattern — skill skills/extract-pattern/
Analizza: pattern MPN passivi (R/C/L/FB).
- Skip se: MPN opaco; DigiKey/value fallback copre prima.
- Test:
tests/test_inductor_specs.py(13, Z ferrite solo se il PDF dice N Ω @ freq);tests/test_pcb_software_bugs.py(test_lqw_decoder_and_unknown_skip,test_fb1_blm_is_bead_not_dcr_resistor).
Resolve DigiKey / catalogo (esatto MPN)
Modulo: services/digikey.py, passive_from_distributor.py, passive_from_mpn.py. Analizza: parametri catalogo per auto-resolve. Hit fuzzy rifiutati.
- Skip se: MPN non esatto; API assente (fail-soft).
- Test:
tests/test_digikey_match.py(3);tests/test_passive_from_distributor.py(7);tests/test_passive_from_mpn.py(7);tests/test_datasheet_finder.py(17);tests/test_library.py(5).
Resolve da stringa Value (solo progetto)
Modulo: services/passive_from_value.py. Specs value-derived non in libreria condivisa.
- Skip se: stringa ambigua / placeholder.
- Test:
tests/test_passive_from_value.py(8).
1.3 Check deterministici schema
Fail-soft per modulo. Senza evidenza: skip (lista vuota), non folklore.
PE-MUX-001 — pin_mux_check.py
Analizza: funzione pin vs net (UART/SPI/I2C mux).
Skip se: functions vuote; link inter-device stesso peripheral; net opaco.
- Test:
tests/test_pin_mux_check.py—test_real_defect_uart5_swapped_is_error,test_correct_assignment_no_finding,test_inter_device_same_peripheral_link_is_skipped,test_transceiver_peer_without_peripheral_still_fires,test_empty_functions_skipped,test_pin_exposes_peripheral_but_not_signal_no_complement,test_opaque_net_not_flagged,test_token_parser_and_normalizer,test_spi_legacy_net_names_match_modern_pin_functions,test_spi_controller_peripheral_names_are_synonyms,test_simple_project_uart0_nets_are_feasible_on_mspm0_pins,test_simple_project_uart0_swapped_on_mspm0_is_error,test_spi_genuine_infeasibility_still_fires_with_modern_names,test_finding_prints_full_raw_capability_list_and_intent_caveat,test_legacy_report_without_source_validates.
PE-NC-001 — nc_pin_check.py
Analizza: pin NC collegato a net attivo.
Skip se: niente pintable.
- Test:
tests/test_nc_pin_check.py—test_nc_pin_on_active_net_warns,test_nc_pin_on_nc_net_silent,test_no_pintable_silent.
PE-DEC-001 / PE-DEC-002 — passive_rail_check.py check_supply_decoupling
Analizza: condensatore sul net di alimentazione IC (001 presenza; 002 valore vs datasheet).
Skip se: net NC; pin enable strap; manca valore per 002.
- Test:
tests/test_passive_rail_check.py—test_missing_decoupling_is_warning,test_cap_to_gnd_clears_decoupling,test_enable_strapped_to_rail_is_not_decoupling,test_nc_supply_net_is_skipped,test_ldo_vout_needs_cout,test_ldo_vout_100n_only_is_value_warning,test_vdd_100n_is_not_a_value_warning,test_ki_cad_voltage_prefix_is_power,test_fb_and_rn_prefixes.
PE-I2C-001 / PE-I2C-002 — passive_rail_check.py check_i2c_pullups
Analizza: pull-up I2C (001 presenza; 002 valore vs banda).
Skip se: pin SDA è alias SPI; pull-up senza valore (002 non sizato); bus assente.
- Test:
tests/test_passive_rail_check.py—test_i2c_missing_pullup,test_i2c_pullup_present,test_i2c_pullup_to_3v3_digital_typed_as_signal,test_spi_pin_alias_sda_is_not_i2c,test_i2c_from_slash_alias_in_pin_name,test_i2c_4k7_pullup_is_in_nxp_wide_band,test_i2c_100ohm_pullup_is_too_stiff,test_i2c_100k_pullup_is_too_weak,test_i2c_pullup_without_value_is_not_sized.
PE-RST-001 / PE-RST-002 — passive_rail_check.py check_reset_pullups
Analizza: reset/enable pull (001 presenza; 002 verso vs datasheet).
Skip se: GPIO guida il reset.
- Test:
tests/test_passive_rail_check.py—test_reset_no_finding_when_gpio_drives,test_reset_floating_is_warning,test_nrst_pulldown_is_warning,test_nrst_pullup_is_not_pulldown.
PE-BOM-001 / PE-BOM-002 — bom_match_check.py
Analizza: MPN schema vs BOM (001 mismatch; 002 riga BOM orfana).
Skip se: mappa schematica vuota (PADS/EDIF senza properties).
- Test:
tests/test_bom_match_check.py—test_matching_mpns_produce_no_findings,test_mpn_mismatch_is_error_ps_bom_001,test_orphan_bom_ref_is_warning,test_mpn_case_and_whitespace_are_not_a_mismatch,test_empty_bom_mpn_with_schematic_mpn_is_not_a_mismatch,test_empty_schematic_map_skips_check,test_legacy_design_graph_without_source_fields_still_validates,test_build_graph_kicad_mpn_mismatch_surfaces.
PE-DNP-001 — dnp_check.py
Analizza: DNP vs enable floating.
Skip se: colonna DNP assente.
- Test:
tests/test_dnp_check.py—test_dnp_pull_leaves_enable_floating,test_fitted_pull_is_silent,test_no_dnp_column_skips_floating_enable,test_parse_bom_reads_dnp_and_skips_when_column_absent.
LED corrente — led_current_check.py (nessun PE-*)
Analizza: I_f Ohm vs rating canale. Source led_current_check.
Skip se: niente forward_current_*; tensione rail sconosciuta (non si indovina).
- Test:
tests/test_led_current_check.py—test_over_current_is_error,test_proper_resistor_no_finding,test_unknown_rail_no_error,test_no_rating_skipped,test_parse_resistance.
PE-TH-001 / PE-TH-002 / PE-TH-003 — thermal_check.py
Analizza: P = I_load × drop; Tj = Ta + P·θJA (001 INFO senza θJA o Tj ok; 002 WARNING Tj alto — non in catalogo finding_engine; 003 I²R shunt).
Skip se: manca I_load (Iout_max non è carico).
- Test:
tests/test_thermal_check.py—test_ldo_without_theta_ja_is_info,test_iout_max_is_not_used_as_load,test_ldo_hot_tj_is_warning,test_shunt_over_rating_is_warning,test_led_resistor_within_rating_is_silent.
PE-PWR-001 (schema) — power_margin_check.py
Analizza: Σ IQ + I_load vs Iout regolatore; caduta su R serie. Source power_margin_check.
Skip se: manca I_load; IQ assente non è fail.
- Test:
tests/test_power_margin_check.py—test_load_over_iout_max_is_ps_pwr_001,test_missing_iq_is_not_guessed_into_margin_fail,test_series_r_ir_drop_uses_i_load_not_trace,test_no_series_r_does_not_invent_trace_drop.
PE-SEQ-001 — sequencing_check.py
Analizza: PG → EN da note datasheet.
Skip se: niente spec power_sequence.
- Test:
tests/test_sequencing_check.py—test_pg_not_tied_to_en_is_warning,test_pg_tied_to_en_is_silent,test_no_power_sequence_spec_skips_even_if_pg_open.
PE-FLT-001 / PE-FLT-002 / PE-FLT-003 — filter_check.py
Analizza: topologia filtro (001), pezzo (002), fc vs ADC / DCR ferrite (003).
Skip se: manca C; pull-up+decoupling non è filtro; DCR ferrite senza limite datasheet.
- Test:
tests/test_filter_check.py—test_rc_reports_fc_info_without_adc_rate,test_rc_vs_adc_rate_is_warning,test_pullup_plus_decoupling_is_not_a_filter,test_missing_c_value_does_not_invent_fc_warning,test_pi_and_t_need_l_and_c,test_ferrite_dcr_warns_only_with_datasheet_limit.
PE-XTAL-001 / PE-XTAL-002 / PE-XTAL-003 — crystal_cl_check.py
Analizza: CL vs C1/C2 (001 coppia; 002 serie/stray; 003 drive). Cstray solo se in specs.
Skip se: niente CL in specs.
- Test:
tests/test_crystal_cl_check.py—test_no_cl_in_specs_is_silent,test_series_above_cl_without_stray_warns,test_with_stray_mismatch_warns,test_simple_project_without_cl_silent.
PE-LF-001 / PE-LF-002 / PE-LF-003 — lifecycle.py
Analizza: Obsolete / NRND / RoHS non-compliant.
Skip se: catalogo assente.
- Test:
tests/test_lifecycle_check.py—test_obsolete_is_warning_and_uses_distributor_replacement,test_nrnd_is_info,test_explicit_rohs_non_compliant_is_warning,test_active_is_silent,test_rohs_not_applicable_is_not_a_fail,test_missing_catalog_and_missing_substitute_are_not_guessed.
PE-INT-001 — internal_features_check.py
Analizza: ESD/pull interni vs net.
Skip se: internal_features vuoto (non si indovina open-drain).
- Test:
tests/test_internal_features_check.py—test_listed_open_drain_without_pull_is_warning,test_listed_pin_with_pullup_is_silent,test_empty_features_does_not_guess_open_drain.
PE-ESR-001 — hf_coverage_check.py
Analizza: copertura HF/ESR (bulk vs 100 n).
Skip se: valore C sconosciuto.
- Test:
tests/test_hf_coverage_check.py—test_bulk_only_is_info_ps_esr_001,test_bulk_plus_100n_is_silent,test_unknown_cap_value_is_not_guessed.
PE-ERRATA-001 — errata_check.py
Analizza: errata pubblicata vs pull sul pin.
Skip se: MPN sconosciuto o entry senza URL.
- Test:
tests/test_errata_check.py—test_missing_errata_pullup_is_ps_errata_001,test_pullup_present_is_silent,test_unknown_mpn_and_url_less_entry_are_silent.
Suite deterministica end-to-end: tests/test_validation_deterministic_seed.py test_deterministic_findings_seeded_and_not_reviewed; tests/test_eval_report.py test_simple_project_eval_matches_committed_golden.
1.4 Certifier di classe (grafo — schema e PCB)
Moduli: interface_class_check.py (schema e PCB), hf_bus_class.py (2.62.0, solo run_pcb_checks), usb_pd_check.py (2.62.1, solo PCB). Niente geometria. Niente connettore/dispositivo → silenzio.
USB-C — solo se receptacle USB-C sul grafo
PE-USBC-001classe USB2 vs USB3 da BOM/footprint/MPN/net.PE-USBC-002CC1 e CC2.PE-USBC-003Rd 5.1 kΩ ±10% o Rp 56/22/10 kΩ. Skip/INSUFFICIENT se R ignota o CC verso controller senza R.PE-USBC-004VBUS e GND.PE-USBC-005SuperSpeed solo se classe USB3; USB2 = N/A (non ERROR).
Test: tests/test_interface_class_check.py — test_no_connector_emits_nothing, test_usbc_rd_vbus_gnd_certified, test_usbc_missing_cc2_is_error, test_usbc_wrong_rd_is_error, test_usbc_cc_to_controller_without_r_is_insufficient_not_error, test_usbc_unknown_r_value_is_insufficient, test_usb3_class_without_ss_pairs_is_error, test_usb3_with_ss_pairs_is_certified, test_missing_vbus_is_error, test_simple_project_usbc_not_false_error, test_hubaudio_like_usbc_usb2_and_poe_magjack, test_usbc_vbus_does_not_invent_usb_500ma, test_does_not_use_layout_geometry, test_rule_catalog_shared_not_si.
Ethernet — solo se RJ45/MagJack
PE-ETH-001classe 10/100 vs GbE. Skip/INSUFFICIENT se velocità assente (non si inventa GbE).PE-ETH-002TX/RX (10/100) o quattro MDI (GbE).PE-ETH-003magnetics se GbE.PE-ETH-004Bob Smith 75 Ω: REVIEW (spesso in MagJack).
Test: tests/test_interface_class_check.py — test_ethernet_10_100_magjack_no_gbe_magnetics_error, test_gbe_without_magnetics_is_error, test_gbe_with_magnetics_is_certified, test_rj45_without_speed_is_insufficient_not_invented_gbe.
PoE — solo con evidenza PoE (RJ45 nudo = skip)
PE-POE-001evidenza PoE.PE-POE-002classe/tipo (802.3af/at/bt, Class n) — mai inventata.PE-POE-003magnetics/isolamento (MagJack o LAN transformer).PE-POE-004(2.62.1) tensione di isolamento solo da numero sourced. Skip senza V.
Test: tests/test_interface_class_check.py — test_bare_rj45_does_not_invent_poe, test_poe_with_evidence_requires_magnetics_isolation, test_poe_evidence_on_bare_jack_is_isolation_error, test_hubaudio_bom_has_usbc_and_poe_rj45_not_ddr, test_run_pcb_checks_skips_absent_interfaces; tests/test_pcb_phase_b.py — test_poe_isolation_skips_without_voltage_fact.
DDR — solo se DRAM sul grafo (2.62.0)
PE-DDR-001classe DRAM.PE-DDR-002CK, DQS, ≥8 DQ.PE-DDR-003VTT/VREF solo se quei net esistono (altrimenti skip, non VTT inventato).
Test: tests/test_hf_line_check.py — test_no_ddr_cpu_fpga_on_usb_only_graph, test_ddr_present_class_and_nets_skip_invented_vtt, test_rule_catalog_hf_ids.
CPU bus parallelo — solo se D/A/controllo esistono (2.62.0)
PE-CPU-001presenza bus parallelo.PE-CPU-002≥8 D/DQ/AD.PE-CPU-003address o AD mux.PE-CPU-004CS/WE/OE (o FMC).
Test: tests/test_hf_line_check.py — test_cpu_parallel_bus_only_when_data_addr_control_exist.
FPGA — solo se FPGA sul grafo (2.62.0)
PE-FPGA-001classe FPGA.PE-FPGA-002flash di config se c’è un flash IC (altrimenti skip).PE-FPGA-003VCCINT/VCCIO solo se net nominati.
Test: tests/test_hf_line_check.py — test_fpga_only_when_present_config_flash_optional.
USB-PD contratto — usb_pd_check.py (2.62.1)
PE-PD-001controller PD sul grafo (FUSB302/TPS257/…). Non è USB2 Rd. PDO non inventati.
Test: tests/test_pcb_phase_b.py — test_usb_pd_skips_without_pd_controller.
1.5 Review AI per-IC + post-pass
Moduli: review_session.py, pcb_review.py non entra qui. DeepSeek, PDF una volta per IC, fail-soft. Prompt tools grafo (find_connected_components, get_net_for_pin, get_pintable, get_datasheet_excerpt). Finding LLM = REVIEW, mai RULE ERROR (finding_engine).
Skip se: niente MPN; niente PDF (not_reviewed); fingerprint invariato (review_fingerprint.py).
- Review loop:
tests/test_native_review_loop.py(5);tests/test_validation_no_tool_recovery.pytest_no_tool_calls_triggers_forced_submit_next_turn;tests/test_validation_concurrency.py(3);tests/test_validation_trace_log.py(3);tests/test_review_parse.py(2);tests/test_quote_verify.py(5);tests/test_finding_engine.py(test_llm_review_is_never_rule,test_review_and_risk_cannot_stay_error,test_insufficient_evidence_does_not_stay_error);tests/test_fase_b_checks.pytest_llm_error_review_clamped_in_complete_finding;tests/test_review_fingerprint.py(2);tests/test_reprocess.py(4);tests/test_deepseek_provider.py(test_thinking_only_echoes_reasoning_content_on_follow_upe roundtrip tool). - Excerpt cross-IC:
tests/test_datasheet_excerpt_tool.py(12);tests/test_cache_breakpoint_limit.py(3). - Normalize (downgrade-only):
tests/test_normalize_findings.py(14);tests/test_periscope_postpass_rewrite.pytest_emmaforo_uart_normalize_cannot_promote_warning. - Dedupe cross-IC:
tests/test_dedupe_findings.py(11);tests/test_periscope_postpass_rewrite.pytest_emmaforo_uart_dedupe_collapses_both_endpoints.
2. Esame PCB (MODE=pcb)
Stadi: ensure_graph → parse_pcb → classify → inventory → run_pcb_checks → ai_review → pcb_report.json. ID finding PCB-{ref}-{001}. Mutex vs analisi schema e vs placement. Inventario net (pcb_inventory.py) è numeri, non finding.
KiCad DRC non è un nodo Periscope. tests/test_pcb_software_bugs.py test_drc_unconnected_items_count e test_hubaudio_pcb_lay004_vs_drc_order_of_magnitude servono solo a non copiare il DRC.
Suite orchestrazione: tests/test_pcb_review.py test_run_pcb_checks_assigns_pcb_ids_and_recommendations, test_pcb_pipeline_imports_build_placement_plan; tests/test_pcb_phase_b.py test_run_pcb_checks_phase_b_absent_is_silent, test_phase_b_rule_catalog; tests/test_interface_class_check.py test_merge_drops_duplicate_pcb_interface_findings; tests/test_pcb_sse_terminal.py (4).
2.1 Layout ingest (non DRC)
parsers_kicad_pcb.py → LayoutGraph. Nessun default 1 oz.
- Test:
tests/test_kicad_pcb.py(14);tests/test_pcb_via_not_pad.py(geometria via≠pad);tests/test_pcb_software_bugs.pytest_kicad10_name_only_nets_fill_index.
2.2 Net / footprint — pcb_net_match.py + pcb_checks._incomplete_layout_finding
PE-LAY-001
Pad PCB su net diverso dallo schema (stesso pin).
Skip se: layout assente.
- Test:
tests/test_pcb_review.py—test_pad_net_mismatch_is_pe_lay_001,test_hierarchy_plus_real_mismatch_keeps_only_real_pe_lay_001.
PE-LAY-002
Ref in schema, nessun footprint (tranne #PWR). Distingue “manca sulla PCB”.
- Test:
tests/test_pcb_review.pytest_missing_footprint_is_pe_lay_002;tests/test_incomplete_pcb.pytest_unplaced_ref_is_lay_002_not_invented_xy.
PE-LAY-003
Stesso net, solo prefisso /sheet/ KiCad (INFO, una volta).
- Test:
tests/test_pcb_review.pytest_kicad_hierarchy_slash_is_one_sync_finding_not_per_pad.
PE-LAY-004 — pcb_checks.py (non in catalogo finding_engine)
Pad net senza rame (track o via o zone). Skip NC unconnected-(…). INFO INSUFFICIENT, non FAIL inventato.
- Test:
tests/test_incomplete_pcb.pytest_run_pcb_checks_on_partial_layout_does_not_invent_tracks;tests/test_pcb_software_bugs.py—test_lay004_zone_counts_as_copper,test_lay004_skips_unconnected_nc_and_matches_sheet_prefix,test_hubaudio_pcb_lay004_vs_drc_order_of_magnitude.
2.3 Placement vs layout_rules — placement_check.py
Senza mm in layout_rules: skip. Niente 3 mm default. Distanza euclidea pad-pad non usata.
PE-PLC-001
Path rame (segmenti) vs max_distance_mm.
- Test:
tests/test_placement_check.py—test_crystal_load_cap_beyond_max_distance_mm_is_ps_plc_001,test_crystal_load_cap_within_max_distance_mm_is_silent,test_track_path_longer_than_max_distance_mm_is_ps_plc_001;tests/test_pcb_review.pytest_close_decoupling_has_no_plc_001;tests/test_placement_check.pytest_simple_project_without_pcb_has_no_ps_plc.
PE-PLC-002
Via in courtyard vs min_via_count. Skip senza vertici courtyard e senza min.
- Test:
tests/test_placement_check.pytest_via_count_is_calculated_from_courtyard_and_min_parameter(geometria_in_poly; non emette ancora il finding end-to-end).
PE-PLC-003
same_layer decoupling.
- Test:
tests/test_placement_check.py—test_same_layer_param_opposite_layers_is_ps_plc_003,test_same_layer_param_same_copper_is_silent,test_opposite_layers_without_same_layer_param_is_silent,test_opposite_layers_with_via_in_courtyard_is_silent.
PE-PLC-004
Keepout: net estraneo nel courtyard. Non è DRC rame-pad.
- Test:
tests/test_placement_check.py—test_keepout_foreign_track_in_courtyard_is_ps_plc_004,test_ic_courtyard_pad_nets_are_not_keepout_violations,test_keepout_own_net_in_courtyard_is_silent,test_keepout_without_courtyard_is_silent.
PE-PLC-005 (non in catalogo finding_engine)
Proximity non misurabile perché manca la traccia.
- Test:
tests/test_placement_check.pytest_unrouted_crystal_cap_is_insufficient_not_euclidean.
Schema runner omette i check layout: tests/test_placement_check.py test_schema_deterministic_runner_omits_layout_checks.
2.4 SI — si_check.py + ImpedenceFinder
Gate: layout_rules kind + net_class/quote sul bus citato. Skip I2C/GPIO/EN/CC/strap RC. Bus: USB2, USB3, ETH MDI, RGMII, SGMII, DDR3 CLK/DQS/DQ/ADDR, HDMI, PCIe, LVDS; 2.62.0 aggiunge MIPI e clock HF (bus_class); XTAL/OSCIN fuori.
Z0: impedance.py / impedance_traces.py. CPWG → errore, non numero inventato. Senza stackup: skip misura.
Suite gate: tests/test_si_check.py test_skip_i2c_gpio_cc_regn, test_i2c_not_checked_as_50_ohm, test_simple_project_without_pcb_has_no_ps_si_001; tests/test_hf_line_check.py test_bus_class_mipi_hf_clk_not_xtal. Calcolatrice: tests/test_impedance.py (20); misura net: tests/test_impedance_traces.py (10).
PE-SI-001 length_match / skew coppia
Skip senza mm datasheet.
- Test:
tests/test_si_check.pytest_length_match_2_5mm_vs_1mm_is_fail,test_coverage_mdi_rgmii_ddr3_usb3_gated_not_cross_mapped.
PE-SI-002 Zavg/min/max vs finestra datasheet
Mai folklore 90 Ω.
- Test:
tests/test_si_check.pytest_emmaforo_usb_avg_in_window_min_out_is_margin,test_coverage_mdi_rgmii_ddr3_usb3_gated_not_cross_mapped.
PE-SI-003 lunghezza max mm
- Test:
tests/test_si_check.pytest_coverage_mdi_rgmii_ddr3_usb3_gated_not_cross_mapped.
PE-SI-004 spacing intra-coppia mm
Skip senza mm. Copertura indiretta nella stessa suite SI gated.
PE-SI-005 piano di riferimento / layer
Skip senza FACT datasheet.
PE-SI-006 conteggio via HS vs min/max datasheet
Skip senza min/max.
PE-SI-008 return via accanto alla coppia (return_path)
Skip senza kind.
PE-SI-009 serie R ohm sul net HS (non EN-RC)
- Test:
tests/test_si_check.pytest_en_rc_series_resistor_does_not_paint_usb.
PE-SI-010 bus HS misurato, libreria senza FACT Z → INFO, non FAIL 90 Ω
- Test:
tests/test_si_check.pytest_usb_without_library_z_is_insufficient_not_90ohm_fail,test_empty_net_class_impedance_does_not_paint_usb;tests/test_hf_line_check.pytest_existing_si_usb_not_polluted_by_hf_geometry.
Refresh extract SI vecchio: tests/test_pcb_plan_closeout.py test_si_refresh_when_old_extract_has_only_decoupling, test_si_extract_needed_skips_board_ics_only_not_shared_library.
2.5 Linee HF extra — hf_line_check.py (2.62.0 Fase A)
Track ≠ via ≠ pad ≠ zona. Stub = traccia dangling.
PE-SI-007 stub vs mm datasheet
INFO se misura c’è e mm mancano (INSUFFICIENT). Skip: pad-pad, via, zone.
- Test:
tests/test_hf_line_check.py—test_no_layout_skips_hf_geometry,test_pad_to_pad_usb_has_no_stub,test_via_is_not_a_stub,test_zone_is_not_a_track_stub,test_dangling_track_stub_vs_datasheet_mm_is_fail,test_measured_stub_without_datasheet_mm_is_insufficient.
PE-SI-011 gap pour GND sotto coppia HF (REVIEW)
Skip senza stackup/zone.
- Test:
tests/test_hf_line_check.pytest_split_under_pair_needs_stackup_and_zone.
PE-SI-012 terminazione BOM serie/parallelo FACT
Skip se manca il terminatore (non si inventa 50 Ω).
- Test:
tests/test_hf_line_check.pytest_bom_termination_is_fact_missing_is_skip.
Catalogo HF: tests/test_hf_line_check.py test_rule_catalog_hf_ids. DDR/CPU/FPGA: §1.4 (stesso check_memory_fpga_classes in run_pcb_checks).
2.6 Potenza / via / termico sul board — pcb_power_thermal.py
PE-PWR-001 (PCB) — check_pcb_power_traces
Larghezza traccia × spessore rame vs I_load/Imax/I_abs. IPC-2221 solo con thickness e ΔT da Tjmax. Iout_max non è carico. Niente 500 mA USB.
Skip se: manca I datasheet (skip vero, non INFO INSUFFICIENT — 2.61.1).
- Test:
tests/test_pcb_review.py—test_power_trace_ipc2221_errors_when_load_exceeds_ampacity,test_power_trace_uses_parsed_width_and_thickness,test_power_trace_skips_without_i_load,test_power_trace_skips_iout_max_as_load,test_power_trace_uses_imax_when_i_load_absent,test_power_trace_uses_i_abs_when_i_load_absent;tests/test_interface_class_check.pytest_usbc_vbus_does_not_invent_usb_500ma.
PE-VIA-001 — check_pcb_via_current
Se I c’è e sul net zero via: INFO conteggio. Se le via ci sono: silenzio — nessuna tabella ampacity. Via ≠ traccia.
Skip se: manca I.
- Test:
tests/test_pcb_software_bugs.pytest_via_current_skips_without_i_load.
PE-VIA-002 (2.62.1)
I + conteggio/drill FACT. Tabella IPC via non applicata.
Skip se: manca I.
- Test:
tests/test_pcb_phase_b.pytest_via_current_skips_without_i_does_not_invent_ipc.
PE-THM-001 — check_pcb_thermal_copper
P = I_load × drop; courtyard senza pour/via.
Skip se: P sconosciuta.
- Test:
tests/test_pcb_review.pytest_thermal_copper_warns_without_pour_or_vias.
PE-THM-002 — check_pcb_junction_temp
Tj = Ta + P·θJA solo con P, θJA, area rame, conteggio via. Non è FEM.
Skip/INSUFFICIENT se manca un fattore.
- Test:
tests/test_pcb_plan_closeout.py—test_tj_when_theta_copper_vias_exist,test_tj_insufficient_without_theta.
PE-KEL-001
Pin Kelvin/sense sullo stesso net di carico. Ignora CRS/IN±.
- Test:
tests/test_pcb_review.pytest_kelvin_sense_pin_on_shared_net;tests/test_pcb_software_bugs.pytest_kelvin_ignores_crs_and_in_plus.
PE-STCH-001
Segnale sopra pour GND senza via GND nel bbox. Skip GPIO minuscoli.
- Test:
tests/test_pcb_review.py—test_gnd_stitch_skips_tiny_gpio,test_gnd_stitch_info_when_signal_has_pour_but_no_via.
2.7 Derating / gerarchia / timing / PI
PE-DRT-001 / PE-DRT-002 / PE-DRT-003 — pcb_checks.check_pcb_derating + derating.py
Vop vs Vrated: ERROR / MARGIN / PASS INFO. Niente % dielettrico inventato. Skip se manca Vop o Vr.
- Test:
tests/test_fase_b_checks.pytest_derating_pass_margin_risk;tests/test_derating.py(7, C_eff stima — non è un PE-* a parte).
PE-HIER-001 — hierarchy.py
Pin IC senza net nominato.
- Test:
tests/test_fase_b_checks.pytest_hierarchy_component_pin_net_block.
PE-TIM-001 / PE-TIM-002 — timing_check.py
001 RC reset vs t_reset; 002 strap vs Vih/Vil.
Skip senza R/C e t_reset o Vih/Vil.
- Test:
tests/test_fase_b_checks.py—test_timing_skips_without_numbers,test_timing_reset_rc_vs_t_reset.PE-TIM-002non ha un test che fa scattare il finding (solo skip condiviso).
PE-PI-001 / PE-PI-002 — pi_check.py
001 cap locale sul rail IC; 002 locale vs bulk se i valori C esistono. Distanza mm solo da layout_rules (altrimenti è PE-PLC-001). Skip net NC.
- Test:
tests/test_fase_b_checks.py—test_pi_missing_local_is_risk_not_error,test_pi_any_cap_on_slash_prefixed_rail_suppresses_missing_local,test_pi_bulk_only_does_not_claim_no_local;tests/test_pcb_software_bugs.pytest_emi_and_pi_skip_unconnected_nets.PE-PI-002non ha un assert dedicato sulrule_id.
2.8 ESD / return / EMI / SPOF
PE-ESD-001 — esd_return_check.check_esd
Net J* ∩ IC senza parte ESD: REVIEW, non ERROR. Niente GPIO/NC/rail spam.
- Test:
tests/test_fase_b_checks.py—test_esd_without_part_is_review_not_error,test_esd_skips_gpio_nc_unconnected_and_onboard_power,test_esd_one_finding_per_connector_ic_path,test_esd_skips_when_protection_part_on_net.
PE-ESD-002 (2.62.1) — check_esd_distance
Distanza pad TVS–connettore (via ≠ pad). INFO se no mm.
- Test:
tests/test_pcb_phase_b.pytest_esd_distance_uses_pads_not_vias.
PE-RET-001 — check_return_path
Net HS sopra pour GND senza via GND nel bbox: REVIEW.
- Test:
tests/test_fase_b_checks.pytest_return_path_hs_is_review.
PE-EMI-001 — emi_check.py
Solo se layout_rules cita choke/ferrite/shield. Non IEC 61000. Skip NC.
- Test:
tests/test_pcb_plan_closeout.pytest_emi_only_with_datasheet_fact;tests/test_pcb_software_bugs.pytest_emi_and_pi_skip_unconnected_nets.
PE-SPOF-001 — spof_check.py
Un regolatore o XTAL condiviso: REVIEW, mai ERROR.
- Test:
tests/test_pcb_plan_closeout.pytest_spof_review_single_ldo.
2.9 BOM ↔ PCB ↔ datasheet — bom_pcb_check.py
Skip se manca un lato (BOM, footprint, o numero datasheet).
PE-BOM-010 famiglia package
- Test:
tests/test_pcb_plan_closeout.pytest_package_family_mismatch_is_pe_bom_010.
PE-BOM-011 pintable vs pad, join per nome
Join datasheet pintable × .kicad_mod lib × pad embedded. Non pin_count scalare. A5/B5 USB-C sono pin, non EP. EP/SH/mount classificati; via ≠ pad. Senza pintable: skip.
- Test:
tests/pcb/test_bom_011_named_join.py;tests/pcb/test_pcb_plan_closeout.pytest_package_family_mismatch_is_pe_bom_010;tests/pcb/test_pcb_software_bugs.pytest_ep_split_pads_not_bom_011;tests/pcb/test_pcb_via_not_pad.py.
PE-BOM-012 Vop vs rating/abs-max legato al pin
- Test:
tests/test_pcb_plan_closeout.pytest_abs_max_voltage_and_temp_and_current;tests/test_pcb_software_bugs.pytest_vddcr_absmax_does_not_bind_3v3_io.
PE-BOM-013 Top vs abs-max T
- Test:
tests/test_pcb_plan_closeout.pytest_abs_max_voltage_and_temp_and_current.
PE-BOM-014 I_load vs rating
Skip se manca I.
- Test:
tests/test_pcb_plan_closeout.py—test_abs_max_voltage_and_temp_and_current,test_inductor_current_rating.
2.10 Resto Fase B (2.62.1)
PE-STK-001 — stackup_check.py
Spessore rame board vs stackup fab sourced. Mai 1 oz default.
Skip se: niente stackup layout o niente FACT fab.
- Test:
tests/test_pcb_phase_b.py—test_stackup_skips_without_fab_spec,test_stackup_vs_fab_spec_is_review_not_invented_oz.
PE-ANT-001 / PE-ANT-002 — antenna_layout_check.py
Keepout zona e matching L/C sul feed. Solo se antenna/net RF sul grafo. Niente 50 Ω inventati.
Skip se: antenna assente; matching manca e non c’è FACT (002 non emette).
- Test:
tests/test_pcb_phase_b.py—test_antenna_skips_when_absent,test_antenna_keepout_and_match_are_facts.
PE-PDN-001 — pdn_check.py
Z(f) solo con FACT in frequenza. Z0 SI non è PDN.
- Test:
tests/test_pcb_phase_b.pytest_pdn_skips_without_zf.
Silenzio Fase B se assente: tests/test_pcb_phase_b.py test_run_pcb_checks_phase_b_absent_is_silent. Catalogo: test_phase_b_rule_catalog.
2.11 Review AI PCB
Modulo: pcb_review.py + services/pcb_validation.py. Stesso oggetto finding. Spiega FACT deterministici; non rilegge il PDF; non inventa interfacce / PoE / SuperSpeed / mm / Z / I.
Skip se: niente JSON libreria per l’IC.
- Test:
tests/test_pcb_review.py—test_pcb_ai_finding_gets_action,test_parse_review_action_field_without_recommendation,test_layout_context_includes_via_counts,test_layout_context_includes_domain_and_group,test_pcb_ai_skips_without_library_extraction,test_library_constraints_fill_from_storage,test_inventory_lists_net_length_and_pair;tests/test_finding_engine.pytest_pcb_review_ai_finding_action_without_recommendation;tests/test_pcb_software_bugs.pytest_thinking_reasoning_content_echo_still_present.
2.12 Tab antenna RF (non in run_pcb_checks)
Moduli: antenna_rf.py, antenna_geometry.py. Topologia matching + ricetta routing. No EM/VSWR/CPWG. Distinto da PE-ANT-001/002.
- Test:
tests/test_antenna_rf.py—test_verify_finds_matching_path_to_ant_footprint,test_verify_missing_matching_is_warning,test_design_recipe_needs_marker_without_ant,test_design_recipe_ready_with_ant_and_stackup,test_geometry_templates_produce_export,test_geometry_overflow_tiny_zone,test_design_recipe_meander_template.
Placement/auto-place non è esame PCB: tests/test_placement_pack.py, tests/test_placement_pipeline.py (fuori da questo albero di analisi).
Motore finding (condiviso)
finding_engine.py: FACT / REQUIREMENT / INFERENCE; ERROR solo RULE+MANDATORY; decisions.json non ri-naga.
- Test:
tests/test_finding_engine.py(11);tests/test_finding_schema.py(7);tests/test_fase_b_checks.pytest_sort_findings_error_then_class;tests/test_review_workflow.py(10 — stati finding UI, non check PE). CAD bridge:tests/test_cad_bridge.py(5).
Test che esistono ma non sono analisi
tests/ ha 114 file / ~730 test. Oltre ai nodi sopra restano overlay nativi, upload, auth, billing seam, UI rewrite. Non sono check PE-*.
Upload / ingest cartella (non analisi): tests/test_periscope_frontend_upload_rewrite.py test_upload_zone_is_src; tests/test_kicad_project.py (picker cartella, .history, Safari stem); tests/test_netlist_bundle.py (zip, zip-slip); tests/test_kicad_pcb.py test_upload_pcb_sets_has_pcb, test_upload_sch_as_pcb_is_rejected; tests/test_purple_parts_resolver.py (upload BOM/LCSC); tests/test_reopen_replace.py test_reopen_then_replace_bom_and_netlist.
Auth: i test auth esistono (tests/test_local_auth.py, tests/test_periscope_auth_rewrite.py, tests/test_pinscope_compat.py, più overlay che tengono il contratto login). Non si descrivono segreti, JWT, password, o flussi di autenticazione.
Altri non-analisi: rewrite frontend/Docker (test_periscope_*_rewrite.py, test_periscope_leftover_package_requirements.py, test_periscope_boot_without_dependency_product.py); delete progetto; cost estimator; event bridge; job runner; test_deepseek_only.py (routing modello, non finding).
Conteggio nodi
| Gruppo | Nodi |
|---|---|
| Check solo schema (27 PE-* + LED senza ID) | 28 |
| USB-C / ETH / PoE (schema e PCB) | 13 |
PE-PWR-001 (due source: schema e PCB) |
1 |
DDR / CPU / FPGA / PD (grafo, invocati da run_pcb_checks) |
11 |
| Check solo PCB (layout, SI/HF, potenza, Fase B, …) | 47 |
| Processo: 3 skill + DigiKey + value + IC AI + PCB AI + tab RF | 8 |
| Totale nodi analisi | 108 |
Check PE-* in codice: 99 (tutti elencati). Più LED senza rule_id. PE-LAY-004, PE-PLC-005, PE-TH-002 sono in codice; PE-LAY-004 / PE-PLC-005 non sono in _seed() di finding_engine.py.
Buchi di test noti (il check c’è, il fire test no): PE-TIM-002, PE-PI-002 (nessun assert rule_id), PE-PLC-002 (solo geometria _in_poly), PE-SI-004 / PE-SI-005 / PE-SI-006 / PE-SI-008 (gate SI, niente caso dedicato).