skill
molecule-publish
Public Made by Adomby adom
Publish molecules AND generic boards to the Adom wiki - one publisher, two shapes: OCCT conversion (molecule mode with stats gates, or plain for boards), component packaging, adom-wiki publish, APM render assets + component dependencies. Companion to adom-molecule-import.
← Commit history
Publish 2.6.0
4 files changed
+92−6
SKILL.md+19−3@@ -277,9 +277,9 @@ from a pre-rendered `render/` folder; without it, boards trip APM's red "missing render folder" bar and fall back to slow live rendering. ```bash-adom-wiki pkg install adom/adom-project-manager # once per container-adom-project-manager --render-board <slug> # (the adom-nucleus name still-# resolves via the deprecated alias shim, but prefer adom-project-manager)+adom-wiki pkg install adom/adom-nucleus # once per container (APM was RENAMED+adom-nucleus --render-board <slug> # to adom-nucleus; the old+# adom-project-manager name still works via the rename shim's symlink) ``` **Ordering is load-bearing: run this AFTER Stage 3's `pkg publish` + repo@@ -302,6 +302,19 @@ Verify after the run: version you just published; - a content-changing publish added a `versions[]` entry + `render/<version>/` files; a metadata-only republish did NOT (dedup working as intended).+- **`render/board.glb` is not DEGRADED (adom/wiki#91).** `--render-board`+ sometimes writes a `render/board.glb` with far fewer meshes than the board+ actually has, and the page serves it via `model_3d_path`. Gate on MESH+ COUNT, never file size (size gives false positives both ways):+ ```bash+ python3 scripts/render_parity.py render/board.glb <slug>.glb+ ```+ A faithful render has the SAME mesh count as the page-level `<slug>.glb`+ (verified: zu 190=190, pinch 155=155; the degraded ones were 35 vs 336 and+ 11 vs 20). Non-zero exit = the render dropped geometry: re-run+ `--render-board`; if it recurs, the render *emitter* is at fault (report the+ board to the `--render-board` / service-kicad owner, this is not fixable in+ the publish flow beyond refusing to ship it). **Make the sheets VISIBLE (#3):** component pages have no schematic viewer slot, so rendered `render/sheet-*.svg` are invisible unless embedded. After@@ -327,6 +340,9 @@ landing in APM; nothing changes on this side when it does). flagged pending with what it needs - [ ] `render/manifest.json` on the page with `current` == the version you just published (Stage 3.5)+- [ ] `render/board.glb` mesh count == the page `<slug>.glb` (adom/wiki#91) —+ `scripts/render_parity.py render/board.glb <slug>.glb`; a degraded+ render is what the 3D tab serves, so refuse to ship it - [ ] molecule shape only: provenance stamp + footprint/symbol artifacts - [ ] **web-grade GLB** — the conversion stats' `web_grade.overBudget` is `false` (< 8 MB / < 4M verts). Over budget, the component-page 3D
package.json+2−2@@ -1,6 +1,6 @@ { "slug": "molecule-publish",- "version": "2.5.2",+ "version": "2.6.0", "type": "skill", "description": "Publish molecules AND generic boards to the Adom wiki - one publisher, two shapes: OCCT conversion (molecule mode with stats gates, or plain for boards), component packaging, adom-wiki publish, APM render assets + component dependencies. Companion to adom-molecule-import.", "tags": [@@ -44,4 +44,4 @@ "prompt": "Convert my molecule through OCCT and publish it" } ]-}+}
page.json+1−1@@ -1,6 +1,6 @@ { "slug": "molecule-publish",- "version": "2.5.2",+ "version": "2.6.0", "type": "skill", "description": "Publish molecules AND generic boards to the Adom wiki - one publisher, two shapes: OCCT conversion (molecule mode with stats gates, or plain for boards), component packaging, adom-wiki publish, APM render assets + component dependencies. Companion to adom-molecule-import.", "tags": [
scripts/render_parity.pyadded+70@@ -0,0 +1,70 @@+#!/usr/bin/env python3+"""render_parity.py - catch a degraded render/board.glb at publish (adom/wiki#91).++`--render-board` (nucleus/service-kicad) sometimes writes a DEGRADED+`render/board.glb` - fewer meshes than the board really has - and because board+pages declare `model_3d_path = render/1.0.0/board.glb`, that degraded file is+what the 3D tab serves. The wiki-side alphabetical fallback was fixed (Colby),+but a declared path still selects the degraded copy, so the pipeline must+refuse to publish one.++Signal is MESH COUNT, never file size (Colby: 28-byte deltas are mesh-identical,+and some molecules have a legitimately larger render/ copy - size gives false+positives both ways). When the render is faithful, `render/board.glb` and the+page-level `<slug>.glb` have the SAME mesh count (verified on the workcell+boards: zu 190=190, pinch 155=155; the degraded ones diverged 35 vs 336, 11 vs+20). So the gate is: render/board.glb mesh count >= the page model's, within a+small tolerance.++ check <render/board.glb> <page-model.glb> [--tolerance 0.05]+ exit 0 = parity OK; exit 1 = render is degraded (do not publish)+"""+import argparse+import json+import struct+import sys+++def mesh_count(path: str) -> int:+ with open(path, "rb") as f:+ b = f.read()+ if b[:4] != b"glTF":+ raise ValueError(f"{path} is not a GLB")+ json_len = struct.unpack_from("<I", b, 12)[0]+ j = json.loads(b[20:20 + json_len])+ return len(j.get("meshes", []))+++def main():+ ap = argparse.ArgumentParser(description=__doc__,+ formatter_class=argparse.RawDescriptionHelpFormatter)+ ap.add_argument("render_glb", help="render/board.glb emitted by --render-board")+ ap.add_argument("page_glb", help="the page-level <slug>.glb (the faithful model)")+ ap.add_argument("--tolerance", type=float, default=0.05,+ help="allowed shortfall fraction (default 0.05 = render may be "+ "up to 5%% below the page model before it's called degraded)")+ a = ap.parse_args()++ try:+ rn = mesh_count(a.render_glb)+ pg = mesh_count(a.page_glb)+ except Exception as e:+ print(f"FAIL: {e}")+ return 2++ floor = pg * (1 - a.tolerance)+ if rn < floor:+ pct = 100 * rn / pg if pg else 0+ print(f"FAIL: render/board.glb is DEGRADED - {rn} meshes vs {pg} in the page "+ f"model ({pct:.0f}%). The 3D tab would serve a stripped model "+ f"(adom/wiki#91). Re-run --render-board; if it recurs, the render emitter "+ f"is dropping geometry (report to the --render-board / service-kicad owner "+ f"with this board).")+ return 1+ extra = f" (render has {rn - pg} more - a legitimately richer render/ copy)" if rn > pg else ""+ print(f"OK: render/board.glb parity - {rn} meshes vs {pg} in the page model{extra}.")+ return 0+++if __name__ == "__main__":+ sys.exit(main())