From f3cdc1ad8d3cee5d07610a05e90a9f0712208c99 Mon Sep 17 00:00:00 2001 From: doxa-maps-88655c70 <88627970+doxa-maps-88655c70@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:48:33 +0000 Subject: [PATCH] A five-second studio check, so a dev-surface regression cannot ride along MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One commit shipped the requested change and a regression together: a base prefix applied to an already-rooted URL 404'd all 29 studio tabs, and finding it took 32 minutes. The root-cause analysis attributes the largest single share of that to there being no gate that exercises the dev server at all — of 46 gate-ish scripts and 13 browser gates, none did. The built manifest hands relative refs and the dev manifest hands rooted ones, so a base-join bug is invisible to every build-time gate and fatal to every developer. The check finishes in about four seconds against an already-running dev server, which is the point: the full sweep costs about seventy-five, so it only ever gets run at the end of a change, which is exactly how a regression rides along unnoticed. It activates one tab rather than twenty-nine because a single mount already exercises the whole resolver path — manifest fetch, script resolve, module load, define, mount. If the resolver is wrong, the first tab fails like all of them. It asserts the five things that have actually broken: that the root serves the studio and not a staging page, that the element both mounts and registers, that the tab list is not empty, that no request failed, and that the activated pane holds real content — because an element can register and attach while its content never arrives, which is what a missing API base looks like. An unreachable dev server exits 2 rather than 1. Conflating "no server" with "broken product" is how a gate earns a reputation for flakiness and gets switched off. Negative-tested: removing the tree base makes it fail on the empty tab list, and an unreachable URL exits 2; restoring returns to green. --- internal/smoke-studio.mjs | 179 ++++++++++++++++++++++++++++++++++++++ package.json | 5 +- 2 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 internal/smoke-studio.mjs diff --git a/internal/smoke-studio.mjs b/internal/smoke-studio.mjs new file mode 100644 index 000000000..a43fde28c --- /dev/null +++ b/internal/smoke-studio.mjs @@ -0,0 +1,179 @@ +#!/usr/bin/env node +/** + * smoke-studio.mjs — the FIVE-SECOND studio check, runnable on every edit. + * + * WHY THIS EXISTS (measured, 2026-09-22). A single commit shipped the requested change AND a + * regression: a base prefix applied to an already-rooted URL produced + * 404 /__plugin-gallery//plugin-designs//index.js + * and 404'd ALL 29 studio tabs. Finding it took 32 minutes. The root-cause analysis + * (_qa-cycle/01-ideation-research/RESEARCH-why-plugin-studio-changes-are-slow.md) attributes the + * single largest share of that to there being NO DEV-SURFACE GATE. The census it measured: + * package.json scripts ........................ 76 + * gate-ish (check:/verify:/smoke:/probe:) ..... 46 + * gates that launch a real browser ............ 13 + * gates in verify:browser-all ................. 7 + * gates that exercise the DEV SERVER .......... 0 <- the hole this closes + * + * ★ WHY THE BUILD COULD NEVER HAVE CAUGHT IT. The BUILT manifest hands RELATIVE refs + * ("./big-picture/big-picture.js"); the DEV manifest hands ROOTED ones + * ("/plugin-designs/big-picture/index.js"). A `base + ref` join is therefore correct forever in the + * built tree and broken instantly in dev — every build-time gate stays green while every developer's + * studio is broken. A product that must work on ten laptops cannot be verified by the build alone. + * See REFERENCE-the-four-surface-contract.md. + * + * ★ WHY IT ACTIVATES ONE TAB, NOT 29. The full sweep costs ~75s (29 tabs x ~2.5s), so it only ever + * gets run at the END of a change — which is exactly how a regression rides along undetected. One + * mount exercises the whole resolver path: manifest fetch -> scriptUrl resolve -> module load -> + * customElements.define -> mount. If the resolver is wrong, tab 1 fails like all 29. Cheap enough to + * run on every edit is worth more than thorough enough to run once. + * + * WHAT IT ASSERTS — each one maps to a defect that actually happened: + * 1. `/` serves the STUDIO, not a staging page (three staging surfaces have masqueraded as the product) + * 2. the element MOUNTS and its tag is DEFINED (a classic