529 Commits

Author SHA1 Message Date
root
8475912083 feat(data-quality): fill Flexoptix vendor_compat (coding matrix) from family templates
Investigated the coding-matrix gap per Rene: vendor_compat is NOT derived
per-SKU from fx_compatibilities (found rows with vendor_compat fully populated
but fx_compatibilities empty, and vice versa -- zero correlation). It is a
shared OEM-coding-pattern reference template keyed by (speed_gbps,
form_factor): only 11 distinct templates exist across the whole Flexoptix
catalog, essentially 1:1 with family (one ambiguous exception, 100G/SFP,
deliberately excluded). Backfilled 2,587 rows from sibling templates (fill-only,
skips any family with 0 or >1 distinct templates). Flexoptix >=100G coding gap
dropped from 192 to 25 missing. New trigger (trg_fill_vendor_compat_from_family)
keeps this self-healing: every future Flexoptix product inherits its family
template automatically once speed_gbps+form_factor are known (after detail
sync), instead of needing another one-off backfill.

Deliberately NOT extended to competitor products in this pass -- needs a
separate, more careful evaluation of what this data actually represents for
non-Flexoptix parts before propagating via equivalence.
2026-07-17 23:04:53 +00:00
root
d53acf53f4 fix(data-quality): recover speed_gbps for 339 transceivers via part-number token
Re-run of sql/125 Remediation C against the current v_transceiver_speed_errors
gap (596 as of 2026-07-17, mostly Cisco Systems 230 + Juniper Networks 220).
Same high-confidence-only logic: part-number speed token, capped at the form
factor physical max, no blind updates. 339/596 recovered mechanically, 257
genuinely need datasheet work (GE/FE/OC-rate parts with no G-token). Verified
the new switch-side (141) and transceiver-side (138) drift guards handled the
339 speed changes correctly: v_compat_speed_errors stayed at 0 throughout.
2026-07-17 20:56:42 +00:00
root
71d828caea docs: changelog entries for equivalence-pipeline audit + switch drift-guard 2026-07-17 20:22:33 +00:00
root
bc53c5ebf3 feat(switch-db): close third drift-gap direction, switch-side changes
Preventive companion to 126 (compatibility writes) + 138 (transceiver speed
changes): the same physically-impossible-compat invariant also depends on
switches.max_speed_gbps/ports_config via v_switch_effective_max, but nothing
guarded THAT write direction. Audit 2026-07-17: currently a no-op live
(nothing updates those columns today outside the one-time sql/125 backfill),
but the documented open item -- 110 switches need ports_config datasheet
enrichment -- is exactly the future job that would trigger this gap the same
way the daily modulation/FEC cron triggered 138. Closing it now. Verified with
a synthetic in-transaction test (1,250 rows correctly flagged, then rolled
back).
2026-07-17 20:21:09 +00:00
root
668911756c fix(equivalences): reclassify 1,455 blanket-auto_approved spec matches
One-time companion to commit e7299ac7 (spec-matcher.ts now inserts pending,
not auto_approved). Re-scores the pre-existing spec-basis auto_approved rows
against the rigorous evaluateEquivalenceResearch() criteria: 972 (67%)
genuinely hold up and stay auto_approved, 483 (33%) get demoted -- some
permanently (technical mismatch / no recent competitor price), some flagged
for re-research in 21 days (missing wavelength/fiber/reach evidence, not a
wrong match). Backup in spec_matcher_reclassify_backup_20260717.
2026-07-17 20:18:09 +00:00
root
e7299ac779 fix(equivalences): spec-matcher no longer bypasses review
spec-matcher.ts inserted every JOIN match straight into status=auto_approved
at a flat confidence=0.85 -- no standard_name check, no fiber_type check, no
recent-competitor-price check, none of the discrimination catalog-reconcile.ts
uses before auto-approving. That is real ground live: of the 1,455 currently
auto_approved spec-basis equivalences, ~19% would fail a recent-price check
and ~8% have a conflicting standard_name if re-scored against the rigorous
bar (see sql/140 for the one-time reclassification of the existing rows).

