Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion skills/bom/references/ordering-and-fabrication.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@ Paste into the bulk-add box at [digikey.com/ordering/shoppingcart](https://www.d

Format: `quantity, DigiKey_PN, customer_reference` — comma or tab delimited, one line per part.

Separate multiple reference designators with `/`, as shown above — the field itself is
comma-delimited. Files generated by `bom_manager.py order` already use this form
(`_write_digikey_order` rewrites commas to `/`).

**FastAdd URL** — programmatic cart building:
```
https://www.digikey.com/classic/ordering/fastadd.aspx?part1=490-10698-1-ND&qty1=3&cref1=C1/C2/C5&part2=...&newcart=true
https://www.digikey.com/classic/ordering/fastadd.aspx?part1=490-10698-1-ND&qty1=3&cref1=C1/C2/C5&part2=...
```
GET supports ~1700 chars; POST supports 400+ parts.

**Do not add `&newcart=true` unless you mean it.** The default adds to the current cart;
`newcart=true` **starts a new empty cart**, and the shopping-cart page warns that creating
a new cart deletes the items currently in it. Omit it to append.
([DigiKey FastAdd guide](https://forum.digikey.com/t/digikey-fastadd-bulk-add-parts-into-a-digikey-cart-via-third-party-tooling-and-urls/61356))

**BOM Manager** — [digikey.com/en/resources/bom-manager](https://www.digikey.com/en/resources/bom-manager). Upload CSV/XLS/XLSX, map columns interactively. Accepts both DigiKey PNs and MPNs.

### Mouser — Part List Import
Expand Down
10 changes: 7 additions & 3 deletions skills/kicad/scripts/analyze_thermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,10 @@ def _compute_junction_temps(power_comps: list, pcb: dict,
"category": "thermal",
"severity": "info",
"confidence": "heuristic" if rtheta_source == "default" else "deterministic",
"evidence_source": "datasheet" if rtheta_source == "package_table" else "heuristic_rule",
# rtheta_source is only ever "package_table" (footprint regex matched the
# generic PACKAGE_THERMAL_RESISTANCE average) or "default" — neither is
# per-MPN datasheet data, so neither may claim datasheet provenance.
"evidence_source": "heuristic_rule",
"summary": f"Thermal: {ref} Tj={round(tj, 1)}C (margin {round(margin, 1)}C)",
"description": f"Component {ref} in {pkg_name} package: Tj={round(tj, 1)}C, margin {round(margin, 1)}C to Tj_max ({tj_max}C).",
"components": [ref],
Expand Down Expand Up @@ -483,8 +486,9 @@ def _generate_findings(assessments: list) -> list:
pdiss = a["pdiss_w"]
pkg = a["package"]
confidence = _thermal_confidence(a)
ev_source = ("datasheet" if a.get("rtheta_ja_source") == "package_table"
else "heuristic_rule")
# Both rtheta_ja_source values ("package_table", "default") are generic
# package averages, not per-MPN datasheet data. See analyze_thermal:394.
ev_source = "heuristic_rule"

label = f"{ref} ({val})" if val else ref

Expand Down
24 changes: 21 additions & 3 deletions skills/kicad/scripts/lifecycle_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ def _normalize_status(raw: str | None) -> str:
# Temperature parsing
# ---------------------------------------------------------------------------

def _temp_evidence_source(source: str | None) -> str:
"""Map a temperature-range source tag to a finding evidence_source.

"extraction_cache" is a per-MPN datasheet extraction and is genuinely
datasheet-backed; "api:<distributor>" is a catalogue lookup. Anything else
(or nothing) is not evidence of either.
"""
if not source:
return 'heuristic_rule'
if source == 'extraction_cache':
return 'datasheet'
if source.startswith('api:'):
return 'api_lookup'
return 'heuristic_rule'


def _parse_temp_range(text: str) -> tuple[float, float] | None:
"""Parse temperature range from distributor attribute string.

Expand Down Expand Up @@ -759,7 +775,7 @@ def audit_bom(analysis_json: dict, project_dir: str | None = None,
'category': 'lifecycle',
'severity': 'info',
'confidence': 'deterministic',
'evidence_source': 'datasheet',
'evidence_source': 'api_lookup',
'summary': f'{mpn}: single source ({active_sources[0]})',
'description': f'Component {mpn} ({len(refs)} ref(s)) is only available from {active_sources[0]} out of {total_queried} sources checked.',
'components': sorted(refs),
Expand Down Expand Up @@ -800,7 +816,7 @@ def audit_bom(analysis_json: dict, project_dir: str | None = None,
'category': 'lifecycle',
'severity': severity,
'confidence': 'deterministic',
'evidence_source': 'datasheet',
'evidence_source': 'api_lookup',
'summary': f'{mpn}: {max_lead_weeks} week lead time',
'description': f'Component {mpn} has {max_lead_weeks} week lead time (from {lead_source}).',
'components': sorted(refs),
Expand Down Expand Up @@ -845,7 +861,9 @@ def audit_bom(analysis_json: dict, project_dir: str | None = None,
"rule_id": "LT-001",
"category": "temperature",
"confidence": "deterministic",
"evidence_source": "api_lookup" if temp.get("source") else "heuristic_rule",
# "extraction_cache" is a real per-MPN datasheet extraction and must
# not be downgraded to api_lookup; "api:<distributor>" is a lookup.
"evidence_source": _temp_evidence_source(temp.get("source")),
"summary": f"{mpn}: rated {comp_grade} ({comp_min}C to {comp_max}C), design needs {design_min}C to {design_max}C",
"components": sorted(refs),
"nets": [],
Expand Down