main
John Lauer Component record for cre2512-fz-r001e-3: files batch 1 ff9a35c 2d ago
"""Write README.md, land-pattern/README.md, page.json, package.json, models.json, provenance.json,
verification.json and LICENSE for the CRE2512-FZ-R001E-3 page.

usage: records.py <slug>   (run after build.py, again after finish.py)
"""
import sys, os, json, hashlib, re, math
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from parts import P, TODAY, ROOT, FIGS

slug = sys.argv[1]; assert slug == P["slug"]
OUT = f"/home/adom/project/uta-dynos/work/pages/{slug}"
MPN = P["mpn"]; OWNER = "adom"
B = json.load(open(os.path.join(ROOT, "work", f"{slug}-build.json")))
STEP, FP, SYM, MARKED = B["step"], B["fp"], B["sym"], B["marked"]
check, kcheck = B["check"], B["kicad_check"]
land = json.load(open(os.path.join(OUT, "land-pattern/land-check.json")))
lod = json.load(open(os.path.join(OUT, "lod/manifest.json")))
figs = json.load(open(os.path.join(OUT, "docs/figures/figures.json")))
p_ = lambda f: os.path.join(OUT, f)
ex = lambda f: os.path.exists(p_(f))
sha = lambda f: hashlib.sha256(open(p_(f), "rb").read()).hexdigest()
def blob(f):
    b = open(p_(f), "rb").read(); return hashlib.sha1(b"blob %d\0" % len(b) + b).hexdigest()
D = P["dist"]; ds = P["ds"]; L = P["land"]
by = {"name": "Claude (AI agent) for John Lauer", "handle": "john"}
HERO = f"{slug}-hero.glb"; HERO_SIDE = f"{slug}-hero.overlay.json"; HERO_PNG = "docs/verify/hero-preview.png"
LBR = f"{MPN}.lbr"; SCH = f"altium/{MPN}.SchLib"; PCB = f"altium/{MPN}.PcbLib"; HUB = f"{MPN}.adom-lbr.json"
have_hero, have_alt, have_lbr = ex(HERO), ex(SCH) and ex(PCB), ex(LBR)
code = P["marking_code"]
KREF = f"provenance/kicad-reference/{P['fp']}"
GL = "https://gitlab.com/kicad/libraries"
F = lambda n: f"docs/figures/{n}"
imax = math.sqrt(P["power"] / P["ohms"])
v_rated = math.sqrt(P["power"] * P["ohms"])

# ---------------- land pattern write-up ----------------
k = land["kicad"]
t = "| Dimension | KiCad R_2512_6332Metric | Bourns recommendation (used) | Difference |\n|---|---|---|---|\n"
for r in land["rows"]:
    t += f"| {r['dim']} | {r['kicad_mm']:.3f} mm | {r['maker_nominal']:.2f} mm | {r['difference_mm']:+.2f} mm |\n"
land_readme = f"""# Land pattern check: {MPN}

The footprint on this page, `{FP[:-10]}`, is Bourns' recommended solder pad layout for CRE2512-R001 ~ R004:
two rectangular pads {L['len_b']} mm long and {L['wid_c']} mm wide with a {L['gap_a']} mm gap, {L['overall']} mm overall
(datasheet p.1). KiCad's standard `{P['fp_lib']}:{P['fp']}` was compared with it and not used, because it is drawn for a
thick film 2512 with narrow end terminals and differs from Bourns' land by much more than a placement tolerance.

![KiCad 2512 pads (teal) over Bourns' land (amber dashed), true scale](land-pattern.png)

Grey is the part body at its datasheet nominal size, teal is KiCad's IPC-7351 nominal 2512 copper and the dashed amber
outline is Bourns' recommended land, the copper this page's footprint uses.

## Numbers

{t}
Bourns' letters: {L['letters']}.

Source: {L['source']} ([PDF](../{ds['file']})).

![Bourns datasheet p.1 Recommended Solder Pad Layout](../{F('cre-p1-land.png')})

## Result

KiCad's pads are {k['len']:.3f} x {k['wid']:.2f} mm with a {k['gap']:.2f} mm gap; Bourns asks for {L['len_b']} x {L['wid_c']} mm with a
{L['gap_a']} mm gap. The CRE2512-R001 terminals are {P['overlay']['band_top'][0] + 0.2:.2f} mm long (C, p.2), so their inner
edges sit 1.2 mm from the centre: KiCad's pads start 2.35 mm from the centre and would leave more than 1 mm of each terminal
off the copper, while Bourns' pads start at 0.65 mm and cover the whole terminal. The difference is material for a 3 W,
1 mOhm part (current path, heat spreading and the resistance seen between the sense points), so this page ships Bourns' land.

Bourns' drawing also shows where to take the measurement: the high-current copper trace on the outer end of each pad and a
separate sensing trace leaving each pad from its inner edge. The footprint has two pads; route the two sense traces from the
inner edges of pads 1 and 2 as drawn (a four-terminal Kelvin footprint variant is not provided here).

The footprint is written by `provenance/tools/build.py`; the drawing and [land-check.json](land-check.json) come from
`provenance/tools/landcheck.py`. KiCad's file is kept unchanged in `../{KREF}.kicad_mod`.
"""
open(p_("land-pattern/README.md"), "w").write(land_readme)