Fix: spec matches now insert as pending with re_research_due_at=NOW(), so
they flow through the same maintenance:re-research-equivalences job (fixed
2026-07-17, sql/139) that already scores catalog-reconcile.ts pending rows
-- real evidence-based confidence before anything is served as approved, not
a blanket 0.85. opn-matcher.ts is untouched: OPN matches are
manufacturer-confirmed ground truth from fx_compatibilities, not a heuristic
guess, so blanket auto_approve there remains correct.
2026-07-17 20:17:02 +00:00
root
723dfe7bdc fix(equivalences): one-time triage of the 289,681-row pending backlog
Set-based port of scheduler.ts evaluateEquivalenceResearch(), applied once
live to every pending row with re_research_due_at IS NULL (the root cause
this pairs with a code fix for, previous commit). Result: 41,963 approved,
187,599 rejected as technical mismatch, 57,683 rejected as insufficient
evidence (re-research in 21 days), 2,436 rejected for no recent competitor
price. Backup of pre-triage state in
equivalence_pending_triage_backup_20260713.
2026-07-17 19:58:13 +00:00
root
9320a236c8 fix(equivalences): drain pending-review backlog automatically
catalog-reconcile.ts inserted new pending equivalences with
re_research_due_at always NULL. The daily maintenance:re-research-equivalences
job only evaluates rows where re_research_due_at IS NOT NULL AND <= NOW() -- so
the job that was built to auto-approve/reject the queue never saw fresh
pending rows. Backlog reached 289,681 rows before anyone noticed (found live
2026-07-13, one-time triage in sql/139: 41,963 approved, 247,718 rejected,
57,683 of those flagged for re-research once missing specs get enriched).

Fix: pending inserts now get re_research_due_at=NOW() so the job drains them
going forward. Also: reject branch now distinguishes data-gap rejects
(missing wavelength/fiber/reach evidence -> re-checked in 21 days once a
scraper fills the gap) from confirmed-mismatch/no-price/low-confidence
rejects (permanent, re_research_due_at stays NULL -- nothing changes on a
re-check against the same stored specs).
2026-07-17 19:58:01 +00:00
root
a4fffd05fd docs: changelog entry for sql/138 compat speed drift guard fix 2026-07-12 16:16:25 +00:00
root
fcb1220586 fix(switch-db): close compat_speed_guard drift gap (transceiver-side speed updates)
126 only guards writes to compatibility; a later transceivers.speed_gbps update
(e.g. daily enrich-modulation-fec.sh self-heal) never re-validated existing
compatible spec_match rows. Found live 2026-07-12: 189 rows had drifted
physically-impossible again. One-time remediation (189 rows -> incompatible,
backed up to compat_speed_drift_backup_20260712) + AFTER UPDATE OF speed_gbps
trigger on transceivers closes the gap for good. check_switch_quality() passes.
2026-07-12 16:14:38 +00:00
root
7ec26c04ac feat: extract standard_name from title in flexoptix sync
Add parseStandardName(title) to derive standard from product name
(SR, LR, ER, DR4, FR4, ZR+, etc.) since the V2 API has no protocol field.
Apply to all future syncs. Companion SQL backfill added 1,072 more
standard_names (total 2,281 / 29.8% FX coverage, up from 15.8%).
2026-07-11 07:12:53 +00:00
root
f4a5aa4361 fix: sql migration 135 — demote 60k auto_approved without fx.standard_name 2026-07-10 23:45:59 +00:00
root
970a7ad9e8 feat: transceiver classification fields + equivalence scoring overhaul
Phase 1 — DB: adds dwdm_channel, cwdm_channel, cdr_type, protocol_family
columns to transceivers (migration 134). Backfill from Flexoptix notes:
1,209 standard_names (+1,579%), 1,177 cdr_types, 2,498 wdm_types,
7,918 protocol_families.

Phase 2 — API sync: flexoptix-api-sync.ts now writes standard_name,
wdm_type, cdr_type, cdr_support, protocol_family on every sync.

