Changelog

What's new in BoardLab.

  1. September 25, 2026v2.87.68

    Admin Mail inbox

    Michele: Admin page to read contact mail; reuse the existing contact HTML template.

    • Improved[Added] Contact form messages persist to `admin/mail/inbox/` (even if SMTP is down).
    • Improved[Added] Admin → Mail: inbox list/detail + Templates catalog of built-in email kinds.
    • Improved[Changed] Contact HTML template shared for outbound notify and admin preview.
  2. September 25, 2026v2.87.67

    Completion alert in Settings

    Michele: if the user opts in via Settings, email them when analysis finishes. Toggle lives in the top-bar Settings sheet (same pref as Account).

    • Improved[Added] Notifications section in Settings: **Email me when analysis completes**.
    • Improved[Changed] Account page reuses the same notification control.
  3. September 25, 2026v2.87.66

    Email auth + completion alerts

    Michele: while Stripe is set up, wire local email auth (forgot / reset / change password) and optional alerts when schema or PCB analysis finishes.

    • Improved[Added] Password reset via email (`/forgot-password`, `/reset-password`); change password on `/account`.
    • Improved[Added] Account preference **Email me when analysis completes** (`email_on_complete`); default off.
    • Improved[Changed] Schema and PCB pipelines send report-ready mail only when the user opted in.
    • Improved[Changed] Host deploy sets `EMAIL_FRONTEND_URL` from `SITE` for reset/alert links.
  4. September 25, 2026v2.87.65

    Stripe as free-to-start payments

    Michele: use a free payment platform for credits. **Stripe** (Italy) has no monthly/setup fee — only per successful charge (~1.5% + €0.25 EEA cards). Already wired; `/credits` copy and `.env.example` point to signup. Without keys, manual pack requests + Admin Grant still work.

    • Improved[Changed] Credits page documents Stripe pricing / signup.
    • Improved[Changed] `.env.example` Stripe guidance for Host.
  5. September 25, 2026v2.87.64

    Credits metering + free-service flag

    Michele: enable credits even before selling; Admin → Software → Users can turn **Free service** on per user; `/credits` page for balance and packs. Stripe optional (no monthly fee — only transaction fees); without keys, pack buttons create a manual payment request that admin fulfills with **Grant**.

    • Improved[Added] Credits ledger/packs/gate (`billing_enabled` default on); trial grant; PCB exam charge.
    • Improved[Added] `/credits` wallet UI; top-bar balance link.
    • Improved[Changed] Admin Users: Free service toggle, balance column, Grant credits.
    • Improved[Added] Billing: Stripe Checkout when `STRIPE_SECRET_KEY` set; else `/api/billing/request-pack` + admin fulfill.
  6. September 25, 2026v2.87.63

    Point 8 closed (A–D)

    Michele: close Point 8. BoardLab-only identity on the live path; KiCad plugin `boardlab_plugin.py`; findings bridge `boardlab-findings.json`; env `BOARDLAB_*`; compose transitional aliases removed. Clean-room / intellectual ownership audit closes decision A (`docs/development/POINT8_A_AUDIT.md`). KEEP list: MySQL volume name, git remotes, historical changelog, legacy coerce/token migrate.

    • Improved[Changed] KiCad plugin `boardlab_plugin.py` (removed `periscope_plugin.py`); bridge file BoardLab-only.
    • Improved[Changed] Library/idle/ingest env vars → `BOARDLAB_*`; Host deploy migrates MySQL URL / writer IDs once.
    • Improved[Changed] Compose: no `periscope-*` DNS aliases; `BOARDLAB_LIBRARY_MYSQL_URL` required.
    • Improved[Added] Point 8 A audit + rewrite closure doc; `tests/test_point8_closure.py`.
    • Improved[Changed] README / CLAUDE / planning docs product names → BoardLab.
  7. September 25, 2026v2.87.62

    Point 8: periscope/ → boardlab/

    Michele: close Point 8 ops identity. Product tree renamed `boardlab/`; compose project/containers `boardlab-*`; Host target `/root/boardlab`. MySQL volume name kept (`periscope_library_mysql_data`) so library data is not wiped.

    • Improved[Changed] Directory `periscope/` → `boardlab/` (src, Docker COPY paths, tests, scripts).
    • Improved[Changed] Compose `name: boardlab`; containers `boardlab-backend` / `boardlab-frontend` / `boardlab-library-mysql` (transitional DNS aliases for Caddy).
    • Improved[Changed] Deploy script default `CANONICAL_ROOT=/root/boardlab`.
  8. September 25, 2026v2.87.61

    Cert engine reads cert_library JSON packs

    Michele: every certification's component/requirement specs live as JSON in `cert_library`; the certifying engine must grade from that SoT. `load_certifying_catalog()` overlays pack constraints onto the recognition skeleton; L0–L3 / CertifyingEngine / AF impedance cites use it.

    • Improved[Added] `boardlabx/cert_specs.py` — overlay + `load_certifying_catalog` / `get_pack_constraints`.
    • Improved[Changed] `protocol_exam` / engine / L1–L3 defaults consume cert_library packs (catalog.json remains seed/bootstrap only).
    • Improved[Changed] Admin Certs copy states packs are the engine criteria SoT.
  9. September 25, 2026v2.87.60

    Cert system: family labels + Admin Certs UX

    Michele: certification is first-class. Fix broken pack bus labels (`1000base` from pack-id split), seed with USB/ETHERNET/HDMI families + human titles, dedupe document requests, Admin Certs grouped by family. Auto-refresh packs still on parser `< 1.1.0` at boot. Seed endpoint allowed for admins.

    • FixedCert pack `bus` / `title` from logical protocol family/name (parser 1.1.0).
    • FixedDocument requests deduped per pack+document (was 477 clones → unique work items).
    • Improved[Changed] Admin → Software → Certs groups packs by family; shows criteria + needed document.
    • Improved[Changed] `POST /api/library/cert/seed` — admin or library writer.
  10. September 25, 2026v2.87.59

    Cert packs auto-seed

    Empty certification library was a config gap — BoardLab seeds protocol-catalog packs (USB / Ethernet / HDMI / …) on boot when `cert_library.sqlite` has zero rows. Admin → Software → Certs also has **Seed from protocol catalog**.

    • FixedAdmin Certs showed 0 packs / 0 document requests because seed was never run.
    • Improved[Added] `CertLibraryAccess.ensure_seeded_if_empty()` called from FastAPI lifespan.
    • Improved[Added] Admin UI button + `seedCertPacks()` client for manual re-seed (writer).
  11. September 25, 2026v2.87.58

    Point 8 wave 2: delete inherited tree

    Michele: eliminate remaining legacy product code creatively. `periscope/dependency/` removed; Docker and pytest boot from BoardLab src only.

    • Improved[Removed] Entire `periscope/dependency/` product tree (UI, backend, docs, fixtures moved or deleted).
    • Improved[Changed] Frontend dockerfile copies `src` only (shadcn UI + landing assets owned under BoardLab).
    • Improved[Changed] Backend dockerfile copies `src` + `fixtures/` only — no leftover LLM provider COPY.
    • Improved[Changed] FastAPI title `BoardLab`; Board IR docs on `boardlabx`; terms/privacy BoardLab-only.
    • Improved[Note] Host path `/root/periscope` and compose name still transitional (wave 5).
  12. September 25, 2026v2.87.57

    BoardLab identity · Point 8 wave 1

    Michele A–D: full PinScope intellectual rewrite (brainstorm started); BoardLab-only names; drop legacy identity; scrub comments.

    • Improved[Changed] Package `backend.boardlabx` (was `periscopex`); JWT `boardlab-local`; field `boardlab_version`.
    • Improved[Changed] Deploy script `scripts/update-boardlab.sh` (Host tree rename to `/root/boardlab` still ops).
    • Improved[Changed] Coerce strips `pinscope_version` / `periscope_version` → `boardlab_version` once.
    • Improved[Note] Point 8 not closed — dependency tree + Host path + AGPL attribution remain until rewrite waves finish.
  13. September 25, 2026v2.87.56

    Menu decisions · PCBWay fab default · brand purge start

    Michele menu decisions: Library only in Admin side nav (not top bar); Contact only inside a project; keep Overview|Schema|PCB; kill Exam; Parts tabular; Settings + PCBWay default from PCB layers; boardlab-* downloads; BoardLabMark.

    • Improved[Changed] Top bar: no Library, no global Feedback; project Contact only (admin email).
    • Improved[Changed] Parts table Drafting density; Setup→Settings; kill Exam user copy; `useProjectAnalysisOps`.
    • Improved[Added] PCBWay fab auto-default from `.kicad_pcb` copper layer count (2/4/6L); fab form on Settings.
    • Improved[Changed] Downloads `boardlab-eco.csv` / `boardlab.kicad_dru`; `BoardLabMark`.
    • Improved[Changed] Browser keys `boardlab_token` / `boardlab:` (one-shot migrate from `periscope_*`).
    • Improved[Note] PinScope inventory for Michele — version not closed until full purge (point 8).
  14. September 25, 2026v2.87.55

    Quiet Studio A+1 (chosen)

    Michele chose IA **Studio** + look **Quiet Studio**. Guidelines locked in `docs/development/QUIET_STUDIO_UI.md`. Dark accent stays `#007AFF`; dashboard/report/admin chrome aligned.

    • Improved[Changed] Official UI direction A+1 Quiet Studio.
    • Improved[Changed] Page titles 22px; projects table Quiet surface; findings labels.
    • Improved[Changed] Dark theme primary remains system blue.
  15. September 25, 2026v2.87.54

    Library tab restore · Apple Studio shell

    Library is again an Admin Software tab (Overview | Jobs | Library | Certs | Users). Project default is **Overview** (run pulse), not the BOM table. BOM lives under Parts. Ops for exam runs extracted to `useProjectExamOps`.

    • Improved[Changed] Library → `/admin?tab=library` (Config/library redirects; no Config duplicate).
    • Improved[Changed] Project default tab `overview`; top nav Exam → Overview.
    • Improved[Changed] Workspace secondary bar grouped Parts / Board / Setup.
    • Improved[Added] `ProjectOverviewPanel` + `useProjectExamOps` (UI vs ops split).
  16. September 25, 2026v2.87.53

    Library archive · MySQL admin · JSON

    Config · Library Archive tab: no giant in-app tables. Opens Adminer (`/library-db/`) for library MySQL; ZIP backup/download; JSON component archive export/import.

    • Improved[Changed] `/config/library` Archive | Autoscan (dropped Catalog/Review tables).
    • Improved[Added] Adminer service `library-adminer` + Caddy `/library-db/` → MySQL admin.
    • Improved[Added] `GET`/`POST` `/api/library/archive.json` component JSON export/import.
  17. September 25, 2026v2.87.52

    Config · Library (unified)

    Top-nav Library opens **`/config/library`** with Catalog | Review | Autoscan. Admin Software no longer duplicates Library (legacy `?tab=library` redirects). Old `/library` redirects here.

    • Improved[Changed] Unified library UI at `/config/library` (Catalog / Review / Autoscan).
    • Improved[Changed] Top bar Library → `/config/library`; `/library` redirects.
    • Improved[Changed] Admin Software nav: Overview | Jobs | Certs | Users (Library removed).
  18. September 25, 2026v2.87.51

    Drop legacy periscope.michelebigi.it from Host Caddy

    Public edge is BoardLab-only: `boardlab.it` / `www.boardlab.it`. Legacy `periscope.michelebigi.it` removed from `boardlab-caddy`.

    • Improved[Removed] Host Caddy vhost `periscope.michelebigi.it`.
  19. September 25, 2026v2.87.50

    Host Caddy BoardLab-only

    Edge Caddy serves only `boardlab.it` / `www` / legacy `periscope.michelebigi.it`. Removed api/cvault and any railway-ai vhosts from the Host edge config.

    • Improved[Changed] Host `boardlab-edge` Caddyfile: BoardLab sites only.
  20. September 25, 2026v2.87.49

    Host edge: boardlab-caddy (drop railway-ai)

    Host HTTPS edge moved to `/opt/docker-projects/boardlab-edge` (`boardlab-caddy`). Railway-ai project/container/volumes removed from the VPS. `update-periscope.sh` attaches to `boardlab_edge`.

    • Improved[Changed] Host Caddy ownership: BoardLab edge (no railway-ai site).
    • Improved[Removed] Host `/opt/docker-projects/railway-ai` (server config / runtime only).
  21. September 25, 2026v2.87.48

    Host deploy pull uses github remote

    `scripts/update-periscope.sh` prefers remote `github` (periscope) over legacy `origin` (pinscope) so Host pulls the product branch.

    • FixedHost `git pull` target when `origin` still points at pinscope.
  22. September 25, 2026v2.87.47

    Admin Software Library/Certs polish

    Software Overview shows processes in progress; Library lists (components / scan / obsolete) stay behind expand buttons with export/import and autoscan start/stop; Certs adds document requests + explicit source.

    • Improved[Changed] Admin Software Overview: status strip + live processes in progress.
    • Improved[Changed] Library tab: Components / Scan backlog / Obsolete / Autoscan queue on-demand; Start/Stop autoscan; Export/Import labels.
    • Improved[Added] `GET /api/library/cert/requests` — open `needed_document` requests across cert packs.
  23. September 25, 2026v2.87.46

    Admin Software IA + remove onboarding survey

    Admin left nav matches Software config instructions: **Overview | Jobs | Library | Certs | Users** as first-class Software items (not a nested bolted-on tab). Ops tools (Projects, Components, Credits, …) sit in a separate group. Onboarding survey no longer appears on first login / dashboard.

    • Improved[Changed] Admin Software IA: Overview / Jobs / Library / Certs / Users are primary nav; removed duplicate Pipeline Runs and Users & Credits peers.
    • Improved[Removed] `OnboardingSurvey` from dashboard (backend `/api/survey` left unused).
    • Improved[Changed] Legacy `?tab=software` / `?tab=runs` deep links map to Overview / Jobs.
  24. September 25, 2026v2.87.45

    Admin Software config · idle autoscan · SMTP seam

    Admin **Software** tab: overview (jobs, library, certs, users, autoscan, email) plus Jobs | Library | Certs | Users. Library autoscan is toggleable (persisted, default ON); idle datasheet RESCAN still has priority over popular ingest. SMTP env stubs (`SMTP_*` / `ADMIN_EMAIL`) with no-op `send_email` until credentials arrive.

    • Improved[Added] Admin Software configuration panel (overview + Jobs / Library / Certs / Users).
    • Improved[Added] Persisted `library_autoscan_enabled` (Admin Library tab + `PUT /api/admin/settings/library-autoscan`).
    • Improved[Added] SMTP email seam (`send_email`, invite/reset/admin stubs) + `.env.example` vars; overview shows configured yes/no (no secrets).
    • Improved[Added] Local user create/remove + no-pay flag via `/api/admin/users`.
    • Improved[Changed] Idle refresh / popular ingest respect autoscan toggle without process restart.
  25. September 24, 2026v2.87.44

    Show Zdiff for differential PCB nets

    ImpedenceFinder inventory table showed "—" on USB_D± because pair results live in ``zdiff_*``, not ``z0_*``. UI now shows Zdiff (avg / min–max) for differential nets and keeps Z0 for single-ended.

    • FixedImpedance panel PCB net table uses Zdiff when ``is_differential`` / ``zdiff_avg_ohms`` present.
  26. September 24, 2026v2.87.43

    Scrub library MySQL secrets from compose

    Remove default MySQL passwords / DSN from `docker-compose.yml`. Library MySQL credentials live only in Host `.env` (required vars). Healthcheck uses the image helper (no password in compose).

    • Improved[Security] No `LIBRARY_MYSQL_*` / DSN defaults in git.
    • Improved[Changed] compose requires `LIBRARY_MYSQL_PASSWORD`, `LIBRARY_MYSQL_ROOT_PASSWORD`, `PERISCOPE_LIBRARY_MYSQL_URL`.
  27. September 24, 2026v2.87.42

    Library rescan priority · MySQL · bundle

    Idle **datasheet rescan** (stale parser / missing power) runs before popular new-IC ingest. Component library runtime is **MySQL only** (compose `library-mysql`; SQLite only via explicit test constructor / `PERISCOPE_LIBRARY_ALLOW_SQLITE=1`). Admin Management tab: **download / upload** BoardLab library ZIP.

    • Improved[Changed] Idle refresh does real PDF reparse (1/tick); popular ingest pauses with `rescan_backlog`.
    • Improved[Changed] `LibraryDB.from_env` requires `PERISCOPE_LIBRARY_MYSQL_URL`.
    • Improved[Added] compose `library-mysql` + `scripts/migrate_library_sqlite_to_mysql.py`.
    • Improved[Added] `GET|POST /api/library/bundle` + Management download/upload UI.
    • Improved[Changed] Library page Management / Catalog tabs (2.87.41).
  28. September 24, 2026v2.87.41

    Library Management / Catalog tabs

    Admin Library page splits the two jobs into top-level tabs: **Management** (LibraryAccess triage — parser/scan/power/review) and **Catalog** (browse ICs/passives/discrete/datasheets + PDF import). Same store; less stacked UI.

    • Improved[Changed] `(app)/library/page.tsx` — Management vs Catalog tabs; catalog keeps nested type tabs.
  29. September 24, 2026v2.87.40

    Library scan column + skills_manifest fix

    BoardLab admin Library table shows **scan** version and a **review** checkbox when a row is stale, missing power, or idle-refresh pending. Restores valid `skills_manifest.json` (missing `{` broke default parser + LibraryAccess queries and idle ingest).

    • Fixed`boardlab/src/backend/skills_manifest.json` — valid JSON again (`default_model_version` 1.19.0).
    • Improved[Added] `scan_version` / `needs_review` on LibraryAccess row summaries + table columns.
    • Improved[Note] Popular datasheet ingest loop still runs when idle (pauses during exams); it was failing open on the broken manifest.
  30. September 24, 2026v2.87.39

    BoardLab landing rewrite

    Public home is a new **BoardLab** page (navy / copper / teal, loupe mark, Fraunces + Source Sans). PinScope-style marketing layout and Faradworks/Pinscope footer line removed from the landing. Instructions: create project → upload → exam; file needs + link to File guide. Logo pack from 2.87.37 kept.

    • Improved[Changed] `(marketing)/page.tsx` rewritten end-to-end (hero + how-to + what you need + CTA).
    • Improved[Changed] Landing CTAs use BoardLab teal; signed-in CTA → Projects.
    • Improved[Removed] Landing footer “derived from Faradworks/Pinscope” marketing line (AGPL still in Terms / LICENSE).
  31. September 24, 2026v2.87.38

    Library tab admin-only

    **BoardLab** Library management (catalog + LibraryAccess table) is visible and callable only for admins. Project exam still uses `/api/library/check` for all authenticated users. Logo/casing from 2.87.37 untouched.

    • Improved[Changed] Top-bar / mobile menu: Library link only when `isAdmin`.
    • Improved[Changed] `/library` page redirects non-admins to dashboard.
    • Improved[Changed] Backend `GET /library`, `/library/access*`, idle-refresh/popular-ingest status (+ ticks) require admin.
  32. September 24, 2026v2.87.37

    BoardLab casing + loupe mark

    User-facing product name is **BoardLab** (capital L in Lab). New mark: PCB board edge + lab loupe (navy / copper / teal). Domain stays `boardlab.it`; Host compose IDs stay `periscope*`. No LICENSE / credits / dependency delete.

    • Improved[Changed] SITE_NAME, metadata, PWA name, nav wordmark, legal/email copy → BoardLab.
    • NewBrand pack `public/brand/boardlab-mark.svg` (+ wordmark, favicon_io sizes, OG static).
    • Improved[Changed] Favicon / apple-touch / android-chrome regenerated from the loupe mark.
  33. September 24, 2026v2.87.36

    CertifyingEngine E2–E5 (Grade · UI · class · tiers)

    **BoardLab** cert engine completes S1: Detect→Instantiate (E1) plus Grade full, Present UI, class-check unify, and evidence-only tiers. Present-only cards; no board-name hardcoding; LICENSE / `dependency/` / credits untouched.

    • Improved[Changed] `CertifyingEngine.grade` consumes pack L0–L2 + AF measured Z (certified / not certified / skip) with non-empty remediation on NO/SKIP.
    • Improved[Changed] `protocol_exam` grades after L0–L2 so measured facts and interface-class findings fold into one headline per instance (E4 — no contradictory PE-ETH/USBC double FAIL).
    • Improved[Changed] Protocols UI cards read `cert_outcome` / headline / remediation; class cards suppressed when an engine instance covers that family (E3/E4).
    • Improved[Changed] Speed tiers remain evidence-only (10/100 vs GbE, HDMI 1.4 vs 2.0+ nested); A5/A9/A10 + E2–E5 fixtures in `tests/pcb/test_certifying_engine_e2e5.py`.
  34. September 24, 2026v2.87.35

    Conceptual purge P0 inventory + P3 overlay holes

    PinScope conceptual purge: closed KEEP/R/B inventory on BoardLab tip; native overlays for remaining open-core seams. Dual-read Host checklist left open (no P2 deepen). No Host deploy from this slice; no LICENSE / dependency empty-delete; credits/rail untouched.

    • Improved[Added] `docs/development/PINSCOPE_CONCEPTUAL_PURGE.md` — P0 inventory KEEP/R/B + P2 Host checklist.
    • Improved[Changed] Fence notes BoardLab brand vs `periscope*` technical IDs; P2 ops leftover explicit.
    • Improved[Added] Native `clerk-theme-provider.tsx` + `proxy.ts` overlays (Docker after dependency).
    • Improved[Changed] Metering/auth stub comments aligned to BoardLab; storage keys still `periscope_token`.
  35. September 24, 2026v2.87.34

    BoardLab brand + boardlab.it dual-host

    User-facing product brand is **BoardLab**; primary public URL **https://boardlab.it**. Host keeps serving **periscope.michelebigi.it** until DNS A/AAAA for boardlab.it points at the Host (dual-host Caddy). No merge/deploy until Michele confirms. LICENSE AGPL untouched; no credits activation.

    • Improved[Changed] SITE_NAME / metadata / UI titles / email + contact copy → BoardLab; default SITE_URL → `https://boardlab.it` (`NEXT_PUBLIC_SITE_URL` override still works).
    • Improved[Added] Caddy dual-host snippet + DNS cutover notes (`docs/deploy/caddy-boardlab.it.caddyfile`, `docs/deploy/boardlab-dns.md`).
    • FixedFrontend `tsconfig` excludes `scripts/` so Next build does not typecheck selftest `.mts` under `scripts/` (Host hotfix upstreamed).
    • Improved[Note] Compose project / container names remain `periscope*` for Host path compatibility (`/root/periscope`, `update-periscope.sh`).
  36. September 24, 2026v2.87.33

    PinScope deps purge P3 (metering facade)

    Conceptual purge P3 on product head: metering is a Periscope contract, not a Faradworks gateway identity. `dependency/` KEEP; `LICENSE` AGPL untouched; no Host deploy from this slice.

    • Improved[Changed] `get_metering()` / `MeteringPort` / `NullMetering` — primary API; `get_billing` aliases remain for credits-pricing.
    • Improved[Added] Native null stubs: credits-context, paused-run-banner, pricing-section, use-optional-auth (Docker overlays after dependency).
    • Improved[Changed] JWT-local default documented; Clerk stay pass-through in dependency (no Clerk boot without key + overlay).
    • FixedDependency `use-optional-auth` no longer imports removed `pinscope_token` legacy key.
    • Improved[Note] No empty-delete of `periscope/dependency/`. No Stripe/credits activation.
  37. September 24, 2026v2.87.32

    Stack tip: rail capacity + board-map + metaphor + naming + E1

    Michele close-merge: one Host tip after rail **2.87.31**. Board-map is the single report shell; metaphor A+B empty/bench copy folded in (no duplicate map). Naming purge kills `pinscope_*` dual-read. CertifyingEngine **E1** Detect→Instantiate for ETH/HDMI. No ETH recognize patch, no LICENSE/credits.

    • Improved[Added] Board-map report shell + FACT/REQ/INF finding rows (`?section=` drill-down).
    • Improved[Added] Report metaphor EMPTY_COPY / bench summary language (dashboard, library, exam, report).
    • Improved[Added] `CertifyingEngine` E1 — Detect→Instantiate→Grade stub→Present for ETH/HDMI; catalog recognition hints.
    • Improved[Changed] Kill `pinscope_*` dual-read in product head (legacy_id_compat only).
    • Improved[Note] Includes live rail source capacity from 2.87.31. ETH recognize evidence branch not merged.
  38. September 24, 2026v2.87.31

    Board-agnostic rail source capacity

    Michele: rail power budget must grade PASS/MARGIN/FAIL whenever capacity can be deduced from **library / datasheet / part class / net topology** — never leave USB / charger / LDO rails UNKNOWN for lack of a contact rating, and **never** special-case a project or board name.

    • Improved[Added] `SourceCapacity` on library `ComponentConstraints` (Iout_max / IINLIM / ISYS) — separate from load `power_requirements`.
    • Improved[Added] Extract skill + schema: fill `source_capacity` for regulators/chargers; Wi-Fi/RF SoC TX peak in `power_requirements`.
    • Improved[Changed] `rail_power_budget` capacity order: library source_capacity → specs → abs-max → charger on net (IINLIM/ISYS) → USB-IF class estimate (Type-C 1.5/3 A, USB2 500 mA).
    • Improved[Changed] Battery charger / power-path ICs (VBUS→SYS) are rail **sources**; SYS not attributed to a bare header when a charger produces it.
    • Improved[Changed] Taxonomy: `ic.power.charger`, `ic.rf.wifi`, `connector.usb.type_c`; Wi-Fi SoC family estimate for TX peak.
    • Improved[Changed] `skills_manifest` **1.19.0** — stale library rows auto-reparse on examine.
    • Improved[Added] Tests: USB-IF class, charger IINLIM/SYS, library source_capacity, Wi-Fi family estimate, no project-name hardcoding.
    • Improved[Note] Board-agnostic only. Version **2.87.31** (2.87.30 claimed by undeployed ETH recognize patch).
  39. September 24, 2026v2.87.29

    Cert cards + HDMI/ETH under Certifications

    Michele: HDMI and Ethernet must be visible under **Certifications**; each protocol gets a **card** (`USB-3.0 — certified` / `not certified`, blue/red) with requirements **OK** (green) / **NO** (red) and remediation. Hard rule: only protocols **present** on the board; nested lower rates (100BASE-TX under GbE, HDMI 1.4 under 2.0, USB2 under USB3) may PASS when the higher rate FAILs — never invent Gigabit on a 10/100-only PHY.

    • Improved[Changed] Findings tree — PE-ETH / PE-USBC / PE-POE / AF cert headlines join PE-PRT under Certifications → Protocols (no longer buried under Info → Ethernet).
    • Improved[Changed] Protocol UI — cert cards with blue certified / red not-certified headers; hide pure NOT_APPLICABLE instances.
    • Improved[Changed] Recognition — GbE emits nested 100BASE-TX; HDMI 2.0/FRL emits nested HDMI 1.4; RJ45-only for PE-ETH (SFP/midplane MDI nets no longer fake Ethernet jacks).
    • Improved[Note] Project `c84a208638c3`: Ethernet + 1000BASE-T present (no HDMI on board — correctly omitted).
  40. September 24, 2026v2.87.28

    Auto-reparse stale component on examine

    Michele: when examining a component whose library row is behind the current parser version, re-parse from the datasheet and KiCad footprint/symbol, upsert into the component library (writer-gated remotely), then continue the exam with fresh data. One MPN only — idle batch stays paused.

    • Improved[Added] `library_reparse.ensure_fresh_for_examine` — stale `parser_version` → sync datasheet extract + KiCad align → `LibraryAccess` upsert when allowed.
    • Improved[Changed] `review_ic_async` — runs ensure before pintable/context tools (schema + PCB examine).
    • Improved[Note] Local/self-host always writes; remote respects `PERISCOPE_LIBRARY_WRITER_IDS` (exam still gets workspace-fresh JSON).
    • Improved[Added] Tests: stale → reparse → aligned; non-writer skips shared upsert.
  41. September 24, 2026v2.87.27

    Rail power budget report card

    Michele: dedicated **Rail power budget** card on the report (not only PE-BUD in the findings tree). Per-rail ordinary/peak vs source with PASS/MARGIN/FAIL/UNKNOWN colors, remediation when failing. PE-BUD now also runs in the **PCB** pipeline (was schematic-only for findings; PCB already used rail peak for PE-PWR/VIA).

    • Improved[Added] `build_rail_power_section` → `ValidationReport.rail_power_budget` on schema + PCB reports.
    • Improved[Added] Report UI `PowerRailsSection` card + Markdown export section.
    • Improved[Changed] `run_pcb_checks` includes `check_rail_power_budget` (PE-BUD-001/002/003/010).
    • Improved[Note] Card shows only rails/domains present on the design. Re-run exam to populate on existing projects.
  42. September 24, 2026v2.87.26

    Certifications together in findings tree

    Michele: certification findings must live in **one** place in the report tree — not scattered under Error / Warning / Info. The tree keeps severity folders for non-protocol findings, then a single top-level **Certifications → Protocols** branch with every protocol instance and PE-PRT finding. Existing severity and PASS-green colors are unchanged. Rebased onto live 2.87.25 (`cd69f1d`).

    • Improved[Changed] `FindingsTree` — one Certifications sibling after Error/Warning/Info (not nested per status).
    • Improved[Added] `hasCertifications` in `findings-forest` for the single cert branch gate.
  43. September 24, 2026v2.87.25

    Continuous top-25 IC idle ingest

    Michele loop: periodically fetch ~25 most-used ICs → idle-process one-by-one into the **component library** → when empty, refetch, drop MPNs already present, top-up to **25 NEW**, repeat. Not a one-shot seed. Same exam pause as library scan.

    • Improved[Added] `library_popular_sources` — DigiKey → LCSC → curated ranking; rate-limited.
    • Improved[Added] `library_popular_ingest` — persistent queue, idle one-by-one extract→`LibraryAccess` upsert, continuous refill.
    • Improved[Added] `/api/library/popular-ingest/{status,tick,refill}` (writer-gated remotely).
    • Improved[Note] Cert library untouched. No deploy while exam `c84a208638c3` runs. Handoff: `internal/top25-ic-ingest.md`.
  44. September 24, 2026v2.87.24

    Two libraries + writer gate + idle refresh

    **Hard rule:** all chip-specific data lives in the **component library** (SoT). **Certification library** = standards/cert packs only. AF joins chip row + cert pack. Remote component-library writes restricted to `PERISCOPE_LIBRARY_WRITER_IDS`. Idle refresh pauses when any exam runs.

    • Improved[Added] `CertLibraryAccess` / `cert_library.sqlite` — cert packs; rejects pintable/power/bus chip fields; **seed skips chip-SoT packs** (e.g. `lan8720a-rmii`).
    • Improved[Added] `component_chip_seeds` — LAN8720A RMII timing/power migrated into component library; lifespan + `POST /api/library/seed-chips`.
    • Improved[Added] `LibraryAccess` writer allowlist (`library_auth`) on PUT/POST library mutations.
    • Improved[Added] Idle library refresh loop — stale/missing power|bus; pause on schema/PCB/placement jobs.
    • Improved[Added] `/api/library/cert`, `/api/library/writers/me`, `/api/library/idle-refresh/*`.
    • Improved[Changed] AF RMII certifies from component `bus_requirements` only — **no catalog/cert chip-number fallback**.
    • Improved[Changed] Chip `bus_requirements` / power remain on component extracts (`parser_version` 1.18.0).
    • Improved[Note] Deploy after exam: 2.87.22 then this branch. Protocol catalog may retain archival pack rows; they are **not** SoT.
  45. September 24, 2026v2.87.23

    Deep rail power budget + library access

    Deep per-rail **ordinary / peak** current budget (PE-BUD-001/002/003/010) with cited estimates — no silent skip. Library stores **power_requirements** (startup/ordinary/peak) and **parser_version**; **MySQL** is the management store (SQLite local fallback). Callers use **LibraryAccess** only. PCB PE-PWR/VIA prefer rail peak. Z inventory remains 2.87.22.

    • Improved[Added] `rail_power_budget.py` — Σ load ordinary/peak vs regulator/connector capacity (PASS/MARGIN/FAIL).
    • Improved[Added] `LibraryAccess` + `library_db` (MySQL/SQLite), `/api/library/access` pagination (stale / missing power).
    • Improved[Added] `PowerRequirements` + `parser_version` on `ComponentConstraints`; skills_manifest **1.17.0**.
    • Improved[Changed] Schema capacity leave `power_margin_check` (series-R IR stays PE-PWR-001); PCB traces use rail budget currents.
    • Improved[Added] Library UI management strip: parser version + I start/ord/peak filters.
    • Improved[Note] JSON `library/extracted` is write-through cache / import-export, not a parallel read API.
  46. September 24, 2026v2.87.22

    Inventory Z rewrite (AF-only + plane index)

    **Michele product rule:** inventory Z computes only on **AF/SI protocol nets** plus nets the project **explicitly requests** (`ProjectFabSettings.impedance_nets`). Walking every routed non-POWER/GROUND net is enormous and useless — no silent full-board fallback. **Hot path rewrite:** `coverage_at` no longer rebuilds Shapely polygons per sample. Zone outlines become a per-board `_BoardPlaneIndex` (layer lists, prepared geometries, STRtree) once; samples only query. `exclude_net` (CPWG) filters the index without re-parsing outlines. Complexity drops from roughly \(O(S \cdot Z_\ell \cdot P)\) polygon rebuilds to \(O(Z \cdot P)\) build + \(O(S \cdot Q)\) queries (\(Q \ll Z_\ell\) candidates from the tree). Mid-run SSE reports `Z i/N (%) net (samples)`.

    • Improved[Changed] `nets_needed` / `analyze_where_needed` — AF (+ `extra_nets`) only; skip reason `no AF or requested nets`.
    • Improved[Changed] `vendor/impedancefinder/planes.py` — board plane index + STRtree contains; `clear_zone_polygon_cache()`.
    • Improved[Added] `ProjectFabSettings.impedance_nets` — explicit extra Z nets for inventory.
    • Improved[Added] Inventory progress SSE during Z walk.
  47. September 24, 2026v2.87.21

    Fix `.kicad_pro` open-file accept

    Chromium `showOpenFilePicker` rejects extensions with `_` («Extension '.kicad_pro' contains invalid characters»). Create-project no longer puts `.kicad_pro` in the `accept` list — it opens an untyped picker and filters by filename, then still loads sch/PCB via the folder `startIn` step. Invalid-accept errors fall back to folder pick.

    • Fixed`pickKicadProject` — omit underscore extensions from File System Access `accept`; name-filter `.kicad_pro`; folder fallback.
  48. September 24, 2026v2.87.20

    Create from `.kicad_pro` (sch + PCB)

    Create-project now starts from the **`.kicad_pro`** file: after you pick it, Periscope requests the containing folder (Chrome `startIn`) and loads companion `.kicad_sch` / `.kicad_pcb` (plus hierarchical sheets). Dropping a project folder still works. The raw browser `TypeMismatchError` («path … not an entry of requested type») stays humanized; directory walks only call `getFile` on `kind === "file"` entries. Multi-unit symbols that share one reference across hierarchical sheets (e.g. COM Express `J12` units on `com_express_7_interfaces` + `com_express_7_mgmt`) no longer fail upload with «Duplicate reference». True clashes (same ref, different symbol/footprint) still error with both sheet names and a rename hint.

    • FixedCreate upload — select `.kicad_pro` then ingest schematic + PCB siblings (not folder-only / not lone-pro dead end).
    • Fixed`file-upload-zone` — `getAsFileSystemHandle` drop path; skip non-file directory entries to avoid TypeMismatch; DirEntry typing so production `next build` accepts `kind === "file"`.
    • FixedKiCad sch parser — merge multi-unit refs across sheets; actionable error for real duplicates.
    • Improved[Changed] Create-project label/helper: “Select .kicad_pro”.
  49. September 24, 2026v2.87.19

    Clear KiCad folder pick (path type)

    Michele saw the browser File System Access error «The path supplied exists, but was not an entry of requested type.» when opening a project after the `.kicad_pro` file-guide highlight. That string is `TypeMismatchError` (file vs directory), not KiCad CLI. Create-project now maps it to a clear hint: select the **folder** that contains `.kicad_pro` (not the file alone, not only `.kicad_pcb`). Lone file drops and folder picks without a `.kicad_pro` get the same guidance.

    • Fixed`file-upload-zone` — catch/humanize `TypeMismatchError`; refuse lone `.kicad_pro`/`.kicad_pcb` drops; require `.kicad_pro` after folder pick.
    • Improved[Changed] Create-project helper + missing-pro/sch copy aligned with “highlight `.kicad_pro`” intent (folder that *contains* it).
  50. September 24, 2026v2.87.18

    RMII data−clock timing (not skew-as-hold)

    LAN8720A Table 5-11 `tsu`/`tihold` are TXD/TXEN setup/hold **to/after rising CLKIN** at the PHY pin. PE-AF-003 no longer treats inter-line skew (`Lmax−Lmin`) as the hold/setup budget. PCB measurable is **data−clock Δt**; full PASS still needs cited MAC clock-to-out (otherwise not certified / INSUFFICIENT). `toval`/`tohold` are PHY output characteristics — INFO cite only, not PCB flight PASS/FAIL. Inter-line skew is INFO FACT when measurable; Table 5-11 has no skew limit. REF_CLK 50 MHz (Table 5-12) unchanged.

    • Improved[Changed] `_lan8720a_phy_cert_findings` — data−clock model for setup/hold; chip-spec note for toval/tohold; skew FACT only.
    • Improved[Changed] Tests: large inter-line skew must not fail hold; data−clock without MAC tco is not certified.
  51. September 24, 2026v2.87.17

    Highlight `.kicad_pro` in downloads

    On the File Upload Guide download / example list, the KiCad **`.kicad_pro`** project file is the primary callout — not buried among `.kicad_pcb`, sheets, or zip companions. Zip archives should contain / start from the `.kicad_pro`. Create-project upload UI unchanged.

    • Improved[Changed] File guide intro, Example files, KiCad export, and PCB sections lead with `.kicad_pro`.
    • Improved[Changed] Guide markdown styles `.kicad_pro` code / list rows with quiet emphasis (no badge cluster).
  52. September 24, 2026v2.87.16

    100 MB project uploads

    KiCad archives, PCB, stackup/fab docs, and datasheet PDFs may be up to **100 MB** (was 30 MB). The exact client message was `File too large (max 30 MB)` from the project upload router.

    • Improved[Changed] `MAX_UPLOAD_BYTES` / KiCad `MAX_BUNDLE_BYTES` / library `MAX_DATASHEET_BYTES` → **100 MB**.
    • Improved[Note] Live Caddy has no `request_body` cap; the FastAPI check is the gate. No nginx `client_max_body_size` on this host.
  53. September 24, 2026v2.87.15

    English UI menus

    Chrome and project settings labels are English everywhere. No change to finding report content.

    • Improved[Changed] Project settings bar: **Project settings** · Impedance · Domains · Project (was Impostazioni progetto / Impedenza / Domini / Progetto).
    • Improved[Changed] Exam actions and status bar: **Schematic analysis** / **PCB analysis** / Preparation / Cancel (was Analisi schema / Analisi PCB / Preparazione / Annulla).
    • Improved[Changed] Gear sheet + mobile menu link **Project settings**; Stackup / fab section copy and buttons in English.
    • Improved[Changed] Dashboard empty state, upload folder messages, and related chrome strings.
  54. September 23, 2026v2.87.14

    Analytic tpd from stackup ε_r

    When fab `tpd_ps_per_mm` is empty but stackup/project cites ε_r (and W/H/T for outer microstrip), length→delay derives tpd analytically — **IPC-2141/Wheeler** microstrip ε_eff, stripline ε_eff=ε_r, `tpd=√ε_eff/c` with `c=0.299792 mm/ps`. Provenance **DERIVED** with formula + inputs. Manual/fab tpd still overrides. Missing geometry → clear FAIL (no invented ε_r). Sanity WARNING outside ~5–7.5 ps/mm FR-4. UI shows calculated tpd when derived from ε_r. Not BEM/FEM.

    • Improved[Added] `tpd_analytic.py` — microstrip/stripline formulas + resolve priority (fab > per-layer > project ε_r).
    • Improved[Changed] PE-AF-003 RMII length→delay uses derived tpd with `cite_source=DERIVED` when fab tpd is empty.
    • Improved[Added] Fab settings API `derived_tpd` preview; Stackup/fab UI shows calculated tpd.
    • Improved[Added] Unit tests for known microstrip/stripline numeric cases + priority/sanity.
  55. September 23, 2026v2.87.13

    Impostazioni progetto (barra interna)

    Project settings live in a segmented bar **inside** `/project/:id` (below the TopBar): BOM · Impedenza · Rail · Domini · Stackup / fab · Derating · Progetto. TopBar no longer has a duplicate Settings tab — the gear sheet is **Appearance only**, with a link to Impostazioni progetto.

    • Improved[Added] `ProjectSettingsBar` on the project page (`?tab=` segments).
    • Improved[Changed] TopBar secondary **Settings** tab removed; Exam · Schema · PCB stay.
    • Improved[Changed] Gear Settings sheet = theme/Appearance; link to Impostazioni progetto (`?tab=settings` / Progetto).
    • Improved[Changed] Stackup / fab has its own segment (`?tab=fab`); Progetto keeps PCB upload, collaborators, skipped, report version (no Appearance).
  56. September 23, 2026v2.87.12

    Project Stackup & fab settings (tpd)

    Project **Impostazioni stackup / fab**: cited tpd (ps/mm, with ps/inch helper), optional εr / note / fab PDF·MD. Empty = unknown — **no** silent 150 ps/in. Curated **JLCPCB** / **PCBWay** import profiles (VENDOR cite; tpd only when the maker page states it). RMII LAN8720A setup/hold uses project tpd for mm×tpd→ns (IMPLEMENTATION/FAB); missing tpd Action points at Stackup & fab settings.

    • Improved[Added] `ProjectFabSettings` on `project.json`; GET/PUT fab-settings, import profile, upload fab doc.
    • Improved[Added] Curated fab profiles (`fab_profiles_data.json`) — JLCPCB impedance Dk/stackups + blog ~6/7 ps/mm; PCBWay 4L/6L εr=4.29.
    • Improved[Changed] PE-AF-003 LAN8720A length→delay reads project tpd; Action: “Set tpd in project Stackup & fab settings…”.
    • Improved[Added] Settings tab UI: Impostazioni stackup / fab + Importa da PCBWay / JLCPCB.
  57. September 23, 2026v2.87.11

    RMII=PHY DS, MII=Clause 22, GMII=Clause 35

    Michele model: RMII has no consortium/IEEE PCB cert — certify from the PHY datasheet in use (HubAudio → LAN8720A). MII from IEEE 802.3 Clause 22 (Section Two). GMII from Clause 35 (Section Three). AN-133 is optional helper only.

    • Improved[Changed] HubAudio RMII PE-AF-003 lines are LAN8720A PASS/FAIL (`RMII certified|not certified — according to LAN8720A §…`); no more INFO “timing cite”; AN-133 Z0 UNKNOWN is no longer the headline.
    • Improved[Added] `mii-pcb` packed from Clause 22 (setup/hold 10 ns, TX clock-to-out 0–25 ns, levels).
    • Improved[Added] `gmii-pcb` packed from Clause 35 Table 35–8 (125 MHz, setup/hold).
    • Improved[Changed] `lan8720a-rmii` expands Tables 5-11/5-12 (refclk 50 MHz, toval/tohold, tclkp).
  58. September 23, 2026v2.87.10

    Schema USB Z N/A + ESD TVS + report default

    HubAudio audit fix: Schema must not look like a failed PCB USB cert, and PESD TVS on USB_D± must suppress PE-ESD-001.

    • FixedSchematic-only USB Zdiff (`layout is None`) → **NOT_APPLICABLE / silent** — never ERROR “Z cannot be calculated” spam. PCB exam with layout still ERRORs when Zdiff is uncalculable.
    • FixedPE-ESD-001 recognizes `discrete.diode.tvs`, value/MPN `TVS` / `PESD*`, and common ESD diode keywords (USBLC, TPD…).
    • FixedBare `/report` redirects to `?kind=pcb` when a PCB report exists (else schema) — Schema/PCB tabs already in 2.87.8 stay the explicit pick.
  59. September 23, 2026v2.87.9

    UI flow: no Docs limbo, login→dashboard, attach + severity colors

    • Improved[Removed] Marketing top-bar **Docs** (`/file-guide`) — PinScope/proprietary leftover (“Documentazione”). Product top bar stays Exam · Schema · PCB · Settings.
    • FixedSign-in / sign-up land on **`/dashboard`** (honor `?next=`); signed-in visits to `/` redirect to projects — no marketing limbo.
    • FixedOpen project while Schema/PCB runs → **Exam** with bottom status bar (%/ETA); dashboard shows PCB/Schema running (not stale complete); legacy `/progress` and `/pcb` always redirect to Exam; start buttons lock with “In corso…”.
    • Improved[Changed] Report tree severity colors: **ERROR** red, **WARNING** yellow, **INFO** blue; Certifications **PASS / certified** green. English labels unchanged.
  60. September 23, 2026v2.87.8

    Exam flow: Schema vs PCB + status bar

    Michele grey-zone fix: a schematic reprocess must never look like a fresh PCB report. Exam now has exactly two primary actions — **Analisi schema** and **Analisi PCB** — with separate reports and a bottom status bar (label + % + ETA) instead of the scrolling log wall. New projects auto-run **preparation** only (BOM / datasheets / graph), then wait for an explicit analysis choice.

    • Improved[Changed] Create → `MODE=prepare` → status `ready`; buttons start schema (`run`) or PCB.
    • Improved[Changed] Report `?kind=schema|pcb` never mixes findings; header shows label, timestamp, Periscope version; PCB shows stale if schema re-ran later.
    • Improved[Changed] Bottom `RunStatusBar`; kill Log tab + progress stepper wall from the main path.
    • Improved[Changed] Top bar: Exam · Schema · PCB · Settings (iPad light shell).
  61. September 23, 2026v2.87.7

    Pair Zdiff calc + LAN8720A timing (HubAudio 46 Ω)

    **FATTO for Michele.** HubAudio Ethernet **46.0053 Ω** was **single-ended Z0** (`w=0.2`/`h=0.1`), not Zdiff — ImpedanceFinder did not pair `RJ45_RXP`/`RXN`. Now: pair → always **differential Z** via IPC-2141A `coupled_diff_z` (=2·Zodd); SE → Z0 only; report `zdiff_*` vs `z0_*` split; actionable Action cites the target. Pack **LAN8720A** Table 5-11 timing (`lan8720a-rmii`) and emit **both** bus + PHY PE-AF-003 lines when both apply. Builds on 2.87.6 USB ±15% Zdiff work.

    • September 23, 2026v2.87.6

      USB Zdiff ±15% tolerance (88≠ERROR)

      USB D+/D− compare **Zdiff** to packed 90 Ω ±15% (USB 2.0 §7.1.1.1/§7.1.1.3 cable Z0; PCB `should` RECOMMENDED). Inside band → PASS; outside → WARNING; uncalculable → ERROR. Never SE Z0. Bus cite + datasheet VENDOR are two cert lines. IEEE 802.3-2012 §25.4.9.2.2 Ethernet is nominal 100 Ω with **no** ± band — outside stays ERROR; MDI pairs also use Zdiff only.

      • September 23, 2026v2.87.5

        UI reorder: one shell, one report tree, KiCad-only ingress

        Full frontend cleanup after iPad top-bar landed beside leftover sidebar-era report chrome. Report shows **only** the findings tree (+ Save as Markdown). Project create/replace is **KiCad folder only** — no BOM csv/xlsx or PADS/EDIF entry UI. Soft-bump on the 2.87 line (FPGA 2.88.x stays separate). No deploy until Michele says so.

        • Improved[Removed] Dual report look: old FindingCard dashboard chrome inside the tree; dead `ComponentGroup` / `PcbExamSection`; top-bar Protocols tab (duplicate of Report).
        • Improved[Removed] Sidebar stub; BOM/non-KiCad upload options at project ingress.
        • Improved[Changed] Uniform iPad language: top bar chips, tree leaf rows, filters, Exam/Settings surfaces, English Error/Warning/Info labels.
        • Improved[Changed] Ingress copy: Open / Replace KiCad project; BOM derived from schematic fields on the server.
      • September 23, 2026v2.87.4

        U18 PE-PLC-002 thermal vias cite gate

        ADAU1467WBCPZ300R (U18) was ERROR for `9 thermal vias … (min_via_count 49)`. The `49` came from datasheet p.203 Figure 87 — an **example** 7×7 via grid (“shows 49 vias”), not a mandatory minimum. Same EP/ESD cite rule: ERROR only for a MANDATORY count with cite; figure/example counts are REVIEW + quote, or skip with no cite.

        • Improved[Changed] `placement_check.py` PE-PLC-002: mandatory-language gate; EXAMPLE → WARNING/REVIEW with `source_quote`.
        • Improved[Changed] `extract-pintable` skill: `min_via_count` only for “at least N”; figure grids stay note-only. Skills manifest **1.16.0**.
        • Improved[Changed] pytest: ADAU Fig.87 REVIEW; “at least 4” ERROR; uncited skip.
      • September 23, 2026v2.87.3

        HubAudio AF verify + re-run cue

        Live already carried the 2.87.2 PE-AF-002 cleanup, but HubAudio's last PCB exam was still stamped **2.87.0** — so Michele still saw duplicate RD/TD “speed not identified”, ETH_MDIO 100 Ω, Italian RMII/USB tr/f. Replay of the saved HubAudio design/layout graphs confirms the fix. Soft-bump so the report version moves; **re-run HubAudio PCB exam** on live.

        • Improved[Changed] Regression: USB_D+ skips PE-AF-002; protocol owns the English 90 Ω cert line.
        • Improved[Changed] Changelog cue: HubAudio must be re-examined after AF noise fixes.
      • September 23, 2026v2.87.2

        HubAudio AF noise: MDIO≠MDI, RD≡RX, USB/RMII cert

        HubAudio PE-AF-002 cleanup on live 2.87.x. Ethernet MDI aliases (`RD+/−` ≡ `RXP/RXN`, `TD+/−` ≡ `TXP/TXN`) are one cert per pair; LAN8720A supplies 10/100 when the magnetics-side nets lack the PHY MPN. `ETH_MDIO` / `MDC` are management — not IEEE 100BASE-TX 25.4.9. USB D+/D− leave the AF tr/f skip (protocol 90 Ω cert owns them). RMII stays on the AN-133 PE-AF-003 English line.

        • Improved[Changed] `si_check.py`: `is_mdio_mgmt`; `MDI(?!O)` so MDIO is not eth_mdi.
        • Improved[Changed] `af_trace_check.py`: MDI channel dedupe; graph-wide PHY speed; USB skips PE-AF-002.
        • Improved[Changed] pytest `test_hubaudio_af_noise.py`; AF geometry tests use HDMI (USB is cert-owned).
      • September 23, 2026v2.87.1

        Remove coffee/email progress notice

        Drop the running-pipeline “grab a coffee / we’ll email you” banner. Progress shows a neutral “Pipeline running…” status instead.

        • Improved[Removed] Coffee icon + email promise on project progress while a run is active.
      • September 23, 2026v2.87.0

        Live integrate: iPad top-bar, MAC–PHY pack, USB/RMII cert

        Combines the iPad top-bar shell (light default, Save as Markdown), the MAC–PHY bus catalog pack (Micrel AN-133, OPEN Alliance RGMII EPL V2.2, Cisco SGMII ENG-46158), USB 2.0 D+/D− cert lines versus the packed 90 Ω cite, RMII not-certified-on-recognition, and the `not_reviewed` count fix. One coherent live version above 2.86.0.

        • Improved[Changed] App shell: `TopBar` instead of sidebar; theme default `light`; Markdown report export.
        • Improved[Changed] `protocol_catalog.py` / `catalog.json`: `rmii-pcb`, `mii-pcb`, `rgmii-pcb`, `sgmii-pcb`.
        • Improved[Changed] PE-AF-003 / USB / Ethernet cert lines; J2 silence on missing L1/L2/L3 fields.
        • Improved[Changed] `not_reviewed` one designator per row; AI failures → `review_errors`.
        • Improved[Changed] pytest mac-phy / USB / RMII / not_reviewed; frontend shell + export tests.
        • Improved[Changed] Root `README.md` (+ `periscope/README.md`): product copy for 2.87.0 — PCB analysis, protocol cert, findings tree, top-bar UI, Markdown export; Gitea as source of truth.
      • September 23, 2026v2.86.0

        MAC–PHY bus pack (RMII/MII/RGMII/SGMII)

        Packed Micrel AN-133, OPEN Alliance RGMII EPL V2.2, and Cisco SGMII ENG-46158 into the protocol catalog. Only explicitly stated NUMERIC fields with provenance. PCB Z0 / length stay UNKNOWN where the PDF does not state them. PE-AF-003 no longer certifies on recognition alone. HubAudio-style RMII (LAN8720A ETH_RXD/TXD/TXEN) reports `RMII not certified — because …` with the AN-133 cite when PCB impedance is UNKNOWN. SGMII uses the Cisco 100 Ω Rload / Rin 80–120 Ω cite when geometry allows a pair Z. RJ45/MDI 100 Ω stays separate.

        • Improved[Changed] `protocol_catalog.py` / `catalog.json`: `rmii-pcb`, `mii-pcb`, `rgmii-pcb`, `sgmii-pcb`.
        • Improved[Changed] `af_trace_check.py` PE-AF-003 cert lines.
        • Improved[Changed] `standards/protocol-specs/INDEX.md` (+ on-disk PDFs, gitignored).
        • Improved[Changed] pytest `test_mac_phy_pack.py`, `test_rmii_cert_line.py`.
      • September 23, 2026v2.85.0

        USB / RMII cert lines; not_reviewed count

        USB 2.0 D+/D− is one line: calculated pair Z versus the packed 90 Ω board cite. Certified names the measured ohm and the cite. Not certified says why — Z is outside that cite, or Z cannot be calculated from the PCB stackup/geometry. Missing length, stub, via, termination, rise/fall, and channel fields do not each warn. L3 is omitted when no channel fact is on file. LAN8720A ETH_RXD / ETH_TXD / ETH_TXEN are RMII (single-ended PHY–MAC), not RJ45/MDI 100 Ω. Recognition alone is not certification (fixed in 2.86.0). RJ45 pairs keep `Ethernet certified / not certified`. `not_reviewed` count matches the list (one designator per row). Real PCB AI failures go to `review_errors` with the exception message — not a blanket `pcb_review error` on every skip. ICs already in coverage are not listed as not-reviewed.

        • Improved[Changed] `protocol_l1.py`, `protocol_l2.py`, `protocol_l3.py`, `protocol_report.py`, `af_trace_check.py`, `si_check.py`.
        • Improved[Changed] `pcb_validation.py`, `pcb_pipeline.py`, `pcb_checks.py` merge; report UI copy.
        • Improved[Changed] Protocol tree shows the certification sentence.
        • Improved[Changed] pytest `tests/pcb/test_j2_usb_cert_line.py`, `test_rmii_cert_line.py`, `test_not_reviewed_count.py`.
      • September 22, 2026v2.84.0

        Exposed-pad names, ESD cites, CC-via-net, Ethernet pair Z

        PE-BOM-011 treats EP, EPAD, THERMAL PAD, exposed pad, and the footprint's exposed land (including pin_count+1) as the same pad when both sides have one. A datasheet exposed pad with no land on the footprint stays ERROR. PE-ESD-001 says "datasheet-specified" only with a part and section/page. A 3V3 jack rail and VBUS are not warned without that cite. Optical S/PDIF (TOSLINK/optocoupler) is not an ESD warning; an unverified S/PDIF path stays a visible warning. PE-PRT-L0-001 follows Type-C CC pins (A5/B5) to the net and looks for the packed CabCon Rd 5.1 kΩ. The net does not have to be named CC1/CC2. PE-AF-002 on an Ethernet MDI pair compares one calculated pair Z to the packed cite for the speed on the board (LAN8720A 10/100 → 100 Ω, IEEE 100BASE-TX 25.4.9; Clause 40 only if gigabit). Inside is PASS, outside is FAIL, and no calculation is ERROR. No tr/f request.

        • Improved[Changed] `bom_pcb_check.py`, `esd_return_check.py`, `protocol_l0.py`, `af_trace_check.py`.
        • Improved[Changed] pytest `tests/pcb/test_bom_esd_ep_cc_eth.py`.
        • Improved[Changed] Findings tree labels are English: domains, Certifications, Protocols, actions, and empty states. Error / Warning / Info stay.
      • September 22, 2026v2.83.0

        Apple-like shell; USB-C vSafe still UNKNOWN

        Shell Finder/Settings: sidebar, large title, system font, hairline. Findings tree keeps Error / Warning / Info folders (FAIL first) with + disclosure, then domains/rules, then Certificazioni/Protocolli. HDMI 1.4 TMDS electrical displays UNKNOWN — no guessed Zdiff. Alta Frequenza zip and `af-allegati` were searched for vSafe5V / vSafe0V. Contents are TI SI (`snla027b` AN-807, `sdaa499` EMI) — they do not state vSafe voltages. USB Type-C CabCon R2.5 §1.6 p.35 points at USB PD without a volt range. Charger Figure 4-39 4.75–5.5 V stays not-vSafe.

        • Improved[Changed] App chrome (`sidebar`, `globals.css`, dashboard list, report large title).
        • Improved[Changed] Findings tree grouping + protocol section inside the tree.
        • Improved[Changed] Protocol UI: HDMI 1.4 TMDS Zdiff/limit/measured show `UNKNOWN`.
        • Improved[Changed] Frontend tests `findings-forest`, `protocol-report`.
        • Improved[Changed] `vsafe5v` / `vsafe0v` needed_document; `catalog.json`.
        • Improved[Changed] INDEX archives AF TI SI as not packed for vSafe.
      • September 22, 2026v2.82.0

        HDMI 2.0+ TI fields use source_type VENDOR

        Michele exception: HDMI 2.0 and FRL electrical/PCB numbers from TMDS1204 / SLLA633 use `source_type=VENDOR` (not HDMI Forum STANDARD). TMDS1204-specific limits (skew, vias, FRL data_rate, SIGDET) are PHY_DEPENDENT with a document/rev/section cite and no number. HDMI 1.4 TMDS stays UNKNOWN. pcbsync.com not packed.

        • Improved[Changed] `SourceType` includes `VENDOR`; `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`.
      • September 22, 2026v2.81.0

        Protocol PDF archive + HDMI 2.0/FRL TI VENDOR overlay

        On-disk archive `standards/protocol-specs/` (PDFs gitignored). INDEX.md lists cites. HDMI 2.0 and FRL take TMDS1204 Table 8-6 layout as VENDOR/PHY RECOMMENDED — not HDMI Forum STANDARD. HDMI 1.4 TMDS Zdiff stays UNKNOWN. pcbsync.com not packed.

        • New`standards/protocol-specs/INDEX.md`; `.gitignore` `standards/protocol-specs/*.pdf`.
        • Improved[Changed] HDMI 2.0 / FRL constraints; `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest pdf-pack / m6.
      • September 22, 2026v2.80.0

        TI TMDS1204 HDMI layout as VENDOR/PHY only

        TMDS1204 datasheet SLLSF57A fills sink/source PCB layout (ZPCB 90 Ω / 75 Ω ranges, skew, length, vias, XTALK −24 dB, 5W spacing, RINT, AC cap) on physical ids `tmds1204-hdmi-sink` / `tmds1204-hdmi-source`. source_type PHY, source_class VENDOR, RECOMMENDED. Generic `hdmi-*` TMDS/FRL Zdiff stays UNKNOWN. SLLA633 is SIGDET wakeup (PHY_DEPENDENT), no layout ohms. pcbsync.com blog not packed.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`, `test_protocol_catalog_m0.py`.
      • September 22, 2026v2.79.0

        HDMI CEC electrical from HDMI Specification 1.3

        `CEC_HDMI_Specification.pdf` is High-Definition Multimedia Interface Specification Version 1.3 (22 June 2006), not a CEC-only pamphlet. CEC pull-up 27 kΩ, VOL 0.6 V, VOH 2.5 V, device 200 pF / cable 700 pF, interconnect 5 Ω are packed. TMDS/FRL Zdiff/skew stay UNKNOWN (Adopter spec still required). DDC/HPD not packed.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`, `test_protocol_m6_m7.py`.
      • September 22, 2026v2.78.0

        1000BASE-T from IEEE 802.3-2012 Section Three

        IEEE Std 802.3-2012 Section Three Clause 40 fills 1000BASE-T: 1000 Mb/s, 100 m Class D link, cable 100 Ω, MDI return loss 16 dB (1–40 MHz), pair skew 50 ns, isolation 2 MΩ / 1500 V rms, MDI peak 0.67 V, link delay 570 ns. Cable 100 Ω is **CABLE**; L2 PCB Zdiff stays UNKNOWN. Clause 36 fills 1000BASE-X 1000 Mb/s (optical Zdiff N/A). Insertion-loss formula not packed as a single dB.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`, `test_protocol_m6_m7.py`.
      • September 22, 2026v2.77.0

        10BASE-T from IEEE 802.3-2015 Section One

        IEEE Std 802.3-2015 Section One Clause 14 fills 10BASE-T: 10 Mb/s, 100 m design-objective link, cable 100 Ω ± 15 Ω, 11.5 dB link insertion loss, MAU TD return loss 15 dB, isolation 2 MΩ / 1500 V rms, TD peak 2.2 V. Cable 100 Ω is **CABLE**, not L2 PCB Zdiff. 1000BASE-T (Clause 40) is not in this volume.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`, `test_protocol_m6_m7.py`.
      • September 22, 2026v2.76.0

        Type-C CabCon R2.0 hole-fill (CC shall-detect; VBUS from R2.5)

        USB Type-C Cable and Connector Specification Release 2.0 (August 2019) fills Source CC shall-detect voltages that R2.5 only illustrates as variance examples (Table 4-32 p.240: vRd 1.50 V, vOPEN 1.65 V, vRa 0.15 V). Type-C Current charger VBUS 4.75–5.5 V no-load / 4.0–5.5 V at 3 A, zOPEN 126 kΩ, tCCDebounce 100–200 ms, and tVBUSON 275 ms stay on newer CabCon R2.5 (Figure 4-39 / Tables 4-30, 4-32, 4-34). Rp/Rd/Ra unchanged. vSafe5V volt range still needs USB PD.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`.
      • September 22, 2026v2.75.0

        Protocol packs from USB 2.0 Rev 2.0 and Type-C CabCon R2.5

        USB 2.0 Base Specification (April 27, 2000) fills LS 1.50 Mb/s, FS 12 Mb/s, HS 480 Mb/s, pull-up/down, VBUS 4.75–5.25 V, LS/FS edges. Cable Z0 90 Ω is `source_type=CABLE`; HS PCB traces *should* 90 Ω is RECOMMENDED PCB — L2 `differential_impedance` stays UNKNOWN so 45/50 Ω fixtures are not treated as Zdiff. Type-C Cable and Connector Specification Release 2.5 fills Rp/Rd/Ra from Tables 4-27/4-28/4-29. VBUS volts still need USB PD vSafe5V. IEEE 802.3 Section One/Three and HDMI Adopter remain missing.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`.
        • Improved[Changed] pytest `tests/pcb/test_protocol_pdf_pack.py`.
      • September 22, 2026v2.74.0

        Protocol packs from recovered PDFs (USB CTS, Type-C FTS, DVI 1.0, IEEE 802.3-2012 §2)

        NUMERIC constraints now carry title, revision, section/table, and page from the recovered PDFs. USB 2.0 HS fills data rate / rise-fall / 1.5 kΩ pull-up / DCR from Electrical CTS v1.08; Zdiff stays UNKNOWN (CTS does not state 90 Ω). Type-C Rp/Rd/VBUS volts stay UNKNOWN (Functional Test Spec points at Cable and Connector tables). DVI 1.0 is a separate protocol from HDMI. IEEE 802.3-2012 Section Two fills 100BASE-TX cabling 100 Ω / 100 m / isolation and 100 Mb/s; 10BASE-T Clause 14 and 1000BASE-T Clause 40 are not in Section Two.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`; DVI recognition.
        • Newpytest `tests/pcb/test_protocol_pdf_pack.py`.
      • September 22, 2026v2.73.0

        Protocol certification M6/M7 (USB-C / Ethernet / HDMI packs)

        USB 2.0 (LS/FS/HS) is the protocol; USB Type-C is a connector/interface system; USB 2.0 over Type-C is the physical implementation. Type-C does not imply USB3 or USB4. Mini HDMI is a connector, not a protocol. Ethernet variants (10/100/1000/2.5G/5G/10G, SGMII, 1000BASE-X, 100BASE-FX, 10GBASE-R) are incomplete skeletons. All listed numeric fields stay **UNKNOWN** with `needed_document` (USB-IF / IEEE 802.3 / HDMI Adopter). No invented ohms, no typical-as-standard, no OpenEMS.

        • Improved[Changed] `protocol_catalog.py` + `catalog.json`; `needed_document` on UNKNOWN/MISSING_SOURCE.
        • Improved[Changed] USB/Ethernet/HDMI recognition: connector alone is not the protocol.
        • Newpytest `tests/pcb/test_protocol_m6_m7.py`.
      • September 22, 2026v2.72.0

        Protocol certification M10 (catalog skeletons)

        Catalog skeletons and `required_checks` for **PCIe / CXL** (logical vs physical), **I2C**, **CAN**, **RGMII**, plus missing high-speed processor ids (PCI, PCI-X, CCIX, OpenCAPI, UPI, DMI, Infinity Fabric, HyperTransport, UCIe). Numbers stay **UNKNOWN / MISSING_SOURCE / PHY_DEPENDENT** until an official cite is in the pack. `pcb_relevant` is YES or CONDITIONAL as appropriate. No invented ohms, no USB-IF fill, no OpenEMS.

        • Improved[Changed] `protocol_catalog.py` + committed `catalog.json`.
        • Newpytest `tests/pcb/test_protocol_catalog_m10.py`.
      • September 22, 2026v2.71.0

        Protocol certification M9 (L3 channel + visible skip)

        L3 **CHANNEL** certifier: structure for timing budget (TOTAL−USED=MARGIN), insertion loss, return loss, crosstalk, and complete channel. Numerical PASS/FAIL only when **existing channel FACT** (dB/ps) is already present — never invented S-parameters, never OpenEMS/FEM. Otherwise a visible skip: «Interfaccia X non certificata a L3 per mancanza di …». Internals (AXI/HBM) stay NOT_APPLICABLE. L0/L1 are not electrical. No M6 numeric packs.

        • New`protocol_l3.py`; `PE-PRT-L3-001` / `PE-PRT-L3-002`.
        • Newpytest `tests/pcb/test_protocol_l3_m9.py`.
      • September 22, 2026v2.70.0

        Protocol certification M8 (DDR instance + L1 grouping)

        DDR **physical instances** are controller-aware: one instance per memory device, DQ/DQS **byte lanes** separate from ADDRESS / COMMAND / CONTROL / CLOCK. Skew/length stay **CONTROLLER_DEPENDENT / PHY_DEPENDENT / UNKNOWN** — no universal mm/ps/ohm. HBM is package/interposer (`pcb_relevant: NO`); classic DDR PCB DQ rules are not applied. M6 numeric packs and L3 solver are not in this release.

        • New`protocol_ddr.py`; L1 grouping reconstruction without PCB geometry.
        • Newpytest `tests/pcb/test_protocol_ddr_m8.py`.
      • September 22, 2026v2.69.0

        Protocol certification M5 (Protocolli report)

        Report section **Protocolli**: recognised instances, max level L0–L3 (L3 is a visible not-run skip, no solver), each check with measured / limit / margin / source / method, traceability chain net → group → physical interface → protocol → constraint → document → section. FAIL is listed first and styled as Error — not hidden under Warning (HubAudio). Visible skips stay on the page. No pack numbers, no invented Z, no OpenEMS.

        • New`protocol_report.py`; Protocolli table UI.
        • Newpytest `tests/pcb/test_protocol_report_m5.py`; `protocol-report.test.ts`.
      • September 22, 2026v2.68.0

        Protocol certification M4 (L2 electrical)

        L2 ELECTRICAL certifier: impedance, termination, voltage/levels, rise/fall when sources exist. Z only from datasheet / stackup / fabricator / **cited pack** — never invented 90 Ω USB. USB-IF/IEEE only if the pack has a cite. Silicon cross is max PCB × PHY subset when datasheet windows exist. Length is not delay. No L3/OpenEMS. L0/L1 are **not** electrical. RECOMMENDED never FAIL. MISSING_SOURCE / UNKNOWN when cite is absent. Visible skip when Z cannot be obtained.

        • New`protocol_l2.py`; `PE-PRT-L2-001` / `PE-PRT-L2-002`.
        • Newpytest `tests/pcb/test_protocol_l2_m4.py`.
      • September 22, 2026v2.67.0

        Protocol certification M3 (L1 geometric)

        L1 GEOMETRIC certifier: length, topology, vias, stubs, layer, grouping. Geometric skew only vs **NUMERIC** millimetre or an explicit **DESIGN LIMIT**. Otherwise UNKNOWN / VENDOR_DEPENDENT / CONTROLLER_DEPENDENT / PHY_DEPENDENT — never invent mm/ps. L1 is **not** electrical. No L2/L3. RECOMMENDED never FAIL. Internal interfaces stay NOT_APPLICABLE. Missing DQ/DQS grouping is a visible skip, not PASS.

        • New`protocol_l1.py`; `PE-PRT-L1-001` / `PE-PRT-L1-002` / `PE-PRT-L1-003`.
        • Newpytest `tests/pcb/test_protocol_l1_m3.py`.
      • September 22, 2026v2.66.0

        Protocol certification M2 (L0 structural)

        L0 STRUCTURAL certifier: nets must exist and connect at least two components. FAIL only for missing **MANDATORY** structure. AXI4 / internal interconnects are **NOT_APPLICABLE** (not FAIL). RECOMMENDED never FAIL. No L1–L3, no invented ohms/mm/ps.

        • New`protocol_l0.py`; `PE-PRT-L0-001` / `PE-PRT-L0-002`.
        • Newpytest `tests/pcb/test_protocol_l0_m2.py`.
      • September 22, 2026v2.65.0

        Protocol certification M1 (instance recognition)

        `physical_bus_instance` from declaration / silicon / part / pin / net / pairs. Output: instances, signal groups (DIFF pair, byte lane, clock/address), confidence. Ambiguity is **REVIEW**, never FAIL. AXI4 internal is recognised with `pcb_relevant: NO` and **no PCB nets**. No L0–L3 certifier. No invented ohms.

        • New`protocol_recognize.py`; report Protocolli lists recognised instances or stays empty.
        • Newpytest `tests/pcb/test_protocol_recognize_m1.py` (USB/DDR fixtures; AXI has no nets).
      • September 22, 2026v2.64.0

        Protocol certification M0 (catalog, no numbers)

        Versioned JSON protocol pack + Python loader/validator. Catalog skeletons for USB2 / USB-C-USB2 / 100BASE-TX / HDMI (connector distinct) / DDR / LPDDR / HBM / HyperBus / QSPI-octal / eMMC / UFS / AMBA / Wishbone / Avalon / TileLink / PCIe-CXL. Constraints without an official cite are UNKNOWN / CONTROLLER_DEPENDENT / PHY_DEPENDENT / MISSING_SOURCE — **no invented 90/100/50 Ω**. `logical_protocol_id` ≠ `physical_interface_id`. `pcb_relevant` is YES|NO|CONDITIONAL. RECOMMENDED is not FAIL-mandatory. Typical-as-standard is rejected by the parser. Report section **Protocolli** is empty (`nessun protocollo riconosciuto`). Recognition and L0–L3 certifiers are not in this release.

        • New`protocol_catalog.py`, `protocol_data/catalog.json`, schema 1.0.0.
        • New`protocol_certification` on `ValidationReport`; UI section Protocolli.
        • Newpytest `tests/pcb/test_protocol_catalog_m0.py`.
        • FixedNative `boardlab/src` wins over inherited `periscopex` on the package path.
      • September 22, 2026v2.63.5

        AF trace analysis (trigger, cascade, visible skips)

        PCB exam adds **AF trace analysis** after unchanged `run_pcb_checks` (SI/HF stay). Trigger is λ/10 or tr/(6 tpd) from FACT only. Differential pairs are one unit. Z0/Zdiff only vs a **datasheet** window. Missing tr/f/εr/stackup/Z target/via span is a visible INSUFFICIENT finding («Pista ad alta frequenza non controllata per mancanza di …»), not invented 50/90 Ω. Trigger false → no AF finding. Numerical cascade is lossless RLGC sections (ImpedenceFinder Z0); not OpenEMS/FEM. Python. PE-AF-001 AI path unchanged.

        • New`check_af_traces` / `af_trigger` / `af_rlgc`; pipeline stage `af_trace`.
        • New`PE-AF-002` visible skip; `PE-AF-020`…`061` on triggered nets.
        • NewVia `(layers …)` parsed on `LayoutVia` (span; size is not a track).
        • Improved[Changed] Changelog / PCB progress lists AF trace before AF+AI.
      • September 22, 2026v2.63.4

        Report Error group, J2, U18 max severity

        The findings tree always has an **Error** folder when ERROR findings are visible. Group badge is the worst child (U18 PE-PLC-002 ERROR is not labeled WARNING). Connectors (J2) sit in the same sidebar as U*. PE-PLC stays in the PCB exam bucket. No auth change.

        • FixedStatus folders Error / Warning / Info; severity = max of children.
        • FixedJ2 and other non-U refs listed with ICs.
        • Fixed`isPcbExamFinding` matches layout findings (PE-PLC with PE-BOM).
      • September 22, 2026v2.63.3

        Module die, truncated QFN pintable, QFN=VQFN

        HubAudio software leftovers on PE-BOM-010/011: a WROOM module is not the ESP32 die pintable; a QFN-48 land is not wrong because extraction stopped at pins 1–24; VQFN-24 4×4 is the same QFN family as datasheet QFN-24. Extra signal pads above the declared QFN-n still ERROR. Pad ≠ via. Kelvin unchanged.

        • FixedPE-BOM-011 skips die-pintable extras on WROOM/WROVER module footprints (U11).
        • FixedPE-BOM-011 skips QFN-n pads the pintable never listed (U12 25–48).
        • FixedPE-BOM-010 treats VQFN/WQFN/HVQFN as QFN (U19).
      • September 22, 2026v2.63.2

        PE-BOM-011 joins pins by name, not pin_count

        Datasheet `pin_count` and PCB pad cardinality are incommensurable (USB-C 16P vs SH/mount/EP). PE-BOM-011 joins the pintable × KiCad `.kicad_mod` × embedded PCB pads by **pin name**. USB-C A5/B5 are CC pins, not EP. Missing pintable is a skip, never ERROR on `pin_count=16`. The library footprint is checked against the datasheet; lib vs embedded PCB is a separate mismatch. AI still extracts the table and runs review/class/SI — it does not count pads. Pad ≠ via.

        • FixedPE-BOM-011 no longer treats `[A-Z]\\d+` as EP (HubAudio J2 16 vs 1 SH).
        • FixedScalar `package_info.pin_count` is not an ERROR authority.
        • Improved[Changed] Named join: datasheet pintable vs lib vs PCB; SH/EP/mount classified first.
      • September 21, 2026v2.63.1

        Library component from PDF; AF+AI beside PCB checks

        Library import registers a **component** (not only a PDF blob) with no exam. AF Board+AI is a pipeline section **after** unchanged `run_pcb_checks` (PE-SI / HF line stay in 2.62.1).

        • Improved[Fix] `POST /api/library/datasheets` writes an IC inbox card or a passive/discrete model. Empty pintable never lands in `library/extracted/`.
        • Improved[Fix] PCB pipeline stage `af_ai` calls `append_investigated` beside `run_pcb_checks`. Duplicate SI clones are not double-counted. `PE-AF-001` stays additive.
        • NewReport tree root “AF Board + AI”. Progress step between deterministic checks and PCB AI exam.
      • September 21, 2026v2.63.0

        Library as its own product door

        Standalone `/library` + `/api/library`: browse, add a datasheet PDF without an exam, update a component card. Datasheet prelim stays on the analysis path. Tests grouped datasheet → library → schematic → PCB → AF+AI (extra HF flags, then deterministic investigate). Rust criteria documented; no rustup. FEM out. DRC remains KiCad.

        • New`POST /api/library/datasheets` stores a PDF by MPN with no project id.
        • New`GET`/`PUT /api/library/components/{type}/{mpn}` for extracted cards.
        • NewLibrary page import form; empty library no longer says “run a review”.
        • New`investigate_hf_hypotheses` (`PE-AF-001`) — AI Z0 flag without stackup is INSUFFICIENT, never 50/90 Ω. Existing `run_pcb_checks` unchanged.
      • September 21, 2026v2.62.1

        PCB analysis remainder (Phase B)

        Stackup vs fab spec, via current with datasheet I (no IPC via chart), ESD pad distance TVS–connector, USB-PD contract, PoE isolation voltage, antenna keepout/matching, PDN Z(f). Same pipeline and finding quality as 2.61.2 / 2.62.0. Skip if no evidence. Not DRC. Not FEM.

        • New`PE-STK-001` board copper thickness vs sourced fab stackup (never 1 oz).
        • New`PE-VIA-002` I + via count/drill FACT; IPC via ampacity is not applied.
        • New`PE-ESD-002` TVS–connector **pad** distance (via ≠ pad); INFO if no mm.
        • New`PE-PD-001` USB-PD only with a PD controller (not USB2 Rd).
        • New`PE-POE-004` isolation voltage only from a sourced number.
        • New`PE-ANT-001`/`002` antenna keepout and matching if an antenna exists.
        • New`PE-PDN-001` Z(f) only with frequency-domain FACT; SI Z0 is not PDN.
      • September 21, 2026v2.62.0

        HF lines/buses in PCB checks (Phase A)

        USB / Eth / DDR / MIPI / PCIe / HDMI / LVDS / HF clock in `run_pcb_checks` at the same finding quality as 2.61.2. Pair integrity: stub (track only; via ≠ pad ≠ zone), reference-split under the line, BOM termination. CPU data/address/control and FPGA only if that device is on the graph. Skip if no evidence. Not DRC. Not FEM. Datasheet millimetres only; no invented Z/I.

        • New`PE-SI-007` dangling track stub vs datasheet mm (INFO if no mm).
        • New`PE-SI-011` GND-pour gap under an HF pair (REVIEW; skip without stackup/zone).
        • New`PE-SI-012` BOM series/parallel terminator FACT (skip if none).
        • New`PE-DDR-001`…`003` DRAM class / CK-DQS-DQ / VTT only if DRAM present.
        • New`PE-CPU-001`…`004` parallel CPU bus only if D/A/control exist.
        • New`PE-FPGA-001`…`003` FPGA class / config flash / VCCINT·VCCIO only if FPGA present.
        • Improved[Changed] `bus_class` adds MIPI and leftover HF clocks; XTAL/OSCIN stay out.
      • September 21, 2026v2.61.2

        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.

        • FixedAbsent USB-C / RJ45 / PoE no longer emit INFO N/A.
        • FixedBare RJ45 is Ethernet only; PoE is skipped without PoE evidence.
      • September 21, 2026v2.61.1

        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.

        • FixedPE-PWR-001 / PE-VIA-001 skip when datasheet current is absent.
        • FixedImax / I_abs accepted for width; Iout_max is still not load.
      • September 21, 2026v2.61.0

        Interface class certifiers (USB-C, Ethernet, PoE)

        Dedicated per-interface certifiers (deterministic + AI explanation). Not generic SI. USB-C: CC1/CC2, Rp/Rd 5.1 kΩ, VBUS/GND, SuperSpeed only if the class is USB3. Ethernet: 10/100 vs GbE; magnetics required for GbE. PoE only with PoE evidence — a bare RJ45 is N/A, never invented PoE. Missing generation/class/ohms → INSUFFICIENT. DDR3 and via IPC ampacity are out of this slice. No FEM.

        • New`PE-USBC-001`…`005` USB-C class + CC + Rd/Rp + VBUS/GND + SuperSpeed gate.
        • New`PE-ETH-001`…`004` Ethernet 10/100 vs GbE, TX/RX pairs, GbE magnetics, Bob Smith REVIEW.
        • New`PE-POE-001`…`003` PoE evidence / class / isolation; bare RJ45 is N/A.
        • NewTaxonomy `connector.rj45`. AI prompts must not invent PoE or SuperSpeed.
      • September 21, 2026v2.60.11

        PCB software false positives

        KiCad 9/10 boards have no numeric net table (`(net "GND")` on pads/tracks). The net index is filled from those names. PE-LAY-004 counts copper on **tracks, vias, and pours**, skips `unconnected-(…)` NC nets, and matches `/sheet/` prefixes — it must not report ~139 “unrouted” nets when KiCad DRC `unconnected_items` is ~30 (islands on already-named nets). Missing `I_load` is INSUFFICIENT on PE-PWR-001 / PE-VIA-001. Thermal/EP extra pads are not PE-BOM-011 ERROR. Voltage abs-max binds to the named pin. Kelvin ignores CRS/IN±. EMI/PI skip NC nets. LQW18AN `murata_lqw_inductance` decodes nH. FB/BLM beads are ferrite; DCR is not Z. Thinking `reasoning_content` echo unchanged.

        • FixedEmpty `LayoutGraph.nets` on KiCad 9/10 name-only nets.
        • FixedPE-LAY-004 zone/via/NC join vs DRC unconnected order of magnitude.
        • FixedPE-PWR-001 / PE-VIA-001 emit INSUFFICIENT without `I_load`.
        • FixedPE-BOM-011 EP/thermal extras; PE-BOM-012 pin-bound abs-max.
        • FixedPE-KEL-001 / PE-EMI-001 / PE-PI-001 NC and IN± / CRS false positives.
        • FixedLQW decoder; BLM/FB not typed as a DCR resistor.
      • September 21, 2026v2.60.10

        Hierarchical sheets + DeepSeek thinking echo

        Apri progetto still skips `.history` / `.git` / backups so the folder pick does not hang. It now keeps **every** linked schematic: all `*.kicad_sch` next to the `.kicad_pro`, plus `Sheetfile` / `(sheet` / `file=` children in a subfolder. Not only `HubAudio.kicad_sch`. DeepSeek thinking-only review turns (HubAudio U11/U12/U38) 400'd because the next request dropped `reasoning_content`. The native client echoes it on the follow-up. Retry failed IC reviews after this deploy.

        • FixedUSB / Codec / POWER (and other hierarchical modules) are ingested with the root sheet.
        • FixedNested sheet paths are followed; `.history` copies are ignored.
        • FixedThinking-mode `reasoning_content` is passed back on subsequent turns.
      • September 21, 2026v2.60.9

        Apri progetto does not walk forever

        After folder permission, 2.60.8 kept `Next` disabled because `showDirectoryPicker` then recursed `dirHandle.entries()` / `getFile()` through the whole tree (HubAudio `.history` is ~2000 files). We only read the project directory: `.kicad_pro`, `.kicad_sch`, `.kicad_pcb`. Timeout shows an error instead of a spinner forever. Next enables when a `.kicad_pro` is in.

        • FixedFolder pick no longer hangs on nested dirs / permission / giant trees.
        • FixedNext on step 1 when `.kicad_pro` is present.
      • September 21, 2026v2.60.8

        Folder picker, not Carica file dialog

        Apri progetto opened the Mac file list (**Carica**, no row selected) because the control was a React `<input type="file" accept="">` without a working `webkitdirectory`. Empty Carica then looked like “no .kicad_pro”. It now uses `showDirectoryPicker` (Chrome) or a hidden input created with `webkitdirectory=true` and **no accept**. Cancel/empty pick is ignored.

        • FixedOne folder gesture; `.kicad_pro` from name or webkitRelativePath.
      • September 21, 2026v2.60.7

        Detect HubAudio.kicad_pro after folder pick

        Apri progetto was rejecting the folder that actually contains `HubAudio.kicad_pro`. Safari/macOS folder pick often puts the real name in `webkitRelativePath` while `File.name` is the stem without `.kicad_pro`, and React was not setting `webkitdirectory` on the input. We match name **or** relative path, sniff JSON if the suffix is missing, and set the folder attribute on the DOM.

        • FixedFolder that contains `HubAudio.kicad_pro` is accepted.
        • Fixed`webkitdirectory` set via DOM `setAttribute` so Safari/Chrome recurse.
      • September 21, 2026v2.60.6

        Apri progetto KiCad (cartella)

        Un controllo: **Apri progetto KiCad**. Si sceglie la cartella dove sta il `.kicad_pro`. Carichiamo root + fogli hierarchical `.kicad_sch` e il `.kicad_pcb` fratello. Niente netlist, niente CSV. MPN solo da proprietà schematico (PNM/MPN/Value). Uno `.asc` PADS vecchio nella stessa cartella è ignorato.

        • NewFolder picker / drop della cartella progetto.
        • Fixed`.kicad_pro` da solo non finge di avere lo schematico.
        • FixedConnectivity dallo schematico, non da un netlist stantio (niente U13 fantasma).
      • September 21, 2026v2.60.5

        Hierarchical schematic MPN when BOM omits a ref

        graph_build reads `PNM` on `.kicad_sch` symbols (all nested sheets). If the CSV has no row for a designator, the child-sheet `PNM`/`MPN`/IC `Value` still fills `mpn`. Empty child-sheet fields stay empty — no invented part numbers. A sibling `.kicad_sch` next to a PADS netlist is consulted the same way.

        • FixedKiCad property `PNM` is an MPN alias on symbols, not only on BOM CSV.
        • NewHierarchical fixture: U13 on a child sheet with PNM, omitted from CSV, still gets TPD2E007DCKR.
      • September 21, 2026v2.60.4

        KiCad PNM and honest missing-MPN skips

        KiCad BOM column `PNM` is an MPN alias. Grouped `Reference` lists still split. IC `Value` fills MPN when PNM is blank (PCA9534ARGTR). Netlist-only U* with no BOM row are `INSUFFICIENT_EVIDENCE` (quoted Value/Footprint), not a silent drop and not an invented part number.

        • FixedProgress skip text no longer says “no MPN in BOM” when the designator is absent from the CSV.
        • NewHubAudio KiCad BOM fixture: PNM header, U2/U3 Value fallback, L4 bead PNM, U13…U39 not invented.
      • September 21, 2026v2.60.3

        Ferrite Z from library MPN datasheet

        graph_build looks up the bead MPN PDF in project `uploads/datasheets` and `library/datasheets` (named files and blob refs). Z is filled only when the PDF states impedance (e.g. 120 Ω @ 100 MHz). Missing Z stays omitted; graph_build does not abort.

        • FixedHubAudio-style beads recover `impedance_ohm` from the manufacturer PDF, not from inventing Z or stuffing ohms into `value_henries`.
        • NewTests: MPN + datasheet PDF fills Z; MPN + PDF without Z does not invent and still loads.
      • September 20, 2026v2.60.2

        Ferrite Z from datasheet, no graph_build abort

        Beads with an MPN pull `impedance_ohm` from the datasheet or a quoted `N ohm @ freq` string. Missing Z after that is INSUFFICIENT, not a crash. Ohms are never written to `value_henries`. Leftover dependency validator no longer requires Z.

        • Fixed`graph_build` loads DCR-only beads; leftover `ferrite bead requires impedance_ohm` removed.
        • Improved[Changed] Ferrite Z recovered from datasheet PDF / quoted value; extract-specs skill 1.15.0.
      • September 20, 2026v2.60.1

        Ferrite bead without Z still loads

        Ferrite beads that only have current/DCR validate. Missing `impedance_ohm` is not invented and does not crash `graph_build`. Other inductors still need `value_henries`.

        • Fixed`InductorSpecs` no longer requires Z on `passive.ferrite_bead`.
        • Improved[Changed] Bad `models/*.json` are skipped with a log, not a pipeline abort.
      • September 20, 2026v2.60.0

        Incomplete PCB exam and owner project delete

        Unfinished placing/routing still uses MODE=pcb. Parser and checks run on partial layouts; missing copper is INSUFFICIENT or skip, never invented millimetres. Via≠Pad unchanged. Dashboard owners can delete a project after a confirm dialog.

        • Improved[Changed] Decoupling proximity uses routed copper only (`PE-PLC-005` when unrouted).
        • New`PE-LAY-004` INFO when pad nets have no tracks.
        • NewOwner-only `DELETE /api/projects/{id}` with confirm dialog; collaborators get 403.
      • September 20, 2026v2.59.0

        Docker without unused PinScope product tree

        Images copy `boardlab/src` plus leftover seams (shadcn/Clerk/billing, unused LLM providers, GCS, landing png/gif) and `vendor/`. They do not copy the inherited PinScope product tree. `dependency/` stays in git. Audit: `boardlab/src/docs/development/DEPENDENCY_AUDIT.md`. Pad≠Via unchanged.

        • Improved[Changed] Backend/frontend Dockerfiles drop wholesale `COPY periscope/dependency/{backend,frontend}`.
        • NewBoot test runs FastAPI with `PYTHONPATH=boardlab/src` only.
      • September 20, 2026v2.58.0

        Native JWT middleware and useAuthApi

        `backend/middleware/auth.py` and `frontend/src/hooks/use-auth-api.ts` are original Periscope code. Skip paths, Bearer/query token, Clerk RS256 leftover, and local HS256 (`local_jwt.decode_token`) stay the same HTTP contract. `routers/auth.py`, `data/auth/users`, and `AUTH_JWT_SECRET` are unchanged. Pad≠Via unchanged.

        • NewRequest JWT verification rewrite under `boardlab/src`.
        • New`useAuthApi` rewrite wires `setTokenGetter` from the optional-auth seam.
        • Improved[Changed] App stamp 2.58.0; login identifiers and password hashes are not rotated.
      • September 20, 2026v2.57.0

        Native package.json, requirements, and unused Docker copies

        Frontend `package.json` (`periscope-web`) and lockfile, `components.json`, and backend `requirements.txt` overlay from `boardlab/src`. Docker installs those files from src. Unused PinScope public blobs (Faradworks logo, power-tree.gif, create-next-app SVGs) are dockerignored. EDA logos and KiCad tutorial examples live under src `public/`. Landing `report.png` / `datasheet.gif` / `derating.png` stay in `dependency/` until native UI captures exist. Auth/JWT still inherited. Pad≠Via unchanged.

        • NewNative npm package name `periscope-web` at 2.57.0 with the same Next 16 scripts and dependency set.
        • NewNative pip requirements (DeepSeek stack first; leftover GCS/Gmail/LLM extras remain optional).
        • Improved[Changed] Frontend Docker `npm ci` and backend `pip install` read src manifests.
        • Improved[Changed] `.dockerignore` drops unused PinScope marketing blobs from the image.
      • September 20, 2026v2.56.0

        Native taxonomy JSON and local skills overlay

        Component taxonomy JSON and DeepSeek `skills/*/SKILL.md` (plus local `validate.py` / schema) live under `boardlab/src`. `repo_paths` prefers src; Docker copies dependency then src; compose mounts `src/taxonomy`. Manifest `1.14.0`. App `favicon.ico` matches the Periscope mark. Auth/JWT, package.json, landing png/gif unchanged. Pad≠Via unchanged.

        • NewPeriscope taxonomy catalog in `boardlab/src/taxonomy` (same subtype keys and spec names).
        • NewLocal extraction skill prompts rewritten; no Anthropic Console upload.
        • Improved[Changed] Compose no longer bind-mounts `dependency/taxonomy` over `/app/taxonomy`.
      • September 20, 2026v2.55.0

        Native Next overlay config and CSP seam

        `next.config.ts`, ESLint/PostCSS/tsconfig, and `lib/csp-hosts.ts` overlay from `boardlab/src/frontend`. `backend/middleware/__init__.py` is a native package marker. JWT stays in inherited `middleware/auth.py`. `package.json` unchanged. Legal markdown already Periscope; changelog kept. Pad≠Via unchanged.

        • NewNext CSP/redirect/pdfjs overlay rewrite; login still maps to `/sign-in`.
        • NewCSP host lists stay empty for Clerk/Stripe on self-host.
        • NewMiddleware package marker rewrite; auth module not re-exported.
      • September 20, 2026v2.54.0

        Native leftover frontend widgets and tokens

        PDF sheet, theme provider/toggle, file drop zone, reviewed-finding hooks, and `globals.css` are original Periscope code in `boardlab/src/frontend`. Inherited copies stay on disk. shadcn, Clerk, billing, Reddit pixels, `proxy.ts`, and auth/JWT are unchanged. Pad≠Via unchanged.

        • NewDatasheet sheet, theme chrome, and upload drop-zone rewrite.
        • NewReviewed-finding localStorage hooks rewrite (legacy key migrate kept).
        • NewApp token stylesheet rewrite; light/dark oklch values unchanged.
      • September 20, 2026v2.53.0

        Native site, legal shells, OG, and Next BFF

        `lib/site.ts`, `version.ts`, `report-export.ts`, legal page chrome, Open Graph images, and the local `/api/projects` `/api/report/[id]` `/api/graph/[id]` BFF routes are original Periscope code in `boardlab/src/frontend`. Inherited copies stay on disk. Clerk `proxy.ts`, shadcn `components/ui/*`, billing, Reddit pixels, and auth/JWT are unchanged. Pad≠Via unchanged.

        • NewSite identity, version stamp, and findings Excel export rewrite.
        • NewLegal/changelog/file-guide shells and OG image rewrite.
        • NewLocal Next BFF JSON routes rewrite; Clerk proxy stays the open-core seam.
      • September 20, 2026v2.52.0

        Native leftover frontend overlay

        Dashboard, project, report, progress, admin, feedback, marketing, and the HTTP client (`lib/api.ts`, `types.ts`) are original Periscope UI in `boardlab/src/frontend`. Docker still copies OSS then src. Routes, API contracts, and layout are unchanged. Billing/Clerk/analytics stay imported seams. Auth/JWT untouched. Pad≠Via unchanged.

        • NewFrontend types + API client rewrite (export names preserved).
        • NewApp and marketing pages rewrite so overlay wins without a product restyle.
      • September 20, 2026v2.51.0

        Native Settings, FastAPI app, leftover routers

        `config.py`, `main.py`, `pipeline_worker.py`, and leftover HTTP routers (`admin`, `contact`, `deps`, `feedback`, `pipeline`, `projects`, `reports`, `survey`) are original Periscope code in `boardlab/src`. Inherited copies stay on disk. `routers/auth.py` is unchanged. JWT middleware remains leftover. Frontend product chrome is still the Docker overlay (src pages already win for library/PCB/placement/sign-in). Pad≠Via unchanged.

        • NewSettings rewrite: DeepSeek-only routing; Anthropic env names coerced or ignored.
        • NewFastAPI entry + worker rewrite; worker still must not import `backend.main`.
        • NewProject/pipeline/report/admin HTTP surface rewrite.
      • September 20, 2026v2.50.0

        Native analysis pipeline and leftover checks

        `pipeline.py`, `projects.py`, `email.py`, `purple_parts.py`, and leftover analysis modules (`resolve_passives`, `derating`, `bom_summary`, `pin_mux_check`, `led_current_check`, `pin_function_tokens`, plus `validate`/`validation_tools` aliases) are original Periscope code in `boardlab/src`. Inherited copies stay on disk. Live path is still `job_workspace` / `datasheet_extract` / `review_session`. Auth untouched. Pad≠Via unchanged.

        • NewAnalysis job rewrite: BOM parse, extract, graph, review; LCSC column backstop only.
        • NewProject meta writes follow `owner_user_id` (Emmaforo JWT prefix).
        • NewExact-MPN LCSC reverse lookup; prefix hits rejected.
      • September 20, 2026v2.49.0

        Native normalize, cross-IC dedupe, billing seam

        `normalize_findings.py`, `dedupe_findings.py`, and `billing_hook.py` are original Periscope code in `boardlab/src`. Inherited copies stay on disk. Self-host `get_billing()` is NullBilling (no Stripe at import). Downgrade-only clamp unchanged (U2-001 / Emmaforo UART).

        • NewPer-IC normalize builder + tool schema rewrite; fail-soft to originals.
        • NewCross-IC dedupe rewrite (CH340E↔MCU interface collapse).
        • NewBilling seam rewrite; credits stay lazy behind `billing_enabled`.
      • September 20, 2026v2.48.0

        Native models, schematic parsers, taxonomy loader

        `models.py`, `parsers.py`, `parsers_edif.py`, and `taxonomy.py` are original Periscope code in `boardlab/src` (not overlay stamps). Inherited copies stay on disk. Taxonomy JSON is still `repo_paths.taxonomy_dir()` → `periscope/dependency/taxonomy`. Native `parsers_kicad.py` / `parsers_kicad_pcb.py` (via≠pad) unchanged.

        • NewPeriscope Pydantic contracts: disjoint LayoutPad / LayoutVia / LayoutSegment / LayoutZone.
        • NewPADS/BOM dispatch and EDIF 2.0.0 ingest rewrite; KiCad schematic still native.
        • NewTaxonomy loader rewrite: `TAXONOMY_DIR = taxonomy_dir()`.
      • September 20, 2026v2.47.0

        Native DesignGraph builder

        `backend.periscopex.graph` is original Periscope code in `boardlab/src` (not an overlay stamp). Inherited `dependency/.../graph.py` stays on disk. PCB via≠pad remains in native `parsers_kicad_pcb.py`.

        • NewPeriscope `graph.py`: classify refs, infer net type/voltage, BOM+netlist+optional `.kicad_pcb` nets → `DesignGraph`.
      • September 20, 2026v2.46.0

        Remove PinScope overlay copies from boardlab/src

        Stamped near-identical copies of inherited modules are gone from `boardlab/src`. Docker still copies `dependency/` then native `src`. Tests load graph/parsers/models/pipeline from `periscope/dependency` again. Native work stays: finding engine, PCB/placement, review session, job workspace, datasheet extract, KiCad PCB via≠pad parser, Periscope mark, local JWT, `pinscope_compat`.

        • Improved[Changed] Deleted overlay copies of graph, models, parsers, leftover services, main/routers, skills JSON, taxonomy JSON from `boardlab/src`.
        • Improved[Changed] Overlay stamp tests removed. Inherited files remain in `periscope/dependency/` (not empty-deleted).
      • September 20, 2026v2.45.0

        Overlay leftover app entry, routers, and jobs

        `main.py`, `config.py`, `middleware/auth.py`, leftover `routers/*` (not native `auth`/`impedance`), `pipeline_worker.py`, `job_runner`, `event_bridge`, `projects`, and `admin_settings` resolve from `boardlab/src`. Inherited copies stay on disk. Auth users and `AUTH_JWT_SECRET` unchanged.

        • Newsrc overlay of the leftover FastAPI entrypoint, settings, JWT middleware, and HTTP routers the live app still imported from `dependency/`.
        • Newsrc overlay of `pipeline_worker` and job/project settings services.
      • September 20, 2026v2.44.0

        Overlay leftover services src still imported

        Pipeline helpers still pulled from `dependency/` (`api_logs`, `normalize_findings`, `dedupe_findings`, `billing_hook`, `datasheet_store`, `cost_estimator`, `storage`, `purple_parts`, `email`, `digikey`) plus LLM `factory` / `types` / `base` now resolve from `boardlab/src`. Inherited copies stay on disk.

        • Newsrc overlay of leftover `backend/services` modules the live pipeline/review path still imports.
        • Newsrc overlay of `services/llm/{factory,types,base}.py` (DeepSeek provider stays native; Anthropic/Gemini files stay in dependency).
      • September 20, 2026v2.43.0

        Overlay leftover PinScope modules src still imported

        `utils`, `resolve_passives`, `derating`, `bom_summary`, `pin_mux_check`, `led_current_check`, `pin_function_tokens`, plus live analysis `validate` / `validation_tools` / `pipeline` / `validation` / `extraction` (fallback), resolve from `boardlab/src`. Skills (`extract-*`) and taxonomy JSON are copied to `boardlab/src/{skills,taxonomy}`; Docker overlays them after `dependency/`. Inherited files stay on disk.

        • Newsrc overlay of the leftover `periscopex` helpers analysis/PCB still import.
        • Newsrc overlay of `services/{pipeline,validation,extraction}.py` (re-exports `job_workspace` unchanged).
        • New`boardlab/src/taxonomy/*.json` and `boardlab/src/skills/extract-*`.
        • Improved[Changed] `repo_paths` prefers src (then `/app`, then dependency) for taxonomy and skills.
      • September 20, 2026v2.42.0

        Native graph/parsers/models/taxonomy overlay + Periscope mark

        Graph builder, PADS/EDIF/BOM parsers, Pydantic models, and taxonomy loader resolve from `boardlab/src`. Inherited copies stay in `periscope/dependency/` (not deleted). KiCad schematic parser was already native. Taxonomy JSON still lives in the inherited `taxonomy/` tree. New Periscope mark (periscope/lens, not the PinScope CPU glyph) at the existing favicon and PWA pixel sizes.

        • New`boardlab/src/backend/periscopex/{graph,models,parsers,parsers_edif,taxonomy}.py` overlay Docker/src-first imports.
        • Improved[Changed] `taxonomy.TAXONOMY_DIR` uses `repo_paths` so src overlay still reads `dependency/taxonomy`.
        • NewBrand mark: `public/brand/periscope-mark.svg`, favicon_io 16/32/180/192/512, header `PeriscopeMark`.
      • September 20, 2026v2.41.0

        Native job workspace for PCB and placement

        `pcb_pipeline` and `placement_pipeline` no longer import PinScope `pipeline.py`. Workspace download/upload and the in-memory event broker live in `boardlab/src` (`job_workspace.py`). Analysis `run_pipeline` still lives in `dependency/` and re-exports the same singleton so `pipeline_worker.set_broker` keeps PCB SSE on the GCS event log. Parsers/graph unchanged. `pipeline.py` not deleted.

        • New`backend.services.job_workspace`: `PipelineWorkspace`, `EventBroker`, `set_broker`.
        • Improved[Changed] PCB/placement import `job_workspace`; `pipeline.py` re-exports the native types.
      • September 20, 2026v2.40.0

        Fase C3: native datasheet extraction

        Pipeline pintable/pattern/specs/auto-resolve run from `boardlab/src` (`datasheet_extract.py`): DeepSeek + local SKILL.md, no Anthropic Console skill ids. Inherited `extraction.py` stays in `dependency/`.

        • Improved[Changed] `pipeline.py` and project LCSC resolve import `datasheet_extract`.
        • Improved[Changed] Extract stages pin the DeepSeek provider.
      • September 20, 2026v2.39.1

        src no longer imports PinScope review loop

        After 2.39.0 live smoke (Emmaforo ERROR 2 / WARNING 12 / INFO 18), native modules are the only review path from `boardlab/src`. PinScope `validate.py` / `validation_tools.py` remain on disk.

        • Improved[Changed] PCB review and deterministic checks import `review_parse` / `constraints_lookup` / `review_session`, not `validate.py`.
        • Improved[Changed] Tests exercise the native parser and graph tools.
      • September 20, 2026v2.39.0

        Fase C2: native DeepSeek review loop

        Live per-IC review runs from `boardlab/src` (`review_session.py`, parse, graph tools). PinScope `validate.py` / `validation_tools.py` stay in `dependency/` as fallback; they are not deleted. LLM findings stay REVIEW; recommended never ERROR. AGPL unchanged. No parser/graph rewrite. No auto-place.

        • Improved[Changed] `review_ic_async` is native (`backend.services.review_session`); inherited copy kept as `_inherited_review_ic_async`.
        • New`review_parse.py` (FACT/REQUIREMENT/INFERENCE + `complete_findings` ids), `review_tools.py`, `review_context.py`, `constraints_lookup.py`.
        • Improved[Changed] `finding_engine.complete_finding` remains the clamp after submit_review.
      • September 20, 2026v2.38.0

        Physical split: boardlab/src vs periscope/dependency

        Split the checkout so native Periscope and inherited PinScope are separate trees. No finding-engine rewrite. AGPL `LICENSE` stays at the repo root. The GitHub fork is not detached.

        • Improved[Changed] Native modules live under `boardlab/src/` (PCB, placement, finding clamp, DeepSeek, local auth, plugin, Dockerfiles).
        • Improved[Changed] PinScope-derived modules live under `periscope/dependency/` (graph, parsers, `validate.py`, pipeline, OSS Next shell, skills, taxonomy, `simple_project`).
        • Improved[Changed] Docker overlays dependency then src. Local `backend` package merges both trees. Do not delete the inherited tree; Fase C replaces modules incrementally.
      • September 20, 2026v2.37.1

        PCB not_reviewed is board ICs, not the shared library

        Emmaforo showed 20 “components not reviewed” that were other projects’ 1.5–1.7 extracts (LAN8720A, W25Q, …). BOM ICs were already 1.13.0 and *were* reviewed.

        • Fixed`si_extract_needed_skips` only flags ICs on this graph. Shared `library/extracted` cache is not `not_reviewed`.
      • September 20, 2026v2.37.0

        SI bus gate (EN RC ≠ USB series R)

        Datasheet SI facts apply only to the bus in the quote. ESP32 EN RC 10 kΩ / 1 µF is not a USB D+/D− series resistor. USB without a library Z number stays measurement-only (88 Ω), not a 90 Ω FAIL. Coverage: PHY+RJ45 MDI, MAC–PHY RGMII/SGMII, DDR3, USB-C SuperSpeed.

        • Fixed`PE-SI-009` (and other SI kinds) require `net_class` / quote bus match; strap/EN RC is skipped.
        • Improved[Changed] `bus_class`: `usb2` / `usb3` / `eth_mdi` / `rgmii` / `sgmii` / `ddr3_*`.
        • Improved[Changed] `PE-SI-010` is per bus with no impedance FACT (not silenced by an unrelated SI kind).
        • Improved[Changed] Pintable skill `1.13.0`: SI `net_class` required; EN/CHIP_PU RC is not `series_resistor`.
      • September 20, 2026v2.36.0

        Fase A: operator identity + PinScope fence

        This instance is operated by Michele Bigi. Faradworks, Inc. is not the operator. PinScope identifiers are dual-read only. PCB BOM/SPOF/EMI/θJA slices from 2.35.0 stay on this branch.

        • Improved[Changed] Terms, privacy, contact, footers, and HTML metadata no longer claim Faradworks, Inc.
        • Improved[Changed] Attribution to Faradworks/Pinscope remains for AGPL lineage (`LICENSE` unchanged).
        • Improved[Changed] `pinscope-compat` / `pinscope_compat.py`: write `periscope_*` / `periscopex:`; migrate `pinscope_*` on read.
        • New`docs/development/PINSCOPE_FENCE.md` — inherited tree stays in place; GitHub fork is not detached.
      • September 20, 2026v2.35.0

        BOM↔PCB↔datasheet, SPOF, EMI FACT, gated Tj

        Remaining Fase B slices except auto-place and thermal FEM / OpenEMS.

        • New`PE-BOM-010`…`014` package / pinout / voltage / temp / current when BOM, PCB, and datasheet all have numbers.
        • New`PE-SPOF-001` single regulator or shared crystal — REVIEW, never ERROR.
        • New`PE-EMI-001` only if `layout_rules` quotes EMI/common-mode/ferrite/shield (not IEC 61000).
        • New`PE-THM-002` Tj = Ta + P·θJA when P, θJA, copper area, and via count exist; else INSUFFICIENT.
        • Improved[Changed] Pintable skill `1.12.0`: SI+EMI kinds; empty SI on older extracts triggers schematic re-extract (`si_extract_needed.json` on PCB). ImpedenceFinder license remains UNKNOWN (no upstream LICENSE).
      • September 20, 2026v2.34.0

        ImpedenceFinder SI checks (not a dump table)

        USB/HDMI/PCIe/ETH/LVDS/DDR layout_rules (diff/SE Z, skew, max length, spacing, ref plane, vias, layer, return, series R) are compared to ImpedenceFinder + copper. One PASS/FAIL/MARGIN finding per requirement. I2C/GPIO/CC/REGN are not 50 Ω.

        • New`PE-SI-002`…`PE-SI-010`; ImpedenceFinder `z0_avg/min/max` in `run_pcb_checks`.
        • Improved[Changed] `PE-SI-001` only on impedance-controlled buses matching the rule `net_class`.
        • Improved[Changed] extract-pintable `layout_rules` kinds for SI; `default_model_version` 1.11.0.
      • September 20, 2026v2.33.2

        PCB complete UI, not a raw SSE error

        A finished PCB exam no longer shows the raw watcher string `pcb_status=complete (terminal)`. The SSE hatch emits `pcb_complete`; the PCB page then opens `/report?domain=layout` (expand-on-click tree).

        • FixedSynthetic PCB SSE for `pcb_status=complete` is `pcb_complete`, not `pcb_error`.
        • Fixed`/project/[id]/pcb` navigates to the layout report when the run finishes.
        • FixedRestored changelog heading for 2.33.0 (version history).
      • September 20, 2026v2.33.1

        ESD/PI filters, ERROR-first sort, findings tree

        PE-ESD-001 only on J* ∩ IC nets (no NC / unconnected / VSYS/GND/3V3 spam). PE-PI-001 treats any capacitor on the rail, including KiCad `/` names, as decoupling. Report API and UI sort ERROR then WARNING then INFO, then RULE > RISK > REVIEW > INFO. The report left list is an expand-on-click tree (IC → pin/net → cards), not a dump of open groups.

        • FixedConnector GPIO / onboard rails no longer flood PE-ESD-001.
        • FixedBulk or slash-prefixed caps (C68 `/VBUS`, C71–C75 VSYS) suppress “no local cap”.
        • Improved[Changed] GET `/report` and `complete_findings` order by severity then class.
        • Improved[Changed] Findings sidebar is a collapsed tree; PCB exam cards live in the same tree.
      • September 20, 2026v2.33.0

        Fase B: hierarchy, derating bands, timing, PI, ESD/return

        Usable slices (not a platform): component→pin→net→block inventory, capacitor PASS/MARGIN/RISK from Vop/Vrated, RC/strap timing only with numbers, local vs bulk PI, ESD and HS return as REVIEW.

        • Fixed`complete_finding` clamps ERROR unless `finding_class=RULE` and `provenance=MANDATORY` (LLM REVIEW cannot stay ERROR).
        • New`hierarchy.json` + `PE-HIER-001` dangling IC pins.
        • NewDerating table `stress` PASS/MARGIN/RISK; findings `PE-DRT-001/002/003`.
        • New`PE-TIM-001/002` skip without R/C and t_reset or Vih/Vil.
        • New`PE-PI-001/002` local vs bulk; distance only with `layout_rules` mm.
        • New`PE-ESD-001`, `PE-RET-001` are REVIEW, never RULE ERROR.
      • September 20, 2026v2.32.1

        PCB Action on card + parsed geometry in AI context

        Finding cards always show an **Action.** sentence (`action`, else `recommendation`, else a default). PCB AI context now includes vias under the footprint, copper thickness, nearby trace widths, courtyard, and keepout polygons from `.kicad_pcb`.

        • FixedLayout/AI findings no longer show an empty Action chip; the sentence is on the card.
        • Improved[Changed] PCB exam injects parsed via counts/drills, stackup thickness, pin-net widths, courtyard/keepout. Insufficient evidence only when those extracts are empty.
        • Improved[Changed] submit_review `recommendation` is required for INFO as well as ERROR/WARNING.
      • September 20, 2026v2.32.0

        Finding engine (schema + PCB)

        Same finding object on schematic analysis and PCB exam: FACT / REQUIREMENT / INFERENCE, datasheet provenance in the rule DB, RULE vs REVIEW, designer decisions, independent severity/confidence/evidence.

        • New`docs/motore-finding.md` — engine spec. `finding_engine.py` + `decisions.json`.
        • NewReport cards show Fact / Requirement / Inference, class, provenance, insufficient evidence.
        • Improved[Changed] Recommended datasheet notes cannot stay ERROR. LLM findings are REVIEW, never RULE.
        • Improved[Changed] Schematic and PCB share `library/extracted`; PCB does not re-read the PDF.
      • September 20, 2026v2.31.0

        Shared library PCB exam (no second PDF pass)

        Schematic and PCB share `library/extracted`. PCB AI consumes that cache (pintable required; no PDF attach). Report **PCB exam** section plus power-trace/thermal checks.

        • NewReport section **PCB exam** (`source=pcb_review` and PE-PWR/THM/VIA/KEL/STCH).
        • New`PE-PWR-001` width × copper vs I_load (IPC-2221 only with stackup + Tjmax).
        • New`PE-THM-001` dissipation vs courtyard vias/pour; `PE-VIA-001` via share of I_load (INFO).
        • New`PE-KEL-001` Kelvin/sense on a shared load net; `PE-STCH-001` GND stitch in a signal bbox over a pour.
        • Improved[Changed] PCB review skips ICs without library pintable (“run schematic review first”).
      • September 19, 2026v2.30.0

        PCB review pipeline (exam, not auto-place)

        Parallel `MODE=pcb` job examines an uploaded `.kicad_pcb`: domains/groups, trace inventory, deterministic layout checks, and per-IC AI datasheet review. Findings merge into the report with a Layout filter. No packing or pcbnew write-back.

        • New`POST /api/pipeline/{id}/pcb/start` — PCB exam job (`pcb_status`).
        • NewDeterministic `PE-LAY-*`, `PE-PLC-*`, `PE-SI-001`, `PE-DRT-001` with required recommendations.
        • NewAI PCB review (same loop as schematic) with layout/domain context.
        • Improved[Changed] Schematic review no longer seeds placement/SI checks.
      • September 13, 2026v2.29.1

        Fix sign-in /login 404 after rebrand

        Landing CTAs pointed at `/login`, which did not exist (page is `/sign-in`). Added redirects, accepted legacy JWT issuer `pinscope-local`, and CORS for both Periscope and Pinscope hosts.

        • Fixed`/login` → `/sign-in`, `/register` → `/sign-up`; marketing links updated.
        • FixedJWT decode accepts `pinscope-local` issuer from pre-rebrand sessions.
        • FixedDeploy script CORS includes both public hostnames.
      • September 13, 2026v2.29.0

        Rebrand to Periscope

        Product name, package (`periscopex`), Docker containers, deploy script, and default site URL are now **Periscope** (`https://periscope.michelebigi.it`). Deterministic finding IDs use the `PE-*` prefix. Existing project.json `pinscope_version` and browser storage keys are still read.

        • Improved[Changed] Brand Pinscope → Periscope across UI, docs, and APIs.
        • Improved[Changed] `backend/pinscopex` → `backend/periscopex`; rule IDs `PS-*` → `PE-*`.
        • Improved[Changed] Default host / update script → `periscope.michelebigi.it` / `update-periscope.sh`.
      • September 13, 2026v2.28.12

        Antenna templates: IFA / meander / stub + .kicad_mod

        Progetta antenna now returns a full parametric drawing: polyline segments (mm), SVG preview, and a downloadable KiCad footprint. Choose IFA, meander, or stub; geometry scales to the `antenna` zone when present. Still a routing template — no EM/VSWR invented.

        • New`antenna_geometry.py` (IFA / meander / stub → segments + SVG + `.kicad_mod`).
        • Improved[Changed] `POST /antenna/design` accepts `template`; recipe includes `geometry`.
        • Improved[Changed] RF / Impedance Progetta UI: template select, SVG preview, download footprint.
      • September 13, 2026v2.28.11

        RF / Impedance: verify antenna + design recipe

        Project tab renamed **RF / Impedance**. Verify matching from IC ANT/RF pins toward an `ANT*` / `ANT_FEED` marker; Progetta returns microstrip `w` for 50 Ω (stackup or UI h/εr), optional λ/4 length from `f0`, and antenna-zone bbox. Auto-draw copper comes later — no EM/VSWR invented.

        • New`antenna_rf.py` + `GET/POST /api/projects/{id}/antenna`.
        • NewVerify + Progetta cards on the impedance panel.
        • Improved[Changed] Sidebar label **RF / Impedance**.
      • September 13, 2026v2.28.10

        Classify strap/bootstrap satellites; hide other

        Caps on EN/BOOT/REGN/PMID and bootstrap caps between IC pins get real roles. Unclassified `other` parts are dropped from satellites and assemble_order.

        • Improved[Changed] `_role_hint` classifies GND bypass on bias/strap nets and flying bootstrap caps.
        • Improved[Changed] Assemble / IC groups omit `role_hint=other`.
      • September 13, 2026v2.28.9

        Cleaner Domains / Power rails membership

        Power rails follow primary domain only. IC satellites for decoupling/bulk/filter/pullup stay on the IC’s primary supply rail (LDO 3V3 no longer inherits VSYS input caps). Connectors/switches drop out of noisy “other” satellites.

        • FixedRails view membership = domain primary rail (not transitive satellite nets).
        • Fixed`_group_for_ic` primary-rail filter for power-role satellites; skip connector/switch “other”.
      • September 13, 2026v2.28.8

        Stronger layout_rules extraction skill

        Pintable skill now treats PCB / typical-application layout guidance as a first-class extract. Page trim keeps layout keywords; IC cache re-extracts once when `layout_rules` are empty under an older `model_version` (1.10.0+).

        • Improved[Changed] `skills/extract-pintable` — dedicated `layout_rules` step, examples, hard negatives; tighter `validate.py`.
        • Improved[Changed] Datasheet page trim includes PCB layout / decoupling / typical-application keywords.
        • Improved[Changed] Analysis IC extraction refreshes empties when `model_version` < default (1.10.0).
        • Improved[Changed] `default_model_version` → `1.10.0`.
      • September 13, 2026v2.28.7

        Placement F2 pack skeleton (gated)

        Placement pipeline can propose satellite xy only when a `.kicad_pcb` layout exists and a `decoupling_proximity` rule has numeric `max_distance_mm`. No millimetres invented; otherwise `placement_pack.json` is skipped with an explicit reason.

        • New`placement_pack.py` + `placement_pack.json` after F1 plan.
        • New`GET /api/pipeline/{id}/placement/pack` and Pack section on the placement page.
        • Improved[Changed] Placement stepper adds a **Pack satellites** stage.
      • September 13, 2026v2.28.6

        Split Domains by primary supply rail

        Domains no longer merge the whole board when a charger/LDO bridges VBUS→VSYS→3V3. Each IC is clustered by its primary supply rail (output for power ICs, regulated digital rail for consumers).

        • Fixed`_build_domains` groups by primary rail instead of transitive POWER union-find.
        • Improved[Changed] Domain ids use the rail name (e.g. `domain_3V3_DIGITAL`).
      • September 13, 2026v2.28.5

        Domains & power-rail topology views

        Browse routing-first functional groups from the project sidebar: Domains (power-net islands) and Power rails, each highlighting IC groups and satellite roles.

        • NewSidebar tabs **Domains** and **Power rails** (from `placement_plan` / `functional_groups`).
        • Improved[Changed] Analysis `graph_build` also writes `placement_plan.json`.
        • FixedHeal stuck Placement `queued`/`running` when the worker is dead.
      • September 13, 2026v2.28.4

        Unstick zombie running pipelines

        A finished run whose worker died before flipping meta stayed `running`, so Progress showed Review spinning forever. Heal those projects when the event log already ends with `pipeline_complete`.

        • Fixed`heal_if_pipeline_finished` on project get / pipeline status.
        • FixedProgress stepper marks all stages complete on `pipeline_complete`.
        • FixedAdmin sweeper also covers local zombies without `execution_name`.
      • September 13, 2026v2.28.3

        Stop progress→report bounce on finished projects

        Opening a finished project no longer flashes Processing and dumps you on the report. Progress only auto-opens the report after a live run on that visit.

        • Fixed`/progress` checks project status before SSE; finished projects go to the hub.
        • FixedAnalysis SSE ignores placement events and does not treat already-terminal status as a crash.
      • September 13, 2026v2.28.2

        Fix project sidebar navigation

        Opening a finished project no longer dumps you on the report with a stuck left menu. Hub first; Report stays in the sidebar. Leaving `/report` for BOM/tabs uses a full navigation so the page actually changes.

        • FixedDashboard project cards/table open `/project/{id}` (not `/report`).
        • FixedSidebar Dashboard / Library / BOM tabs escape nested report/progress/placement routes.
      • September 12, 2026v2.28.1

        Placement pipeline (parallel)

        Dedicated Placement job builds the routing-first topology plan without touching the analysis pipeline status or spending credits. No millimetres — domains, IC groups, satellites only.

        • New`POST /api/pipeline/{id}/placement/start` (+ cancel, events SSE, get plan).
        • NewProject page **Build placement plan** → `/project/{id}/placement` progress + topology viewer.
        • NewWorker `MODE=placement` writes `placement_plan.json` (and refreshes `functional_groups.json`).
      • September 12, 2026v2.28.0

        Layout F1 topology + crystal/NC checks

        Routing-first floorplan foundation without inventing millimetres: domains and satellite role hints after graph build, plus deterministic crystal CL and NC-pin checks.

        • New`functional_groups.json` from `graph_build` (domains, IC groups, `role_hint`, attached `layout_rules`).
        • New`crystal_cl_check` (PS-XTAL-*) and `nc_pin_check` (PE-NC-001) in the deterministic suite.
        • Improved[Docs] Piano §0c Placement F1/F2; packing mm stays Layout F2.
      • September 12, 2026v2.27.1

        DeepSeek roadmap integrations

        Close the open P0/P2 items from the growth plan: offline smoke on `simple_project`, reviewer `shortest_path`, library promotion gate, PDF drop logging, per-stage cache hit-rate helper. IC placement stays Layout-product backlog.

        • New`scripts/smoke_simple_project.py` + `simple_project/smoke_baseline.json`.
        • NewGraph tool `shortest_path`; `library_gate` before shared extracted/.
        • New`cache_stats_by_stage()`; PDF truncate/omit page logs.
        • Improved[Test] `tests/test_roadmap_integrations.py`.
      • September 11, 2026v2.27.0

        Local multi-user auth

        Self-host Periscope accounts (email + password) so several people can share a project. Invite collaborators by email from the project page — same flow as cloud, without Clerk.

        • New`AUTH_JWT_SECRET` enables register/login; first user is admin and inherits `users/local` projects.
        • New`/sign-in` and `/sign-up`; sidebar account menu. Set `NEXT_PUBLIC_AUTH_MODE=local` on the frontend build.
        • Improved[Changed] Collaborator lookup works for local users; Clerk still used when its keys are set.
      • September 11, 2026v2.26.5

        Prefer PCB nets for connectivity

        When a `.kicad_pcb` is present, pad nets from the board drive the design graph. Schematic geometry alone was inventing swapped rails (GND↔3V3) and floating pins on good KiCad 10 designs.

        • FixedKiCad 10 `(net "Name")` pad form.
        • FixedGraph build overrides sch nets with board connectivity; `/NET` → `NET`.
        • Improved[Test] PCB nets beat a misleading schematic.
      • September 11, 2026v2.26.4

        KiCad power nets merge

        `.kicad_sch` connectivity treated every `GND` power flag as its own island (`GND_`, `GND__`…), so the reviewer invented swapped rails and floating pins on good designs.

        • FixedSame-name power symbols and global/local labels merge within a sheet (KiCad semantics).
        • FixedPins sitting mid-wire attach to that net; `mirror x`/`y` handled correctly.
        • Improved[Test] Disconnected GND flags, local labels, mid-segment wire.
      • September 11, 2026v2.26.3

        KiCad project zip upload

        One zip (or every `.kicad_sch`) covers hierarchical sheets. If the zip has `bom.csv` and `.kicad_pcb`, those are taken too. Pipeline re-reads companions from storage.

        • NewZip → sheets + optional BOM/PCB. Nested `Sheetfile` paths kept.
        • Improved[Test] Upload → workspace re-parse finds child sheet parts.
      • September 11, 2026v2.26.2

        Three file boxes

        New project: BOM, schematic, and PCB on the first screen. PCB is optional.

        • Improved[Changed] No extra wizard step for the board.
      • September 11, 2026v2.26.1

        Ask for the KiCad board

        The create-project wizard has a dedicated PCB step (skip still allowed). Report load errors show the API detail instead of a generic fetch failure.

        • NewWizard step for `.kicad_pcb`. Upload later from Settings or Impedance.
        • ImprovedReport page retries briefly and links back to pipeline progress when `report.json` is missing.
        • NewDrop the KiCad project folder (or a zip). Extra library junk is ignored; the board is picked up if present.
      • September 11, 2026v2.26.0

        ImpedenceFinder Z0 on PCB nets

        A pipeline run with `.kicad_pcb` + stackup samples routed **signal** nets (power/ground skipped). Extra net names can be analyzed from the Impedance tab. Z0 is ImpedenceFinder net_walk/zsolver; no invented εr.

        • New`impedance_nets.json` after graph build. GET/POST `/api/projects/{id}/impedance/nets`.
      • September 10, 2026v2.25.0

        Keepout courtyard

        `layout_rules` `keepout` flags a foreign net whose track endpoint is inside the KiCad courtyard. Own net and missing courtyard skip. No invented analog/digital classes.

        • New`PE-PLC-004` WARNING. Tests use `X1` / `/HFXIN` / `GND` from `simple_project`.
      • September 10, 2026v2.24.0

        Crystal load caps and track path

        Load caps on XIN/XOUT use the same `max_distance_mm` as decoupling. If the PCB has segments on the net, the limit is shortest-path length, not a guessed “loop is too big” ratio.

        • NewCrystals (`X1` / C9 / C10 on `simple_project`) run `PE-PLC-001` when `layout_rules` has millimetres.
        • NewDetour tracks: path along segments vs the same `max_distance_mm`. No segments → euclidean pad distance.
      • September 10, 2026v2.23.0

        same_layer decoupling

        If `layout_rules` sets `same_layer: true`, a decoupling cap on the opposite copper from the IC is a WARNING. A via inside the courtyard (calculated) is enough. Unset flag → skip.

        • New`PE-PLC-003` WARNING when every placed cap on the net is on F vs B opposite the IC.
      • September 10, 2026v2.22.0

        Thermal vias vs min_via_count

        Via count is calculated inside the KiCad courtyard. The limit is the `min_via_count` parameter from `layout_rules`. No courtyard or no count → skip. No pad radius default.

        • New`PE-PLC-002` when vias in courtyard < `min_via_count`. `simple_project` has no PCB so it stays silent.
      • September 10, 2026v2.21.0

        Layout SI skew (datasheet mm only)

        Intra-pair skew is measured on the PCB only when `layout_rules` `length_match` has a number. 3W, creepage, and CPWG are not guessed.

        • New`PE-SI-001` ERROR when a named pair (_DP/_DM, _P/_N) exceeds that millimetre. No mm in the datasheet → skip.
      • September 10, 2026v2.20.0

        Placement vs datasheet (PCB)

        Decoupling distance is measured on the `.kicad_pcb` against `layout_rules`. No board → no `PE-PLC-001`. A null millimetre skips — no 3 mm default.

        • New`PE-PLC-001` when a decoupling cap is farther than datasheet `max_distance_mm`. Empty `layout_rules` and missing caps skip.
      • September 10, 2026v2.19.0

        Finding review and ECO

        Findings can be accepted, marked false-positive, or wontfix with a required reason. Accepted rows export as ECO; OpenEMS-style layout SI is still not this.

        • NewReview state on the report (`open` / `accepted` / `false_positive` / `wontfix`). Empty reason is rejected except when returning to open.
        • NewECO CSV/JSON of accepted findings only. False-positive and wontfix stay off the ECO.
        • NewRelease signature: SHA-256 of findings + user + timestamp. Needs-review filter `?review=open`.
      • September 10, 2026v2.18.0

        ImpedenceFinder calculator

        The Impedance tab uses the closed-form engine from ImpedenceFinder (Hammerstad–Jensen / Cohn), not a second formula set and not OpenEMS.

        • NewProject tab Impedance: microstrip, stripline, coupled-diff Z0, stackup → 50/90/100 Ω widths, download `.kicad_dru` advice.
        • NewVendored ImpedenceFinder core under `vendor/impedancefinder/` (no gerber2ems, no pcbnew).
        • ImprovedCPWG stays unimplemented — no invented number.
      • September 10, 2026v2.17.0

        Lifecycle and datasheet extras

        Distributor lifecycle is a cached check, not a review scrape. Errata and layout_rules stay structured and skip when the catalog or the PDF has no number.

        • New`PE-LF-001` EOL, `PE-LF-002` NRND, `PE-LF-003` explicit RoHS fail. Replacement only if the distributor lists it. Active / RoHS N/A / missing cache row are silent.
        • New`PE-ERRATA-001` when a catalogued workaround pull-up is missing. No URL → skip.
        • New`PE-INT-001` when `internal_features.pullup_pins` has no rail resistor.
        • New`layout_rules` closed kinds; non-numeric `max_distance_mm` is stored as null.
      • September 10, 2026v2.16.0

        KiCad cad-bridge

        Periscope writes `periscope-findings.json` next to the report so a KiCad 9/10 action plugin can pan to the symbol uuid on the right sheet.

        • NewE2 cad-bridge JSON (`version`, `ref`, `pins`, `sheet`, `uuid`, `severity`). Layout rule ids target pcbnew; others target eeschema.
        • New`.kicad_sch` symbols keep `cad_uuid` + `cad_sheet` in `cad_index` (child sheet, not the empty root).
        • NewAction plugin in `plugins/kicad/` reads the JSON beside `.kicad_pro` / `.kicad_pcb`.
      • September 10, 2026v2.15.0

        Power margin, sequencing, DNP enable

        Schema checks now compare regulator load to Iout_max, look at PG→EN when a sequence is declared, and treat DNP as a fitted-variant graph.

        • New`PE-PWR-001` when specified IQ+I_load exceeds Iout_max, or an explicit series R/ferrite DCR drops >5% of the rail. Missing IQ and PCB traces are not guessed.
        • New`PE-SEQ-001` WARNING if `power_sequence` is in IC specs and upstream PG does not net to downstream EN.
        • NewBOM `DNP`/`Fitted`/`Variant` on `bom_fields`. Fitted enable with only a DNP pull is `PE-DNP-001` ERROR; no DNP column skips the check.
      • September 10, 2026v2.14.0

        Filtri e termico schema

        Deterministic checks now match RC/LC/π/T filters and estimate LDO/resistor dissipation without inventing missing numbers.

        • NewFilter topology `PE-FLT-001` (fc INFO) / `PE-FLT-002` vs `adc_sample_rate` only when that spec exists. Ferrite DCR `PE-FLT-003` only with a datasheet limit.
        • NewLDO `P = I_load×(Vin−Vout)` and `Tj = 25 + P·θJA`. Missing θJA is `PE-TH-001` INFO. `Iout_max` is not treated as load.
        • NewResistor `I²R` vs `power_rating_w` on LED paths and shunts with known ΔV (`PE-TH-003`).
      • September 10, 2026v2.13.0

        DC-bias C_eff stima

        The derating table now shows an effective capacitance under DC bias for C0G/X7R/X5R ceramics. It is labelled *stima* — not a vendor lot curve.

        • New`C_eff` column from an empirical V/Vrated table. Tantalum/electrolytic and unknown dielectrics are left blank.
        • ImprovedC0G/NP0 stays at nominal C; X7R at 50% of rated V is about 70% of C.
        • NewBulk C without a ~100 nF ceramic is `PE-ESR-001` INFO (no invented Z(f) target).
      • September 10, 2026v2.12.0

        Pull-up sizing and LDO Cout

        Deterministic schema checks now size I2C pull-ups, flag NRST pull-downs, and look at LDO VOUT capacitance — still WARNING, never a invented datasheet µF ERROR.

        • NewI2C pull-up value vs a wide NXP UM10204 band (`PE-I2C-002`). 4.7 kΩ is in-band; missing values are not sized.
        • NewActive-low reset with a resistor to ground is `PE-RST-002`.
        • NewRegulator VOUT needs Cout (`PE-DEC-001`); 100 nF-only on VOUT is `PE-DEC-002`. MCU VDD 100 nF is not flagged.
        • ImprovedPin-mux UART0 on the `simple_project` MSPM0 nets is covered in tests (SPI PICO/POCI already was).
      • September 10, 2026v2.11.0

        DeepSeek V4.1 and re-analyze

        Periscope now defaults to DeepSeek-V4.1-Flash (`deepseek-flash`) for every LLM stage, shows API cost in dollars, and lets you replace the BOM and netlist on an existing project without deleting it.

        • NewDefault model is `deepseek-flash` (native vision). Legacy `deepseek-v4-flash` / `deepseek-v4-flash-vision-exp` names still work; they route to V4.1.
        • NewReplace BOM & netlist on a finished project and re-run the analysis. History, library cache, and prior spend stay on the same project.
        • ImprovedAPI cost uses V4.1 Flash peak rates and is shown on the report, logs tab, and run estimate (not only credits).
      • August 27, 2026v2.10.0

        Deeper datasheet review

        Each IC review now sees more of the datasheet and starts from a structured abs-max table, so voltage, decoupling, and interface checks are less likely to stop at "Unverified".

        • ImprovedExtraction pulls Absolute Maximum Ratings (supplies, pin voltages, current, temperature) alongside the pin table, and the reviewer gets those numbers in context.
        • ImprovedDeepSeek ingest uses PyMuPDF text (tables survive better than pypdf) and, on vision models, renders pin / abs-max / electrical / application pages instead of always the first 24.
        • ImprovedReview checklist now includes recommended operating conditions, VIH/VIL, crystal load caps, and datasheet-named external parts. Turn budget 16, more excerpt pages, three follow-ups per concern.
      • August 27, 2026v2.9.0

        Component library

        Chips and passives stay in a shared library after the first look, so the next board does not re-download datasheets or re-extract pin tables.

        • NewLibrary page in the sidebar: ICs (pin tables), passive series, discrete specs, and saved PDFs.
        • NewDatasheets are written to the library as soon as they are fetched or uploaded, not only after a full review.
        • ImprovedThe create-project wizard already skipped parts that were extracted once; that reuse now covers the PDF itself as well.
      • August 27, 2026v2.8.0

        Automatic datasheets

        Periscope now finds datasheet PDFs on its own. You can still upload a file, but you no longer need DigiKey keys for the common case.

        • NewAuto-fetch from LCSC (no API key) by manufacturer part number or LCSC code, with exact-MPN matching so a CH340E never silently becomes a CH340G.
        • NewDirect Texas Instruments datasheet URLs (`ti.com/lit/ds/symlink/…`) as a second source for TI parts.
        • NewPipeline fallback: if a datasheet was not uploaded in the wizard, extraction and review try the same lookup before skipping the IC.
        • ImprovedDigiKey remains an optional third source when `DIGIKEY_CLIENT_ID` / `DIGIKEY_CLIENT_SECRET` are set.
      • August 27, 2026v2.7.0

        DeepSeek API

        Periscope now talks to DeepSeek by default. Extraction skills run locally; datasheet PDFs are converted to text (and page images on the vision model) because DeepSeek does not accept native PDF documents.

        • NewDeepSeek provider (`deepseek-v4-flash`, `deepseek-v4-pro`, `deepseek-v4-flash-vision-exp`) via the OpenAI-compatible Chat Completions API.
        • NewLocal skill runner: `skills/*/SKILL.md` is inlined and `validate.py` runs in-process — no Anthropic Console upload required.
        • NewPDF ingest for DeepSeek: pypdf text extraction plus optional PyMuPDF page renders on vision models.
        • ImprovedAnthropic and Gemini remain optional fallbacks via `PROVIDER_*` / `FALLBACK_PROVIDER_*`.
      • July 12, 2026v2.6.0

        Export Report to Excel

        Download a project's findings as an Excel spreadsheet straight from the report — one click, ready to share, filter, or archive outside Periscope.

        • New"Export Excel" button on the validation report. Every finding becomes a spreadsheet row — designator, part number, ID, severity, title, description, recommendation, and its datasheet source (page included) — sorted most-severe first.
      • July 4, 2026v2.5.1

        More Thorough Reviews

        Schematic review now works through every functional area of a component before finishing, so a part with several independent issues has all of them surfaced in one pass instead of just the first.

        • ImprovedFor each IC, the review covers power and decoupling, every signal interface, absolute-maximum ratings, and reset/boot/configuration and unused pins before reporting — catching multiple issues on the same component that could previously be missed.
      • July 2, 2026v2.5.0

        Light Mode

        Periscope now has a light theme. Toggle between light and dark with the sun/moon button — in the sidebar next to your account menu, or in the header on the website.

        • NewTheme toggle. Switch between light and dark mode anywhere in the app; your choice is remembered on this device. Everything defaults to dark, exactly as before, until you flip it.
        • ImprovedEvery status color — error, warning, and pass badges, finding cards, the progress view, billing — is tuned for both themes, so reports stay legible either way.
        • ImprovedThe sign-in page and account menu now follow the app theme instead of always rendering light.
      • July 1, 2026v2.4.0

        Automatic Pin & LED Current Checks

        Two datasheet-grounded checks now run on every project, independent of the schematic review — catching a swapped-peripheral pin or an over-driven LED — plus a clear list of any components that had no datasheet to review against.

        • NewPin-function feasibility check. Periscope now flags when a net assigns an IC pin a peripheral function its silicon can't route — for example a `UART5_TX` net on a pin whose alternate-function table only offers `UART5_RX`. It's reported as an error straight from the datasheet's pin table and names the likely swap (TX↔RX, SDA↔SCL). It deliberately does not judge signal *direction* across an interface — a direct UART crosses TX↔RX while a transceiver runs straight through — so it only fires on physically impossible pin assignments, never on wiring style.
        • NewLED forward-current check. For each LED, Periscope computes the forward current from the supply rail, the series resistor, and the LED's rated forward voltage, and flags any channel whose current exceeds the LED's rated maximum. Each color of an RGB LED is checked separately, and a leg with no current-limiting resistor at all is called out as a caution.
        • New"Not reviewed" list on the report. Components with no datasheet on file — for instance a do-not-populate footprint that isn't in the BOM — are now called out explicitly, so a mis-wired pin on an unreviewed part shows up as a known gap instead of being silently absent.
        • NewFindings from these automatic checks carry an "Automated check" badge, so they're easy to tell apart from datasheet-review findings.
      • June 8, 2026v2.3.3

        Faster Reviews

        Multi-chip designs now review several times faster — Periscope works through ICs in parallel instead of one at a time.

        • ImprovedDatasheet extraction and schematic review now process multiple ICs at once, so reports on multi-IC projects come back substantially faster. The findings are unchanged — only the wait is shorter.
      • May 26, 2026v2.3.2

        Smarter RF Topology Review

        Schematic review now reasons about *what each external part is for* before flagging it — catching valid bias, coupling, and matching circuits that previously looked like errors.

        • ImprovedThe reviewer states the role of every external part on an IC pin (choke, blocking cap, divider, decoupling, matching) before judging the connection. Common RF topologies like bias-T (DC injected onto a coax through a choke, with the chip protected by an internal DC block and a downstream load doing the actual draw) are no longer flagged as errors against the chip.
        • ImprovedStricter absolute-maximum-rating checks: the cited limit must come from the same pin under stress (a Vdd abs-max no longer counts against an RF or signal pin), and the inequality must be a strict exceed — equal-to-abs-max is at most a Warning.
        • ImprovedSingle-concern deep dives are capped at two follow-up queries; concerns that can't be resolved in that budget are reported as Warnings with the unresolved question stated, so one suspect finding can't starve the rest of the IC review.
        • ImprovedInferred rail voltages from the power-tree pass are no longer treated as ground truth by the schematic reviewer. Voltages set by net name (`+5V`, `+3V3`) or by user power-source hints are trusted as before; voltages the power-tree LLM guessed for an adjustable regulator output or propagated through inference are kept on the power-tree view for reference but excluded from review reasoning, so a single misread rail can't anchor a false-positive Error.
        • ImprovedAfter each IC's review, a second pass normalizes findings against a fixed Error/Warning/Info rubric and merges any two findings that share a single root cause (e.g. "series resistor drops VIN" and "VOUT setpoint exceeds available VIN" are one defect, not two). Cuts run-to-run severity drift and avoids inflating the error count when one defect can be described from multiple angles.
      • May 25, 2026v2.3.1

        EDIF Netlist Support

        EDIF 2.0.0 netlists upload alongside PADS-PCB, with a sub-design picker for files that contain more than one design. Schematic review is also more cautious about polarity / direction-control findings.

        • NewUpload EDIF 2.0.0 (`.edn`) netlists directly. Format is auto-detected from the file contents — no need to convert to PADS-PCB first. Verified against Siemens xDX Designer exports.
        • NewWhen an EDIF file contains multiple sub-designs, project setup shows a picker so you can choose which one to review. The picker auto-confirms when there's a single clean match against your BOM and only asks when it's ambiguous; unselected sub-designs are filtered out of the design graph.
        • ImprovedStronger verification of differential and polarity pin assignments (USB D+/D−, TX/RX, IN+/IN−, anode/cathode) directly against the datasheet.
        • ImprovedImproved support for bidirectional buffers and level translators (74xx245 and friends) — direction-control truth tables are factored into bus-contention analysis.
        • ImprovedFindings that share a single root cause on the same chip are grouped into one combined finding.
      • May 24, 2026v2.3.0

        LCSC Part Number Support

        JLCPCB-style BOMs with LCSC part numbers (e.g. `C12044`) now work out of the box — Periscope auto-detects the column, resolves each id to the real manufacturer part number, and shows you what it resolved to before the pipeline runs.

        • NewLCSC part numbers in the manufacturer part number column are auto-detected at BOM upload and converted to real MPNs. Works with JLCPCB / EasyEDA exports without any column renaming.
        • NewProject setup now shows the LCSC → MPN mapping on each IC row in the datasheet step (e.g. `C12044 → TP4057-42-SOT26-R`), so you can see what each LCSC id became before the pipeline starts.
        • NewPassive specs (value, voltage, tolerance, dielectric, package) are resolved from the LCSC catalog during project setup, with per-row progress and status — you see what's resolved before spending credits on the full pipeline.
        • ImprovedDatasheet auto-fetch hit rate is dramatically higher on LCSC BOMs, because DigiKey now sees real MPNs instead of `C…` ids.
      • May 22, 2026v2.2.1

        Easier Netlist Uploads & Xpedition Support

        Tabbed file upload guide with per-tool instructions, Xpedition coverage, and direct `.net` / `.txt` uploads.

        • NewDocumentation for exporting a PADS-PCB netlist from Siemens Xpedition Designer / DxDesigner (VX.2.x, including VX.2.14).
        • ImprovedFile upload guide reorganized into tabs — KiCad, Altium, OrCAD/Allegro, Xpedition, EasyEDA, and Eagle each get their own panel.
        • ImprovedNetlist uploads now accept `.asc`, `.net`, `.NET`, and `.txt` directly — no more renaming required before upload.
        • ImprovedFile guide now calls out the difference between the PADS-PCB schematic netlist Periscope needs and the `!PADS-POWERPCB` PCB-layout dump that some EDA tools also save as `.asc`.
      • May 20, 2026v2.2.0

        Cross-chip Datasheet Review

        The reviewer now reads neighbor-chip datasheets to verify cross-chip constraints, with fewer false errors when a spec can't be confirmed.

        • ImprovedSchematic review now cross-references connected chips: when an issue depends on a neighbor's spec (5V tolerance, absolute-max, drive strength), the reviewer pulls the relevant pages from that chip's datasheet before flagging it.
        • ImprovedFewer false errors on cross-chip findings: if a counterpart spec can't be confirmed from the datasheet, the issue is reported as a Warning with the unverified assumption stated — instead of being overstated as an Error.
        • FixedSome review findings could occasionally fail to appear in the report.
      • May 19, 2026v2.1.0

        Datasheet Reference Highlighting

        Datasheet citations now highlight the exact supporting sentence on the PDF page, with more reliable page numbers on large datasheets.

        • ImprovedDatasheet references now highlight the exact supporting sentence on the PDF page, not just the page number.
        • FixedDatasheet citations landing on the wrong page for large (multi-hundred-page) datasheets.
        • FixedReviewed findings losing their checked state on page refresh.
      • May 1, 2026v2.0.1

        Flagging & Onboarding

        One-click flags on finding cards, an onboarding survey for new users, and small UI polish.

        • NewReport findings with one click via the flag button on any finding card.
        • NewOnboarding survey for new users to help us improve the product.
        • ImprovedComment input box now fills available width.
      • April 29, 2026v2.0.0

        Public Changelog

        • NewInitial public changelog.