← Commit history

2.21.0 ships module 2.20.1: the refusal returns rows:[] so it cannot arrive as a TypeError; name the layer with the number

John Lauer ·27a8f9a4ec ·1mo ago ·parent 5ffc8e4
3 files changed +42−8
assets/module/newbie-panel.js+11−5
@@ -419,11 +419,17 @@      * as a specific layout regression rather than an invalid run, and project-manager nearly      * filed it as a bug. A refusal cannot be misread. (project-manager, 2026-08-25.) */     var w0 = Math.round(panel.getBoundingClientRect().width);-    if (w0 === 0) return { ok: false, invalid: true,-      error: 'panel measures 0px wide: this tab is not foregrounded, so every layout row would ' ++    /* rows: [] is deliberate. The refusal previously omitted the key entirely, and EVERY+     * caller does r.rows.map(...) because every healthy result has rows, so a correct refusal+     * arrived at the caller as "Cannot read properties of undefined (reading 'map')" and read+     * like harness noise. kicad hit exactly that and logged it as its own crash. A guard whose+     * failure mode is a TypeError in someone else's stack is a guard that will be misread. */+    if (w0 === 0) return { ok: false, invalid: true, rows: [],+      error: 'panel measures 0px wide: this tab is not foregrounded (or the panel is hidden), ' ++             'so every layout row would ' +              'be computed from a collapsed pane while the style rows pass normally. Activate ' +-             'the tab by name and re-run. No rows reported, because a partial result from an ' +-             'unrendered pane looks like a real bug.' };+             'the tab by name (or open the panel) and re-run. No rows reported, because a ' ++             'partial result from an unrendered pane looks like a real bug.' };     var cs = getComputedStyle(panel), rows = [], ok = true;     /* Chrome reports the USED border-width, snapped to whole device pixels, so a declared      * 1px reads as 0.666667px at dpr 1.5. Compare against the snapped value, not the@@ -587,6 +593,6 @@   }    root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText,-                           checkSend: checkSend, version: '2.19.1',+                           checkSend: checkSend, version: '2.20.1',                            TWO_COL_MIN: TWO_COL_MIN, PHRASE_BUDGET: PHRASE_BUDGET }; })(typeof window !== 'undefined' ? window : this);
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "2.20.0",+  "version": "2.21.0",   "type": "skill",   "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths, dark-default, input-feedback, settings-layout). One install drops the whole set of skill files onto your container, plus shared icon assets (the settings cog) so every Adom app draws the same glyph.",   "dependencies": {},
skills/newbie-panel/SKILL.md+30−2
@@ -654,8 +654,16 @@ when the habit fails. Have both.  ### ⛔ A PARTIAL RESULT FROM AN UNRENDERED PANE IS WORSE THAN NO RESULT -`selfCheck` now **refuses to report** when the panel measures 0px wide, returning-`{ok:false, invalid:true, error:...}` and **no rows at all.**+`selfCheck` **refuses to report** when the panel measures 0px wide, returning+`{ok:false, invalid:true, rows:[], error:...}`.++**CHECK `invalid` BEFORE TOUCHING `rows`.** The first version omitted the `rows` key entirely,+and every caller does `r.rows.map(...)` because every healthy result has rows — so a correct+refusal arrived as `Cannot read properties of undefined (reading 'map')` and read like harness+noise. kicad hit exactly that and logged it as its own crash before finding the guard in the+source. It now returns `rows: []`, so the shape is safe, but branch on `invalid` anyway or you+will report an empty pass. **A guard whose failure mode is a TypeError in someone else's stack+is a guard that will be misread.**  The reason is the most dangerous instrument shape found all day. An unforegrounded tab returns zero-height rects **while computed styles still resolve normally**, so the check produced@@ -672,6 +680,26 @@ The general form, worth more than the panel: **when an instrument can detect tha preconditions are unmet, it must refuse, not degrade.** Degrading produces confident wrong answers that cost someone a bug hunt. +### ⛔ NAME THE LAYER WITH THE NUMBER. THE PACKAGE AND THE MODULE ARE DIFFERENT VERSIONS.++`adom-ui-design` **2.20.0 ships module 2.19.1.** They move independently by design: a doc-only+package release deliberately leaves the module's bytes untouched, which is what makes an+unchanged sha a positive signal.++**So "the module is at 2.20.0" is a sentence that cannot be true**, and an app told it will+grep its vendored file, find 2.19.1, conclude it is behind, and either re-vendor an identical+file or hunt for an asset version that does not exist. kicad caught this on the way into a+convergence sweep.++Always say: **package X ships module Y, sha Z.** And the convergence question is never "what+version are you on", it is:++> **does my asset's sha match the asset in the current package?**++A sha comparison also survives a stale files-endpoint, which a version string does not. kicad's+form, converged three ways and byte-identical: the package source under+`~/.claude/skills/adom-ui-design/assets/module/`, its own working copy, and the INSTALLED tree.+ ### A PURE LAYOUT NUMBER DOES NOT NEED A SLOT ON HIS MACHINE  **The module embeds Satoshi as base64, so the font program in a container is byte-identical to