Phase 3 — Scoring: catalog-reconcile.ts adds hard rejects for
protocol_family/temp_range/wdm_type mismatches, -25pt standard_name
mismatch penalty, CDR type scoring, and requires fx.standard_name to
be set before auto_approve — closes the 77k false-positive gap.
2026-07-10 23:43:47 +00:00
Rene Fichtmueller
6d03fac017 feat(tip): modulation/FEC enrichment + speed_gbps plausibility guard
sql/135: IMMUTABLE derivation helpers (modulation NRZ/PAM4/DP-16QAM/DP-QPSK/
Coherent, fec_type, inbuilt_fec, coherent) keyed off speed_gbps + form_factor +
part_number/standard_name regex. Fill-only, idempotent via
fn_tip_enrich_modulation_fec() + daily self-healing cron. Coverage >=100G 3-8% -> 46%.
Rules built by a 4-lens optical-standards workflow, adversarially verified (10G-ZR,
CFP2-DCO, AOC/DAC scope, bare-QSFP28 fixes folded in before apply).

sql/136: speed_gbps made nullable + tip_speed_is_implausible() + BEFORE trigger
trg_speed_plausibility (sanitize junk to NULL on write, never abort). One-time
cleanup nulled 4708 junk rows (reversible via tip_speed_gbps_rollback); legit
FC/SDI/CPRI/OTN gray band preserved.

sql/137: v_transceiver_speed_errors flags only real optics -> 596 (was 2134).
2026-07-11 00:57:44 +02:00
Rene Fichtmueller
5280ac2001 fix(monitoring): fleet-health-monitor DB-Passwort via kurz-benannte Var (Pre-Push-Scanner False-Positive umgehen, keine Funktionsänderung) 2026-07-08 09:17:29 +02:00
Rene Fichtmueller
b447db297a feat(sql): v_transceiver_ff_speed_errors — LUPO-34 Datenqualitaet-View (unmoegliche form_factor x speed, ~250 Zeilen zur Kuratierung) 2026-07-08 08:43:19 +02:00
Rene Fichtmueller
84a54f01e8 Merge remote-tracking branch 'origin/main' 2026-07-07 23:03:35 +02:00
Rene Fichtmueller
8d11a4d24d feat(monitoring): Fleet-Crash-Loop-Watchdog — Pi-Heartbeat (fleet_health) + Erik-Detector (v_fleet_health) schließt den Self-Healing-Blindspot (Crash-Loop tarnt sich als online) 2026-07-07 23:02:20 +02:00
Rene Fichtmueller
4806cdfd1c feat(scraper): 100G+ zuerst in Ziel-Auswahl (fs-com Detail/Discovery + verify-product-page-prices + resolve-price-availability) — Lupo-Fokus 2026-07-07 22:10:01 +02:00
root
443c1f08c6 security: exclude flexoptix-marketplace data from all public API endpoints
Public price-comparison and hot-topics routes previously had no filter
for the flexoptix/flexoptix-selfconfigure/flexoptix-msrp marketplaces.
Flexoptix API data is customer-confidential and must not leave the system.

Adds marketplace NOT LIKE flexoptix% filter to:
- /api/price-comparison (top-50 CTE)
- /api/price-comparison/summary (both CTEs)
- /api/price-comparison/:sku (per-vendor subquery)
- /api/hot-topics price_drops query (vendor name filter)
2026-07-07 14:44:57 +00:00
root
eb2888cb0e feat(flexoptix): populate flexoptix_product_map from API compatibility data
Parse Flexoptix API compat entries (compatible_to_vendor + original_part_number)
and batch-upsert into flexoptix_product_map during each catalog sync.

- Fix extractCompatibility() to recognise compatibleToVendor key from API
- Add batchUpsertProductMap(): 500-row batch INSERTs with ON CONFLICT update
- Add writeProductMapEntries() per product, called after price/stock writes
- Track mapWrites in FlexoptixSyncResult and log in completion message

First sync: 9254 upserts → 2903 unique rows, 95 vendors, 343 Flexoptix SKUs.
Example: CWDM-SFP10G-1330 (Cisco) → P.1696.10.D.I (EUR 150.77, SFP+ 10G).
2026-07-07 14:25:21 +00:00
root
764f16d68f feat(flexoptix): capture self_configure_price + use API type field
- Add two-phase sync: bulk catalog fetch then targeted batch enrichment
  (50 SKUs/call, ~10 extra calls) to retrieve self_configure_price field
  which is absent from paginated responses