# ---------------- verification.json ----------------
entries = []
ck = [{"text": f"{c['dim']}: model {c['model_mm']:.3f} mm, datasheet {c['datasheet_min']:.2f} to {c['datasheet_max']:.2f} mm",
       "result": "pass" if c["pass"] else "fail"} for c in check["checks"]]
ck += [{"text": "Z-up, seated on z = 0, centred on the footprint origin, long axis on X", "result": "pass"},
       {"text": "no Bourns STEP is reachable by plain HTTP (bourns.com answers 403 to non-browser requests; the datasheet links no CAD file); the model is built from the datasheet by provenance/tools/make_step.py", "result": "note"},
       {"text": "overcoat thickness (0.15 mm) and the overcoat on the underside are not dimensioned by Bourns: display choices read from the p.2 side view", "result": "note"},
       {"text": "KiCad's R_2512_6332Metric.step was checked first and fails: T " + f"{[c for c in kcheck['checks'] if c['dim']=='T/H'][0]['model_mm']:.2f} mm (0.70 to 1.10) and terminal length C "
                + f"{[c for c in kcheck['checks'] if c['dim'].startswith('C (terminal, top')][0]['model_mm']:.2f} mm (1.80 to 2.20)", "result": "note"}]
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Datasheet-built 3D model matches the datasheet package dimensions",
                "scope": ["3d-model"], "variants": ["*"], "checks": ck,
                "evidence": [{"label": "overlay (top, bottom, side, end at true scale)", "href": f"docs/verify/{slug}-overlay.png"},
                             {"label": "numbers", "href": f"docs/verify/{slug}-check.json"},
                             {"label": "KiCad 2512 model check (fails)", "href": "docs/verify/kicad-2512-model-check.png"},
                             {"label": "datasheet p.2 Product Dimensions", "href": F("cre-p2-dimensions.png")},
                             {"label": "datasheet", "href": ds["file"]}],
                "files": {STEP: sha(STEP), ds["file"]: sha(ds["file"])}})
lck = [{"text": f"footprint pads = Bourns land: {L['len_b']} x {L['wid_c']} mm rectangles at +/-{L['gap_a']/2 + L['len_b']/2:.2f} mm (gap {L['gap_a']} mm, overall {L['overall']} mm)", "result": "pass"}]
lck += [{"text": f"KiCad 2512 {r['dim']}: {r['kicad_mm']:.3f} mm vs Bourns {r['maker_nominal']:.2f} mm ({r['difference_mm']:+.2f} mm)", "result": "note"} for r in land["rows"]]
lck.append({"text": "the footprint pads cover the full 2.00 mm terminal on each end of the model", "result": "pass"})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Footprint is Bourns' recommended land (KiCad's IPC 2512 differs materially and is not used)",
                "scope": ["footprint"], "variants": ["*"], "checks": lck,
                "evidence": [{"label": "comparison drawing", "href": "land-pattern/land-pattern.png"}, {"label": "numbers", "href": "land-pattern/land-check.json"},
                             {"label": "write-up", "href": "land-pattern/README.md"}, {"label": "datasheet p.1 pad layout", "href": F("cre-p1-land.png")}],
                "files": {FP: sha(FP)}})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": f"Marking: datasheet code {code} on the top overcoat",
                "scope": ["3d-model", "marking"], "variants": ["*"],
                "checks": [{"text": f"{P['marking']} ({P['marking_src']})", "result": "pass"},
                           {"text": f"the marked display copy {MARKED} adds {code} as its own light solid group (Adom.Marking.R001) 5 um above the overcoat, reading across the short axis as drawn; the unmarked STEP is kept for board CAD", "result": "pass"},
                           {"text": "no AI-added part-number etch: the real marking is the identification shown", "result": "pass"}],
                "evidence": [{"label": "datasheet p.1 marking", "href": F("cre-p1-construction-marking.png")}],
                "files": {MARKED: sha(MARKED), STEP: sha(STEP)}})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Board-use LOD GLBs are clean and share the STEP pose",
                "scope": ["lod"], "variants": ["*"],
                "checks": [{"text": "four levels written, read back, bounds equal the STEP (Z-up, metres, seat z = 0)", "result": "pass"},
                           {"text": "no footprint, pad outline, label or silkscreen helpers; terminals present at every level", "result": "pass"},
                           {"text": f"marking {code} kept in high and medium, omitted in low and super-low", "result": "pass"},
                           {"text": "previews looked at by the AI agent, not yet by a person", "result": "note"}],
                "evidence": [{"label": "manifest", "href": "lod/manifest.json"}], "files": {lv["path"]: lv["sha256"] for lv in lod["levels"]}})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Pin 1, polarity and symbol",
                "scope": ["footprint", "3d-model", "symbol"], "variants": ["*"],
                "checks": [{"text": "non-polar two-terminal resistor: pads 1 and 2 are interchangeable; symbol pins 1 and 2 map to pads 1 and 2", "result": "pass"},
                           {"text": "symbol pin ends at (0, +5.08) and (0, -5.08) mm, on the 2.54 mm grid", "result": "pass"},
                           {"text": "symbol fields MPN, Manufacturer, Mouser, DigiKey, LCSC, Adom Wiki, Datasheet and Footprint filled", "result": "pass"},
                           {"text": "model terminals sit on the footprint pads (both centred on the origin, long axis on X)", "result": "pass"}],
                "evidence": [], "files": {FP: sha(FP), SYM: sha(SYM), STEP: sha(STEP)}})
