test(ui): await initial roster before digest assertions

The final digest rendered correctly, but the test captured zero matching
sessions.list requests before initial roster bootstrap was released. Its
no-extra-read assertion then mistook the first roster read for an event
reload (expected length 0, received 1).

Introducing ordering: b023df8086 (#146591) prioritizes selected chat
history over automatic background lists. A selected descriptor can already
render the sidebar row while chat.startup still holds that first list.

Hold chat.startup to exercise the early descriptor path, release it, then
wait for a second row available only from roster admission before recording
the request baseline. Preserve the exact final-digest and no-extra-list-read
assertions. No production change, retry, timeout increase, or sleep is added.

Probe evidence on main 1a94ee9ed7:
- Original whole file: 5 passed, target failed with the CI 0-to-1 signature.
- Holding startup until after the final digest deterministically reproduces
  the same failure; the final digest is visible before the assertion fails.
- The identical probe passes with only the background-startup gate introduced
  by b023df8086 temporarily removed. That production change was reverted.
- Suspect-range samples before and at b7e2666e6b and at 3a306a430e pass the
  unmodified file. Snapshot stamping is not the stale-digest cause: static
  list fixtures already seed canonical descriptors, and the digest renders.
- Full replay at b023df8086 cannot build with the installed dependency set
  (missing historical ms dependency); no dependencies were installed. The
  attribution uses its parent-relative patch plus the isolated gate control.

Validation:
- Complete sidebar presentation E2E file: 6 passed, 49.08s wall including
  bundle build; changed scenario 1.405s.
- Bootstrap, sidebar narration, roster event and reconciliation owners:
  4 files / 107 tests passed, one worker, 29.23s runner wall.
- pnpm tsgo:ui, oxfmt, targeted core-tsconfig oxlint, git diff --check.
- Line-cap, max-lines suppression and assertion-safety ratchets pass.
  The combined max-lines command also reports the existing environment-name
  budget failure (484 vs 483), reproduced from the untouched HEAD index.
- Independent Codex autoreview: scoped-clean through P2.

Release-note context: test reliability only; product behavior is unchanged.
This commit is contained in:
Peter Steinberger 2026-09-28 08:31:14 -07:00
parent 917e1b811d
commit 6b9da9dc02

View file

@ -162,6 +162,12 @@ suite.define(() => {
});
const key = "agent:main:session-a";
const runId = "run-sidebar-metadata";
const rosterPeer = {
key: "agent:main:roster-peer",
kind: "direct",
label: "Roster peer",
updatedAt: 1,
};
const running = chatSessionListResponse([
{
key,
@ -180,6 +186,7 @@ suite.define(() => {
revision: 1,
},
},
rosterPeer,
]);
const completed = chatSessionListResponse([
{
@ -200,8 +207,10 @@ suite.define(() => {
revision: 2,
},
},
rosterPeer,
]);
const gateway = await installMockGateway(page, {
deferredMethods: ["chat.startup"],
methodResponses: { "sessions.list": running },
sessionKey: key,
});
@ -210,6 +219,11 @@ suite.define(() => {
await page.goto(controlUiSessionUrl(suite.server.baseUrl, key));
const row = page.locator(`.sidebar-recent-session[data-session-key="${key}"]`);
await row.getByText("Implementing the repair").waitFor();
// A descriptor can render the selected row before startup releases the roster.
// Wait for a roster-only row before measuring event-triggered list reads.
await gateway.waitForRequest("chat.startup");
await gateway.resolveDeferred("chat.startup");
await page.locator(`.sidebar-recent-session[data-session-key="${rosterPeer.key}"]`).waitFor();
if (captureUiProofEnabled) {
await writeFile(
path.join(