# PHASE 0 — PinScope / Periscope forensic audit **Status:** observational only. No source, license, git history, remotes, or fork relationship was modified as part of this audit. **Goal:** architectural independence of Periscope from PinScope — not deletion of every inherited line. **Does not implement Phase 1.** Disposition labels are inventory, not a rewrite plan. | Field | Value | | --- | --- | | Audit date | 2026-09-20 | | GitHub repo | https://github.com/manvalan/periscope (`fork: true`) | | Declared parent / source | https://github.com/Faradworks/Pinscope | | Product snapshot (working tree described here) | `origin/cursor/pcb-review-plan-44dd` = `facbaa23058be51de3eb2551e074ada270b394d5` | | GitHub default branch | `origin/main` = `ab1c5b081cefb6445b053c170203d6ffe0a88d1b` | | Upstream `main` | `upstream/main` = `b26ad3509f4a19878fb7050aad3da9eacba8d914` (fetched locally for comparison only; **GitHub remotes of the fork were not changed**) | | Merge-base (all three tips) | `b26ad35` — upstream HEAD *is* the fork point | | This document | `docs/development/PINSCOPE_AUDIT.md` (only file this phase is allowed to add) | --- ## 1. Executive summary Periscope is a **live GitHub fork** of Faradworks/Pinscope (AGPL-3.0). Upstream has **five** commits and has not moved since 2026-07-17. GitHub `main` on the fork is only **three** commits ahead (Docker / OSS / README). The **product** (DeepSeek, rebrand, PCB exam, finding engine, v2.32.1) lives on `cursor/pcb-review-plan-44dd`: **92** commits ahead of upstream, **89** ahead of `origin/main`, **not merged** to the default branch. GitHub lists **no pull requests**. On the product snapshot (`facbaa2`, 404 files, 123 544 text lines): | Class | Files | File % | Lines | Line % | | --- | --- | --- | --- | --- | | UPSTREAM (identical blob) | 125 | 30.9% | 45 211 | 36.6% | | DERIVED (measurable overlap with an upstream path or rename) | 127 | 31.4% | 52 455 | 42.5% | | REPLACEMENT (same path, Jaccard < 0.20) | 4 | 1.0% | 359 | 0.3% | | NEW (no upstream match at the thresholds below) | 139 | 34.4% | 24 437 | 19.8% | | THIRD_PARTY (`vendor/` except empty `__init__.py` mis-tagged — see §3) | 9 | 2.2% | 1 082 | 0.9% | | UNKNOWN | 0 | — | — | — | **PinScope-lineage share (UPSTREAM + DERIVED + REPLACEMENT):** 63.4% of files, 79.4% of lines. **New / vendored share (NEW + THIRD_PARTY):** 36.6% of files, 20.7% of lines. Architectural independence is **not** blocked by leftover strings. It **is** blocked by: (1) the still-PinScope pipeline (`periscopex` ← `pinscopex`: graph, parsers, `validate.py`, extraction, Next.js report shell); (2) Faradworks legal/metadata identity still shipping in the UI; (3) GitHub `main` not carrying the product; (4) Clerk / Anthropic seams still in the runtime graph; (5) vendored ImpedenceFinder with **no license file and GitHub `license: null`**. Most important to replace **first** (identity and branch topology), not the finding engine or PCB job: Faradworks terms/privacy/contact/metadata; then isolate Clerk and Anthropic; keep parsers/graph as KEEP until a later phase. --- ## 2. Method and non-goals **Compared trees** - Upstream: `git fetch` of `https://github.com/Faradworks/Pinscope.git` into a **local** remote named `upstream` on a disposable clone. This audit did not `git remote set-url`, force-push, rewrite history, or detach the GitHub fork. - Product: `origin/cursor/pcb-review-plan-44dd` (also compared `origin/main` and `origin/cursor/deepseek-71c5`). - File identity: `git ls-tree` blob SHAs. - Text overlap: line-**set** Jaccard on `git show` text. Thresholds (fixed, not guessed): identical SHA → UPSTREAM; same path and Jaccard ≥ 0.20 **or** ≥ 20 shared lines → DERIVED; same path and below that → REPLACEMENT; path only in HEAD with identical SHA to an unmatched upstream blob, or Jaccard ≥ 0.15 against a basename / `pinscopex`→`periscopex` map → DERIVED/REPLACEMENT with `renamed_from`; `vendor/` → THIRD_PARTY; else NEW. - Licenses: root `LICENSE` blob vs upstream; npm `license` field on **every** `frontend/package-lock.json` `packages` entry (827 entries, 0 missing); PyPI JSON `info.license` / `license_expression` / License classifiers for each `backend/requirements.txt` name; ImpedenceFinder GitHub API + tree + `pyproject.toml` + `LICENSE` URL. **No license was inferred from a package name.** - Strings: ripgrep for `Pinscope`, `PinScope`, `pinscope`, `Faradworks`, `faradworks`, `SPDX`, `copyright` (lockfile excluded from hit lists). Matches were classified, not deleted. **Classifier caveat (empty blobs):** git empty-file SHA `e69de29` is shared by `backend/__init__.py` (UPSTREAM) and three HEAD empty files. The rename heuristic tagged `backend/periscopex/__init__.py`, `tests/impedancefinder/__init__.py`, and `vendor/impedancefinder/__init__.py` as DERIVED-from-`backend/__init__.py`. That is **not** a meaningful derivation. Corrected intent: package markers NEW / THIRD_PARTY. Counts in §1 are the **raw** classifier (reproducible). Adjusted: DERIVED 124, NEW 141, THIRD_PARTY 10. **Non-goals:** no refactors, no PCB/finding-engine edits, no license changes, no history rewrite, no “delete every PinScope line.” --- ## 3. Git history map ### 3.1 Exact upstream and remotes (GitHub, not this clone) From `GET https://api.github.com/repos/manvalan/periscope` (2026-09-20): | Field | Value | | --- | --- | | `full_name` | `manvalan/periscope` | | `fork` | `true` | | `parent.full_name` / `source.full_name` | `Faradworks/Pinscope` | | `default_branch` | `main` | | `license.spdx_id` | `AGPL-3.0` (same as parent) | | `created_at` | 2026-07-17T16:23:01Z | | Parent `pushed_at` | 2026-07-17T07:34:32Z | | Fork `pushed_at` | 2026-09-20T07:13:57Z | | Open / listed PRs | `[]` (empty) | GitHub still records a **fork of Faradworks/Pinscope**. This audit did not detach it. Visible `origin` branches: `main`, `cursor/deepseek-71c5`, `cursor/pcb-review-plan-44dd`. Upstream GitHub has only `main`. ### 3.2 Upstream commit list (complete — 5 commits) | SHA | Date | Author | Subject | | --- | --- | --- | --- | | `6672d2be5744239bd6edfee8abc2ac43d3705f93` | 2026-07-17 | Siddharth Kothari `` | Pinscope open-source core (root commit; extracted from cloud codebase; auth/billing in private gateway) | | `6e83ef9da021ae3a21b76bf38058f034e8dc40d9` | 2026-07-17 | Siddharth Kothari | Remove internal review case log; public support address | | `f89ca0803f571a57703766a154d628def1fe3696` | 2026-07-17 | Siddharth Kothari | README: rewrite for the public launch | | `a8c242933a6917aaeeade383c09f0ea998d467d0` | 2026-07-17 | Siddharth Kothari | README: add pipeline diagram | | `b26ad3509f4a19878fb7050aad3da9eacba8d914` | 2026-07-17 | Sid / GitHub | Update README.md (demo screenshot) | `upstream/main` **is** `b26ad35`. Fork `origin/main` contains those five plus three fork-only commits. **0** upstream commits are missing from the fork (ahead/behind `upstream/main...origin/main` = `0 3`). ### 3.3 Divergence ``` 6672d2b Pinscope OSS root (Faradworks) … b26ad35 upstream/main = merge-base ├─ origin/main (+3) │ 4888092 Docker, remove Clerk, OSS mode │ 2c5d9d3 Document fork changes in README │ ab1c5b0 Fix Anthropic skill references and backend git support └─ origin/cursor/pcb-review-plan-44dd (+92 from upstream, +89 from origin/main) 48246f3 Adapt Pinscope to DeepSeek, auto datasheets, shared library … DeepSeek, KiCad, layout F1, placement, impedance, rebrand 8d2b856, PCB job 16c606a, finding engine dc65e96, … facbaa2 (2.32.1) origin/cursor/deepseek-71c5 is 14 commits behind pcb-review (linear ancestor) ``` `origin/main` does **not** contain DeepSeek, `periscopex`, PCB exam, or the rebrand. A clone of default `main` is still branded Pinscope plus Docker. ### 3.4 Periscope vs PinScope authorship on product snapshot `git log --format='%an <%ae>'` on `origin/cursor/pcb-review-plan-44dd` (97 commits including upstream): | Count | Author | | --- | --- | | 88 | Michele Bigi `` | | 2 | manvalan `` | | 1 | Michele `` | | 1 | Cursor Agent `` | | 3 | Siddharth Kothari `` | | 1 | Siddharth Kothari `` | | 1 | Sid `<44057927+Monacrylic@users.noreply.github.com>` | PinScope authors = the five upstream commits. Periscope authors = the 92 fork commits (Michele / manvalan / Cursor Agent). ### 3.5 Product commit spine (fork-only, oldest → newest groups) Not every SHA is repeated here; `git log origin/main..origin/cursor/pcb-review-plan-44dd` is the complete 89-commit list. Grouped: 1. **DeepSeek / library** (`48246f3` … `30aaf55`): OpenAI-compatible provider, local skills, datasheet fetch, catalog passives, reprocess, quote verify. 2. **CAD / KiCad** (`e4fd6c3` … `c5b260b`): hierarchy zip, `.kicad_sch` / `.kicad_pcb` nets, cad-bridge plugin later. 3. **Deterministic schematic checks** (`b1ee445` … `7aed64c`): decoupling, I2C, DNP, sequencing, thermal, errata, layout_rules. 4. **Impedance / antenna** (`6fc2ac5` … `556306b`): vendored ImpedenceFinder, RF tab. 5. **Auth** (`5a69b38`): local multi-user JWT (PinScope-named originally). 6. **Layout F1 / Placement F2** (`2950446` … `86121e6`): domains, satellites, gated xy pack. 7. **Rebrand** (`8d2b856`, `dc364f5`): Pinscope → Periscope, `pinscopex` → `periscopex`, `PS-*` → `PE-*`. 8. **Deploy** (`6b0e44a` … `344ecb3`): `/root/periscope`, Docker networks `pinscope_pinscope` / `pinscope_periscope`. 9. **PCB exam + finding engine** (`721ede4` … `facbaa2`): MODE=pcb, shared `library/extracted`, FACT/REQUIREMENT/INFERENCE. --- ## 4. File classification vs upstream Rules: see §2. Full per-file table: **Appendix A**. Snapshot: 404 HEAD files vs 254 upstream files. **Unmatched upstream path still absent from HEAD:** `backend/pinscopex/__init__.py` (package renamed; other `pinscopex/*` files matched as `periscopex/*`). **REPLACEMENT (4)** — same path, low overlap: | Path | Jaccard | Note | | --- | --- | --- | | `README.md` | 0.133 | DeepSeek/Periscope README vs Pinscope launch README | | `frontend/src/lib/auth.ts` | 0.093 | Local JWT + legacy `pinscope_token` vs open-core stub | | `frontend/src/components/layout/sidebar-auth.tsx` | 0.105 | Local account UI vs Clerk seam stub | | `skills/extract-pintable/SKILL.md` | 0.066 | Prompt rewritten; sibling `schema.json` / `validate.py` still DERIVED | **THIRD_PARTY:** `vendor/impedancefinder/*` except `__init__.py` (empty-blob caveat). `SOURCE.md` cites https://github.com/manvalan/ImpedenceFinder commit `a0c8d0ec37c9a1b099082926e50a245778ec8d6e`. Wrapper `backend/periscopex/impedance.py` is NEW. Tests under `tests/impedancefinder/` are NEW (except empty `__init__` mis-tag). **NEW (high-signal, not exhaustive):** `finding_engine.py`, PCB/placement/antenna/impedance modules, `pcb_pipeline.py` / `placement_pipeline.py`, DeepSeek/local skill/PDF ingest, local auth routers, KiCad plugin, `docs/motore-finding.md`, `docs/piano-pcb-review.md`, `scripts/update-periscope.sh`, `docker-compose.yml`. **DERIVED core:** `backend/periscopex/{graph,models,parsers,parsers_edif,validate,validation_tools,resolve_passives,derating,bom_summary,taxonomy,pin_mux_check,led_current_check}.py` with Jaccard typically 0.63–0.98 vs `backend/pinscopex/*`. `parsers_edif.py`, `pin_function_tokens.py`, `taxonomy.py` are **identical blobs** after rename. **UPSTREAM clusters:** `LICENSE` (identical AGPL-3.0 text), most `frontend/src` primitives / marketing assets, `frontend/public`, `skills/extract-pattern` + `extract-specs` trees, most `taxonomy/*.json`, `simple_project` netlist/BOM/PDF/design_graph, several `backend/services` and routers unchanged. --- ## 5. Architectural dependency map (PinScope → Periscope) Strengths: **DIRECT** = still the same module/control flow; **INDIRECT** = new code that imports DIRECT modules; **WEAK** = naming, docs, compatibility aliases, unused seams; **NONE** = no PinScope type/control coupling observed. ``` PinScope OSS (pinscopex + FastAPI + Next.js + skills) │ DIRECT ├─ Design graph / BOM / netlist parsers / taxonomy / derating ├─ LLM review loop (validate.py, validation_tools, extraction, pipeline.py) ├─ Finding Pydantic model + normalize/dedupe ├─ Next.js report / project / admin shell ├─ Clerk/billing gateway seams (stubs + remaining calls) └─ Claude Console skills contract (manifest + upload_skills.py) │ ▼ Periscope (rebrand + DeepSeek + extra jobs) │ INDIRECT (new jobs on the same graph/library) ├─ MODE=pcb (pcb_pipeline → parsers_kicad_pcb, graph, validate._parse_review, finding_engine) ├─ MODE=placement ├─ cad-bridge / KiCad plugin ├─ finding_engine.complete_finding() wrapping models.Finding └─ datasheet finder / Mouser / local skills (replaces Anthropic upload in practice) │ WEAK ├─ pinscope_version alias, pinscopex: localStorage, pinscope_token, JWT issuer pinscope-local ├─ Docker network names pinscope_* ├─ Faradworks terms/privacy/metadata/Twitter └─ CLAUDE.md still describing Console Skills while README forbids Anthropic │ NONE (new engines, still may import geometry types) ├─ antenna_geometry / antenna_rf └─ vendor ImpedenceFinder (third party) via vendor_path ``` | Subsystem | Strength | Evidence | | --- | --- | --- | | `periscopex.graph` / `parsers*` / `models` / `taxonomy` | DIRECT | Rename + high Jaccard; `pipeline.py` still `build_graph` / `parse_bom` / `parse_netlist_any` | | `periscopex.validate` / `validation_tools` / `services/validation.py` | DIRECT | Same per-IC datasheet review; `complete_findings` grafted at end of validate | | `services/pipeline.py` + `pipeline_worker.py` | DIRECT | Same stage machine; provider swapped | | `finding_engine.py` | INDIRECT | NEW; imports `models.Finding`; seeds `PE-*`; used by `validate.py` and `pcb_checks.py` | | PCB exam (`pcb_pipeline`, `pcb_*`) | INDIRECT | NEW; `ensure_graph` uses PinScope graph; AI path reuses `_parse_review` | | Placement F2 | INDIRECT | NEW on `functional_groups` + graph | | Impedance tab | INDIRECT + THIRD_PARTY | NEW facade; solver from vendor | | Frontend report / wizard | DIRECT / DERIVED | Same App Router tree; FindingCard extended | | Local auth | REPLACEMENT + WEAK | Replaces Clerk for self-host; Clerk still in `middleware/auth.py`, admin, email | | Legal content | DIRECT | `terms.md` / `privacy.md` still Faradworks, Inc. | | `skills/extract-pattern`, `extract-specs` | DIRECT | UPSTREAM blobs | | `skills/extract-pintable/SKILL.md` | REPLACEMENT | Contract (schema/validate) still DERIVED | | `scripts/upload_skills.py` | DIRECT | UPSTREAM; README on product branch says do not run it | | Docker / `update-periscope.sh` | WEAK / NONE | New deploy; leftover `pinscope` host/network names | | `LICENSE` | DIRECT | Identical AGPL-3.0 | PCB/finding-engine **code was not modified** for this audit. Observation only: PCB is already a second job, but it is not architecturally independent of PinScope’s graph, pintable cache, or review parser. --- ## 6. Package and lockfile licenses Root project license: **GNU AGPL v3** text, blob-identical to upstream (`LICENSE` = UPSTREAM). README on the product branch: “AGPL-3.0, same as upstream Pinscope (Faradworks). For commercial licensing of the original, write to dev@faradworks.com.” GitHub API also reports `AGPL-3.0` on both repos. No `SPDX-License-Identifier` headers in the tree (0 files). There is **no** Python lockfile (`poetry.lock` / `uv.lock` / `requirements.lock`). Versions below are **declared ranges** plus **PyPI’s current JSON license field** (fetched 2026-09-20), not the exact installed wheel in a given deploy. ### 6.1 `backend/requirements.txt` (direct) | Requirement | PyPI `info.license` (as returned) | Classifiers / notes | | --- | --- | --- | | fastapi | MIT | | | uvicorn | BSD-3-Clause | | | openai | Apache-2.0 | OSI Apache; **added on fork** | | anthropic | MIT | still declared; product README says do not use Anthropic | | google-genai | Apache-2.0 | | | pydantic | MIT | | | pydantic-settings | MIT | OSI MIT | | python-multipart | Apache-2.0 | | | sse-starlette | BSD-3-Clause | | | python-dotenv | BSD-3-Clause | | | openpyxl | MIT | | | google-cloud-storage | Apache-2.0 | | | google-cloud-run | Apache-2.0 | | | google-api-python-client | `Apache 2.0` (PyPI spelling, not SPDX token) | OSI Apache | | pypdf | BSD-3-Clause | | | pymupdf | `Dual Licensed - GNU AFFERO GPL 3.0 or Artifex Commercial License` | **added on fork**; dual license from PyPI, not inferred | | PyJWT | MIT | extras `[crypto]` | | cryptography | Apache-2.0 OR BSD-3-Clause | | | httpx | BSD-3-Clause | **added on fork** | | packaging | Apache-2.0 OR BSD-2-Clause | | | shapely | `BSD 3-Clause` (PyPI spelling) | OSI BSD; **added on fork** (ImpedenceFinder) | | PyYAML | MIT | **added on fork** | Transitive Python licenses were **not** enumerated (no lockfile). Marked INVESTIGATE. ### 6.2 Frontend direct dependencies (`package-lock.json` `packages["node_modules/"]`) Lockfile version field is `2.10.0` while `package.json` is `2.26.3` (quality note §8). Every lock `packages` entry has a `license` field (827/827). | Package | Locked version | `license` field | | --- | --- | --- | | @base-ui/react | 1.3.0 | MIT | | @xyflow/react | 12.10.2 | MIT | | @types/dagre | 0.7.54 | MIT | | class-variance-authority | 0.7.1 | Apache-2.0 | | clsx | 2.1.1 | MIT | | dagre | 0.8.5 | MIT | | lucide-react | 1.8.0 | ISC | | next | 16.2.3 | MIT | | next-themes | 0.4.6 | MIT | | react / react-dom | 19.2.4 | MIT | | react-markdown | 10.1.0 | MIT | | react-pdf | 10.4.1 | MIT | | shadcn | 4.2.0 | MIT | | tailwind-merge | 3.5.0 | MIT | | tw-animate-css | 1.4.0 | MIT | | xlsx | 0.18.5 | Apache-2.0 | | @tailwindcss/postcss / tailwindcss | 4.2.2 | MIT | | typescript | 5.9.3 | Apache-2.0 | | eslint / eslint-config-next | 9.39.4 / 16.2.3 | MIT | | @types/node | 20.19.39 | MIT | | @types/react / react-dom | 19.2.14 / 19.2.3 | MIT | ### 6.3 Transitive npm license histogram (lockfile fields only) MIT 684; ISC 44; Apache-2.0 43; MPL-2.0 13 (e.g. `axe-core`, `lightningcss*`); BSD-2-Clause 11; LGPL-3.0-or-later 10 (`@img/sharp-libvips-*`); BSD-3-Clause 9; BlueOak-1.0.0 3; Apache-2.0 AND LGPL-3.0-or-later 3; 0BSD 2; plus one each of Apache-2.0 AND LGPL-3.0-or-later AND MIT, Python-2.0 (`argparse`), CC-BY-4.0 (`caniuse-lite`), CC0-1.0, (MIT OR CC0-1.0). **Copyleft transitive (frontend):** LGPL-3.0-or-later via sharp/libvips optional platform packages; MPL-2.0 via lightningcss/axe-core. Not removed; recorded. ### 6.4 Vendored ImpedenceFinder | Probe | Result | | --- | --- | | GitHub `license` on `manvalan/ImpedenceFinder` | JSON `license: null` | | `LICENSE` at vendored commit `a0c8d0ec…` | HTTP 404 | | `pyproject.toml` on default `main` | **no** `[project].license` / license-files | | README | **no** license section (Italian functional README) | | Vendored Python headers | describe KiCad formula provenance; **no** SPDX, **no** copyright line | License of the vendored snapshot is **UNKNOWN from evidence**. Do not treat as MIT/AGPL by name. INVESTIGATE before any additional distribution story. --- ## 7. String search: Pinscope / PinScope / pinscope / Faradworks / SPDX / copyright **Do not remove these in Phase 0.** Classification only. | Needle | Files | Match lines (approx) | Class of hits | | --- | --- | --- | --- | | `PinScope` | 0 | 0 | none | | `SPDX` | 0 | 0 | none in source | | `copyright` / `Copyright` | 1 (`LICENSE`) | AGPL template + FSF | UPSTREAM license text | | `Pinscope` | 3 | 4 | README license line; changelog rebrand notes; deploy CORS comment | | `pinscope` (any case via listing) | 9 | 30 | legacy IDs, paths, Docker networks, clone URL | | `Faradworks` | 8 | 67 | terms, privacy, marketing, layout metadata, footers | | `faradworks` | 7 | 21 | `dev@faradworks.com`, faradworks.com, `@getFaradWorks` | ### 7.1 Compatibility / ops (KEEP or ISOLATE — still serving a migration) | Location | Hit | Role | | --- | --- | --- | | `backend/services/projects.py` | `pinscope_version` alias | Reads old `project.json` | | `frontend/src/lib/api.ts` | `p.pinscope_version` | Same | | `frontend/src/lib/auth.ts` | `LEGACY_TOKEN_STORAGE_KEY = "pinscope_token"` | Pre-rebrand JWT | | `frontend/src/lib/storage-keys.ts` | still **writes** `pinscopex:*` keys | Comment says migrate; implementation still PinScope prefix | | `scripts/update-periscope.sh` / `docker-compose.yml` | `pinscope_pinscope`, `pinscope.michelebigi.it`, clone `manvalan/pinscope` | Live VPS topology | | `frontend/content/changelog.md` | historical Pinscope / `PS-*` | Documentation of migration | ### 7.2 Faradworks identity still on the Periscope product UI (REPLACE for independence; not “delete PinScope code”) | Location | Hit | | --- | --- | | `frontend/src/app/layout.tsx` | `authors` / `creator` / `publisher`: Faradworks; `url: https://faradworks.com` | | `frontend/src/lib/site.ts` | `TWITTER_HANDLE = "@getFaradWorks"`; `SITE_NAME` already `"Periscope"` | | `frontend/src/components/legal/*` | `© {year} Faradworks` | | `frontend/content/terms.md` | Entire TOS: Faradworks, Inc. Delaware; ownership of “the Service”; `dev@faradworks.com` | | `frontend/content/privacy.md` | Faradworks contact | | `frontend/src/app/(marketing)/page.tsx`, `contact/*` | `dev@faradworks.com` | | `README.md` | commercial license → `dev@faradworks.com` | `terms.md` still defines the operator as Faradworks while `SITE_URL` defaults to `https://periscope.michelebigi.it`. That is a **product-identity coupling**, not a parser coupling. ### 7.3 © in LICENSE FSF copyright on the AGPL **license document** itself (2007). That is expected and KEEP. No per-file `Copyright (C) Faradworks` headers were found in `.py`/`.ts` (search limited as in §2). Absence of headers ≠ absence of copyright; the fork inherits AGPL obligations from the parent work. --- ## 8. Duplicated concepts and partial migrations | Concept | PinScope side (still present) | Periscope side | Migration state | | --- | --- | --- | --- | | Package name | `backend/pinscopex` gone; empty `__init__` only unmatched | `backend/periscopex` | **Done** (rename); imports updated | | Finding IDs | changelog `PS-*` | `PE-*` in finding_engine | **Done** for new IDs; old reports not in repo | | App version field | `pinscope_version` alias | `periscope_version` | **Partial** — dual read | | Browser storage | `pinscopex:` keys still **produced** | comment claims migration | **Partial / inverted** | | Auth | Clerk JWKS, Clerk admin/email, `ClerkThemeProvider` | local JWT `AUTH_JWT_SECRET` | **Partial** — two stacks | | LLM | `anthropic` dep, `upload_skills.py`, CLAUDE.md Console Skills | DeepSeek + `local_skill.py` + README “do not use Anthropic” | **Partial** | | Review findings | `validate._parse_review`, normalize/dedupe | `finding_engine.complete_finding` | **Layered**, not replaced | | Jobs | `MODE=run` analysis | `MODE=pcb`, `MODE=placement` | **Additive** three mutexed jobs | | Default branch vs product | GitHub `main` = Docker Pinscope OSS | pcb-review = 2.32.1 | **Not merged** | | Docker networks | `pinscope_pinscope` (Caddy) | `pinscope_periscope` / aliases | **Partial** rename | | Legal | Faradworks TOS/privacy | SITE_NAME Periscope | **Partial** | | Changelog vs lockfile | `package-lock.json` `"version": "2.10.0"` | `package.json` `2.26.3`, changelog 2.32.1 | **Drift** | | Impedance | (none upstream) | vendor + `periscopex.impedance` | NEW + THIRD_PARTY | | Open-core seams | `billing_hook`, proxy.ts, clerk-theme | OSS no-op + local auth | Stubs KEEP for API shape; identity REPLACE | --- ## 9. Technical quality observations (no rewrite proposals) These are facts about the snapshot, not a license to rip out PinScope. 1. **Default branch is not the product.** Anyone cloning `manvalan/periscope` without a branch flag gets pre-DeepSeek Pinscope + Docker (`ab1c5b0`). Live notes refer to 2.32.1 on the PCB branch. 2. **Docs disagree:** `CLAUDE.md` (DERIVED, Jaccard 0.67) still titles Periscope but describes Claude Console Skills as required. Product `README.md` (REPLACEMENT) says skills are local and Anthropic must not be used. 3. **Finding engine is a clamp, not a new IR.** `validate.py` still produces `Finding` objects; `complete_findings` fills FACT/REQUIREMENT/INFERENCE. Replacing PinScope review in one shot would discard the working schematic loop. 4. **PCB job correctly refuses auto-place** (comments in `pcb_pipeline.py`) but **depends** on schematic graph + pintable cache (“run schematic review first”). That is coupling, not a bug by itself. 5. **Empty `__init__.py` files** share one git blob; mechanical rename detection over-claims derivation (§2). 6. **`frontend/package-lock.json` is almost identical to upstream** (Jaccard 0.999) while app version moved to 2.26.3/2.32.1 — lock **name-version** stale; dependency licenses still readable from the lock. 7. **PyMuPDF dual AGPL/commercial** on PyPI is a distribution constraint for binaries/SaaS (AGPL network clause already applies via root LICENSE). Recorded, not changed. 8. **ImpedenceFinder** has no license metadata. KiCad formula comments are provenance of **math**, not a license grant. 9. **xlsx@0.18.5** lock field is Apache-2.0 (not guessed from “SheetJS”). 10. **Auth production guard** still mentions Clerk (`backend/main.py`, `update-periscope.sh` dies if `ENVIRONMENT=production` without Clerk). Local JWT exists but deploy script language is mixed. 11. **No per-source-file copyright/SPDX** — harder provenance later; AGPL still applies to the combined work. 12. Tests for NEW modules are substantial (`tests/test_pcb_review.py`, `test_finding_engine.py`, etc.) — quality of *additions* is high relative to unmerged `main`. --- ## 10. Disposition (KEEP / ISOLATE / REPLACE / REMOVE / INVESTIGATE) Independence means Periscope can evolve its product, legal identity, and review contract without pretending to be Faradworks/Pinscope. It does **not** mean deleting `graph.py`. | Area | Action | Why | | --- | --- | --- | | AGPL `LICENSE` blob | **KEEP** | Identical upstream license; changing it is out of scope and would not create independence | | Parsers, graph, taxonomy, BOM, derating, EDIF | **KEEP** | DIRECT lineage; this *is* the schematic core; replacing is a later engineering program | | `models.Finding` + normalize/dedupe | **KEEP** + **ISOLATE** | Keep types; route new semantics through `finding_engine` | | `validate.py` LLM loop | **KEEP** for now; **ISOLATE** provider/skills | Working product; independence = provider + finding contract, not a greenfield reviewer | | PCB / placement / antenna / finding_engine / KiCad plugin | **KEEP** | NEW Periscope surface | | `vendor/impedancefinder` | **ISOLATE** + **INVESTIGATE** | Boundary already in `impedance.py`; license unknown | | Faradworks TOS, privacy, footers, layout authors, Twitter, contact email | **REPLACE** | Operator identity; largest *non-engine* coupling | | `pinscope_version` / JWT issuer / CORS host aliases | **ISOLATE** then expire | Needed for live data; not the architecture | | `storage-keys.ts` still writing `pinscopex:` | **REPLACE** (write path) after dual-read | Partial migration bug-shaped | | Clerk seams (`clerk-theme`, JWKS, admin Clerk API, email) | **ISOLATE**; **REMOVE** only when local auth is the only supported mode | Dual stack | | `anthropic` dependency, `upload_skills.py`, Console-oriented CLAUDE.md | **ISOLATE**; **REMOVE** later if DeepSeek-only is policy | README already forbids Anthropic | | GitHub `main` vs pcb-review | **INVESTIGATE** (process) | Merge/publish strategy; do not detach fork | | PyMuPDF dual license + Python transitives | **INVESTIGATE** | No pip lock | | ImpedenceFinder license from author | **INVESTIGATE** | Blocker for *clean* third-party story, not for reading code | | `simple_project` / how-it-works.svg | **KEEP** | UPSTREAM fixtures; rebrand docs separately | | Billing hook / gateway stubs | **KEEP** signatures; **ISOLATE** comments that imply Faradworks cloud | Open-core seam | | PinScope *strings* in changelog | **KEEP** | Historical accuracy | **REMOVE** is empty for Phase 0. Nothing should be deleted on the basis of this audit alone. --- ## 11. Phase 1 sequence (recommended order; not this change) Phase 1 should increase **independence**, not maximize diff against PinScope. 1. **Land this audit** on a branch that does not rewrite engines (`docs/development/PINSCOPE_AUDIT.md` only). 2. **Branch topology:** decide how GitHub `main` relates to `cursor/pcb-review-plan-44dd` without detaching the fork (merge/PR of product onto `main`, or document that `main` is archival). Until then, every clone is the wrong tree. 3. **Operator identity:** replace Faradworks TOS/privacy/contact/metadata/Twitter/footers with Periscope operator documents; keep AGPL and a factual “derived from Faradworks/Pinscope” attribution (README already has a form of this). 4. **Compatibility fence:** one module/doc for legacy `pinscope_*` keys, JWT issuer, CORS, Docker network names; stop writing new `pinscopex:` storage keys. 5. **Auth ISOLATE:** make the self-host path (local JWT) the documented default; keep Clerk behind a named seam so admin/email do not assume Clerk. 6. **LLM ISOLATE:** document DeepSeek as the supported provider; treat Anthropic SDK + `upload_skills.py` as optional/legacy so CLAUDE.md matches README. 7. **Finding contract:** keep using `finding_engine` as the independence layer on top of `Finding`; do not rewrite `validate.py` in Phase 1. 8. **Vendor license:** obtain an explicit license for ImpedenceFinder (or stop distributing the vendor tree until known). 9. **Python lock:** add a lockfile so transitive licenses can be audited like npm. 10. **Only then** consider isolating parsers/graph behind a narrower Periscope API — a large KEEP surface, not a Phase 1 delete. --- ## 12. Unresolved questions and evidence gaps 1. **Intent of GitHub `main`:** accidental staleness vs deliberate “OSS mirror of upstream + Docker”? No PRs exist to explain it. 2. **Legal operator of periscope.michelebigi.it** vs documents that still say Faradworks, Inc. — this audit cannot assign a legal entity. 3. **ImpedenceFinder license** (author, KiCad cpp port implications). GitHub API `license` is null. 4. **PyMuPDF** AGPL vs Artifex commercial: which grant is used in the VPS deploy? 5. **Python transitive licenses** without a lockfile. 6. **Whether Anthropic is still reachable** if env keys exist despite README (code path exists; runtime not executed here). 7. **Private Faradworks gateway** files mentioned in upstream CLAUDE.md — not in this repo; cannot audit what the parent still replaces in cloud builds. 8. **Trademark** “Pinscope” / “Periscope” / “Faradworks”: search found **use**, not a registration database. No legal conclusion. 9. **Empty-file DERIVED tags** — see §2; raw vs adjusted counts. 10. **`origin` on the analyst clone** included a local `upstream` remote for fetch-only comparison. GitHub fork remotes were not edited; confirm live GitHub still has `parent: Faradworks/Pinscope` after this docs-only PR. 11. **mbparks/pinscope** (Arduino) is a **different project**; zero code overlap observed; ignored. 12. **Exact installed npm/pip versions on production** (`/root/periscope`) were not inspected; licenses are from lock + PyPI JSON as of 2026-09-20. --- ## Appendix A — Per-file classification Evidence strings are mechanical (SHA / Jaccard / path). Empty-blob rename caveat applies to three `__init__.py` files listed as DERIVED. ### UPSTREAM (125) | Path | Evidence | | --- | --- | | `.github/workflows/ci.yml` | identical blob SHA | | `LICENSE` | identical blob SHA | | `backend/__init__.py` | identical blob SHA | | `backend/middleware/__init__.py` | identical blob SHA | | `backend/routers/__init__.py` | identical blob SHA | | `backend/routers/deps.py` | identical blob SHA | | `backend/routers/feedback.py` | identical blob SHA | | `backend/routers/survey.py` | identical blob SHA | | `backend/services/__init__.py` | identical blob SHA | | `backend/services/admin_settings.py` | identical blob SHA | | `backend/services/billing_hook.py` | identical blob SHA | | `backend/services/purple_parts.py` | identical blob SHA | | `backend/services/storage.py` | identical blob SHA | | `backend/services/storage_gcs.py` | identical blob SHA | | `backend/services/survey.py` | identical blob SHA | | `docs/how-it-works.svg` | identical blob SHA | | `frontend/.gitignore` | identical blob SHA | | `frontend/AGENTS.md` | identical blob SHA | | `frontend/README.md` | identical blob SHA | | `frontend/components.json` | identical blob SHA | | `frontend/eslint.config.mjs` | identical blob SHA | | `frontend/postcss.config.mjs` | identical blob SHA | | `frontend/public/datasheet.gif` | identical blob SHA | | `frontend/public/derating.png` | identical blob SHA | | `frontend/public/eda-logos/altium.svg` | identical blob SHA | | `frontend/public/eda-logos/autodesk.svg` | identical blob SHA | | `frontend/public/eda-logos/cadence.svg` | identical blob SHA | | `frontend/public/eda-logos/easyeda.svg` | identical blob SHA | | `frontend/public/eda-logos/kicad.svg` | identical blob SHA | | `frontend/public/eda-logos/orcad.svg` | identical blob SHA | | `frontend/public/eda-logos/siemens.svg` | identical blob SHA | | `frontend/public/examples/TI-MSP-KICAD9-TUTORIAL-SCHEMATIC.pdf` | identical blob SHA | | `frontend/public/examples/TI-MSP-KICAD9-TUTORIAL.asc` | identical blob SHA | | `frontend/public/examples/TI-MSP-KICAD9-TUTORIAL.csv` | identical blob SHA | | `frontend/public/faradworks-logo-white.png` | identical blob SHA | | `frontend/public/favicon_io/android-chrome-192x192.png` | identical blob SHA | | `frontend/public/favicon_io/android-chrome-512x512.png` | identical blob SHA | | `frontend/public/favicon_io/apple-touch-icon.png` | identical blob SHA | | `frontend/public/favicon_io/favicon-16x16.png` | identical blob SHA | | `frontend/public/favicon_io/favicon-32x32.png` | identical blob SHA | | `frontend/public/favicon_io/favicon.ico` | identical blob SHA | | `frontend/public/file.svg` | identical blob SHA | | `frontend/public/globe.svg` | identical blob SHA | | `frontend/public/next.svg` | identical blob SHA | | `frontend/public/power-tree.gif` | identical blob SHA | | `frontend/public/report.png` | identical blob SHA | | `frontend/public/vercel.svg` | identical blob SHA | | `frontend/public/window.svg` | identical blob SHA | | `frontend/scripts/sync-version.mjs` | identical blob SHA | | `frontend/src/app/(app)/api/graph/[id]/route.ts` | identical blob SHA | | `frontend/src/app/(app)/api/projects/route.ts` | identical blob SHA | | `frontend/src/app/(app)/api/report/[id]/route.ts` | identical blob SHA | | `frontend/src/app/(marketing)/contact/contact-form.tsx` | identical blob SHA | | `frontend/src/app/(marketing)/layout.tsx` | identical blob SHA | | `frontend/src/app/favicon.ico` | identical blob SHA | | `frontend/src/app/globals.css` | identical blob SHA | | `frontend/src/app/layout.tsx` | identical blob SHA | | `frontend/src/app/robots.ts` | identical blob SHA | | `frontend/src/app/sitemap.ts` | identical blob SHA | | `frontend/src/app/twitter-image.tsx` | identical blob SHA | | `frontend/src/components/analytics/reddit-pixel-match-keys.tsx` | identical blob SHA | | `frontend/src/components/analytics/reddit-pixel.tsx` | identical blob SHA | | `frontend/src/components/billing/credits-context.tsx` | identical blob SHA | | `frontend/src/components/billing/paused-run-banner.tsx` | identical blob SHA | | `frontend/src/components/feedback/feedback-dialog.tsx` | identical blob SHA | | `frontend/src/components/legal/file-guide-page.tsx` | identical blob SHA | | `frontend/src/components/marketing/pricing-section.tsx` | identical blob SHA | | `frontend/src/components/pdf/pdf-viewer-sheet.tsx` | identical blob SHA | | `frontend/src/components/progress/pipeline-stepper.tsx` | identical blob SHA | | `frontend/src/components/report/finding-comments.tsx` | identical blob SHA | | `frontend/src/components/report/mention-input.tsx` | identical blob SHA | | `frontend/src/components/report/reviewed-section.tsx` | identical blob SHA | | `frontend/src/components/report/status-badge.tsx` | identical blob SHA | | `frontend/src/components/theme/clerk-theme-provider.tsx` | identical blob SHA | | `frontend/src/components/theme/theme-provider.tsx` | identical blob SHA | | `frontend/src/components/theme/theme-toggle.tsx` | identical blob SHA | | `frontend/src/components/ui/alert-dialog.tsx` | identical blob SHA | | `frontend/src/components/ui/badge.tsx` | identical blob SHA | | `frontend/src/components/ui/button.tsx` | identical blob SHA | | `frontend/src/components/ui/card.tsx` | identical blob SHA | | `frontend/src/components/ui/collapsible.tsx` | identical blob SHA | | `frontend/src/components/ui/dialog.tsx` | identical blob SHA | | `frontend/src/components/ui/dropdown-menu.tsx` | identical blob SHA | | `frontend/src/components/ui/input.tsx` | identical blob SHA | | `frontend/src/components/ui/label.tsx` | identical blob SHA | | `frontend/src/components/ui/progress.tsx` | identical blob SHA | | `frontend/src/components/ui/scroll-area.tsx` | identical blob SHA | | `frontend/src/components/ui/select.tsx` | identical blob SHA | | `frontend/src/components/ui/separator.tsx` | identical blob SHA | | `frontend/src/components/ui/sheet.tsx` | identical blob SHA | | `frontend/src/components/ui/skeleton.tsx` | identical blob SHA | | `frontend/src/components/ui/tabs.tsx` | identical blob SHA | | `frontend/src/components/ui/textarea.tsx` | identical blob SHA | | `frontend/src/components/ui/toast.tsx` | identical blob SHA | | `frontend/src/components/ui/tooltip.tsx` | identical blob SHA | | `frontend/src/hooks/use-auth-api.ts` | identical blob SHA | | `frontend/src/lib/mock-data.ts` | identical blob SHA | | `frontend/src/lib/utils.ts` | identical blob SHA | | `frontend/src/proxy.ts` | identical blob SHA | | `frontend/tsconfig.json` | identical blob SHA | | `scripts/backfill_passive_subtype.py` | identical blob SHA | | `scripts/clear_rules_from_extractions.py` | identical blob SHA | | `scripts/gc_orphan_blobs.py` | identical blob SHA | | `scripts/migrate_datasheets_to_blobs.py` | identical blob SHA | | `scripts/migrate_datasheets_to_library.py` | identical blob SHA | | `scripts/upload_skills.py` | identical blob SHA | | `simple_project/TI-MSP-KICAD9-TUTORIAL-SCHEMATIC.pdf` | identical blob SHA | | `simple_project/TI-MSP-KICAD9-TUTORIAL.asc` | identical blob SHA | | `simple_project/TI-MSP-KICAD9-TUTORIAL.csv` | identical blob SHA | | `simple_project/design_graph.json` | identical blob SHA | | `skills/extract-pattern/SKILL.md` | identical blob SHA | | `skills/extract-pattern/schema.json` | identical blob SHA | | `skills/extract-pattern/validate.py` | identical blob SHA | | `skills/extract-specs/SKILL.md` | identical blob SHA | | `skills/extract-specs/schema.json` | identical blob SHA | | `skills/extract-specs/validate.py` | identical blob SHA | | `taxonomy/connector.json` | identical blob SHA | | `taxonomy/discrete.json` | identical blob SHA | | `taxonomy/fuse.json` | identical blob SHA | | `taxonomy/ic.json` | identical blob SHA | | `taxonomy/switch.json` | identical blob SHA | | `taxonomy/test_point.json` | identical blob SHA | | `taxonomy/transformer.json` | identical blob SHA | | `tests/__init__.py` | identical blob SHA | | `tests/test_cache_breakpoint_limit.py` | identical blob SHA | ### DERIVED (127) | Path | Evidence | | --- | --- | | `.dockerignore` | same path; line-set Jaccard=0.857; shared_lines=12; head_lines=13; upstream_lines=13 | | `.gitignore` | same path; line-set Jaccard=0.963; shared_lines=52; head_lines=54; upstream_lines=52 | | `CLAUDE.md` | same path; line-set Jaccard=0.669; shared_lines=89; head_lines=111; upstream_lines=111 | | `backend/.env.example` | same path; line-set Jaccard=0.236; shared_lines=26; head_lines=77; upstream_lines=59 | | `backend/CLAUDE.md` | same path; line-set Jaccard=0.847; shared_lines=111; head_lines=121; upstream_lines=121 | | `backend/Dockerfile` | same path; line-set Jaccard=0.600; shared_lines=18; head_lines=25; upstream_lines=23 | | `backend/_version.py` | same path; line-set Jaccard=0.812; shared_lines=26; head_lines=29; upstream_lines=29 | | `backend/config.py` | same path; line-set Jaccard=0.628; shared_lines=172; head_lines=261; upstream_lines=185 | | `backend/main.py` | same path; line-set Jaccard=0.715; shared_lines=108; head_lines=138; upstream_lines=121 | | `backend/middleware/auth.py` | same path; line-set Jaccard=0.372; shared_lines=42; head_lines=84; upstream_lines=71 | | `backend/periscopex/__init__.py` | identical blob to upstream backend/__init__.py (rename/move) renamed_from=`backend/__init__.py` | | `backend/periscopex/bom_summary.py` | path absent; matched upstream backend/pinscopex/bom_summary.py Jaccard=0.9231; shared_lines=72 renamed_from=`backend/pinscopex/bom_summary.py` | | `backend/periscopex/derating.py` | path absent; matched upstream backend/pinscopex/derating.py Jaccard=0.6358; shared_lines=96 renamed_from=`backend/pinscopex/derating.py` | | `backend/periscopex/graph.py` | path absent; matched upstream backend/pinscopex/graph.py Jaccard=0.7812; shared_lines=275 renamed_from=`backend/pinscopex/graph.py` | | `backend/periscopex/led_current_check.py` | path absent; matched upstream backend/pinscopex/led_current_check.py Jaccard=0.983; shared_lines=231 renamed_from=`backend/pinscopex/led_current_check.py` | | `backend/periscopex/models.py` | path absent; matched upstream backend/pinscopex/models.py Jaccard=0.7241; shared_lines=252 renamed_from=`backend/pinscopex/models.py` | | `backend/periscopex/parsers.py` | path absent; matched upstream backend/pinscopex/parsers.py Jaccard=0.6929; shared_lines=185 renamed_from=`backend/pinscopex/parsers.py` | | `backend/periscopex/parsers_edif.py` | identical blob to upstream backend/pinscopex/parsers_edif.py (rename/move) renamed_from=`backend/pinscopex/parsers_edif.py` | | `backend/periscopex/pin_function_tokens.py` | identical blob to upstream backend/pinscopex/pin_function_tokens.py (rename/move) renamed_from=`backend/pinscopex/pin_function_tokens.py` | | `backend/periscopex/pin_mux_check.py` | path absent; matched upstream backend/pinscopex/pin_mux_check.py Jaccard=0.9379; shared_lines=136 renamed_from=`backend/pinscopex/pin_mux_check.py` | | `backend/periscopex/resolve_passives.py` | path absent; matched upstream backend/pinscopex/resolve_passives.py Jaccard=0.9652; shared_lines=388 renamed_from=`backend/pinscopex/resolve_passives.py` | | `backend/periscopex/taxonomy.py` | identical blob to upstream backend/pinscopex/taxonomy.py (rename/move) renamed_from=`backend/pinscopex/taxonomy.py` | | `backend/periscopex/utils.py` | path absent; matched upstream backend/pinscopex/utils.py Jaccard=0.8824; shared_lines=15 renamed_from=`backend/pinscopex/utils.py` | | `backend/periscopex/validate.py` | path absent; matched upstream backend/pinscopex/validate.py Jaccard=0.8792; shared_lines=793 renamed_from=`backend/pinscopex/validate.py` | | `backend/periscopex/validation_tools.py` | path absent; matched upstream backend/pinscopex/validation_tools.py Jaccard=0.7846; shared_lines=499 renamed_from=`backend/pinscopex/validation_tools.py` | | `backend/pipeline_worker.py` | same path; line-set Jaccard=0.817; shared_lines=94; head_lines=109; upstream_lines=100 | | `backend/requirements.txt` | same path; line-set Jaccard=0.696; shared_lines=16; head_lines=22; upstream_lines=17 | | `backend/routers/admin.py` | same path; line-set Jaccard=0.831; shared_lines=404; head_lines=429; upstream_lines=461 | | `backend/routers/contact.py` | same path; line-set Jaccard=0.925; shared_lines=98; head_lines=102; upstream_lines=102 | | `backend/routers/pipeline.py` | same path; line-set Jaccard=0.467; shared_lines=236; head_lines=490; upstream_lines=251 | | `backend/routers/projects.py` | same path; line-set Jaccard=0.696; shared_lines=626; head_lines=810; upstream_lines=716 | | `backend/routers/reports.py` | same path; line-set Jaccard=0.551; shared_lines=150; head_lines=268; upstream_lines=154 | | `backend/services/api_logs.py` | same path; line-set Jaccard=0.775; shared_lines=79; head_lines=100; upstream_lines=81 | | `backend/services/cost_estimator.py` | same path; line-set Jaccard=0.961; shared_lines=292; head_lines=298; upstream_lines=298 | | `backend/services/datasheet_store.py` | same path; line-set Jaccard=0.586; shared_lines=102; head_lines=168; upstream_lines=108 | | `backend/services/dedupe_findings.py` | same path; line-set Jaccard=0.923; shared_lines=300; head_lines=309; upstream_lines=316 | | `backend/services/digikey.py` | same path; line-set Jaccard=0.679; shared_lines=188; head_lines=256; upstream_lines=209 | | `backend/services/email.py` | same path; line-set Jaccard=0.933; shared_lines=610; head_lines=632; upstream_lines=632 | | `backend/services/event_bridge.py` | same path; line-set Jaccard=0.881; shared_lines=133; head_lines=145; upstream_lines=139 | | `backend/services/extraction.py` | same path; line-set Jaccard=0.772; shared_lines=563; head_lines=711; upstream_lines=581 | | `backend/services/job_runner.py` | same path; line-set Jaccard=0.744; shared_lines=203; head_lines=260; upstream_lines=216 | | `backend/services/llm/__init__.py` | same path; line-set Jaccard=0.838; shared_lines=31; head_lines=34; upstream_lines=34 | | `backend/services/llm/anthropic_provider.py` | same path; line-set Jaccard=0.911; shared_lines=276; head_lines=297; upstream_lines=282 | | `backend/services/llm/base.py` | same path; line-set Jaccard=0.897; shared_lines=70; head_lines=73; upstream_lines=75 | | `backend/services/llm/factory.py` | same path; line-set Jaccard=0.806; shared_lines=54; head_lines=62; upstream_lines=59 | | `backend/services/llm/gemini_provider.py` | same path; line-set Jaccard=0.958; shared_lines=276; head_lines=283; upstream_lines=281 | | `backend/services/llm/pricing.py` | same path; line-set Jaccard=0.742; shared_lines=66; head_lines=85; upstream_lines=70 | | `backend/services/llm/types.py` | same path; line-set Jaccard=0.883; shared_lines=68; head_lines=75; upstream_lines=70 | | `backend/services/normalize_findings.py` | same path; line-set Jaccard=0.945; shared_lines=430; head_lines=440; upstream_lines=445 | | `backend/services/pipeline.py` | same path; line-set Jaccard=0.657; shared_lines=1157; head_lines=1569; upstream_lines=1350 | | `backend/services/projects.py` | same path; line-set Jaccard=0.630; shared_lines=511; head_lines=789; upstream_lines=533 | | `backend/services/validation.py` | same path; line-set Jaccard=0.816; shared_lines=738; head_lines=863; upstream_lines=779 | | `backend/skills_manifest.json` | same path; line-set Jaccard=0.417; shared_lines=10; head_lines=17; upstream_lines=17 | | `frontend/CLAUDE.md` | same path; line-set Jaccard=0.882; shared_lines=75; head_lines=80; upstream_lines=80 | | `frontend/content/changelog.md` | same path; line-set Jaccard=0.198; shared_lines=58; head_lines=285; upstream_lines=66 | | `frontend/content/file-guide.md` | same path; line-set Jaccard=0.702; shared_lines=87; head_lines=107; upstream_lines=104 | | `frontend/content/privacy.md` | same path; line-set Jaccard=0.943; shared_lines=100; head_lines=103; upstream_lines=103 | | `frontend/content/terms.md` | same path; line-set Jaccard=0.936; shared_lines=176; head_lines=182; upstream_lines=182 | | `frontend/next.config.ts` | same path; line-set Jaccard=0.710; shared_lines=44; head_lines=59; upstream_lines=47 | | `frontend/package-lock.json` | same path; line-set Jaccard=0.999; shared_lines=4170; head_lines=4172; upstream_lines=4172 | | `frontend/package.json` | same path; line-set Jaccard=0.953; shared_lines=41; head_lines=42; upstream_lines=42 | | `frontend/public/favicon_io/site.webmanifest` | same path; line-set Jaccard=0.789; shared_lines=15; head_lines=17; upstream_lines=17 | | `frontend/src/app/(app)/admin/page.tsx` | same path; line-set Jaccard=0.983; shared_lines=1188; head_lines=1205; upstream_lines=1191 | | `frontend/src/app/(app)/dashboard/page.tsx` | same path; line-set Jaccard=0.980; shared_lines=300; head_lines=303; upstream_lines=303 | | `frontend/src/app/(app)/feedback/page.tsx` | same path; line-set Jaccard=0.981; shared_lines=102; head_lines=103; upstream_lines=103 | | `frontend/src/app/(app)/layout.tsx` | same path; line-set Jaccard=0.545; shared_lines=18; head_lines=27; upstream_lines=24 | | `frontend/src/app/(app)/project/[id]/page.tsx` | same path; line-set Jaccard=0.757; shared_lines=758; head_lines=967; upstream_lines=792 | | `frontend/src/app/(app)/project/[id]/progress/page.tsx` | same path; line-set Jaccard=0.729; shared_lines=266; head_lines=346; upstream_lines=285 | | `frontend/src/app/(app)/project/[id]/report/page.tsx` | same path; line-set Jaccard=0.721; shared_lines=271; head_lines=362; upstream_lines=285 | | `frontend/src/app/(marketing)/changelog/page.tsx` | same path; line-set Jaccard=0.895; shared_lines=17; head_lines=18; upstream_lines=18 | | `frontend/src/app/(marketing)/contact/actions.ts` | same path; line-set Jaccard=0.949; shared_lines=37; head_lines=38; upstream_lines=38 | | `frontend/src/app/(marketing)/contact/nav.tsx` | same path; line-set Jaccard=0.918; shared_lines=56; head_lines=59; upstream_lines=58 | | `frontend/src/app/(marketing)/contact/page.tsx` | same path; line-set Jaccard=0.909; shared_lines=60; head_lines=63; upstream_lines=63 | | `frontend/src/app/(marketing)/file-guide/page.tsx` | same path; line-set Jaccard=0.895; shared_lines=17; head_lines=18; upstream_lines=18 | | `frontend/src/app/(marketing)/landing-cta.tsx` | same path; line-set Jaccard=0.865; shared_lines=45; head_lines=49; upstream_lines=48 | | `frontend/src/app/(marketing)/page.tsx` | same path; line-set Jaccard=0.977; shared_lines=340; head_lines=344; upstream_lines=344 | | `frontend/src/app/(marketing)/privacy/page.tsx` | same path; line-set Jaccard=0.895; shared_lines=17; head_lines=18; upstream_lines=18 | | `frontend/src/app/(marketing)/terms/page.tsx` | same path; line-set Jaccard=0.895; shared_lines=17; head_lines=18; upstream_lines=18 | | `frontend/src/app/opengraph-image.tsx` | same path; line-set Jaccard=0.933; shared_lines=84; head_lines=87; upstream_lines=87 | | `frontend/src/components/dashboard/create-project-dialog.tsx` | same path; line-set Jaccard=0.849; shared_lines=1960; head_lines=2218; upstream_lines=2050 | | `frontend/src/components/dashboard/onboarding-survey.tsx` | same path; line-set Jaccard=0.980; shared_lines=100; head_lines=101; upstream_lines=101 | | `frontend/src/components/dashboard/project-card.tsx` | same path; line-set Jaccard=0.882; shared_lines=134; head_lines=147; upstream_lines=139 | | `frontend/src/components/dashboard/projects-table.tsx` | same path; line-set Jaccard=0.917; shared_lines=143; head_lines=153; upstream_lines=146 | | `frontend/src/components/layout/sidebar.tsx` | same path; line-set Jaccard=0.685; shared_lines=185; head_lines=250; upstream_lines=205 | | `frontend/src/components/legal/changelog-timeline.tsx` | same path; line-set Jaccard=0.974; shared_lines=151; head_lines=153; upstream_lines=153 | | `frontend/src/components/legal/legal-page.tsx` | same path; line-set Jaccard=0.983; shared_lines=116; head_lines=117; upstream_lines=117 | | `frontend/src/components/pdf/pdf-viewer-panel.tsx` | same path; line-set Jaccard=0.992; shared_lines=257; head_lines=258; upstream_lines=258 | | `frontend/src/components/report/component-group.tsx` | same path; line-set Jaccard=0.911; shared_lines=82; head_lines=88; upstream_lines=84 | | `frontend/src/components/report/finding-card.tsx` | same path; line-set Jaccard=0.696; shared_lines=167; head_lines=231; upstream_lines=176 | | `frontend/src/components/report/finding-focus-view.tsx` | same path; line-set Jaccard=0.935; shared_lines=115; head_lines=122; upstream_lines=116 | | `frontend/src/components/report/findings-list.tsx` | same path; line-set Jaccard=0.824; shared_lines=136; head_lines=161; upstream_lines=140 | | `frontend/src/components/report/report-filters.tsx` | same path; line-set Jaccard=0.678; shared_lines=78; head_lines=115; upstream_lines=78 | | `frontend/src/components/report/report-summary.tsx` | same path; line-set Jaccard=0.872; shared_lines=68; head_lines=77; upstream_lines=69 | | `frontend/src/components/upload/file-upload-zone.tsx` | same path; line-set Jaccard=0.364; shared_lines=55; head_lines=143; upstream_lines=63 | | `frontend/src/hooks/use-optional-auth.ts` | same path; line-set Jaccard=0.198; shared_lines=24; head_lines=113; upstream_lines=32 | | `frontend/src/hooks/use-pipeline-progress.ts` | same path; line-set Jaccard=0.953; shared_lines=202; head_lines=212; upstream_lines=202 | | `frontend/src/hooks/use-report.ts` | same path; line-set Jaccard=0.263; shared_lines=15; head_lines=50; upstream_lines=22 | | `frontend/src/hooks/use-reviewed-count.ts` | same path; line-set Jaccard=0.688; shared_lines=22; head_lines=31; upstream_lines=23 | | `frontend/src/hooks/use-reviewed-findings.ts` | same path; line-set Jaccard=0.841; shared_lines=58; head_lines=67; upstream_lines=60 | | `frontend/src/lib/api.ts` | same path; line-set Jaccard=0.726; shared_lines=605; head_lines=816; upstream_lines=622 | | `frontend/src/lib/csp-hosts.ts` | same path; line-set Jaccard=0.500; shared_lines=7; head_lines=13; upstream_lines=8 | | `frontend/src/lib/report-export.ts` | same path; line-set Jaccard=0.860; shared_lines=49; head_lines=56; upstream_lines=50 | | `frontend/src/lib/site.ts` | same path; line-set Jaccard=0.895; shared_lines=51; head_lines=54; upstream_lines=54 | | `frontend/src/lib/types.ts` | same path; line-set Jaccard=0.570; shared_lines=241; head_lines=419; upstream_lines=245 | | `frontend/src/lib/version.ts` | same path; line-set Jaccard=0.333; shared_lines=2; head_lines=4; upstream_lines=4 | | `scripts/dedup_library_datasheets.py` | same path; line-set Jaccard=0.975; shared_lines=78; head_lines=79; upstream_lines=79 | | `skills/extract-pintable/schema.json` | same path; line-set Jaccard=0.522; shared_lines=35; head_lines=67; upstream_lines=35 | | `skills/extract-pintable/validate.py` | same path; line-set Jaccard=0.416; shared_lines=57; head_lines=137; upstream_lines=57 | | `taxonomy/crystal.json` | same path; line-set Jaccard=0.857; shared_lines=18; head_lines=21; upstream_lines=18 | | `taxonomy/passive.json` | same path; line-set Jaccard=0.955; shared_lines=42; head_lines=43; upstream_lines=43 | | `tests/conftest.py` | same path; line-set Jaccard=0.939; shared_lines=31; head_lines=33; upstream_lines=31 | | `tests/impedancefinder/__init__.py` | identical blob to upstream backend/__init__.py (rename/move) renamed_from=`backend/__init__.py` | | `tests/test_cost_estimator.py` | same path; line-set Jaccard=0.970; shared_lines=64; head_lines=65; upstream_lines=65 | | `tests/test_cost_estimator_model_aware.py` | same path; line-set Jaccard=0.530; shared_lines=70; head_lines=94; upstream_lines=108 | | `tests/test_datasheet_excerpt_tool.py` | same path; line-set Jaccard=0.962; shared_lines=150; head_lines=153; upstream_lines=153 | | `tests/test_dedupe_findings.py` | same path; line-set Jaccard=0.849; shared_lines=107; head_lines=125; upstream_lines=108 | | `tests/test_edif_parser.py` | same path; line-set Jaccard=0.970; shared_lines=129; head_lines=131; upstream_lines=131 | | `tests/test_led_current_check.py` | same path; line-set Jaccard=0.957; shared_lines=90; head_lines=92; upstream_lines=92 | | `tests/test_netlist_parser.py` | same path; line-set Jaccard=0.974; shared_lines=76; head_lines=77; upstream_lines=77 | | `tests/test_normalize_findings.py` | same path; line-set Jaccard=0.869; shared_lines=153; head_lines=175; upstream_lines=154 | | `tests/test_pin_mux_check.py` | same path; line-set Jaccard=0.828; shared_lines=154; head_lines=183; upstream_lines=157 | | `tests/test_purple_parts_resolver.py` | same path; line-set Jaccard=0.961; shared_lines=368; head_lines=375; upstream_lines=376 | | `tests/test_validation_concurrency.py` | same path; line-set Jaccard=0.961; shared_lines=146; head_lines=149; upstream_lines=149 | | `tests/test_validation_deterministic_seed.py` | same path; line-set Jaccard=0.970; shared_lines=64; head_lines=65; upstream_lines=65 | | `tests/test_validation_no_tool_recovery.py` | same path; line-set Jaccard=0.951; shared_lines=136; head_lines=140; upstream_lines=139 | | `tests/test_validation_trace_log.py` | same path; line-set Jaccard=0.961; shared_lines=172; head_lines=176; upstream_lines=175 | | `vendor/impedancefinder/__init__.py` | identical blob to upstream backend/__init__.py (rename/move) renamed_from=`backend/__init__.py` | ### REPLACEMENT (4) | Path | Evidence | | --- | --- | | `README.md` | same path; low overlap Jaccard=0.133; shared_lines=10; head_lines=54; upstream_lines=31 | | `frontend/src/components/layout/sidebar-auth.tsx` | same path; low overlap Jaccard=0.105; shared_lines=6; head_lines=55; upstream_lines=8 | | `frontend/src/lib/auth.ts` | same path; low overlap Jaccard=0.093; shared_lines=4; head_lines=35; upstream_lines=12 | | `skills/extract-pintable/SKILL.md` | same path; low overlap Jaccard=0.066; shared_lines=10; head_lines=114; upstream_lines=48 | ### NEW (139) | Path | Evidence | | --- | --- | | `backend/periscopex/antenna_geometry.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/antenna_rf.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/bom_match_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/cad_bridge.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/crystal_cl_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/dnp_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/errata_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/eval_report.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/filter_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/finding_engine.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/functional_groups.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/hf_coverage_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/impedance.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/impedance_traces.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/internal_features_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/layout_rules.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/library_gate.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/lifecycle.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/nc_pin_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/netlist_bundle.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/parsers_kicad.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/parsers_kicad_pcb.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/passive_rail_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pcb_checks.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pcb_inventory.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pcb_net_match.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pcb_power_thermal.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pcb_review.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/pdf_text.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/placement_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/placement_pack.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/power_margin_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/quote_verify.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/review_fingerprint.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/review_workflow.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/sequencing_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/si_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/periscopex/thermal_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/routers/auth.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/routers/impedance.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/datasheet_finder.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/llm/deepseek_provider.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/llm/local_skill.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/llm/pdf_ingest.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/local_jwt.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/local_users.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/mouser.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/passive_from_distributor.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/passive_from_mpn.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/passive_from_value.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/pcb_pipeline.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/pcb_validation.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/placement_pipeline.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/services/user_directory.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `backend/vendor_path.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `docker-compose.yml` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `docs/motore-finding.md` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `docs/piano-implementazione.md` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `docs/piano-pcb-review.md` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/dockerfile` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/app/(app)/library/page.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/app/(app)/project/[id]/pcb/page.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/app/(app)/project/[id]/placement/page.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/app/(marketing)/sign-in/page.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/app/(marketing)/sign-up/page.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/layout/auth-gate.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/project/impedance-panel.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/project/pcb-upload.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/project/topology-panel.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/report/finding-review-controls.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/components/report/pcb-exam-section.tsx` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/hooks/use-pcb-progress.ts` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/hooks/use-placement-progress.ts` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/lib/layout-finding.ts` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `frontend/src/lib/storage-keys.ts` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `plugins/__init__.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `plugins/kicad/__init__.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `plugins/kicad/focus.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `plugins/kicad/periscope_plugin.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `scripts/smoke_simple_project.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `scripts/update-periscope.sh` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `simple_project/eval_golden.json` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `simple_project/smoke_baseline.json` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/impedancefinder/conftest.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/impedancefinder/test_geometry.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/impedancefinder/test_net_walk.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/impedancefinder/test_planes.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/impedancefinder/test_zsolver.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_antenna_rf.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_bom_match_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_bom_parser.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_cad_bridge.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_crystal_cl_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_datasheet_finder.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_deepseek_only.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_deepseek_provider.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_derating.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_digikey_match.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_dnp_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_errata_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_eval_report.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_event_bridge.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_filter_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_finding_engine.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_finding_schema.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_functional_groups.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_hf_coverage_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_impedance.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_impedance_traces.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_internal_features_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_job_runner.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_kicad_parser.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_kicad_pcb.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_layout_rules.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_library.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_lifecycle_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_local_auth.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_nc_pin_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_netlist_bundle.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_passive_from_distributor.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_passive_from_mpn.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_passive_from_value.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_passive_rail_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_pcb_review.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_pdf_ingest.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_placement_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_placement_pack.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_placement_pipeline.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_power_margin_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_quote_verify.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_reopen_replace.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_reprocess.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_review_fingerprint.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_review_parse.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_review_workflow.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_roadmap_integrations.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_sequencing_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_si_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | | `tests/test_thermal_check.py` | path absent from upstream/main; no identical-SHA or >=0.15 Jaccard rename match | ### THIRD_PARTY (9) | Path | Evidence | | --- | --- | | `vendor/impedancefinder/SOURCE.md` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/geometry.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/model.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/net_analysis.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/net_walk.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/planes.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/report.py` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/stackup.schema.yml` | lives under vendor/; see SOURCE.md if present | | `vendor/impedancefinder/zsolver.py` | lives under vendor/; see SOURCE.md if present | ### UNKNOWN (0) | Path | Evidence | | --- | --- |