← Commit history

2.16.0: checkSend() makes a missing send gate visible; retire by port ownership not argv (kicad killed a bystander); assert on every string replacement

John Lauer ·37f23adb50 ·1mo ago ·parent 83fbe22
4 files changed +90−3
assets/module/newbie-panel.js+31−1
@@ -514,6 +514,36 @@     return { ok: ok, rows: rows };   } -  root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText, version: '2.8.0',+  /* checkSend(apiBase) - prove the send path EXISTS, without sending anything.+   * gate() fails OPEN on purpose, so a broken probe cannot block a user from sending. The+   * consequence, which kicad found in itself: A MISSING GATE READS AS AN ALLOWED GATE. Its+   * /updater/status route had been lost in a rebuild, the gate got HTML, caught, and returned+   * open, so the version gate had been silently no-opping. Nothing anywhere said so.+   * This makes that visible. It never posts a prompt: the run-prompt route is probed with+   * OPTIONS, so it can report "wired" without creating a thread in anyone's list. */+  function checkSend(base) {+    base = base == null ? '' : base;+    var rows = [], ok = true;+    function add(what, want, got, pass) { rows.push({what: what, want: want, got: got, pass: pass}); if (!pass) ok = false; }+    return fetch(base + '/updater/status', {cache: 'no-store'})+      .then(function (r) { return r.text().then(function (t) { return {s: r.status, t: t}; }); })+      .then(function (res) {+        var v = null, parsed = false;+        try { var j = JSON.parse(res.t); parsed = true; v = j && j.updater && j.updater.current_version; } catch (e) {}+        add('gate route wired', '200 with JSON', res.s + (parsed ? ' JSON' : ' NOT JSON'), res.s === 200 && parsed);+        add('gate reports a version', 'updater.current_version', String(v), !!v);+        if (v) add('version meets the minimum', MIN_API.join('.'), String(v), verGte(verNum(v), MIN_API));+      })+      .catch(function (e) { add('gate route wired', '200 with JSON', 'FETCH FAILED: ' + e.message, false); })+      .then(function () {+        return fetch(base + '/ai-threads/run-prompt', {method: 'OPTIONS'})+          .then(function (r) { add('send route wired', 'not 404', String(r.status), r.status !== 404); })+          .catch(function (e) { add('send route wired', 'not 404', 'FETCH FAILED: ' + e.message, false); });+      })+      .then(function () { return {ok: ok, rows: rows}; });+  }++  root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText,+                           checkSend: checkSend, version: '2.16.0',                            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.15.0",+  "version": "2.16.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/dash-screenshot/SKILL.md+12−1
@@ -153,7 +153,18 @@ that verifies, waits and narrates. Its guard:   disturbance  **And the half that caused fusion's bug: the check must run IMMEDIATELY BEFORE EACH native-event, not once per sequence.** Three clicks means three verifications, because focus can move+event, not once per sequence.** fusion corrected the record on itself here, and the truth is+worse than the generous reading: it did not do one stale check, it did **ZERO**. It looked at+the foreground only AFTER the third click failed, and only because it was hunting an unrelated+symptom. **Had a toast fired on click one it would have reported success and never looked**,+and three clicks into John's live apps would have gone unnoticed and unreported.++That sharpens the rule rather than softening it: **the check must be structural, because the+failure is silent on the side that matters.** A stray click produces no error, no rejection and+no log. The only signal was an absence, and absences are exactly what a busy operator does not+notice. Note too that two independent coordinate computations agreeing to the pixel read, to+fusion, as strong evidence that coordinates were the variable. **They were the only part that+was never wrong.** Three clicks means three verifications, because focus can move between event one and event two. A single up-front check followed by three dispatches is exactly the shape that puts half a password in the wrong window. 
skills/newbie-panel/SKILL.md+46
@@ -606,6 +606,52 @@ If your page needs a wider margin for its own content, put it on the app body BE not on the container the panel mounts in. The panel is the full-width band at the top; the app's own gutter is the app's business. +### ⛔ A MISSING GATE READS AS AN ALLOWED GATE. PROBE IT WITH `checkSend()`.++`gate()` fails OPEN on purpose, so a broken probe cannot stop a user sending. The consequence+is invisible and kicad found it in itself: its `/updater/status` route **had been lost in a+rebuild**, so the gate received HTML, caught, and returned open. Its version gate had been+silently no-opping, and nothing anywhere said so. It could not have found this by reading its+own code, **because the code it was reading no longer existed.**++```js+await AdomNewbiePanel.checkSend()   // -> {ok, rows:[gate wired, version, minimum, send wired]}+```++**It never posts a prompt.** The run-prompt route is probed with `OPTIONS`, so it reports+"wired" without creating a thread in anyone's list. Negative-controlled before shipping: with+no routes it goes red on all three; with a stub gate and a wired POST it goes green.++Run it beside `selfCheck`. `selfCheck` proves the panel is right; `checkSend` proves the button+on it can do anything.++### ⛔ RETIRE BY PORT OWNERSHIP, NEVER BY argv. kicad KILLED A BYSTANDER.++Rehearsing its upgrade (above) against a real predecessor, kicad's retirement retired the old+instance on the target port **and killed an unrelated instance serving a different port**,+because it selected victims by argv and **every instance of a tool has identical argv**. On+John's box that is a dock dashboard dying because someone upgraded something else.++The fix, and the shape to copy: **resolve the listening socket's inode from `/proc/net/tcp`,+map it to a pid via `/proc/*/fd`, and use argv only as a SAFETY FILTER on that single pid.**+Publish your own pid in `/health` so a successor has a direct path, while not depending on it,+since a predecessor may not.++Re-rehearse all three cases: mismatch retires **and the bystander survives**; match returns the+SAME pid with no restart; a foreign server holding the port is **refused with a readable error+rather than killed**.++This skill already said "argv is a claim, not a fact". kicad had implemented the claim, which+is the usual distance between reading a rule and having followed it.++### ⛔ ASSERT ON EVERY STRING REPLACEMENT++kicad's lost route came from a silent string-replace with no assertion, the same shape as the+CSS deletions that cost it earlier in the day. **And it nearly re-shipped the same defect: its+first fix "applied" against an anchor that had drifted, and only the fidelity tool's second red+run caught it.** Asserting on every replacement is the cheap habit; a tool is what catches you+when the habit fails. Have both.+ ### Prove it in one call  ```js