# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: cli-08-tiles.e2e.test.ts >> CLI-08 tiles — RoomRenderer emits floor tiles + TSide1 sides (Wave 4 GREEN gate)
- Location: test/e2e/cli-08-tiles.e2e.test.ts:26:1

# Error details

```
Error: expect(received).toContain(expected) // indexOf

Expected value: "atlas-mvp"
Received array: []

Call Log:
- Timeout 10000ms exceeded while waiting on the predicate
```

# Page snapshot

```yaml
- generic [active] [ref=e1]:
  - generic:
    - generic [ref=e5]: Press T or Enter to chat
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_b
    - generic: uat_a
    - generic: uat_a
```

# Test source

```ts
  1  | // apps/client/test/e2e/cli-08-tiles.e2e.test.ts
  2  | // [int->REQ-CLI-08]
  3  | //
  4  | // Plan 06.1-07 Task 1 — GREEN refinement of the 06.1-03 RED skeleton. Asserts
  5  | // the Wave 2 D-40 verify-bail flip (Plan 06.1-05) actually emits floor tiles
  6  | // + D6.1-25 TSide1 sides via the __rebno hooks RoomRenderer.renderNew exposes.
  7  | //
  8  | // Assertion model (per 06.1-PATTERNS.md S-08 + S-05):
  9  | //   - __rebno.tileCount: populated by RoomRenderer.renderNew (Plan 06.1-05)
  10 | //     after onRoomLayout fires. Polled (not single-shot read) because the
  11 | //     s2c.room_layout event may land a few hundred ms after onLocalSnapshot
  12 | //     sets data-game-ready=true; polling lets the test track the actual
  13 | //     room-render moment without a flaky fixed sleep.
  14 | //   - __rebno.loadedTextures: 'atlas-mvp' is loaded by atlas-loader.ts queue
  15 | //     during preload; serves as a regression guard against atlas-load drift.
  16 | //   - __rebno.tsideCount: TSide1 sprite count populated by
  17 | //     RoomRenderer.renderNew (Plan 06.1-05 D6.1-25 bottom-edge placement).
  18 | 
  19 | import {
  20 |   test,
  21 |   expect,
  22 |   loginAs,
  23 |   waitForGameReady,
  24 | } from './fixtures.js';
  25 | 
  26 | test('CLI-08 tiles — RoomRenderer emits floor tiles + TSide1 sides (Wave 4 GREEN gate)', async ({
  27 |   page,
  28 |   accountA,
  29 |   inviteSuffix,
  30 | }) => {
  31 |   await loginAs(page, accountA, inviteSuffix);
  32 |   await waitForGameReady(page);
  33 | 
  34 |   // 1. atlas-mvp must be loaded into the Phaser TextureManager (atlas-loader.ts
  35 |   //    queues it on scene preload). Polled to avoid race with the TextureManager
  36 |   //    finishing its onload promise mid-frame.
> 37 |   await expect
     |   ^ Error: expect(received).toContain(expected) // indexOf
  38 |     .poll(
  39 |       async () =>
  40 |         page.evaluate(
  41 |           () =>
  42 |             (
  43 |               window as unknown as {
  44 |                 __rebno?: { loadedTextures?: string[] };
  45 |               }
  46 |             ).__rebno?.loadedTextures ?? [],
  47 |         ),
  48 |       { timeout: 10_000 },
  49 |     )
  50 |     .toContain('atlas-mvp');
  51 | 
  52 |   // 2. Floor tiles must render. The s2c.room_layout event may land slightly
  53 |   //    after onLocalSnapshot (which is what flips data-game-ready), so poll
  54 |   //    __rebno.tileCount instead of doing a single-shot read. Polling resolves
  55 |   //    once RoomRenderer.renderNew (Plan 06.1-05) has placed at least one tile
  56 |   //    via group.add(). mvp-room ships 324 tiles, so any positive count clears.
  57 |   await expect
  58 |     .poll(
  59 |       async () =>
  60 |         page.evaluate(
  61 |           () =>
  62 |             (
  63 |               window as unknown as {
  64 |                 __rebno?: { tileCount?: number };
  65 |               }
  66 |             ).__rebno?.tileCount ?? 0,
  67 |         ),
  68 |       {
  69 |         message:
  70 |           'RoomRenderer.renderNew must emit floor tile sprites for mvp-room (D-40 verify-bail flip / Plan 06.1-05)',
  71 |         timeout: 15_000,
  72 |       },
  73 |     )
  74 |     .toBeGreaterThan(0);
  75 | 
  76 |   // 3. TSide1 bottom-edge sprite presence (D6.1-25). Same poll model — Plan
  77 |   //    06.1-05's RoomRenderer.renderNew placement loop is part of the same
  78 |   //    render() call, so by the time tileCount > 0 the tsideCount has also
  79 |   //    been published. Poll anyway to harden against ordering surprises.
  80 |   await expect
  81 |     .poll(
  82 |       async () =>
  83 |         page.evaluate(
  84 |           () =>
  85 |             (
  86 |               window as unknown as {
  87 |                 __rebno?: { tsideCount?: number };
  88 |               }
  89 |             ).__rebno?.tsideCount ?? 0,
  90 |         ),
  91 |       {
  92 |         message:
  93 |           'RoomRenderer must emit 0024-TSide1 sprites along floor bottom edges (D6.1-25)',
  94 |         timeout: 10_000,
  95 |       },
  96 |     )
  97 |     .toBeGreaterThan(0);
  98 | });
  99 | 
```