mirror of
https://github.com/block/buzz.git
synced 2026-11-05 08:51:10 +00:00
revert(desktop): retain startup splash while diagnosing real stalls
Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -107,7 +107,6 @@ export default defineConfig({
|
||||
"**/workspace-rail.spec.ts",
|
||||
"**/community-rail.spec.ts",
|
||||
"**/boot-splash.spec.ts",
|
||||
"**/startup-usable.perf.ts",
|
||||
"**/thread-reply-anchor-roleplay.spec.ts",
|
||||
"**/threadpane-ultrawide.spec.ts",
|
||||
"**/thread-focus-mode.spec.ts",
|
||||
|
||||
@@ -79,8 +79,17 @@ import { StartupWindowDragRegion } from "@/shared/ui/StartupWindowDragRegion";
|
||||
|
||||
const LOADING_TEXT = "Setting up your community...";
|
||||
|
||||
// Minimum time the cold-boot splash stays on screen. A real boot resolves the
|
||||
// community in well under 100ms, and the native window setup plus first paint
|
||||
// can take longer than that — without a hold, the bee is unmounted before it is
|
||||
// ever visible. The hold runs as an overlay above the already-mounted app, so
|
||||
// time-to-interactive is unchanged; only the reveal waits.
|
||||
const BOOT_SPLASH_MIN_VISIBLE_MS = 1_200;
|
||||
const BOOT_SPLASH_FADE_MS = 200;
|
||||
const INITIAL_RENDER_READY_EVENT = "initial-render-ready";
|
||||
|
||||
type BootSplashPhase = "holding" | "fading" | "done";
|
||||
|
||||
function useInitialRenderReady() {
|
||||
useLayoutEffect(() => {
|
||||
if (!isTauri()) {
|
||||
@@ -91,6 +100,44 @@ function useInitialRenderReady() {
|
||||
}, []);
|
||||
}
|
||||
|
||||
// E2E runs skip the hold (it would slow every spec's boot and block pointer
|
||||
// actionability); a spec can opt back in via __BUZZ_E2E__.bootSplashHoldMs.
|
||||
function bootSplashHoldMs(): number {
|
||||
const e2e = (
|
||||
window as Window & {
|
||||
__BUZZ_E2E__?: { bootSplashHoldMs?: number };
|
||||
}
|
||||
).__BUZZ_E2E__;
|
||||
if (e2e) {
|
||||
return e2e.bootSplashHoldMs ?? 0;
|
||||
}
|
||||
return BOOT_SPLASH_MIN_VISIBLE_MS;
|
||||
}
|
||||
|
||||
function useBootSplashHold(): BootSplashPhase {
|
||||
const [phase, setPhase] = useState<BootSplashPhase>(() =>
|
||||
bootSplashHoldMs() > 0 ? "holding" : "done",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const holdMs = bootSplashHoldMs();
|
||||
if (holdMs <= 0) {
|
||||
return;
|
||||
}
|
||||
const fadeTimer = window.setTimeout(() => setPhase("fading"), holdMs);
|
||||
const doneTimer = window.setTimeout(
|
||||
() => setPhase("done"),
|
||||
holdMs + BOOT_SPLASH_FADE_MS,
|
||||
);
|
||||
return () => {
|
||||
window.clearTimeout(fadeTimer);
|
||||
window.clearTimeout(doneTimer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return phase;
|
||||
}
|
||||
|
||||
// Animated Buzz mark for the loading gates. The static BuzzMark renders in
|
||||
// normal flow and sizes the box — it's plain SVG (no JS/SMIL), so it paints on
|
||||
// the very first frame even before scripting starts, avoiding a blank flash on
|
||||
@@ -484,6 +531,8 @@ function CommunityApp({
|
||||
transitionCommunity,
|
||||
]);
|
||||
|
||||
const bootSplashPhase = useBootSplashHold();
|
||||
|
||||
const transaction = communityOnboarding.transaction;
|
||||
useEffect(() => {
|
||||
if (transaction?.stage !== "connecting") {
|
||||
@@ -539,6 +588,12 @@ function CommunityApp({
|
||||
// starter team" screen visibly restarts mid-handoff.
|
||||
const isEnteringCurtain = transaction?.stage === "entering";
|
||||
|
||||
// The app mounts (and starts loading data) beneath the splash overlay; the
|
||||
// overlay just keeps the bee on screen long enough to be seen, then fades.
|
||||
// Community switches keep their quiet gate.
|
||||
const showBootSplashOverlay =
|
||||
bootSplashPhase !== "done" && !isCommunitySwitch && !isContinuingOnboarding;
|
||||
|
||||
let appContent: ReactNode = null;
|
||||
if (!transaction) {
|
||||
if (community.needsSetup) {
|
||||
@@ -570,9 +625,7 @@ function CommunityApp({
|
||||
}
|
||||
}
|
||||
// Wait for this exact community config to be applied to the backend before
|
||||
// rendering anything that connects to the relay. Reveal the app as soon as
|
||||
// this real gate clears; a cosmetic splash must not block usable content.
|
||||
// The appliedKey check avoids
|
||||
// rendering anything that connects to the relay. The appliedKey check avoids
|
||||
// a one-render race where React sees the new active community while the
|
||||
// Tauri backend is still configured for the previous one.
|
||||
const communityApplied =
|
||||
@@ -599,6 +652,19 @@ function CommunityApp({
|
||||
key={communityKey}
|
||||
isSharedIdentity={sharedIdentity}
|
||||
/>
|
||||
{showBootSplashOverlay ? (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 transition-opacity",
|
||||
bootSplashPhase === "fading" ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
data-testid="boot-splash-overlay"
|
||||
style={{ transitionDuration: `${BOOT_SPLASH_FADE_MS}ms` }}
|
||||
>
|
||||
<AppLoadingGate />
|
||||
</div>
|
||||
) : null}
|
||||
</CommunityQueryProvider>
|
||||
) : isCommunitySwitch || isContinuingOnboarding ? (
|
||||
<CommunitySwitchGate />
|
||||
|
||||
@@ -1,166 +1,57 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { installMockBridge } from "../helpers/bridge";
|
||||
|
||||
async function holdStartupCommand(page: Page, commandToHold: string) {
|
||||
// Intercept the existing native boundary, not the readiness hook itself.
|
||||
await page.addInitScript((commandToHold) => {
|
||||
type Invoke = (
|
||||
command: string,
|
||||
args: unknown,
|
||||
options: unknown,
|
||||
) => Promise<unknown>;
|
||||
const state = { pending: 0, release: (_error?: string) => {} };
|
||||
Object.assign(window, { __STARTUP_GATE__: state });
|
||||
let settle: (error?: string) => void = () => {};
|
||||
const gate = new Promise<void>((resolve, reject) => {
|
||||
settle = (error) => (error ? reject(new Error(error)) : resolve());
|
||||
});
|
||||
let holding = true;
|
||||
state.release = (error) => {
|
||||
holding = false;
|
||||
settle(error);
|
||||
};
|
||||
const internals = {};
|
||||
let inner: Invoke;
|
||||
Object.defineProperty(internals, "invoke", {
|
||||
configurable: true,
|
||||
get: () => async (command: string, args: unknown, options: unknown) => {
|
||||
if (command === commandToHold && holding) {
|
||||
state.pending++;
|
||||
await gate;
|
||||
}
|
||||
return inner(command, args, options);
|
||||
},
|
||||
set: (invoke: Invoke) => {
|
||||
inner = invoke;
|
||||
},
|
||||
});
|
||||
Object.assign(window, { __TAURI_INTERNALS__: internals });
|
||||
}, commandToHold);
|
||||
}
|
||||
// Cold-boot splash hold: on a real boot the community resolves in well under
|
||||
// 100ms — before the hidden Tauri window ever puts a frame on screen — so the
|
||||
// loading gate keeps the flapping bee up as an overlay above the already
|
||||
// mounted app for a minimum visible duration, then fades out. E2E runs skip
|
||||
// the hold by default (it would slow every spec's boot and block pointer
|
||||
// actionability); this spec opts back in via __BUZZ_E2E__.bootSplashHoldMs.
|
||||
|
||||
async function releaseStartup(page: Page, error?: string) {
|
||||
await page.evaluate((error) => {
|
||||
(
|
||||
window as Window & {
|
||||
__STARTUP_GATE__: { release: (error?: string) => void };
|
||||
}
|
||||
).__STARTUP_GATE__.release(error);
|
||||
}, error);
|
||||
}
|
||||
|
||||
for (const cached of [false, true]) {
|
||||
test(`ready sidebar accepts input without a cosmetic hold (${cached ? "cached" : "uncached"})`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
await page.addInitScript(() => {
|
||||
// Old production waited 1200 + 200ms; normal E2E skipped that wait.
|
||||
// Keep this override to make restoring the old implementation fail here.
|
||||
Object.assign(window.__BUZZ_E2E__ ?? {}, { bootSplashHoldMs: 1200 });
|
||||
});
|
||||
await page.goto("/");
|
||||
if (cached) {
|
||||
await expect(page.getByTestId("channel-general")).toBeVisible();
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() =>
|
||||
Object.keys(localStorage).some((key) =>
|
||||
key.startsWith("buzz-channels.v1:"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toBe(true);
|
||||
await page.reload();
|
||||
}
|
||||
const row = page.getByTestId("channel-general");
|
||||
await expect(row).toBeVisible();
|
||||
// Synchronous hit-test: unlike click() auto-wait, this cannot hide a splash
|
||||
// intercepting input for another second above an already-mounted sidebar.
|
||||
expect(
|
||||
await row.evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return element.contains(
|
||||
document.elementFromPoint(
|
||||
rect.x + rect.width / 2,
|
||||
rect.y + rect.height / 2,
|
||||
),
|
||||
);
|
||||
}),
|
||||
).toBe(true);
|
||||
await row.click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await expect(page.getByTestId("message-row").first()).toBeVisible();
|
||||
await page.getByTestId("message-input").fill("Ready now");
|
||||
await expect(page.getByTestId("message-input")).toHaveText("Ready now");
|
||||
await expect(page.getByTestId("boot-splash-overlay")).toHaveCount(0);
|
||||
});
|
||||
}
|
||||
|
||||
for (const command of ["set_agent_avatar_communities", "apply_workspace"]) {
|
||||
test(`real startup gate remains while ${command} is pending`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
await holdStartupCommand(page, command);
|
||||
await page.goto("/");
|
||||
const gate = page.getByTestId("app-loading-gate");
|
||||
await expect(gate).toBeVisible();
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(
|
||||
() =>
|
||||
(window as Window & { __STARTUP_GATE__: { pending: number } })
|
||||
.__STARTUP_GATE__.pending,
|
||||
),
|
||||
)
|
||||
.toBeGreaterThan(0);
|
||||
await expect(page.getByTestId("home-inbox-list")).toHaveCount(0);
|
||||
await expect(page.getByTestId("channel-general")).toHaveCount(0);
|
||||
expect(
|
||||
await page.evaluate(() =>
|
||||
window.__BUZZ_E2E_COMMANDS__?.includes("get_channels"),
|
||||
),
|
||||
).toBe(false);
|
||||
const wingState = await gate.locator(".bee-wing-left").evaluate((wing) => ({
|
||||
name: getComputedStyle(wing).animationName,
|
||||
state: wing.getAnimations()[0]?.playState,
|
||||
}));
|
||||
expect(wingState).toEqual({ name: "bee-wing-left-flap", state: "running" });
|
||||
await releaseStartup(page);
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await expect(gate).toHaveCount(0);
|
||||
});
|
||||
}
|
||||
|
||||
test("failed community apply stays closed and retry is usable", async ({
|
||||
test("boot splash overlay holds with a flapping bee, then dismisses", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
await holdStartupCommand(page, "apply_workspace");
|
||||
// Registered after installMockBridge so it runs after the bridge's init
|
||||
// script and can extend the config it assigns.
|
||||
await page.addInitScript(() => {
|
||||
const testWindow = window as Window & {
|
||||
__BUZZ_E2E__?: { bootSplashHoldMs?: number };
|
||||
};
|
||||
testWindow.__BUZZ_E2E__ = {
|
||||
...(testWindow.__BUZZ_E2E__ ?? {}),
|
||||
bootSplashHoldMs: 1_500,
|
||||
};
|
||||
});
|
||||
await page.goto("/");
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(
|
||||
() =>
|
||||
(window as Window & { __STARTUP_GATE__: { pending: number } })
|
||||
.__STARTUP_GATE__.pending,
|
||||
),
|
||||
)
|
||||
.toBeGreaterThan(0);
|
||||
await releaseStartup(page, "Startup apply failed");
|
||||
await expect(page.getByTestId("community-apply-error")).toContainText(
|
||||
"Startup apply failed",
|
||||
);
|
||||
await expect(page.getByTestId("channel-general")).toHaveCount(0);
|
||||
expect(
|
||||
await page.evaluate(() =>
|
||||
window.__BUZZ_E2E_COMMANDS__?.includes("get_channels"),
|
||||
),
|
||||
).toBe(false);
|
||||
await page.getByTestId("community-apply-error-retry").click();
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await expect(page.getByTestId("community-apply-error")).toHaveCount(0);
|
||||
|
||||
const overlay = page.getByTestId("boot-splash-overlay");
|
||||
await expect(overlay).toBeVisible();
|
||||
|
||||
// The bee is actually animating while the overlay holds — pure CSS, no SMIL.
|
||||
const wingState = await overlay.locator(".bee-wing-left").evaluate((wing) => {
|
||||
const animation = wing.getAnimations()[0];
|
||||
return {
|
||||
name: getComputedStyle(wing).animationName,
|
||||
state: animation?.playState,
|
||||
};
|
||||
});
|
||||
expect(wingState).toEqual({ name: "bee-wing-left-flap", state: "running" });
|
||||
|
||||
// The app mounts and loads beneath the overlay — boot is not delayed.
|
||||
await expect(page.getByTestId("home-inbox-list")).toBeVisible();
|
||||
|
||||
// After the hold elapses the overlay fades out and unmounts.
|
||||
await expect(overlay).toHaveCount(0, { timeout: 6_000 });
|
||||
await expect(page.getByTestId("home-inbox-list")).toBeVisible();
|
||||
});
|
||||
|
||||
test("boot splash overlay is skipped when the hold is zero (e2e default)", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
await page.goto("/");
|
||||
|
||||
await expect(page.getByTestId("home-inbox-list")).toBeVisible();
|
||||
await expect(page.getByTestId("boot-splash-overlay")).toHaveCount(0);
|
||||
});
|
||||
|
||||
@@ -927,6 +927,15 @@ test("fresh-key harness completion continues directly into profile onboarding",
|
||||
},
|
||||
{ skipCommunitySeed: true, skipOnboardingSeed: true },
|
||||
);
|
||||
await page.addInitScript(() => {
|
||||
const testWindow = window as Window & {
|
||||
__BUZZ_E2E__?: { bootSplashHoldMs?: number };
|
||||
};
|
||||
testWindow.__BUZZ_E2E__ = {
|
||||
...(testWindow.__BUZZ_E2E__ ?? {}),
|
||||
bootSplashHoldMs: 2_000,
|
||||
};
|
||||
});
|
||||
await page.goto("/");
|
||||
|
||||
await page.getByRole("button", { name: "Create a new identity key" }).click();
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { installMockBridge } from "../helpers/bridge";
|
||||
|
||||
// Opt-in matched browser benchmark. Native startup and relay work are mocked.
|
||||
test.skip(!process.env.BUZZ_STARTUP_BENCHMARK, "opt-in startup measurement");
|
||||
for (const cached of [false, true]) {
|
||||
test(`startup usable (${cached ? "cached roster" : "no snapshot"})`, async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await installMockBridge(page);
|
||||
await page.addInitScript(() => {
|
||||
// Reproduce the OLD production policy, which its default E2E path skips.
|
||||
// The candidate removes this policy altogether and ignores this field.
|
||||
Object.assign(window.__BUZZ_E2E__ ?? {}, { bootSplashHoldMs: 1200 });
|
||||
const samples: Record<string, number> = {};
|
||||
Object.assign(window, { __STARTUP_SAMPLE__: samples });
|
||||
const inspect = () => {
|
||||
const row = document.querySelector('[data-testid="channel-general"]');
|
||||
if (row) {
|
||||
samples.rowMounted ??= performance.now();
|
||||
const box = row.getBoundingClientRect();
|
||||
if (
|
||||
box.width &&
|
||||
box.height &&
|
||||
row.contains(
|
||||
document.elementFromPoint(
|
||||
box.x + box.width / 2,
|
||||
box.y + box.height / 2,
|
||||
),
|
||||
)
|
||||
) {
|
||||
samples.rowReceivesPointer ??= performance.now();
|
||||
}
|
||||
}
|
||||
if (!samples.rowReceivesPointer) requestAnimationFrame(inspect);
|
||||
};
|
||||
requestAnimationFrame(inspect);
|
||||
document.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
if (
|
||||
(event.target as Element).closest('[data-testid="channel-general"]')
|
||||
)
|
||||
samples.channelClicked = performance.now();
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
await page.goto("/");
|
||||
if (cached) {
|
||||
await expect(page.getByTestId("channel-general")).toBeVisible();
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() =>
|
||||
Object.keys(localStorage).some((key) =>
|
||||
key.startsWith("buzz-channels.v1:"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toBe(true);
|
||||
await page.reload();
|
||||
}
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await expect(page.getByTestId("message-row").first()).toBeVisible();
|
||||
await page.getByTestId("message-input").fill("Startup input check");
|
||||
const result = await page.evaluate(() => ({
|
||||
...(window as Window & { __STARTUP_SAMPLE__: Record<string, number> })
|
||||
.__STARTUP_SAMPLE__,
|
||||
contentAndInputReady: performance.now(),
|
||||
snapshotPresence: (
|
||||
performance
|
||||
.getEntriesByName("buzz:sidebar:snapshot-diagnostic")
|
||||
.at(-1) as PerformanceMark
|
||||
)?.detail?.presence,
|
||||
}));
|
||||
expect(result.snapshotPresence).toBe(cached ? "present" : "absent");
|
||||
console.log(
|
||||
"STARTUP_SAMPLE",
|
||||
JSON.stringify({
|
||||
scenario: cached ? "cached" : "no-snapshot",
|
||||
...result,
|
||||
}),
|
||||
);
|
||||
await testInfo.attach("startup-sample", {
|
||||
body: JSON.stringify(result, null, 2),
|
||||
contentType: "application/json",
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
# Startup: reveal usable content without a cosmetic hold
|
||||
|
||||
## Retained change
|
||||
|
||||
Remove the cold-boot overlay and its 1,200 ms hold + 200 ms fade from
|
||||
`desktop/src/app/App.tsx`. Keep the actual community/identity/permission gate,
|
||||
animated loading bee, onboarding curtain, community-switch gate, error recovery,
|
||||
and native first-render/window-geometry reveal unchanged. Fast boots may not show
|
||||
the bee at all: responsiveness takes precedence over a minimum logo viewing time.
|
||||
|
||||
This does **not** make native initialization, relay reads, or the engine faster.
|
||||
It removes a real input-blocking UI wait after the app has mounted. It applies the
|
||||
foreground-first/no-unnecessary-waiting lesson without transplanting a transport.
|
||||
No changes to membership, unread state, recency, subscriptions, or pagination.
|
||||
The production delta is 69 removed lines and 3 added comment lines in one file.
|
||||
|
||||
## Matched browser result — 2026-09-20
|
||||
|
||||
Baseline: `9e5a9518e7f3fb62cdf14dc735d1092ed5844a85`.
|
||||
Candidate: that baseline plus the App.tsx change in this commit.
|
||||
Candidate App.tsx SHA-256:
|
||||
`27210160d45b9d61574bb50a8cffec062404d34cae0ba8ed851f72241676f158`.
|
||||
|
||||
Five runs per scenario/version, one Chromium worker, same mock native/relay fixture,
|
||||
Hermit toolchain, E2E build and machine. Each uncached sample uses a fresh browser
|
||||
context. The cached sample reloads after the app persists its own sidebar snapshot;
|
||||
the harness asserts snapshot diagnostics are `absent` or `present` respectively.
|
||||
Old production's 1,200 ms policy is explicitly enabled: ordinary old E2E runs
|
||||
silently bypassed it. Candidate has no hold policy or E2E exception.
|
||||
|
||||
All times are **median milliseconds from browser document navigation**, not process
|
||||
launch. Raw samples: [STARTUP_REVEAL_RESULTS_2026_09_20.json](STARTUP_REVEAL_RESULTS_2026_09_20.json).
|
||||
|
||||
| Scenario / observation | Before | After |
|
||||
| --- | ---: | ---: |
|
||||
| No snapshot: sidebar row mounted | 332.1 | 313.8 |
|
||||
| No snapshot: row accepts pointer hit-test | 1,655.6 | 376.3 |
|
||||
| No snapshot: actual channel click received | 1,780.5 | 418.6 |
|
||||
| No snapshot: messages visible and composer filled | 2,145.8 | 786.2 |
|
||||
| Cached roster: sidebar row mounted | 118.0 | 116.6 |
|
||||
| Cached roster: row accepts pointer hit-test | 1,486.8 | 156.3 |
|
||||
| Cached roster: actual channel click received | 1,520.0 | 196.5 |
|
||||
| Cached roster: messages visible and composer filled | 1,880.7 | 556.6 |
|
||||
|
||||
The useful interaction completes about **1.32–1.36 seconds sooner** in this fixture.
|
||||
The much smaller change in row-mount time separates loading from the input-blocking
|
||||
cover. Click timestamps include Playwright actionability/retry overhead; the
|
||||
frame-sampled `elementFromPoint` observation independently establishes obstruction.
|
||||
The final endpoint includes a visible message and successful composer fill, not
|
||||
merely a connection badge, overlay removal, or mounted-but-covered element.
|
||||
|
||||
## Regression evidence
|
||||
|
||||
- Two ready-sidebar tests (cached/uncached) **fail on unchanged baseline** at the
|
||||
synchronous pointer hit-test, then pass on the candidate. They explicitly enable
|
||||
the legacy production hold to prevent the old E2E bypass hiding its restoration.
|
||||
- Five startup tests pass: usable cold/warm sidebar; actual permission-trust IPC
|
||||
and workspace-apply IPC keep app/data reads gated while unresolved; failed apply
|
||||
stays closed and its Retry returns to a usable channel. Loading wings still animate.
|
||||
- All 10 sidebar snapshot tests pass (including stale/wrong scope and refresh).
|
||||
- All 72 onboarding tests pass.
|
||||
- All 25 community-rail tests pass on the final full-file run. **One earlier
|
||||
keyboard-reorder test failed** in the combined 40-test run (39 passed). One
|
||||
baseline control and five candidate focused repeats passed, then full-file
|
||||
baseline and candidate runs both passed 25/25. Root cause of that intermittent
|
||||
failure is not established; no unrelated reorder change was made.
|
||||
- E2E TypeScript/build passed. Full desktop lint/typecheck/unit checks are supplied
|
||||
by the standard pre-push hook; see the commit/push report for their result.
|
||||
|
||||
## Reproduce
|
||||
|
||||
In an isolated candidate checkout, activate Hermit, then:
|
||||
|
||||
```sh
|
||||
cd desktop
|
||||
pnpm build:e2e
|
||||
BUZZ_STARTUP_BENCHMARK=1 pnpm exec playwright test --project=smoke startup-usable.perf.ts --repeat-each=5
|
||||
pnpm exec playwright test --project=smoke boot-splash.spec.ts sidebar-snapshot.spec.ts community-rail.spec.ts
|
||||
pnpm exec playwright test --project=integration onboarding.spec.ts
|
||||
```
|
||||
|
||||
For the baseline, use a separate isolated checkout at the stated revision, copy
|
||||
only `startup-usable.perf.ts` and its smoke registration into it, then rebuild and
|
||||
run the same benchmark. Copy the new `boot-splash.spec.ts` there to reproduce the
|
||||
two ready-sidebar failures. Never use a stale port-4173 server/build from the other
|
||||
revision. The control used a separate source/dependency/build directory; no peer
|
||||
worktree or live app storage was altered.
|
||||
|
||||
## Evidence boundary / remaining work
|
||||
|
||||
This is Chromium UI evidence with mocked native and relay commands. There is no
|
||||
native WebKit/window-paint or live-relay before/after measurement here. Native
|
||||
geometry restoration and `initial-render-ready` remain unmodified, but eliminating
|
||||
the decorative reveal must still be visually checked in a packaged native app.
|
||||
The old timer starts at CommunityApp mount: if real initialization already exceeds
|
||||
its deadline, removing it saves little or nothing. These results are not evidence
|
||||
that backend slowness, channel fan-out, or the entire old/new app gap is solved.
|
||||
|
||||
Repository-wide `just ci`, release packaging, native visual validation, PR creation,
|
||||
merge, and deployment are not certified by this slice.
|
||||
@@ -1,201 +0,0 @@
|
||||
{
|
||||
"baseline": {
|
||||
"samples": [
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 362.5,
|
||||
"rowReceivesPointer": 1678.5,
|
||||
"channelClicked": 1817.6999998092651,
|
||||
"contentAndInputReady": 2190.199999809265,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 171.2000002861023,
|
||||
"rowReceivesPointer": 1533.5999999046326,
|
||||
"channelClicked": 1570.7000002861023,
|
||||
"contentAndInputReady": 1933.5999999046326,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 332.09999990463257,
|
||||
"rowReceivesPointer": 1657.8999996185303,
|
||||
"channelClicked": 1780.5,
|
||||
"contentAndInputReady": 2145.7999997138977,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 119,
|
||||
"rowReceivesPointer": 1491,
|
||||
"channelClicked": 1520,
|
||||
"contentAndInputReady": 1880.7000002861023,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 336.5,
|
||||
"rowReceivesPointer": 1655.5999999046326,
|
||||
"channelClicked": 1785.7999997138977,
|
||||
"contentAndInputReady": 2153.2999997138977,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 118,
|
||||
"rowReceivesPointer": 1486.8000001907349,
|
||||
"channelClicked": 1524.5,
|
||||
"contentAndInputReady": 1881.9000000953674,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 325.90000009536743,
|
||||
"rowReceivesPointer": 1655.5,
|
||||
"channelClicked": 1775.8000001907349,
|
||||
"contentAndInputReady": 2141,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 106.90000009536743,
|
||||
"rowReceivesPointer": 1476.3000001907349,
|
||||
"channelClicked": 1492.1000003814697,
|
||||
"contentAndInputReady": 1859.7000002861023,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 320.3999996185303,
|
||||
"rowReceivesPointer": 1644.7999997138977,
|
||||
"channelClicked": 1767.5999999046326,
|
||||
"contentAndInputReady": 2138.0999999046326,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 110.2000002861023,
|
||||
"rowReceivesPointer": 1484.8000001907349,
|
||||
"channelClicked": 1499.9000000953674,
|
||||
"contentAndInputReady": 1868.5999999046326,
|
||||
"snapshotPresence": "present"
|
||||
}
|
||||
],
|
||||
"medians": {
|
||||
"no-snapshot": {
|
||||
"rowMounted": 332.1,
|
||||
"rowReceivesPointer": 1655.6,
|
||||
"channelClicked": 1780.5,
|
||||
"contentAndInputReady": 2145.8
|
||||
},
|
||||
"cached": {
|
||||
"rowMounted": 118,
|
||||
"rowReceivesPointer": 1486.8,
|
||||
"channelClicked": 1520,
|
||||
"contentAndInputReady": 1880.7
|
||||
}
|
||||
}
|
||||
},
|
||||
"candidate": {
|
||||
"samples": [
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 313.7999997138977,
|
||||
"rowReceivesPointer": 376.2999997138977,
|
||||
"channelClicked": 415,
|
||||
"contentAndInputReady": 786.1999998092651,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 117.09999990463257,
|
||||
"rowReceivesPointer": 156.40000009536743,
|
||||
"channelClicked": 196.5,
|
||||
"contentAndInputReady": 556.2999997138977,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 309.3999996185303,
|
||||
"rowReceivesPointer": 373,
|
||||
"channelClicked": 418.59999990463257,
|
||||
"contentAndInputReady": 784.8999996185303,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 115.09999990463257,
|
||||
"rowReceivesPointer": 154.5,
|
||||
"channelClicked": 198.89999961853027,
|
||||
"contentAndInputReady": 557.2999997138977,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 338.2000002861023,
|
||||
"rowReceivesPointer": 402.30000019073486,
|
||||
"channelClicked": 448.59999990463257,
|
||||
"contentAndInputReady": 818.9000000953674,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 116.2999997138977,
|
||||
"rowReceivesPointer": 155.5,
|
||||
"channelClicked": 195.59999990463257,
|
||||
"contentAndInputReady": 553.6999998092651,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 315.7000002861023,
|
||||
"rowReceivesPointer": 377.90000009536743,
|
||||
"channelClicked": 423.5,
|
||||
"contentAndInputReady": 795.6000003814697,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 116.59999990463257,
|
||||
"rowReceivesPointer": 156.2999997138977,
|
||||
"channelClicked": 195.7999997138977,
|
||||
"contentAndInputReady": 556.5999999046326,
|
||||
"snapshotPresence": "present"
|
||||
},
|
||||
{
|
||||
"scenario": "no-snapshot",
|
||||
"rowMounted": 311.59999990463257,
|
||||
"rowReceivesPointer": 374.90000009536743,
|
||||
"channelClicked": 413.09999990463257,
|
||||
"contentAndInputReady": 782.9000000953674,
|
||||
"snapshotPresence": "absent"
|
||||
},
|
||||
{
|
||||
"scenario": "cached",
|
||||
"rowMounted": 117.5,
|
||||
"rowReceivesPointer": 157.19999980926514,
|
||||
"channelClicked": 203.59999990463257,
|
||||
"contentAndInputReady": 563.1999998092651,
|
||||
"snapshotPresence": "present"
|
||||
}
|
||||
],
|
||||
"medians": {
|
||||
"no-snapshot": {
|
||||
"rowMounted": 313.8,
|
||||
"rowReceivesPointer": 376.3,
|
||||
"channelClicked": 418.6,
|
||||
"contentAndInputReady": 786.2
|
||||
},
|
||||
"cached": {
|
||||
"rowMounted": 116.6,
|
||||
"rowReceivesPointer": 156.3,
|
||||
"channelClicked": 196.5,
|
||||
"contentAndInputReady": 556.6
|
||||
}
|
||||
}
|
||||
},
|
||||
"baseCommit": "9e5a9518e7f3fb62cdf14dc735d1092ed5844a85",
|
||||
"candidateAppSha256": "27210160d45b9d61574bb50a8cffec062404d34cae0ba8ed851f72241676f158",
|
||||
"method": "Chromium browser; mocked native/relay boundaries; performance.now from document navigation; old production 1200ms hold explicitly enabled; five samples per scenario per revision; no performance thresholds used as regressions"
|
||||
}
|
||||
Reference in New Issue
Block a user