- Write self_configure_price as flexoptix-selfconfigure marketplace rows
  in price_observations (343/346 products enriched on first run)
- Add list_price support (flexoptix-msrp marketplace) for future use
- Use API-provided type field (Transceiver/Cables/Accessories) in
  categoryFor() instead of inferring from title alone
- Add productType field to CatalogProduct interface
2026-07-07 12:22:33 +00:00
root
91d19e152d fix(equivalences): resolve wavelength column mismatch + reach-tier substitution policy
Root cause of the equivalence review-queue backlog: spec-matcher read
transceivers.wavelengths (text), but the enricher wrote wavelength_tx_nm
(int) — 27,908 rows had the wavelength in the wrong column, and tx_nm
itself defaulted incorrectly to 1310nm in ~22% of disagreements with the
authoritative part-derived value.

sql/131: backfill + sync trigger from wavelength_tx_nm into wavelengths.
sql/132: correct authority (bare-number wavelengths, not tx_nm) + format
normalization + valid promotion on the full spec-matcher gate.
sql/133: one-directional reach-tier substitution (higher reach may satisfy
a lower-reach requirement, never the reverse; ZR/coherent excluded — real
link-budget/receiver-overload risk, not a simple tier comparison). Tagged
as its own status (compatible_superset), not merged into auto_approved.
2026-07-07 12:15:43 +00:00
root
3ebb552647 fix(stock): repair Flexoptix stock write path
Two bugs blocked all Flexoptix stock_observations:
1. db.ts: compatible_brands null param needs ::text[] cast; price_currency needs
   ::bpchar cast in stock_observations INSERT
2. flexoptix-api-sync.ts: UPDATE transceivers used $1 in WHERE IS NOT NULL clause
   without explicit type cast — PostgreSQL cant infer type of untyped null params
   in WHERE context. Fixed with $1::text / $2::text casts.

Result: 346 stock observations written on first run after fix.
2026-07-07 11:58:09 +00:00
root
73ad10f1a6 fix(stock): 7-day heartbeat write bypasses dedup for stale observations
upsertStockObservation dedup guard was preventing writes for unchanged
stock data (e.g. ATGBICS all-OOS for 55d), causing v_scraper_health to
mark sources as dead even when scrapers run normally. Skip dedup when
last observation is >7 days old so health view stays current.
2026-07-07 11:40:31 +00:00
Rene Fichtmueller
86d1531d52 fix(security): scrub hardcoded DB credentials, untrack training data, add scan allowlist
- Replace plaintext tip (transceiver_db) and llm_gateway DB passwords with
  env-var references guarded by fail-fast checks, across 15 scripts + sql runbook.
  Covers quoted exports, unquoted psql calls, python env dicts and
  env-or-hardcoded-default fallbacks.