if have_hero:
    entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Hero GLB built to the adom-hero standard",
                    "scope": ["3d-model", "hero"], "variants": ["*"],
                    "checks": [{"text": "built with component-hero hero_glb.py from package-reference.glb, the footprint and page.json; alignment check OK", "result": "pass"},
                               {"text": "teal dashed pad outlines (alpha 0.5), silkscreen (alpha 0.3) and pad-number labels 1 and 2 (alpha 0.5); no pin-1 dot because the part is non-polar", "result": "pass"},
                               {"text": "preview looked at by the AI agent; the live wiki viewer still needs a person's look", "result": "note"}],
                    "evidence": [{"label": "preview", "href": HERO_PNG}, {"label": "overlay record", "href": HERO_SIDE}],
                    "files": {HERO: sha(HERO), "package-reference.glb": sha("package-reference.glb")}})
if have_alt or have_lbr:
    entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Fusion and Altium libraries generated from the KiCad symbol and footprint",
                    "scope": ["symbol", "footprint"], "variants": ["*"],
                    "checks": [{"text": "adom-lbr generate --part-metadata page.json: .lbr lint passed (MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN attributes)", "result": "pass"},
                               {"text": "adom-lbr import-kicad then assemble-altium --no-dedupe: native .SchLib and .PcbLib written, STEP body embedded; the KiCad fields carried as Altium parameters", "result": "pass"},
                               {"text": "not yet opened in Fusion or Altium (no desktop app used for this page)", "result": "note"}],
                    "evidence": [], "files": {f: sha(f) for f in (LBR, SCH, PCB, HUB) if ex(f)}})
json.dump({"schema": "adom/verification@1", "part": MPN, "variants": [], "entries": entries}, open(p_("verification.json"), "w"), indent=1)

# ---------------- models.json ----------------
MK = {"text": code, "surface": "top overcoat", "colour": "light grey on black"}
SRC = f"Built from the Bourns CRE2512 datasheet REV. 06/25 p.2 dimensions (provenance/tools/make_step.py)"
models = [
    {"path": STEP, "format": "step", "title": "Package model (STEP)", "status": "current", "slot": "step", "variant": "plain", "role": "datasheet-built",
     "use": ["board-cad"], "marking": None, "unique": "The board CAD model, built from the datasheet dimensions (6.40 x 3.20 x 0.90 mm, 2.00 mm terminals), unmarked",
     "source": SRC, "sha256": sha(STEP), "git_blob": blob(STEP), "bytes": os.path.getsize(p_(STEP)), "thumb": "docs/models/step-plain.png"},
    {"path": MARKED, "format": "step", "title": f"Package model with marking {code} (STEP)", "status": "current", "slot": "step_marked", "variant": "etched",
     "role": "datasheet-built", "use": ["render", "board-cad"], "marking": MK,
     "unique": f"The same model plus the datasheet marking {code} as a separate solid group on the top overcoat", "derived_from": STEP, "source": SRC,
     "sha256": sha(MARKED), "git_blob": blob(MARKED), "bytes": os.path.getsize(p_(MARKED)), "thumb": "docs/models/package-reference-step.png"},
    {"path": "package-reference.glb", "format": "glb", "title": "Package model (GLB)", "status": "current", "slot": "model_3d_plain", "variant": "plain",
     "role": "derived", "use": ["render", "board-insertion"], "marking": MK, "derived_from": MARKED,
     "unique": f"Clean board-use model for viewers (step2glb), no footprint artwork, marking {code}", "source": SRC,
     "sha256": sha("package-reference.glb"), "git_blob": blob("package-reference.glb"), "bytes": os.path.getsize(p_("package-reference.glb"))},
    {"path": f"{KREF}.step", "format": "step", "title": "KiCad R_2512_6332Metric model (not used, kept for the comparison)", "status": "previous",
     "variant": "original", "role": "derived", "use": ["archive"], "marking": None,
     "unique": "KiCad's generic thick film 2512: 0.60 mm thick with 0.54 mm terminals, outside the CRE2512 drawing (T 0.90, C 2.00)",
     "source": f"{GL}/kicad-packages3D (CC-BY-SA 4.0 with the KiCad library exception)", "sha256": sha(f"{KREF}.step"), "git_blob": blob(f"{KREF}.step"),
     "bytes": os.path.getsize(p_(f"{KREF}.step")), "thumb": "docs/verify/kicad-2512-model-check.png"},
]
if have_hero:
    models.append({"path": HERO, "format": "glb", "title": "Hero model (GLB)", "status": "current", "slot": "model_3d", "variant": "hero", "role": "derived",
                   "use": ["wiki-hero"], "marking": MK, "derived_from": "package-reference.glb",
                   "unique": "The page's 3D view: the package plus teal dashed pad outlines, silkscreen and pad-number labels from the footprint (adom-hero standard)",
                   "source": "component-hero hero_glb.py", "sha256": sha(HERO), "git_blob": blob(HERO), "bytes": os.path.getsize(p_(HERO)), "thumb": HERO_PNG})
