← Commit history

2.23.0 ships module 2.21.0: checkSend probes a path that cannot exist and requires a different answer, so a blanket preflight can no longer make it green

John Lauer ·ec6e755ee4 ·1mo ago ·parent 7dc0dd7
3 files changed +64−5
assets/module/newbie-panel.js+20−4
@@ -585,14 +585,30 @@       })       .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); });+        /* PROBE A NONSENSE PATH TOO, AND REQUIRE THE TWO TO DIFFER.+         * "not 404" was too weak an assertion. kicad's do_OPTIONS returned 204 for EVERY path+         * unconditionally, so this row was green for any string at all, including routes that+         * exist in no method. An app could fix its GET catch-all, still have a blanket+         * preflight, and keep a green row that tests nothing. Comparing against a path that+         * cannot exist makes the row self-validating: if they answer identically, the server+         * is answering the SHAPE of the question rather than the question. */+        var nonsense = '/__anp_probe_' + String(Math.floor(1e9 * 0.6180339887)) + '__';+        return Promise.all([+          fetch(base + '/ai-threads/run-prompt', {method: 'OPTIONS'}).then(function (r) { return r.status; },+            function () { return 'ERR'; }),+          fetch(base + nonsense, {method: 'OPTIONS'}).then(function (r) { return r.status; },+            function () { return 'ERR'; })+        ]).then(function (both) {+          var real = both[0], fake = both[1];+          add('send route wired', 'answers, and differently from a path that cannot exist',+              'route ' + real + ', nonsense ' + fake,+              real !== 'ERR' && real !== 404 && real !== fake);+        });       })       .then(function () { return {ok: ok, rows: rows}; });   }    root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText,-                           checkSend: checkSend, version: '2.20.1',+                           checkSend: checkSend, version: '2.21.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.22.0",+  "version": "2.23.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+43
@@ -734,6 +734,49 @@ three before it looked: This is kicad's "passes for the wrong reason" arriving three times in one app, hours after it was named. **A permissive default does not fail your checks; it answers them.** +**THERE IS A SECOND CATCH-ALL, AND IT IS THE ONE THAT MATTERS.** kicad fixed its GET catch-all+and its send row stayed green, because its `do_OPTIONS` returned **204 for every path+unconditionally**:++```+OPTIONS /nonsense              -> 204+OPTIONS /ai-threads/run-prompt -> 204     indistinguishable, which is the point+```++So an app can fix the obvious catch-all and still have a row that tests nothing. **Extend the+one-line test to the preflight:**++```sh+curl -o /dev/null -w '%{http_code}' -X OPTIONS <base>/nonsense    # must also 404+```++**`checkSend` now defends itself against this** (module 2.21.0): it probes the real route AND a+path that cannot exist, and requires the two to ANSWER DIFFERENTLY. "Not 404" was too weak an+assertion. Controlled both ways: a blanket preflight reads `route 204, nonsense 204` and goes+red; honest routing reads `route 204, nonsense 404` and passes. **If a server answers a path+that cannot exist, it is answering the shape of the question rather than the question.**++The structural fix, and the one to copy: **both handlers read ONE route table**, so a route can+never be live for OPTIONS and dead for GET. Two independent notions of "does this route exist"+was the actual defect.++**⛔ DO NOT FIX THIS WITH A BLANKET 404, AND HERE IS THE REAL CONSTRAINT.** adom.cloud mounts a+dashboard under a sub-path AND FORWARDS THE PREFIX, so the app's own root arrives as+`/apps/kicad`, which is shape-identical to a typo. **A blanket 404-unless-slash passes the+one-line test and breaks the app in production.** kicad's rule instead:++- 404 if the path is **asset-shaped** (a known file extension), whoever asks+- 404 if it is inside a **namespace you own** (`/api/`, `/ui/`, `/updater/`, `/assets/`,+  `/ai-threads/`), whoever asks+- always serve `/`+- otherwise serve the shell only for a **real browser navigation** (`Accept: text/html`)++**Stated with its caveat rather than as a clean claim, which is how kicad reported it:** a+browser typing a wrong extensionless URL still gets the shell. That is accepted, because what+the 404 watch actually watches is missing pngs, mp3s, favicons and js — all of which carry an+extension or an owned prefix and 404 regardless of client. Verified against an image `Accept`+header. **Do not fix a passes-for-the-wrong-reason bug by shipping another one.**+ ### ⛔ GREP THE ENTITIES TOO  nb's Layer 2 heading carried an em-dash written as `&mdash;`, so it **survived every plain-text