Skip to content

Commit edecd44

Browse files
test(showcase): the boot-splash wait sees both English lines and the data-boot-splash marker (#23030)
Fixes #22992 Clause-②: no Dispatched by the `domain:devx` seat 1 PM (claim comment 6122220922 on #22992); implementing session `https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2`. ## What changes `examples/app-showcase/e2e/showcase-smoke.spec.ts` keyed the boot splash on `/Initializing application/i`, in two places: the render wait and the deadline assertion. objectui `54159d3` (objectstack-ai/objectui#12203) changes that line to "Opening your console…". It also shows the line in the browser's language, and leaves it out until that language's catalogue lands. So the first `.objectui-sha` bump past that commit would turn every surface check into a silent pass. A surface now counts as still on the splash when EITHER holds: - **Marker half.** `[data-boot-splash]` is in the page (a `page.locator(...).count()`). From objectui `54159d3` on, the splash root carries this attribute in every state (loading, `message`, error). It is the only language-independent sign. - **Line half.** The main element's text matches `/Initializing application|Opening your console/i`. Today's pin `088e0f70` has no marker, so this is the half that holds there. Both uses follow: - **The wait.** It reads the marker count, then the text, and returns only when the text is non-empty, the count is 0, and the line does not match. The marker is read first, so a splash that leaves between the two reads errs toward "not yet". - **The deadline assertion.** It asserts both from the wait's last sample: the marker count is 0, with the message "never got past the boot splash ([data-boot-splash] still in the page)", and the text does not match the line. `docs/qa/platform-checklist/areas/platform-core.json`, item `platform-core.nav-surfaces-render`: - The acceptance clause and the boot-splash negative now name the marker and both English lines, the same as the spec. - `revision` 5 → 6, with a history entry. No gate pins the clause text. `check-platform-checklist.mjs` only requires `revision` to equal the last history entry, and the ablation below shows it reads this item. ⛔ No `.objectui-sha` bump and no objectui edit. ## Both halves, proven on today's pin without the bump **No regression on `088e0f70`.** I read both objectui commits in a scratch bare clone: - `git grep data-boot-splash` at `088e0f70`: exit 1. Control at `54159d3`: exit 0, with hits in `LoadingScreen.tsx` and `e2e/smoke.spec.ts`. - `git grep -i 'Opening your console'` at `088e0f70`: exit 1. The same grep over this repository at HEAD: exit 1. - `en.ts` `console.initializing` reads `Initializing application…` at `088e0f70` and `Opening your console…` at `54159d3`. So on today's pin the marker half never fires, and the new alternative matches no text the pinned console or the showcase can draw. For an en run, the predicate reduces to the old one. **String level.** I took the regex literal out of the committed file (HEAD) and the pre-fix file: | sample | new | old | |---|---|---| | `088e0f70` en: "Initializing application…" | match | match | | `54159d3` en: "Opening your console…" | match | miss | | `54159d3` zh: 「正在打开你的控制台…」 | miss | miss | | `54159d3` line absent: product name only | miss | miss | | a rendered surface | miss | miss | The two misses on splash rows are why the marker half exists. **The real spec against static fixtures.** I ran the committed spec file, unmodified, under a scratch Playwright config: - The target was a static HTTP server, one port per fixture. - No globalSetup, no storageState, no backend. - Surface `Capability Map` only, Chromium `/opt/pw-browsers/chromium`. Each fixture is a main element holding one shape the console can be in. | fixture | HEAD `8706217be` | pre-fix (`9432bac07` blob, byte-identical copy) | |---|---|---| | rendered content | pass (0.5 s) | pass | | `088e0f70` splash, "Initializing application…", no marker | **fail**, line assertion | fail, line assertion | | "Opening your console…", no marker | **fail**, line assertion | **pass (0.6 s): silent pass** | | `54159d3` splash, en line + marker | **fail**, marker assertion | **pass (0.5 s): silent pass** | | `54159d3` splash, zh line + marker | **fail**, marker assertion | **pass (0.6 s): silent pass** | | `54159d3` splash, empty line + marker | **fail**, marker assertion | **pass (0.5 s): silent pass** | | old-line splash, replaced by content at 2 s | pass (2.4 s) | pass (2.4 s) | | marker splash (empty line), replaced by content at 2 s | pass (2.3 s): waited past it | pass (**0.4 s**): returned on the splash | HEAD: 5 failed, 3 passed. Pre-fix: 1 failed, 7 passed. The failing HEAD rows each fail at the 25 s budget with the message named in the table. ## Ablations Each ablation was one in-tree mutation of the committed file through `scripts/ablation-replace.mjs`, in WRAP mode. Each time the anchor hit once, the blob changed, an on-disk count was printed before the run, and the file was restored to the HEAD blob `cf29f0737` with an empty `git diff HEAD`. - **Marker half off.** The `count()` read was replaced by `splashMarkers = 0;`. 3 failed, 5 passed: - the zh and empty-line `54159d3` splashes pass silently (0.26 s / 0.30 s); - the marker-then-content fixture returns on the splash (0.34 s); - the en `54159d3` splash is still caught, by the line. - **Line half off: the marker alone.** `BOOT_SPLASH_LINE` was replaced by a never-matching `/(?!)/`. 3 failed, 5 passed: - **the `088e0f70` splash passes silently (0.66 s);** - the old-line-then-content fixture returns on the splash (0.48 s). This is the measured reason the marker never goes in alone on this pin. - **Checklist revision.** `revision` 6 → 5 on `platform-core.nav-surfaces-render`. `check-platform-checklist.mjs` goes from 8 problems to 9, and the new one names this item: "revision (5) must equal the last history entry's revision (6)". ## Not measured **The 49-surface e2e on today's pin: NOT MEASURED.** This container has no vendored console: `packages/console/dist` is absent, and so is `.cache/objectui-*`. Producing one means `scripts/build-console.sh`: a clone, install and turbo build of objectui's console closure at `088e0f70`. That comes on top of the showcase closure build, on a shared 4-core box with a ~10-minute foreground cap. The nightly / `workflow_dispatch` `Showcase Smoke` workflow is the run that measures it. The equivalence argument above stands in for it on today's pin. ## Tests and gates All at HEAD `8706217be`. - `pnpm turbo run build --filter='@objectstack/example-showcase^...' --concurrency=2`: 60/60 tasks, exit 0. - `pnpm --filter @objectstack/example-showcase run typecheck`: exit 0. `tsc --listFiles` includes `e2e/showcase-smoke.spec.ts` (count 1). - `pnpm --filter @objectstack/example-showcase exec vitest run --maxWorkers=2`: 33 files, 408 passed, 1 skipped. vitest excludes `e2e/**`, so this suite cannot see the change; it was run as the package's own suite. - ESLint (`--no-inline-config --format json`) on the 2 changed files: - the spec: 0 errors, 0 warnings; - `platform-core.json`: ignored, because the config's `files` globs cover JS/TS extensions only. This narrowing is a measurement, not a skip. The config enables no type-aware linting (the printed config has no `parserOptions.project`). The spec's 4 rules read only the file's own AST, and the config's only disk reads are two ignore baselines this diff does not touch. So the diff cannot move the verdict on any file it does not touch. The repo-wide scan is CI's. - Gates: the 42 commands `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives from this diff, the same list as the dispatch. Run after the closure build, each with its exit captured before any pipe: - **41 exit 0.** - **`pnpm check:platform-checklist` exits 1.** Its 8 problems are byte-identical to a run at the base `9432bac07`; see the acceptance notes. - `check:dual-build-cjs-loads` answered PREREQUISITE NOT MET on a first pass, because eight packages outside the showcase closure had no `dist/`. I built them (a turbo cache hit), re-ran it, and it measured: exit 0, 107 entries. - `dispatch-gates --ran`: "42 derived, 42 run, 0 NOT-MEASURED, 0 UNRUN", exit 0. ## Changeset None: `skip-changeset`. `examples/app-showcase` is a private package, and `docs/qa/` ships in no package. ## Acceptance notes - The `Opening your console` alternative covers no objectui commit that the marker does not also cover. `54159d3` is a single-parent squash that brought the new line and the marker together. Its parent `ddc2d8e3` has neither: both greps exit 1. The control at the same commit, "Initializing application" in `en.ts`, exits 0. The alternative is kept as triage graded it, as the required half; on any real pin it is redundant with the marker, never harmful. - On today's pin a non-`en` run's splash reads 「正在初始化应用程序…」 (zh at `088e0f70`), and no English pattern matches it. The smoke runs Playwright's `Desktop Chrome` device at its default locale, so CI does not reach this. It closes with the bump, through the marker. - `pnpm check:platform-checklist` is red on `main` at `9432bac07`, with 8 problems in `access-security.json`, `attachments-storage.json` and `search.json`: absent symbol anchors, and one floor loss. Its output is byte-identical on the base and on this branch, and this diff adds nothing to it. The gate is not in per-PR CI (maintainer decision, `lint.yml` NOTE). Its reporting channel is `.github/workflows/platform-checklist-watchdog.yml`. --- _Generated by [Claude Code](https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8f5354b commit edecd44

2 files changed

Lines changed: 42 additions & 12 deletions

File tree

‎docs/qa/platform-checklist/areas/platform-core.json‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@
250250
"title": "Every showcase nav surface renders without page errors, and failures surface the error boundary — never a blank page",
251251
"since": "v15",
252252
"status": "active",
253-
"revision": 5,
253+
"revision": 6,
254254
"priority": "P0",
255255
"surface": "browser",
256256
"personas": ["seeded admin (admin@objectos.ai / admin123)"],
@@ -271,7 +271,7 @@
271271
],
272272
"acceptance": [
273273
{
274-
"clause": "no surface throws a pageerror, renders an empty <main>, stays on the console's boot splash ('Initializing application…'), or leaks a 'no actions configured' placeholder; chart surfaces draw a real SVG whose box is measured by POLLING until non-null within a bounded budget — never by a fixed wall-clock wait followed by a single boundingBox read, which measures the layout window rather than the product",
274+
"clause": "no surface throws a pageerror, renders an empty <main>, stays on the console's boot splash (its data-boot-splash marker is in the page, or <main> reads its English line 'Initializing application…' or 'Opening your console…'), or leaks a 'no actions configured' placeholder; chart surfaces draw a real SVG whose box is measured by POLLING until non-null within a bounded budget — never by a fixed wall-clock wait followed by a single boundingBox read, which measures the layout window rather than the product",
275275
"oracle": "test",
276276
"verify": "pnpm -C examples/app-showcase test:smoke (SURFACES array in e2e/showcase-smoke.spec.ts) — green; the main-content wait treats the boot splash as not-yet-rendered and the assertion refuses a surface still on it; the chart assertion polls boundingBox against a bounded deadline and keeps the last non-null sample, so a null-box failure and a collapsed-panel failure report as different assertions (#7569)",
277277
"evidence": "test run output + the failing assertion's message for any chart red"
@@ -297,7 +297,7 @@
297297
],
298298
"negative": [
299299
"a surface that renders a blank <main> is a FAIL even with no console error — transitional emptiness must be ruled out by the screenshot-first protocol, then the persistent blank is the finding",
300-
"the boot splash is NOT rendered content: 'Initializing application…' is text inside <main>, so a non-empty check passes on a surface that never rendered. QA run #21056 read it as the FIRST <main> text on 22 of 49 surfaces, and the suite's own non-chart check passed on it until revision 5. A hand walk waits past the splash before judging, exactly as the suite now does",
300+
"the boot splash is NOT rendered content: it is text inside <main>, so a non-empty check passes on a surface that never rendered. QA run #21056 read it as the FIRST <main> text on 22 of 49 surfaces, and the suite's own non-chart check passed on it until revision 5. Recognise it by its language-independent data-boot-splash marker (objectui 54159d3 on), or by either English line: 'Initializing application…' before that commit, 'Opening your console…' from it. From that commit on the line follows the browser's language and is absent until that language's catalogue lands, so neither English line matches a non-English splash or an empty-line one, which shows only the product name; on a console pinned before that commit there is no marker. A hand walk waits past the splash before judging, exactly as the suite now does",
301301
"a bad route producing a white page (shell gone) is a FAIL of the error-boundary clause",
302302
"a chart red obtained from a SINGLE boundingBox read at a fixed instant is NOT a product finding and must not be filed as one — it measures the ResponsiveContainer layout window, and it cost a triage cycle every run until #7569 replaced that read with a bounded poll. Re-introducing any fixed sleep-then-read-once in this suite re-opens it. The converse holds both ways: a box that stays null through the WHOLE bounded poll, or a laid-out width ≤ 200 (the #2616 D collapsed-panel case), IS a FAIL"
303303
],
@@ -319,6 +319,12 @@
319319
"date": "2026-10-01",
320320
"change": "the pin caught up with QA run #21056's three findings: SURFACES covered 31 of 49 served destinations, and the 18 the run hand-walked are now in it (Revenue Pulse and the Hours by Status chart report as chart surfaces); the non-chart check passed on the boot splash, and the wait and assertion now treat the splash as not rendered; the config hard-coded port 3000 and offered no browser override, and now reads SMOKE_API_URL for the server it boots and OS_TEST_CHROMIUM_EXECUTABLE_PATH for the browser. Measured on this branch: 49 passed on a free port with the container's chromium, and an instrumented run saw 29 of the 49 surfaces on the splash first",
321321
"ref": "#21060"
322+
},
323+
{
324+
"revision": 6,
325+
"date": "2026-10-12",
326+
"change": "the boot-splash clause and negative named only the old English line 'Initializing application…'. objectui 54159d3 changed that line to 'Opening your console…', in the browser's language and absent until its catalogue lands, and put a language-independent data-boot-splash marker on the splash root. Both now name the two English lines and the marker, matching the suite: a surface is still on the splash when the marker is in the page or <main> reads either line. The line half is the one that holds on a pin older than 54159d3, which has no marker",
327+
"ref": "#22992"
322328
}
323329
]
324330
},