for lv in lod["levels"]:
    models.append({"path": lv["path"], "format": "glb", "title": f"Board LOD, {lv['level']}", "status": "current", "variant": "lod", "role": "derived",
                   "use": ["board-insertion", "render"], "marking": MK if lv["level"] in ("high", "medium") else None, "derived_from": MARKED,
                   "unique": f"{lv['level']} detail for board and scaffold viewers: {lv['triangles']} triangles, {lv['primitives']} primitives",
                   "thumb": lv["preview"]["path"], "source": SRC, "sha256": lv["sha256"], "git_blob": blob(lv["path"]), "bytes": lv["sizeBytes"]})
json.dump({"schema": "adom/models@1", "part": MPN, "models": models, "updated": TODAY}, open(p_("models.json"), "w"), indent=1)

# ---------------- LICENSE ----------------
open(p_("LICENSE"), "w").write(f"""{MPN} component page

Original Adom content on this page (README text, the KiCad symbol {SYM}, the footprint
{FP} (drawn to Bourns' published pad layout), the datasheet-built 3D models
{STEP}, {MARKED}, package-reference.glb, {HERO} and lod/*.glb, the Fusion and Altium
libraries generated from them, the verification drawings, the JSON records and the scripts in
provenance/tools/) is licensed under the Creative Commons Attribution 4.0 International License
(CC-BY-4.0): https://creativecommons.org/licenses/by/4.0/

Third-party files keep their own terms and are not relicensed by this page:
- {KREF}.kicad_mod and {KREF}.step are KiCad library content, CC-BY-SA 4.0 with the KiCad
  library exception ({GL}/kicad-footprints, {GL}/kicad-packages3D), kept unchanged for the comparison.
- The PDF in docs/ and the page crops in docs/figures/ are Bourns documents, copyright of
  Bourns, Inc., included unchanged (or cropped) for reference.
""")

# ---------------- README ----------------
spec_rows = [
    ("Resistance", "1 mOhm (code R001)", "p.2 Resistance Values, How to Order"),
    ("Tolerance", "+/-1 % (code F)", "p.1 Electrical Characteristics, p.2 How to Order"),
    ("Power rating", "3 W at 70 C (power code 3; the -2 version is 2 W), derated linearly to zero at 170 C", "p.1, p.2 Derating Curve"),
    ("Maximum working current", f"(P / R)^1/2 = sqrt(3 W / 1 mOhm) = {imax:.1f} A", "p.1"),
    ("Temperature coefficient", "+/-50 ppm/C (code Z)", "p.1, p.2 How to Order"),
    ("Resistive element", "Mn/Cu metal alloy plate, Ni/Sn plated terminations, overcoat", "p.1 Features, Construction"),
    ("Inductance", "less than 5 nH", "p.1 Features"),
    ("Thermal EMF", "less than 3 uV/C", "p.1 Features"),
    ("Insulation resistance", "more than 100 MOhm", "p.1"),
    ("Operating temperature", "-55 to +170 C", "p.1"),
    ("Short time overload", "5 x rated power for 5 s: delta R < +/-0.5 %", "p.1 Performance Characteristics"),
    ("Load life", "1000 h at rated power, 70 C: delta R < +/-1.0 %", "p.1 Performance Characteristics"),
    ("Qualification", "AEC-Q200 compliant; RoHS compliant", "p.1 Features"),
    ("Size", P["dims_text"].split(": ", 1)[1], "p.2 Product Dimensions"),
    ("Marking", f"{code} on the overcoat", "p.1 Typical Part Marking"),
    ("Packaging (code E)", "4000 pieces on a 180 mm (7 inch) reel, 12 mm embossed tape", "p.2 How to Order, p.3"),
    ("Moisture sensitivity", "MSL 1", "p.2 Environmental Specifications"),
    ("Soldering", "reflow to IPC/JEDEC J-STD-020, 260 C peak", "p.2 Soldering Profile"),
]
spec_tbl = "| Parameter | Value | Datasheet |\n|---|---|---|\n" + "".join(f"| {a} | {b} | {c} |\n" for a, b, c in spec_rows)
dist_tbl = ("| Distributor | Part number | Stock seen " + TODAY + " |\n|---|---|---|\n"
            + "".join(f"| {n} | [{D[kk][0]}]({D[kk][1]}) | {D[kk][2]:,} |\n" for kk, n in (("mouser", "Mouser"), ("digikey", "DigiKey"), ("lcsc", "LCSC / JLCPCB"))))
