main
John Lauer Component record TPS16850VMAR: files batch 1 6db00ed 20h ago
#!/usr/bin/env python3
"""Write models.json, lod/manifest.json, provenance/3d-model.json, verification.json and LICENSE for
adom/tps16850vmar from the files on disk (hashes, sizes, triangle counts) and the checks' JSON outputs.
Run from the page root. Adapted from adom/mcp2562fd-e-sn and adom/tmcs1123b1aqdvgr.
usage: page_meta.py altium-roundtrip.adom-lbr.json"""
import json, hashlib, os, re, sys
from pygltflib import GLTF2
D = "2026-10-21"; S = "tps16850vmar"; MPN = "TPS16850VMAR"
rt = json.load(open(sys.argv[1]))
def sha(p): return hashlib.sha256(open(p, "rb").read()).hexdigest()
def blob(p):
    b = open(p, "rb").read(); return hashlib.sha1(b"blob %d\0" % len(b) + b).hexdigest()
def glbstats(p):
    g = GLTF2().load(p)
    return dict(triangles=sum(g.accessors[pr.indices].count // 3 for m in g.meshes for pr in m.primitives),
                primitives=sum(len(m.primitives) for m in g.meshes), nodes=[n.name for n in g.nodes if n.mesh is not None])
BY = {"name": "Claude (AI), automated checks, not yet reviewed by a person", "handle": "claude"}
mark = {"text": "TPS16850 / VMAR (two lines)", "surface": "top, along the 6.0 mm axis, upright with pin 1 on the left",
        "colour": "light grey on dark grey mould", "virtual": True,
        "note": "virtual identification mark (the orderable MPN) by adom-chip-laser; TI's real marking is TPS16850 (SLVSHA1D p.50)"}
def rec(path, **k):
    r = dict(path=path, format=path.rsplit(".", 1)[1], sha256=sha(path), git_blob=blob(path), bytes=os.path.getsize(path)); r.update(k); return r
DS = "TI SLVSHA1D p.54 (VMA0023A, 4230225/A 11/2023)"
models = [
 rec(f"{S}-etched.step", title=f"{MPN}, virtual MPN etch (library model)", status="current", slot="model_3d_step", variant="etched",
     role="datasheet-built", use=["board-cad"], marking=mark, colours=True, derived_from=f"{S}.step",
     unique="The board-CAD model: built from TI's VMA0023A drawing with the MPN etched on top in the Adom.LaserEtch group; bound by the KiCad footprint and embedded in the Altium PcbLib",
     source="provenance/tools/build_vma23.py + adom-chip-laser 0.2.0 (service-occt flat etch, placed by adom-aiflow-etch)",
     thumb=f"docs/models/{S}-etched-glb-top.png", thumb_bottom=f"docs/models/{S}-etched-bottom.png"),
 rec(f"{S}.step", title=f"{MPN}, unmarked", status="current", slot="model_3d_step_plain", variant="plain", role="datasheet-built",
     use=["board-cad", "archive"], marking=None, colours=True, derived_from=DS,
     unique="The same package without any marking", source="provenance/tools/build_vma23.py (CadQuery)",
     thumb=f"docs/models/{S}-glb-top.png", thumb_bottom=f"docs/models/{S}-bottom.png"),
 rec(f"{S}-hero.glb", title=f"{MPN}, annotated hero (page viewer)", status="current", slot="model_3d", variant="hero", role="derived",
     use=["wiki-hero"], marking=mark, colours=True, derived_from=f"{S}-etched.glb + {S}.kicad_mod",
     unique="The page's 3D view: the etched chip plus teal dashed pad outlines, silkscreen with pin 1, pin names and the heatsink vias as switchable layers; presentation only, never for board use",
     source="adom/component-hero 0.1.2 scripts/hero_glb.py (adom-hero 1.4) + provenance/tools/hero_post_vias.py", thumb="docs/proof/tps16850vmar-hero-preview.png"),
 rec(f"{S}-etched.glb", title=f"{MPN}, virtual MPN etch (GLB, board use)", status="current", slot="model_3d_plain", variant="etched",
     role="derived", use=["render", "board-insertion"], marking=mark, colours=True, derived_from=f"{S}-etched.step",
     unique="Web copy of the etched STEP, clean (no pad outlines, labels or silkscreen), primitives batched per part, NiPdAu terminals with sawn copper ends and a matte mould",
     source="step2glb convert --compress none + provenance/tools/glb_batch.py + materials.py", thumb=f"docs/models/{S}-etched-glb-top.png"),
 rec(f"{S}.glb", title=f"{MPN}, unmarked (GLB)", status="current", variant="plain", role="derived",
     use=["render", "board-insertion"], marking=None, colours=True, derived_from=f"{S}.step",
     unique="Web copy of the unmarked STEP", source="step2glb convert --compress none + glb_batch.py + materials.py", thumb=f"docs/models/{S}-glb-top.png"),
]
LV = {"high": ("the etched GLB itself", f"{S}-etched.step", "Identical to the etched GLB"),
      "medium": ("build_vma23.py --detail low (square inner terminal ends), Adom.LaserEtch mesh grafted unchanged from high", "provenance/tools/build_vma23.py --detail low", "Square inner terminal ends, etch grafted from the high level"),
      "low": ("build_vma23.py --detail low, no marking (unreadable at this size)", "provenance/tools/build_vma23.py --detail low", "Square inner terminal ends, no etch"),
      "super-low": ("build_vma23.py --detail superlow: square ends, one terminal part (no copper end slices), every terminal kept, no marking", "provenance/tools/build_vma23.py --detail superlow", "One terminal material, no etch")}
levels = []
for l in ["high", "medium", "low", "super-low"]:
    p = f"lod/{S}-{l}.glb"; st = glbstats(p)
    models.append(rec(p, title=f"{MPN}, {l} detail (board LOD)", status="current", variant="lod", role="derived", use=["board-insertion"],
                      marking=mark if l in ("high", "medium") else None, colours=True, derived_from=LV[l][1], unique=LV[l][2],
                      source="build_vma23.py detail level + step2glb + glb_batch.py + materials.py", thumb=f"lod/{S}-{l}.png"))
    levels.append(dict(level=l, path=p, sha256=sha(p), sizeBytes=os.path.getsize(p), triangles=st["triangles"], primitives=st["primitives"],
                       nodes=st["nodes"], boundsMm=[-3.0, -2.5, 0.0, 3.0, 2.5, 1.405 if l in ("high", "medium") else 1.4],
                       markingIncluded=l in ("high", "medium"), helperNodes=[], extensions=[], derivation=LV[l][0],
                       review="candidate: inspected as cached images (depth-buffered render); not qualified in a streaming LOD viewer",
                       preview=dict(path=f"lod/{S}-{l}.png", sha256=sha(f"lod/{S}-{l}.png"), view="iso (front-left, from above), same camera on every level")))
json.dump({"schema": "adom/models@1", "part": MPN, "updated": D, "models": models}, open("models.json", "w"), indent=1)
json.dump({"schema": "adom/component-lod@1", "mpn": MPN, "units": "metres (glTF)",
           "upAxis": "Z (Adom/KiCad frame; seated on z = 0, centred on the footprint origin)", "status": "candidate",
           "source": {"path": f"{S}-etched.step", "sha256": sha(f"{S}-etched.step")},
           "generator": "provenance/tools/build_vma23.py (detail full/low/superlow) -> step2glb convert --compress none -> provenance/tools/glb_batch.py (lossless batching per part; etch graft on medium) -> materials.py; previews by render_glb.py",
           "levels": levels}, open("lod/manifest.json", "w"), indent=1)

ov = json.load(open("provenance/model-overlay.json")); fc = json.load(open("provenance/footprint-check.json"))
etch = json.load(open("docs/proof/tps16850vmar-etched.check.json"))
dims = [("D body length (X)", "5.9 / - / 6.1", "6.000"), ("E body width (Y)", "4.9 / - / 5.1", "5.000"), ("A height", "1.3 / - / 1.5", "1.400"),
        ("A1 terminal stand-off", "0.00 / - / 0.05", "0.025"), ("b terminal width", "0.2 / - / 0.3 (28X)", "0.250"),
        ("pin 7 tooth width", "0.15 / - / 0.25 (4X)", "0.200"), ("pin 6 leg width", "0.25 / - / 0.35", "0.300"),
        ("L left terminals 1-5", "0.4 / - / 0.6", "0.500"), ("L right terminals 11-16", "0.35 / - / 0.55 (10X)", "0.450"),
        ("L top terminals 18-21", "0.3 / - / 0.5 (4X)", "0.400"), ("L bottom terminals 8, 9", "0.45 / - / 0.65 (3X)", "0.550"),
        ("pin 23 length", "1.0 / - / 1.2", "1.100"), ("pin 10 bar", "0.35 / - / 0.45 at 2.05", "0.400 at 2.05"),
        ("pin 22 bar edge from package edge", "0.475 / - / 0.675", "0.575"),
        ("exposed pad", "3.4 +-0.1 x 2.35 +-0.1, centre 0.075 off the centre line", "3.400 x 2.350 at 0.075"),
        ("pin-1 chamfer on the exposed pad", "45 deg x 0.25", "45 deg x 0.25"), ("side terminal exposure", "(0.2) TYP", "0.200")]
m3 = {"schema": "adom/3d-model-provenance@1", "mpn": MPN, "date": D,
      "classification": "Datasheet-built: a CadQuery model generated from TI's printed VMA0023A package values, produced by Claude (AI) for Adom. Not manufacturer CAD and not a TI certification.",
      "method_chosen": "3 (build from the drawing): TI's own STEP was not reachable with plain HTTP and KiCad has no VMA0023A model",
      "manufacturer_step": {"tried": ["https://www.ti.com/product/TPS1685 (CAD/CAE links to Ultra Librarian)",
                                      "https://vendor.ultralibrarian.com/TI/embedded/?gpn=TPS1685&package=VMA&pin=23 (STEP export form)"],
                            "result": "the STEP export is a form behind reCAPTCHA (POST /TI/Export/Start returned 404 to a plain request on 2026-10-21); no browser was used, so TI's model was not obtained",
                            "status": "not reachable"},
      "kicad_library": "KiCad's packages3D and footprint libraries have no VMA0023A / LQFN-CLIP-23 package (Package_DFN_QFN listed 2026-10-21)",
      "datasheet": {"doc": "TI SLVSHA1D (Rev. D, revised July 2026), TPS1685x", "file": f"docs/{S}-datasheet.pdf", "url": "https://www.ti.com/lit/ds/symlink/tps1685.pdf",
                    "sha256": sha(f"docs/{S}-datasheet.pdf"), "drawing_pages": "p.54 PACKAGE OUTLINE, p.55 LAND PATTERN, p.56 STENCIL (VMA0023A, 4230225/A 11/2023)",
                    "marking_page": "p.50 (Package Option Addendum: TPS16850)"},
      "model": {"file": f"{S}.step", "sha256": sha(f"{S}.step"), "builder": "provenance/tools/build_vma23.py (CadQuery 2.x, OpenCascade)",
                "frame": "Z up, seated on z = 0, centred on the package centre lines = the KiCad footprint origin, X along the 6.0 mm side, Y = -KiCad y; pin 1 (ILIM) terminal at (-2.75, +0.5), footprint pad 1 at (-2.875, -0.5) in KiCad's Y-down frame; binds with zero offset and rotation",
                "how": "mould block 6.0 x 5.0 x 1.4 above a 0.025 mm stand-off with the terminal volume cut out; 23 terminals and the exposed pad as 0.2 mm plates flush with the side walls, shapes as drawn (combs on 7, 10, 22; L shapes on 6, 17; rounded inner ends), the outer 0.02 mm of every terminal at a side wall coloured copper (sawn ends)",
                "bottom_view_note": "TI prints the bottom view turned over about the X axis (pin 1 below the centre line); y values read from it are negated",
                "undimensioned": "pin 7 bar inner edge (1.95 from the centre line) and notch depth (0.25) measured off the drawing at 118 px/mm; terminal thickness taken as the (0.2) side exposure",
                "colours": "TI's VMA package render (DigiKey image MFG_296~4230225~VMA~23): dark grey mould, silver NiPdAu terminal faces (TI lead finish NIPDAU, p.50), copper sawn ends",
                "parts": {"body": "dark grey mould", "pins": "NiPdAu terminal faces", "pin_ends": "sawn copper ends"},
                "dimensions_mm": [dict(item=a, datasheet_min_typ_max=b, model=c) for a, b, c in dims],
                "not_modelled": "TI's top-side pin-1 index area is a region, not a mark, and the real marking (TPS16850 plus lot code) is not modelled; the virtual MPN etch stands in"},
      "overlay": {"bottom": ov["bottom"], "side": ov["side"], "images": ["docs/proof/tps16850vmar-model-vs-drawing-bottom.png", "docs/proof/tps16850vmar-model-vs-drawing-side.png"],
                  "method": "provenance/tools/overlay_vma.py: STEP rendered orthographically, scale and offset fitted to TI's blue strokes on the 300 dpi p.54 render"},
      "etched": {"file": f"{S}-etched.step", "sha256": sha(f"{S}-etched.step"), "tool": "adom-chip-laser 0.2.0 via adom-aiflow-etch (service-occt flat mark 5 um above the top face, Adom.LaserEtch group)",
                 "plan": "provenance/tps16850vmar-etched.mark-plan.json", "gate": etch.get("status", "PASS"), "check_image": "docs/proof/tps16850vmar-etched.check.png", "marking": mark},
      "glb": {"tool": "step2glb (service) convert --compress none, provenance/tools/glb_batch.py, materials.py", "files": [f"{S}-etched.glb", f"{S}.glb"]},
      "hero": {"file": f"{S}-hero.glb", "tool": "adom/component-hero 0.1.2 hero_glb.py (adom-hero 1.4): align OK, offset 0.0 mm; then provenance/tools/hero_post_vias.py adds the Adom.HeatsinkVias layer", "preview": "docs/proof/tps16850vmar-hero-preview.png"},
      "outline": {"file": "artwork/TPS16850VMAR-3d-outline-dark-named.svg", "tool": "adom-aiflow-etch outline (gate PASS)"},
      "license": "CC-BY-4.0 (Adom-authored model); TI's datasheet keeps TI's terms"}
json.dump(m3, open("provenance/3d-model.json", "w"), indent=1)

# ---- verification log
def entry(title, scope, checks, evidence, files, status="verified"):
    return {"date": D, "by": BY, "status": status, "title": title, "scope": scope, "variants": ["*"],
            "checks": [{"text": t, "result": r} for t, r in checks],
            "evidence": [{"label": os.path.basename(e), "href": e} for e in evidence], "files": {f: sha(f) for f in files}}
sym = open(f"{S}.kicad_sym").read()
pins = re.findall(r'\(pin (\w+) line \(at (\S+) (\S+) \d+\) \(length \S+\) \(name "([^"]+)"\) \(number "(\d+)"\)', sym)
ongrid = all(abs(float(v) / 2.54 - round(float(v) / 2.54)) < 1e-6 for _, x, y, _, _ in pins for v in (x, y))
lbr = open(f"{S}.lbr").read()
nc_ok = len(re.findall(r'<pin name="NC(@\d)?"[^>]*direction="nc"', lbr)) == 3
rt_map = {}
for c in rt.get("connect", []):
    rt_map.setdefault(c.get("pin_number") or c.get("pin"), set()).update(c.get("pads", []) if isinstance(c.get("pads"), list) else [c.get("pad")])
rows = fc["rows"]; worst = max(r["cu"]["xor_mm2"] for r in rows)
entries = [
 entry("Pinout matches the datasheet", ["symbol"], [
   ("Symbol pins match SLVSHA1D Table 5-1 (p.4-5): 1 ILIM, 2 IMON, 3 IREF, 4 dVdT, 5 GND, 6 SFT_SEL, 7-8 OUT, 9 VDD, 10/22/23 IN, 11/17/21 NC, 12 MODE, 13 FLT (active low), 14 ITIMER, 15 TEMP, 16 EN/UVLO, 18 OVP, 19 PGOOD, 20 SWEN, exposed pad (24) IN", "pass"),
   ("Electrical types: IN, VDD, GND power in; OUT power out; EN/UVLO, OVP, MODE input; FLT and PGOOD open drain; SWEN and TEMP bidirectional; resistor/capacitor set pins passive; NC no_connect", "pass"),
   (f"Every pin sits on the 2.54 mm grid: {'yes' if ongrid else 'NO'} (adom-symbol 1.2.6 put the first pin of each column at y = -2.00 with 8.35 mm group gaps; all 24 pins moved by provenance/tools/snap_symbol.py)", "pass" if ongrid else "fail"),
   ("Fusion .lbr: NC pins typed nc (adom-lbr 2.47.5 wrote io; fixed by provenance/tools/lbr_fix.py), every pin visible=both, lint PASS", "pass" if nc_ok else "fail"),
   ("Altium SchLib read back with adom-lbr import-altium: 24 pins, names shown; NC pins read back as Passive because Altium has no no-connect pin type (use a No ERC marker on the sheet)", "note")],
   ["docs/figures/tps16850vmar-ds-p4.png", "docs/figures/tps16850vmar-ds-p5.png"], [f"{S}.kicad_sym", f"{S}.lbr", "altium/TPS16850VMAR.SchLib"]),
 entry("Footprint equals TI's recommended land pattern", ["footprint"], [
   (f"Overlay on SLVSHA1D p.55 at TI's printed 15X scale: {fc['overlay']['copper_outline_on_ti_strokes']*100:.1f} % of the copper outline on TI's strokes (TI draws the metal under mask of pads 7, 10, 22 dashed), comb mask openings {fc['overlay']['comb_mask_on_ti_green']*100:.1f} % on TI's green", "pass"),
   (f"Pad by pad against TI's VMA0023A footprint published through Ultra Librarian: copper, mask and paste of all 24 pad numbers agree to {worst:.3f} mm2 or less (corner treatment only); the 12 vias are at the same positions", "pass"),
   ("Pads 7, 10 and 22 are solder-mask defined combs over a larger copper rectangle, as TI draws them; pads 6 and 17 are L shapes; exposed pad paste is TI's six 0.98 x 1.04 mm windows (p.56, 76 % coverage)", "pass"),
   ("KiCad's standard library has no VMA0023A footprint, so no KiCad comparison is possible", "note"),
   ("adom-lbr 2.47.5 drops KiCad custom-pad shapes and paste-only pads: the Fusion and Altium libraries are made from provenance/tps16850vmar-lbr-input.kicad_mod, the same copper as rectangle unions, copper-only pads with mask and paste expansion -1.2 mm; Fusion gets TI's six paste windows on tCream by hand; Altium gets one exposed-pad paste aperture with the same area (expansion -0.174 mm) because adom-lbr writes no paste-layer regions", "note")],
   ["docs/proof/tps16850vmar-footprint-check.png", "docs/figures/tps16850vmar-ds-p55.png", "docs/figures/tps16850vmar-ds-p56.png"],
   [f"{S}.kicad_mod", f"{S}.lbr", "altium/TPS16850VMAR.PcbLib"]),
 entry("Pin 1 orientation agrees across datasheet, footprint, 3D model and symbol", ["footprint", "3d", "symbol"], [
   ("Datasheet: pin 1 (ILIM) on the left side 0.5 mm above the centre line in the top view (Figure 5-1, p.4; land pattern p.55), pin-1 index corner and exposed-pad chamfer at the top left (p.54)", "pass"),
   ("Footprint: pad 1 at (-2.875, -0.5) in KiCad's Y-down frame, silkscreen dot to its left, fab outline chamfered at the top-left corner; numbering counter-clockwise (1-5 down the left, 6 corner, 7-10 along the bottom, 11-16 up the right, 17 corner, 18-21 along the top right to left, 22-23 top left)", "pass"),
   ("3D model: pin-1 terminal at (-2.75, +0.5) in the Y-up 3D frame (= pad 1), exposed-pad chamfer at the top-left corner; component-hero align check OK, offset 0.0 mm, zero rotation", "pass"),
   ("Symbol pin 1 = ILIM; Fusion and Altium map pin 1 to pad 1 (read back)", "pass"),
   ("Tape and reel: TI quadrant Q1 for pin 1 (p.52)", "pass")],
   ["docs/proof/tps16850vmar-pin1-check.png", "docs/figures/tps16850vmar-ds-p4.png", "docs/figures/tps16850vmar-ds-p52.png"],
   [f"{S}.kicad_mod", f"{S}.step", f"{S}-etched.step", f"{S}.kicad_sym"]),
 entry("3D model inside TI's package drawing", ["3d"], [
   (f"Bottom view over SLVSHA1D p.54: {ov['bottom']['score']*100:.1f} % of the model's edge pixels on TI's strokes at a fitted {ov['bottom']['scale']} px/mm (TI 10X = 118.1 px/mm at 300 dpi)", "pass"),
   (f"Side view: terminal exposures on TI's (0.2) marks; {ov['side']['score']*100:.1f} % edge overlap; TI draws the body at A max 1.5 mm, the model is at the nominal 1.4 mm", "pass"),
   ("Every printed dimension at its nominal (table in provenance/3d-model.json)", "pass"),
   ("Virtual MPN etch gate PASS (axis, upright with pin 1 left, size, flat, group); labelled virtual: TI's real marking is TPS16850", "pass"),
   ("TI's manufacturer STEP was not reachable with plain HTTP (Ultra Librarian export behind reCAPTCHA); the model is AI-built from the drawing", "note")],
   ["docs/proof/tps16850vmar-model-vs-drawing-bottom.png", "docs/proof/tps16850vmar-model-vs-drawing-side.png", "docs/proof/tps16850vmar-etched.check.png", "docs/figures/tps16850vmar-ds-p54.png"],
   [f"{S}.step", f"{S}-etched.step", f"{S}-hero.glb"]),
 entry("Still to do", ["*"], [
   ("Compare with TI's own STEP (Ultra Librarian) when someone can download it through a browser", "open"),
   ("Open the Fusion .lbr and Altium libraries in the native tools and look at the comb pads, paste windows and NC pins", "open"),
   ("A person reviews this page", "open")], [], [], status="open"),
]
json.dump({"schema": "adom/verification@1", "part": MPN,
           "variants": [{"mpn": MPN, "note": "auto-retry variant, 73 A fixed fast trip; 2500-piece large tape and reel (SLVSHA1D p.3, p.50)", "stocked": False}],
           "entries": entries}, open("verification.json", "w"), indent=1)
open("LICENSE", "w").write("""Creative Commons Attribution 4.0 International (CC BY 4.0)
https://creativecommons.org/licenses/by/4.0/

Copyright 2026 Adom Inc.

Applies to the files authored by Adom on this page: the KiCad symbol and footprint, the 3D models
(tps16850vmar*.step, *.glb, lod/), the virtual MPN etch, the chip outline artwork, the Fusion/EAGLE and
Altium libraries, the provenance tools and data, and the README text.

Not covered (they keep their own terms):
- docs/tps16850vmar-datasheet.pdf and the page images under docs/figures/ and inside docs/proof/: Texas
  Instruments Incorporated (SLVSHA1D), redistributed for reference under TI's terms.
""")
print("OK models.json", len(models), "lod levels", [l["triangles"] for l in levels], "verification entries", len(entries), "grid", ongrid, "nc", nc_ok)