‎examples/app-showcase/e2e/showcase-smoke.spec.ts‎

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,30 @@ const SURFACES: { name: string; path: string; chart?: boolean }[] = [
8585

8686
/**
8787
* The console's boot splash — objectui app-shell's `LoadingScreen`, which the
88-
* shell also renders as a `Suspense` fallback INSIDE its `<main>` — reads
89-
* "Initializing application…" under the default locale. Its text is not empty,
90-
* so a check of "main has text" passed on a surface that had not rendered at
91-
* all: QA run #21056 read the splash as the FIRST `<main>` text on 22 of 49
92-
* surfaces. The wait below treats the splash as not-yet-rendered, and the
93-
* assertions refuse a surface that is still on it at the deadline.
88+
* shell also renders as a `Suspense` fallback INSIDE its `<main>`. Its text is
89+
* not empty, so a check of "main has text" passed on a surface that had not
90+
* rendered at all: QA run #21056 read the splash as the FIRST `<main>` text on
91+
* 22 of 49 surfaces. The wait below treats the splash as not-yet-rendered, and
92+
* the assertions refuse a surface that is still on it at the deadline.
93+
*
94+
* A surface is on the splash when EITHER of these holds, and both stay:
95+
*
96+
* - `BOOT_SPLASH_MARKER` is in the page. From objectui `54159d3` on, the
97+
* splash root carries `data-boot-splash` in every state (loading, `message`,
98+
* error). It is the only language-independent sign: the splash's line
99+
* follows the user's language from that commit on, and it is absent until
100+
* that language's catalogue lands, leaving only the product name. Neither
101+
* English line below matches either case.
102+
* - `<main>`'s text matches `BOOT_SPLASH_LINE`, the splash's English line in
103+
* both spellings: "Initializing application…" before objectui `54159d3`,
104+
* "Opening your console…" from it. A console pinned before that commit has
105+
* no marker, so the line is the only half that sees its splash.
106+
* ⛔ Never key on the marker alone while `.objectui-sha` is older than
107+
* `54159d3`: the marker then matches nothing, and the wait passes on the
108+
* splash.
94109
*/
95-
const BOOT_SPLASH = /Initializing application/i;
110+
const BOOT_SPLASH_MARKER = '[data-boot-splash]';
111+
const BOOT_SPLASH_LINE = /Initializing application|Opening your console/i;
96112

97113
/**
98114
* The budget every wait in this file spends, measured from the start of the
@@ -149,10 +165,14 @@ for (const surface of SURFACES) {
149165
// [#21060] Rendered means past the boot splash, not merely non-empty: the
150166
// splash is text too. The last sample is kept whatever it was, so a surface
151167
// stuck on the splash fails as exactly that rather than as "no content".
168+
// The marker is read BEFORE the text: a splash that leaves between the two
169+
// reads then errs toward "not yet", never toward "rendered".
152170
let mainText = '';
171+
let splashMarkers = 0;
153172
await pollUntil(async () => {
173+
splashMarkers = await page.locator(BOOT_SPLASH_MARKER).count();
154174
mainText = ((await main.innerText().catch(() => '')) || '').trim();
155-
return mainText.length > 0 && !BOOT_SPLASH.test(mainText);
175+
return mainText.length > 0 && splashMarkers === 0 && !BOOT_SPLASH_LINE.test(mainText);
156176
}, deadline);
157177

158178
let chartBox: { width: number; height: number } | null = null;
@@ -181,7 +201,11 @@ for (const surface of SURFACES) {
181201
`leaked placeholder on ${surface.name}`,
182202
).toHaveCount(0);
183203
expect(mainText.length, `${surface.name} rendered no main content`).toBeGreaterThan(0);
184-
expect(mainText, `${surface.name} never got past the boot splash`).not.toMatch(BOOT_SPLASH);
204+
expect(
205+
splashMarkers,
206+
`${surface.name} never got past the boot splash (${BOOT_SPLASH_MARKER} still in the page)`,
207+
).toBe(0);
208+
expect(mainText, `${surface.name} never got past the boot splash`).not.toMatch(BOOT_SPLASH_LINE);
185209

186210
if (surface.chart) {
187211
expect(

0 commit comments

Comments
 (0)