fig_tbl = "| Figure | Source |\n|---|---|\n" + "".join(f"| [{f['caption']}]({f['file']}) | {ds['title']}, p.{f['page']} |\n" for f in figs)
cad_rows = [(f"`{SYM}`", "KiCad symbol (standard resistor graphic, pins on the 2.54 mm grid) with MPN, Manufacturer, Mouser, DigiKey, LCSC and Adom Wiki fields"),
            (f"`{FP}`", f"KiCad footprint drawn to Bourns' recommended pad layout (model path `${{KIPRJMOD}}/{STEP}`)")]
if have_lbr: cad_rows.append((f"`{LBR}`", "Fusion / EAGLE library made with `adom-lbr generate` (attributes MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN)"))
if have_alt: cad_rows.append((f"`{SCH}`, `{PCB}`", f"Altium symbol and footprint libraries (native binary) made with `adom-lbr import-kicad` and `assemble-altium` (the PcbLib embeds the STEP body); `{HUB}` is the adom-lbr hub record"))
cad_rows += [(f"`{STEP}`", "3D package model, STEP, built from the datasheet dimensions"), (f"`{MARKED}`", f"the same with the marking {code}, STEP"),
             ("`package-reference.glb`", "3D package model, GLB (clean, for board viewers)")]
if have_hero: cad_rows.append((f"`{HERO}`", "the page's 3D view: package plus footprint pad outlines, silkscreen and pad labels"))
cad_rows += [("`lod/`", "board-use GLBs in four levels of detail, with previews and manifest"),
             (f"`{KREF}.kicad_mod`, `.step`", "KiCad's generic 2512 footprint and model, unchanged, kept only for the comparison")]
