Dependabot for electronic components. A hardware repo commits its BOM; BOMGuard watches the manufacturers' PCN/End-of-Life feeds, and when a chip in your shipping product gets discontinued it opens an evidence-backed GitHub issue before the last-time-buy deadline passes — and repairs its own scrapers when the manufacturer site changes under it.
Built for the Into the Scrape-Verse hackathon with Bright Data Scraper Studio (custom collectors, same-ID self-healing).
A missed discontinuation notice can strand a physical product on an unobtainable component. Enterprise BOM-monitoring SaaS charges ~$250+/mo and hides the source. Small hardware teams get nothing. Manufacturer pages are heterogeneous, frequently redesigned, and break scrapers quietly — the worst kind of failure, because nobody notices until the order fails.
BOMGuard is open-source, GitHub-native, and treats the manufacturer page as the source of truth — permanently frozen at the moment of collection via content-hashed, WARC-referenced evidence.
Bright Data Collector (custom, c_* ID)
│
▼
Raw immutable observation ──────────► WARC / content-hash evidence
│
▼
Typed source adapter (NXP / onsemi / Microchip)
│
▼
Data-contract validator
│ healthy │ unhealthy
▼ ▼
Normalize Diagnose failure ("affected_mpn null in 92%…")
│ │
│ Same-ID heal (strategy battery / bdata scraper heal)
│ │
│ Preview + revalidate
│ │
▼ ▼
Last-known-good store (frozen until a passing run)
│
▼
Domain matching (conservative MPN + packaging aliases)
│
▼
Change detection → GitHub issue (evidence-backed) / dashboard
uv sync
bomguard init . # scaffold config + example boards + fixtures
bomguard fetch # collect + validate NXP & onsemi (fixtures)
bomguard scan --issues # match BOMs, open deduped issues
bomguard serve # http://127.0.0.1:8000 dashboardFull demo including the break-and-heal story:
scripts/demo.shif not rows: heal() is not enough — a redesign can keep the row count while
every affected_mpn goes null. BOMGuard validates collector output against a
per-source data contract:
min row count · required-field null rate · valid notice-ID pattern
valid MPN rate · date-parse success rate · duplicate notice/MPN rate
source-URL validity · historical row-count deviation · unexpected schema fields
When the contract fails:
- Diagnose — one precise sentence, e.g.
affected_mpn null/invalid in 100% of records after the table moved under a details accordion. - Heal on the same Collector ID — locally by walking the extraction
strategy battery (documented selector → structural fallback → regex row
scrape) over the same broken bytes; in production by invoking
bdata scraper heal <c_*id> "<diagnosis>"(Bright Data's AI refactor keeps the ID) thenapprove. - Preview + revalidate the proposed revision before promotion.
- Promote only a passing revision; bump
collector_version. - Preserve last-known-good — the old dataset is frozen (never deleted) so consumers keep working until a passing run.
- Record everything in an append-only healing ledger (old/new revision, diagnosis, content hashes, preview result, timestamps).
State machine: HEALTHY → CONTRACT_FAILED → DIAGNOSING → HEALING → PREVIEWING → PROMOTED (any failure → UNHEALTHY, LKG preserved). Covered by tests
(tests/test_heal.py).
bomguard fetch— dashboards go green (37 components monitored, 0 alerts).bomguard scan --issues— one BOM line is a real NXP part about to be EOL'd: MCIMX31LCVKN5D — Last-time-buy 2026-10-09; another has a manufacturer replacement (NTS0304EPWJ → NTS0302JKZ, flagged as requiring engineering qualification). Issues open with the full evidence.- The site changes (
?broken=1) — contract fails, strategy battery heals, same collector, promoted 1.0 → 1.1, ledger shows the preview. - Worse break (
?broken=2) — collectible data gone; collector goesUNHEALTHYwith the famous diagnosis, last-known-good still served. - Site recovers — green again, no consumer code changed.
- "The website changed. The product did not break."
- Custom collectors created with the
bdataCLI:bdata scraper create <url> "<field description>"→c_*Collector ID (exact prompts for NXP / onsemi / Microchip inscraper-studio/README.md). - Run:
bdata scraper run <c_*id> <url>→ structured rows, validated by the same contracts as our local twins. - Self-healing:
bdata scraper heal <c_*id> "<diagnosis>"+approve(or--auto-approve) — the repair keeps the same Collector ID. - The adapter lives in
bomguard/adapters/brightdata.py; the runner path inbomguard/runner.py.bdata login(OAuth once) orBRIGHTDATA_API_KEY(headless CI). WARC snapshots back every alert as evidence.
| Requirement | Proof in this repo |
|---|---|
| Custom Scraper Studio collector | scraper-studio/README.md — prompts + CLI flow; adapter tested against real CLI output shapes |
| Real run (offline twin) | examples/structured-output/sample.json — real NXP + onsemi captures |
| Live Scraper Studio run | ✓ NXP collector c_mt3z272b1qdvxauw57 ran the real 202606009DN EOL (105 parts, LTB 2026-10-09) + 202409026DN, contract passed, 4 alerts → issues (examples/structured-output/nxp-live-run.json) |
| Live same-ID heal | ✓ real bdata scraper heal + --auto-approve --auto-save completed on the same collector (template saved; envelope in examples/structured-output/nxp-heal-envelope.json) — surfaced in the ledger via bomguard heal-live |
| Downstream use | examples/control-board/.issues/*.md + dashboard — EOL with 2026-10-09 LTB (live countdown) |
| Failure detected | tests/test_validate.py, tests/test_heal.py; ledger diagnosis lines |
| Self-heal | strategy battery → PROMOTED 1.0 → 1.1, same collector ID (ledger) |
| Recovery | re-run passes, downstream schema unchanged |
| Evidence (WARC) | content-addressed WARC snapshots of every collected page under evidence/, referenced by all notices and alerts |
| Public-data compliance | public manufacturer pages only; no login/paywall/personal/government data |
| Reproducibility | uv sync && bomguard init . … one-command local demo; 82 tests |
| Live Bright Data run (pending creds) | bdata login once → set collector_id in config → bomguard fetch |
bomguard/ core package
models.py typed schema (notice, bom, contract, healing ledger)
normalize.py conservative MPN canonicalization + packaging aliases
validate.py per-source data contracts (the failure detector)
heal.py healing state machine + strategy battery
store.py SQLite: last-known-good, observations, ledger, alerts
intercept.py fixture / httpx / browser / brightdata transports
collectors/ NXP (grounded), onsemi (grounded), Microchip, chaos
adapters/ Bright Data bdata CLI adapter
runner.py transport dispatch (local HTML vs Scraper Studio JSON)
rows.py Scraper Studio rows -> typed notices (field-map aware)
issue.py GitHub issue providers (API + offline mock)
server.py dashboard (health, alerts, notices, ledger)
chaos_server.py controlled breakable NXP-shaped page for the demo
cli.py bomguard fetch/scan/…/ledger/serve/chaos
fixtures/raw/ real pages captured from nxp.com and onsemi.com (evidence)
scraper-studio/ collector prompts + integration notes
examples/ control-board demo + structured output sample
.github/ nightly GitHub Action (fetch → self-heal → issues)
tests/ 82 tests (normalize, validate, heal, match, parsers, service, collectors)
- Conservative matching, no LLM part equivalence. Canonical MPN equality plus documented packaging variants (tape/reel) and explicit config aliases. Manufacturer-listed replacements are candidates requiring qualification — NXP itself disclaims form/fit/function equivalence.
- The page is the source of truth. Every alert carries
source_url,source_content_hash,warc_reference, collector id/version — reproducible evidence, not a JSON-only claim. - Local twins of the collectors make the whole pipeline testable without the platform, and make the trip-wire (contract) and the repair (battery / heal API) independently verifiable.
- Live NXP collector runs are proven; onsemi and Microchip collectors are
defined (prompts + local twins + Bright Data reachability verified for
Microchip) — their AI generation is slower against heavy/JS pages, so the
on-repo
collector_ids for those two are set once generation completes. - Every collected page is frozen to a content-addressed WARC snapshot
(
evidence/,BOMGUARD_EVIDENCE_DIR) and every notice references it; a live remote WARC fetch remains a one-flag change onbdata scraper run. bomguard heal-livedrives a real same-ID Bright Data heal on demand and records it in the ledger; the automatic contract-failure heal does the same (the runner already self-heals without any flag).
Built with an AI coding assistant — DeepSeek V4 Flash (model id 0731) — pair-programming the implementation (scraper collectors, orchestration, tests). The architecture, data contracts, and every test expectation are specified, reviewed and verified by a human; the author can explain all of it. Original work completed during the hackathon window per the event rules.
MIT