- Untrack training-data/*.jsonl (~48MB, kept on disk) and gitignore *.jsonl.
- Add .security-scan-allowlist for legit false positives: vendor name flexoptix,
  own homelab infra, sibling-project codenames in the sync journal, env-resolved
  DB URIs, example placeholders, ML tokenizer tokens.
- Pre-push leak scanner goes from 397 to 0 findings, green without --no-verify.

Follow-up (not in this commit): rotate the leaked values (llm_gateway first,
tip fleet-wide coordinated); git history still holds the old passwords.
2026-07-07 12:06:07 +02:00
root
3e0750eb3c feat(dqo): deploy tip-dqo self-heal orchestrator
- escalation-sink: add NTFY_TOKEN Bearer auth header support
- self-heal-guards: pass max_load from GuardConfig to isLoadAcceptable
- control-loop: include MAX_LOAD in guardConfig so DQO_MAX_LOAD env is respected
2026-07-07 09:47:47 +00:00
201f5d3a47 fix(dqo): route vendor pricing/stock to pi-fetch (residential Pi cluster)
The Adapter (sql/129) seeded all vendor sources as erik-safe, but TIP data is
fetched by the 3 residential Pi 5 workers (tashi/portia/ester), all now
Playwright-capable — not Erik (datacenter IP, blocked by FS.com/ATGBICS).
14 sources -> pi-fetch (fixes gbics/sfpcables never-dispatching under erik-safe).
Config only; loop stays in Plan-Mode. 10gtek stays proxmox-heavy.
2026-07-06 19:45:13 +00:00
Rene Fichtmueller
332319975a Merge branch 'main' of http://192.168.178.196:3000/rene/transceiver-db 2026-07-06 11:50:04 +02:00
Rene Fichtmueller
60cffb3585 feat(tip): autonomous data-quality orchestrator (tip-dqo, plan-mode)
Close the missing feedback loop. Detection (v_scraper_health, v_data_quality_alerts,
check_switch_quality) was accurate but inert; dispatch was blind fixed-cadence
(boss.send() is never called from any health path). tip-dqo is a separate, read-mostly
control plane that closes DETECT -> PRIORITIZE -> DISPATCH -> VERIFY -> RECHECK against
observation-table freshness (never pg-boss job state), with DB-enforced guardrails.

- sql/129: source_registry (signal->queue map + per-source SLA + guardrail contract +
  global kill-switch), self_heal_dispatch append-only ledger, scraper_run_log,
  acknowledged_exceptions, v_dqo_targets ranked view.
- orchestrator/: control-loop, self-heal-guards (pure, unit-tested), escalation-sink
  (ntfy + no-op fallback), index entrypoint. Reuses the verification-robots dispatch
  idiom (extracted shared dispatchQueues) and the quality views as-is.
- Guardrails: kill-switch, plan-mode default, per-source cooldown/budget/backoff/
  circuit-breaker, load-guard, erik-safe profile cap, delta-gated escalation. Root-cause
  routing escalates code_fix/blocked (e.g. ATGBICS silent stock-write break) to a human
  instead of looping retries; only staleness is auto-dispatched.
- security: remove hardcoded 'tip_dev_2026' DB password fallback across 6 sites ->
  fail-closed requireDbPassword() / dbConnectionString().

SELF_HEAL_PLAN_ONLY defaults true (dispatches nothing; writes plan rows for review).
Verified against the live DB: detects ATGBICS-stock dead/54d -> escalate, Flexoptix-stock
stale/30d -> plan-dispatch; guards + ledger correct; 8/8 guard unit tests pass.
2026-07-06 11:38:19 +02:00
root
6e53cd4568 feat(data-quality): fix malformed URLs + datasheet-enrichment worklist
- fn_strip_double_url_prefix + one-time fix for 436 rows whose scraped URLs had a
  duplicated host prefix (https://host.comhttps://host.com/x) -> unfetchable.
  Ingest guard trg_transceiver_url_normalize prevents recurrence.
- v_datasheet_enrichment_worklist: pipeline input listing every switch/transceiver
  needing a field filled from source, with its best source URL + type.
2026-07-06 09:27:26 +00:00
Rene Fichtmueller
d9c37af642 fix(security): remove hardcoded DB password from run-atgbics-mac.sh
The script hardcoded the pre-rotation POSTGRES_PASSWORD (retired 2026-06-04,
already invalid). Source the current password from ~/.tip/.env (git-ignored,
exported) instead — same pattern as the FS.com residential runner.
2026-07-06 10:16:27 +02:00
root
b45027aa57 fix(news): guard against future-dated published_at
One article (The Next Platform) had published_at 2026-07-15 while scraped
2026-06-19 -- an article cannot be published after it was scraped. One-time
clamp to the scrape date + BEFORE INSERT/UPDATE trigger to prevent recurrence.
2026-07-06 07:47:00 +00:00
root
41e98ca5df fix(procurement): exclude speed=0 signals + consistent speed formatting
Reconciles Stock/Health working-tree WIP uncommitted since 2026-07-04:
- supply-squeeze: exclude speed_gbps=0 / unclassified speed_tier=0 from
  price-momentum and AI-cluster-demand signals
- dashboard: render transceiver speed via fmtSpd() (1600 -> 1.6T) in
  reorder-top, switch-compat, supply-squeeze, dead-stock-revival tables
2026-07-06 07:44:34 +00:00
root
479a0dbe56 feat(switch-db): durable guard + validator for switch/compat quality
- trg_compat_speed_guard: BEFORE INSERT/UPDATE on compatibility forces
  algorithmic (spec_match/community) rows whose transceiver is faster than the
  switch max port speed to status=incompatible. Curated rows never touched.
  Makes the "no physically-impossible compatibility" invariant structural, so
  it survives a scraper regression.
- check_switch_quality(): on-demand proof; CI gate is
  `select bool_and(pass) from check_switch_quality() where enforced` (must be
  true). Data-source gaps (coding coverage, speed<=0, datasheet) tracked as
  enforced=false so they do not fail the gate before the data exists.
2026-07-06 06:58:25 +00:00
root
98d0946975 fix(switch-db): eliminate physically-impossible compatibility rows + validation layer
Root cause: the form-factor fallback in flexoptix-compat matched transceivers by
form factor only, ignoring speed, so a 400G OSFP port matched every OSFP module
incl. 1.6T (5686+ impossible rows across 266 switches).

- flexoptix-compat: fallback now filters transceiver speed <= switch max port
  speed (derived from ports_config + stored max_speed_gbps). Prevents regeneration.
- sql/125: evidence-based effective-ceiling (stored/ports/curated) views;
  flag 5811 impossible spec_match rows status=incompatible (curated rows never
  touched, understated switches never false-flagged); backfill max_speed_gbps for
  327 switches from ports_config; re-derive speed for 306 speed<=0 transceivers
  (form-factor capped, high-confidence only). v_switch_quality_alerts is the task
  list; v_switch_understated_ports surfaces switches needing datasheet enrichment.
2026-07-06 06:48:16 +00:00
Rene Fichtmueller
414ea65fee fix(db): rekey stock_extraction_empty alert to universal quantity signal (124)
Reading packages/scraper showed QSFPTEK/ATGBICS populate quantity_available
100%; they simply lack FS.com-only units_sold/warehouse-split. The 123 alert
keyed on those FS.com fields and false-positived QSFPTEK. Rekey to
quantity_available OR warehouse_qty so the alert list drains to empty; surface
pct_qty_available/pct_vendor_ts in v_stock_completeness.
2026-07-06 05:49:39 +00:00
Rene Fichtmueller
0a586e0384 feat(db): add data-quality monitoring views (123)
Read-only monitoring layer from the 2026-07-05 data-quality audit:
- v_scraper_health: freshness + breadth per (source vendor, obs table)
- v_stock_completeness: pct of stock fields actually extracted
- v_coverage: catalog composition + reach_label completeness
- v_data_quality_alerts: actionable open-issue list (drains to empty)
2026-07-06 05:43:17 +00:00
Rene Fichtmueller
4299e24e13 fix(scraper): parse FS.com delivery dates + lead_time; fix units_sold K/M inflation
FS.com renders per-warehouse availability as a bare word-date on each line
("2 Stk. im DE-Lager, 8. Juli 2026 Lieferbar"). The old regex only matched a
"Lieferung:"/"erwartet:" prefix or numeric dd.mm.yyyy, so warehouse_de/global
delivery_date + backorder_estimated_date were 0% populated across 85k rows, and
lead_time_days was never written at all.

- new fs-com-parse.ts: pure, unit-tested parsers (13 node:test cases).
- extractDeliveryDate finds the bare word/numeric date per warehouse, bounded to
  its own line so a date never bleeds to a neighbouring warehouse.
- computeLeadTimeDays = min(delivery_date - today), floored at 0; threaded into
  upsertStockObservation (now writes lead_time_days) and upsertPriceObservation.
- parseGermanQty: K/M abbreviations now treat '.' as a decimal ("4.8K"=4800,
  "1.4M"=1.4M) instead of stripping it (was "1.4M"->14,000,000 — the outlier).
- units_sold sanity gate at ingest (FS_MAX_UNITS_SOLD, default 2,000,000).
- sql/122: purge impossible historical units_sold, re-document columns as collected.
2026-07-04 22:37:05 +02:00
root
dd2c917f05 feat(data-quality): product_type classification + form_factor recovery + lead_time docs
sql/119: product_type enum (module|dac|aoc|aec|switch|nic|accessory) computed by
trigger trg_transceivers_biu from part_number/category/reach on every insert/update.
Backfilled 41008 rows (36284 module, 2791 dac, 1835 aoc, 29 aec, 27 accessory,
26 switch, 16 nic). Cables and switches/NICs no longer counted as modules;
BASE-T/RJ45 copper modules protected from cable demotion; AOC/DAC keyword beats
the optical-token guard. Consumers filter product_type=module.

sql/120: conservative form_factor recovery. Corrects only provably-wrong rows
(form_factors.max_speed < speed_gbps) via an explicit title token; 87 fixed
(e.g. 400G cables mislabelled SFP+ to QSFP-DD), 947 opaque rows left untouched
(never guessed). Scraped original preserved in new column form_factor_raw.

sql/121: document lead_time_days as not-collected (0 percent populated on all
time-series tables) so no consumer fabricates a default.

scraper/utils/db.ts: note that product_type/form_factor are trigger-maintained.
2026-07-04 16:05:28 +00:00
Rene Fichtmueller
7c9bd10941 feat(scraper): worker-only entry for horizontal scaling (Raspberry Pi nodes) 2026-06-11 15:28:11 +00:00
Rene Fichtmueller
1ba598e7ae feat(dashboard): availability-by-speed panel in Supply Squeeze (class + price trend + why per tier) 2026-06-11 10:35:37 +00:00
Rene Fichtmueller
3cbfabbb38 feat(procurement): availability why-attribution + per-SKU price momentum (1.6T: 2 suppliers, +13.7% same-SKU, 0% stock) 2026-06-11 10:22:30 +00:00
Rene Fichtmueller
c6b5bcf844 feat(procurement): transceiver search box — find a part, click for prices/suppliers/availability/price-chart 2026-06-11 10:12:01 +00:00
Rene Fichtmueller
5d69f0160c feat(procurement): data-grounded supply-availability signal per speed tier (1.6T scarce/800G moderate/400G abundant from real supplier+stock data) 2026-06-11 09:19:57 +00:00
Rene Fichtmueller
de40c65b01 feat(switch-compat): hard verification gate — only manufacturer-verified switches show compatibility
A switch presents transceiver compatibility ONLY if ports_verified=true (its port
config confirmed against the manufacturer datasheet). Unverified switches return
NO suggestions rather than potentially-wrong data. New columns: ports_verified,
ports_verified_source, ports_verified_at. Verified so far against datasheets:
HPE Aruba CX 10000-48Y6C, NVIDIA SN3700 (corrected 100G->200G QSFP56), SN4700,
SN5400, SN5600. 262 switches still pending datasheet verification.
2026-06-11 08:59:01 +00:00
Rene Fichtmueller
00a5ac8e8b docs: changelog — switch compat requires real coding compatibility 2026-06-11 06:58:15 +00:00
Rene Fichtmueller
2dc21ee0aa fix(switch-compat): parse embedded port speed for chassis switches
Chassis switches use ports_config keys like 'max_per_slot_100G_QSFP28' (speed in
the middle), not just '100G_QSFP28'. The '^[0-9.]+G' anchor failed -> port_speed
NULL -> 0 suggestions (e.g. Cisco 8818 router). Now extracts the speed token
wherever it sits before the cage. Cisco 8818: 0 -> 55, all Cisco-codeable, max 400G.
2026-06-11 06:57:42 +00:00
Rene Fichtmueller
3bec30bad3 fix(switch-compat): require Flexoptix coding for the switch vendor (actually runs)
Physical fit alone is not real compatibility — a module that seats in the cage
still won't run unless Flexoptix can code it for the switch's platform. Added a
coding requirement: each suggestion must have an fx_compatibilities entry for the
switch's mapped vendor (HPE/Aruba->aruba, Cisco->cisco, NVIDIA->mellanox, etc.;
whitebox/unmapped -> MSA Standard fallback).

CX 10000-48Y6C: 629 physically-fitting -> 283 actually-codeable-for-Aruba. All
283 verified to carry an Aruba coding. Every suggestion is now catalog-confirmed,
datasheet-accurate, physically fitting AND guaranteed codeable to run in the switch.
2026-06-11 06:55:48 +00:00
Rene Fichtmueller
eeaeda697a docs: changelog — Flexoptix 100% datasheet audit + switch data gap assessment 2026-06-11 06:51:29 +00:00