cad_tbl = "| File | What it is |\n|---|---|\n" + "".join(f"| {a} | {b} |\n" for a, b in cad_rows)
hero_para = (f"""
The page viewer shows `{HERO}`: the clean model plus nonphysical reference artwork drawn under it to the adom-hero
standard (adom/component-hero): the footprint's pads as teal dashed outlines at 50 % opacity, its silkscreen at 70 %
transparency and the pad numbers 1 and 2 (the terminals have no names). The part is non-polar, so no pin-1 dot is added.
The artwork never goes into the STEP, `package-reference.glb` or the board LODs.

![Hero preview, top and oblique]({HERO_PNG})
""" if have_hero else "")
kT = [c for c in kcheck["checks"] if c["dim"] == "T/H"][0]["model_mm"]
kC = [c for c in kcheck["checks"] if c["dim"].startswith("C (terminal, top")][0]["model_mm"]
readme = f"""# {MPN}

Bourns {MPN}: {P['brief']}. A two-terminal metal strip (Mn/Cu alloy) chip resistor from Bourns' CRE2512 series, made for
measuring large currents: power supplies, motor and stepper drives, battery packs.

::adom-verified{{src="/{OWNER}/{slug}/render/verification.json"}}

| Field | Value |
|---|---|
| Manufacturer | {P['mfr_full']} |
| Manufacturer part number | {MPN} |
| Type | {P['subcategory']} |
| Value | {P['value']} |
| Tolerance | {P['tol']} |
| Power rating | 3 W at 70 C |
| Maximum current | {imax:.1f} A continuous at 70 C, from (P / R)^1/2 |
| Temperature coefficient | +/-50 ppm/C |
| Operating temperature | -55 to +170 C |
| Package | {P['package']}, 6.40 x 3.20 x 0.90 mm |
| Marking | {code} |
| Datasheet | [{ds['title']}]({ds['file']}) |

## Key specifications

{spec_tbl}
All page numbers refer to the datasheet PDF in [docs/]({ds['file']}).

![Datasheet p.1 Electrical Characteristics](docs/figures/cre-p1-electrical.png)

## Current, power and voltage

Bourns gives the maximum working current as (P / R)^1/2 (p.1): with P = 3 W and R = 1 mOhm that is {imax:.1f} A at an
ambient up to 70 C, falling to zero at 170 C along the derating curve (p.2). At {imax:.1f} A the voltage across the part is
{v_rated * 1000:.1f} mV. Power is I^2 x R: 10 A dissipates 0.1 W, 30 A 0.9 W, 50 A 2.5 W. The 1 % tolerance and the
+/-50 ppm/C temperature coefficient set the measurement error; the inductance (under 5 nH) and thermal EMF (under 3 uV/C) are
small enough for switching-current sensing. How much of the rating a design can use depends on the copper and airflow around
the part.

![Datasheet p.2 derating curve](docs/figures/cre-p2-derating.png)

## Ordering

{dist_tbl}
Stock figures are a snapshot from the Adom parts search on {TODAY}; check the distributor before ordering. JLCPCB lists
C840615 as an extended part. Ordering code: CRE 2512 - F (1 %) Z (+/-50 ppm/C) - R001 (1 mOhm) E (4000 per 7 inch reel)
- 3 (3 W); the -2 suffix is the 2 W version (p.2).

![Datasheet p.2 How to Order](docs/figures/cre-p2-ordering.png)

## Manufacturer and resources

| Resource | Link |
|---|---|
| Product family page | {P['product_url']} (Bourns metal strip chip resistors) |
| Datasheet | {ds['title']}, [PDF]({ds['file']}) ([source]({ds['url']})) |
| Inventory and samples | https://www.bourns.com/inventory-search-results?PARTS=CRE2512 |
| Technical library | https://www.bourns.com/resources/technical-library/library-documents/resistors-technical-library |

## Pins

| Pin | Function |
|---|---|
| 1 | terminal (non-polar) |
| 2 | terminal (non-polar) |

A resistor has no polarity: either terminal may face either way. For accurate sensing take the two sense traces from the
inner edge of each pad, as Bourns' pad layout drawing shows (next section).

## Land pattern: Bourns layout, not KiCad's generic 2512

<table>
<tr>
<td width="104"><a href="land-pattern/README.md"><img src="land-pattern/land-pattern-icon.png" width="112" alt="Land pattern"></a><br><sub>&nbsp;&nbsp;&nbsp;&nbsp;Land&nbsp;pattern&nbsp;&nbsp;&nbsp;&nbsp;</sub></td>
<td>The footprint uses Bourns' recommended pads, {L['len_b']} x {L['wid_c']} mm with a {L['gap_a']} mm gap, because KiCad's IPC 2512 pads ({k['len']:.3f} x {k['wid']:.2f} mm, {k['gap']:.1f} mm gap) would leave most of each 2 mm terminal off the copper. The guide lays both over the part at true scale and explains where the sense traces leave the pads.<br><br><a href="land-pattern/README.md">The comparison, with the numbers</a></td>
</tr>
</table>

## Marking

Bourns prints the value code **{code}** on the overcoat of CRE2512-R001 ~ R004 parts, reading across the short axis
(p.1, Typical Part Marking). The marked model shows it there.

![Datasheet p.1 construction and marking](docs/figures/cre-p1-construction-marking.png)

## 3D model

No Bourns STEP for this part could be downloaded by plain HTTP: bourns.com refuses non-browser requests (HTTP 403) and the
datasheet links no CAD file. KiCad's library model `{P['fp']}.step` was checked first and does not fit this part: it is
{kT:.2f} mm thick with {kC:.2f} mm terminals, while the CRE2512-R001 drawing gives T 0.90 +/-0.20 mm and C 2.00 +/-0.20 mm
([check](docs/verify/kicad-2512-model-check.png)). The model on this page is therefore **built from the datasheet** by
`provenance/tools/make_step.py`: a 6.40 x 3.20 x 0.90 mm part with 2.00 mm Ni/Sn terminations wrapping each end, the Mn/Cu plate
between them and a black overcoat on top and bottom. Every printed dimension is used as printed; the overcoat thickness
(0.15 mm) and the underside overcoat are not dimensioned by Bourns and are read from the p.2 side view. A display copy
`{MARKED}` adds the marking {code} as its own solid group 5 um above the overcoat; the unmarked STEP is the board CAD file.
{hero_para}
::adom-models{{src="/{OWNER}/{slug}/render/models.json"}}

## Model checked against the datasheet

The model was rendered in orthographic top, bottom, side and end views at true scale and laid over a drawing made at the same
scale from the printed table (nominal outline, tolerance limits, allowed terminal band). Every dimension is inside the printed
range: {", ".join(f"{c['dim']} {c['model_mm']:.3f} mm (datasheet {c['datasheet_min']:.2f} to {c['datasheet_max']:.2f})" for c in check['checks'])}.
The model is Z-up, seated on z = 0, centred on the footprint origin, long axis on X.

![Model over the datasheet dimensions](docs/verify/{slug}-overlay.png)

Source: {ds['title']}, {P['dims_text']}.

## Board levels of detail

Clean board-use GLBs (no footprint pads, outlines, labels or silkscreen) in four levels, all in the same Z-up, metre,
footprint-origin pose as the STEP. The marking {code} shows in high and medium and is left out of low and super-low.
Previews are rendered from each GLB.

::adom-component-lod{{src="/{OWNER}/{slug}/render/lod/manifest.json"}}

## CAD files

{cad_tbl}
## Datasheet figures

The pages this record cites, cropped from the PDF:

{fig_tbl}
## Sources and license

- Bourns: {ds['title']} ({ds['url']})
- KiCad libraries (comparison only): [{P['fp_lib']}.pretty/{P['fp']}.kicad_mod]({GL}/kicad-footprints/-/blob/master/{P['fp_lib']}.pretty/{P['fp']}.kicad_mod), [{P['fp_lib']}.3dshapes/{P['fp']}.step]({GL}/kicad-packages3D/-/blob/master/{P['fp_lib']}.3dshapes/{P['fp']}.step)
- Distributor numbers: Mouser, DigiKey and JLCPCB/LCSC through the Adom parts search, {TODAY}

Original Adom content, including the datasheet-built models and the footprint, is CC-BY-4.0. The KiCad reference files keep
their upstream license and the PDF remains Bourns' document; see [LICENSE](LICENSE). [provenance.json](provenance.json) records
every source and file hash; the scripts that built the files and checks are in `provenance/tools/`.

This is a catalog record for the part, not a manufacturing approval: check Bourns' current datasheet for your design.
"""
readme = re.sub(r"\n{3,}", "\n\n", readme)
for bad in ("—", "–"):
    assert bad not in readme and bad not in land_readme, "dash in README"
open(p_("README.md"), "w").write(readme)

# ---------------- page.json / package.json ----------------
title = f"{MPN} - {P['mfr']}"
parts_ = {"symbol": SYM, "footprint": FP, "step": STEP, "model_3d": HERO if have_hero else "package-reference.glb",
          "model_3d_plain": "package-reference.glb", "datasheet": ds["file"], "step_marked": MARKED}
if have_lbr: parts_["lbr"] = LBR
if have_alt: parts_.update({"altium_schlib": SCH, "altium_pcblib": PCB})
component = {
    "mpn": MPN, "manufacturer": P["mfr"], "package": P["package"], "category": P["category"], "subcategory": P["subcategory"],
    "pin_count": 2, "body_size": P["body_mm"], "value": P["value"], "tolerance": P["tol"], "power": "3 W at 70 C",
    "rating": f"3 W, {imax:.1f} A max at 70 C, +/-50 ppm/C", "max_current_a": round(imax, 1), "tcr_ppm_c": 50,
    "pins": [{"number": "1", "name": "~"}, {"number": "2", "name": "~"}],
    "parts": parts_,
    "manufacturer_links": {"product": P["product_url"], "datasheet_pdf": ds["url"]},
    "distributor_links": {kk: {"part": D[kk][0], "url": D[kk][1]} for kk in ("mouser", "digikey", "lcsc")},
    "marking": {"text": code, "statement": P["marking"], "source": P["marking_src"]},
    "provenance": {"model_3d": "Built from the Bourns datasheet dimensions (no Bourns STEP reachable; KiCad's 2512 model outside the drawing)",
                   "footprint": "Bourns recommended solder pad layout (KiCad's IPC 2512 differs materially)",
                   "land_pattern_check": "land-pattern/README.md (Bourns land used)", "omitted": ["four-terminal Kelvin footprint variant"]},
}
eda = {"kicad": {"symbol": SYM, "footprint": FP, "model": STEP, "provenance": "generated"}}
if have_lbr: eda["fusion"] = {"lbr": LBR, "provenance": "generated"}
if have_alt: eda["altium"] = {"schlib": SCH, "pcblib": PCB, "provenance": "generated"}
page = {"slug": slug, "title": title, "eda_assets": eda, "type": "hardware", "kind": "component", "version": "0.1.0",
        "description": P["brief"], "brief": P["brief"],
        "tags": ["hardware", "component", "passive", "resistor", "current-sense", "shunt", "2512", "bourns", "aec-q200"],
        "discovery_triggers": [MPN, MPN.lower(), "CRE2512", "1 mOhm 2512 current sense resistor", "1 milliohm shunt 2512 3W"],
        "dependencies": {}, "license": "CC-BY-4.0", "hero": {"path": "docs/hero.png", "chrome": False},
        "component": component, "visibility": {"public": True},
        "source": {"tool": "bourns", "url": P["product_url"]}}
json.dump(page, open(p_("page.json"), "w"), indent=1)
json.dump({"name": slug, "title": title, "version": "0.1.0", "description": P["brief"], "type": "hardware", "kind": "component",
           "license": "CC-BY-4.0", "files": []}, open(p_("package.json"), "w"), indent=1)

# ---------------- provenance.json ----------------
files = {}
for dp, dn, fn in os.walk(OUT):
    for f in fn:
        rel = os.path.relpath(os.path.join(dp, f), OUT)
        if rel != "provenance.json":
            files[rel] = sha(rel)
finp = os.path.join(ROOT, "work", f"{slug}-finish.json")
fin = json.load(open(finp)) if os.path.exists(finp) else {}
prov = {
    "manufacturer_reference": P["product_url"],
    "symbol_source": "Original, written for this page (standard resistor graphic, non-polar, pin ends on the 2.54 mm grid). CC-BY-4.0.",
    "footprint_source": f"Original, drawn by provenance/tools/build.py to {L['source']}: rect pads {L['len_b']} x {L['wid_c']} mm, gap {L['gap_a']} mm",
    "footprint_compared_with": {"file": f"{KREF}.kicad_mod", "sha256": sha(f"{KREF}.kicad_mod"),
                                "url": f"{GL}/kicad-footprints/-/raw/master/{P['fp_lib']}.pretty/{P['fp']}.kicad_mod", "result": "differs materially, not used"},
    "package_source": "Datasheet-built: provenance/tools/make_step.py (cadquery) from the p.2 Product Dimensions, R001 ~ R004 row",
    "package_undimensioned_choices": {"overcoat_thickness_mm": 0.15, "underside_overcoat": "read from the p.2 side view", "marking_glyph_height_mm": 0.75,
                                      "colours": "terminals Ni/Sn light grey, overcoat black, plate Mn/Cu copper brown"},
    "manufacturer_step": {"found": False, "searched": TODAY,
                          "note": "bourns.com answered HTTP 403 to plain requests for the product and technical-library pages; the datasheet's links (product, technical library, inventory, samples, contact) name no CAD file. No browser was used."},
    "kicad_model_check": {"file": f"{KREF}.step", "sha256": sha(f"{KREF}.step"), "result": kcheck, "verdict": "outside the drawing (T and C), not used"},
    "geometry_status": "Datasheet-built package, every printed dimension checked (docs/verify). Not manufacturer-issued CAD.",
    "marking": {"real_marking": code, "statement": P["marking"], "source": P["marking_src"], "display_step": MARKED,
                "method": "cadquery text solid (DejaVu Sans Bold) 5 um above the overcoat, group Adom.Marking.R001"},
    "frame": {"units": "mm (STEP), metres (GLB)", "up_axis": "Z", "seat_z": 0, "origin": "footprint origin", "transform": "none"},
    "glb": {"tool": "step2glb convert (service)", "source": MARKED, "exit": 0},
    "hero_image": {"tool": "step2glb thumbnail --width 1600 --height 1000 (iso, 16:10)", "source": MARKED, "path": "docs/hero.png"},
    "hero_glb": fin.get("hero"), "fusion_lbr": fin.get("lbr"), "altium": fin.get("altium"),
    "datasheet": {"file": ds["file"], "sha256": sha(ds["file"]), "url": ds["url"], "title": ds["title"], "retrieved": TODAY},
    "datasheet_figures": figs,
    "datasheet_check": {"overlay": f"docs/verify/{slug}-overlay.png", "numbers": f"docs/verify/{slug}-check.json", "result": "PASS" if check["all_pass"] else "FAIL"},
    "land_pattern_check": {"readme": "land-pattern/README.md", "numbers": "land-pattern/land-check.json", "source": L["source"], "result": "Bourns land used; KiCad 2512 differs materially"},
    "distributors": {"tool": "adom-parts-search search " + MPN, "date": TODAY, **{kk: {"part": D[kk][0], "url": D[kk][1], "stock": D[kk][2]} for kk in ("mouser", "digikey", "lcsc")}},
    "lod": {"manifest": "lod/manifest.json", "generator": "provenance/tools/lod.py", "source": MARKED, "source_sha256": sha(MARKED)},
    "tools_note": "Scripts adapted from adom/rc0402fr-0733kl (ortho.py reads colours stored on sub-shape labels; landcheck.py takes the compared footprint as an argument).",
    "files": files, "files_note": "provenance.json itself is not listed.", "built_by": "Claude (AI agent) for John Lauer", "date": TODAY,
}
json.dump(prov, open(p_("provenance.json"), "w"), indent=1)
print("records written", slug, "hero" if have_hero else "-", "altium" if have_alt else "-", "lbr" if have_lbr else "-")