# 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: tests/ui/district-delegates.spec.ts >> MP delegate district has a current00 canonical and historical98 redirect
- Location: tests/ui/district-delegates.spec.ts:11:7

# Error details

```
Error: MP:98 must redirect rather than retire or retain an old owner

expect(received).toBe(expected) // Object.is equality

Expected: 301
Received: 410
```

# Page snapshot

```yaml
- generic [active] [ref=f1e1]:
  - banner [ref=f1e2]:
    - heading "Northern Mariana Islands At-Large Congressional District" [level=1] [ref=f1e3]
    - paragraph [ref=f1e4]: Congressional District Profile
  - generic [ref=f1e5]:
    - generic [ref=f1e6]:
      - generic [ref=f1e7]: Not signed in
      - generic [ref=f1e9]:
        - link "Log in" [ref=f1e10] [cursor=pointer]:
          - /url: /outpost.goauthentik.io/start?rd=https%3A%2F%2Fus.elect.info%2Fdistricts%2Fmp-00%2F
        - link "Create an account" [ref=f1e11] [cursor=pointer]:
          - /url: /signin/register?rd=https%3A%2F%2Fus.elect.info%2Fdistricts%2Fmp-00%2F
    - toolbar "Member tools" [ref=f1e12]:
      - button "All cycles (Sign in to use the cycle facet)" [disabled] [ref=f1e13] [cursor=pointer]:
        - generic [ref=f1e17]: All cycles
      - button "Graph (Sign in to use Graph)" [disabled] [ref=f1e20] [cursor=pointer]:
        - generic [ref=f1e29]: Graph
  - generic [ref=f1e32]:
    - heading "Overview" [level=2] [ref=f1e33]
    - generic [ref=f1e34]:
      - term [ref=f1e35]: District ID
      - definition [ref=f1e36]: MP-00
      - term [ref=f1e37]: State
      - definition [ref=f1e38]:
        - link "Northern Mariana Islands" [ref=f1e39] [cursor=pointer]:
          - /url: https://us.elect.info/states/
      - term [ref=f1e40]: District Number
      - definition [ref=f1e41]: "00"
      - term [ref=f1e42]: Total Candidates
      - definition [ref=f1e43]: "17"
      - term [ref=f1e44]: Election Cycles
      - definition [ref=f1e45]:
        - generic [ref=f1e46]:
          - link "2026" [ref=f1e47] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2026/
          - text: ","
          - link "2024" [ref=f1e48] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2024/
          - text: ","
          - link "2022" [ref=f1e49] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2022/
          - text: ","
          - link "2020" [ref=f1e50] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2020/
          - text: ","
          - link "2018" [ref=f1e51] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2018/
          - text: ","
          - link "2016" [ref=f1e52] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2016/
          - text: ","
          - link "2014" [ref=f1e53] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2014/
          - text: ","
          - link "2012" [ref=f1e54] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2012/
          - text: ","
          - link "2010" [ref=f1e55] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2010/
          - text: ","
          - link "2008" [ref=f1e56] [cursor=pointer]:
            - /url: https://us.elect.info/elections/2008/
    - paragraph [ref=f1e57]:
      - link "View office details for U.S. Representative - Northern Mariana Islands District 00" [ref=f1e58] [cursor=pointer]:
        - /url: https://us.elect.info/offices/house/mp-00/
  - generic [ref=f1e59]:
    - heading "Candidates" [level=2] [ref=f1e60]
    - generic [ref=f1e62]:
      - generic [ref=f1e63]:
        - generic [ref=f1e64]:
          - combobox "Search entities" [ref=f1e65]
          - status [ref=f1e66]
        - button "Search" [ref=f1e67] [cursor=pointer]
      - generic [ref=f1e68]:
        - heading "Candidates" [level=3] [ref=f1e70]
        - generic [ref=f1e71]:
          - link "SABLAN, GREGORIO KILILI CAMACHO REP. DEM | $166,150" [ref=f1e72] [cursor=pointer]:
            - /url: /politicians/3b2a40ca-b5e7-316c-45a6-7b51f38f54db/
            - generic [ref=f1e73]: SABLAN, GREGORIO KILILI CAMACHO REP.
            - generic [ref=f1e74]: DEM | $166,150
          - link "TENORIO, PEDRO AGULTO REP | $2,500" [ref=f1e75] [cursor=pointer]:
            - /url: /politicians/1420e225-6b93-a8e9-21ee-d38968746777/
            - generic [ref=f1e76]: TENORIO, PEDRO AGULTO
            - generic [ref=f1e77]: REP | $2,500
          - link "GONZALES, JOHN OLIVER DELOS REYES IND" [ref=f1e78] [cursor=pointer]:
            - /url: /politicians/5a27f046-6beb-338f-ddea-bdd0ec6fca23/
            - generic [ref=f1e79]: GONZALES, JOHN OLIVER DELOS REYES
            - generic [ref=f1e80]: IND
          - link "CRISOSTIMO, LUIS PALACIOS IND" [ref=f1e81] [cursor=pointer]:
            - /url: /politicians/a7396b2d-e793-0533-2d09-df6eee03d409/
            - generic [ref=f1e82]: CRISOSTIMO, LUIS PALACIOS
            - generic [ref=f1e83]: IND
          - link "DAVIS, JOHN HENRY JR IND" [ref=f1e84] [cursor=pointer]:
            - /url: /politicians/812e4238-7aad-3949-b53e-55d28144a94f/
            - generic [ref=f1e85]: DAVIS, JOHN HENRY JR
            - generic [ref=f1e86]: IND
          - link "CING, DAVID MENDIOLA DEM" [ref=f1e87] [cursor=pointer]:
            - /url: /politicians/100fd801-9a5e-5159-76a8-8efe9612b872/
            - generic [ref=f1e88]: CING, DAVID MENDIOLA
            - generic [ref=f1e89]: DEM
          - link "BORJA, JESUS CAMACHO DEM" [ref=f1e90] [cursor=pointer]:
            - /url: /politicians/1855bd13-f34d-0009-eb68-409a48a10e40/
            - generic [ref=f1e91]: BORJA, JESUS CAMACHO
            - generic [ref=f1e92]: DEM
          - link "SALAS, ANDREW SABLAN DEM" [ref=f1e93] [cursor=pointer]:
            - /url: /politicians/682dd9e7-0bf8-1fec-9b2e-80ab4fc77c8a/
            - generic [ref=f1e94]: SALAS, ANDREW SABLAN
            - generic [ref=f1e95]: DEM
          - link "WON, CHONG MAN IND" [ref=f1e96] [cursor=pointer]:
            - /url: /politicians/f83d1d52-7204-fe62-5272-95d705b7ffed/
            - generic [ref=f1e97]: WON, CHONG MAN
            - generic [ref=f1e98]: IND
          - link "DEMAPAN, IGNACIA T DR REP" [ref=f1e99] [cursor=pointer]:
            - /url: /politicians/9bf30b07-7f32-cd72-0ed6-c5acaedb690e/
            - generic [ref=f1e100]: DEMAPAN, IGNACIA T DR
            - generic [ref=f1e101]: REP
          - link "RAYPHAND, JAMES MICHAEL IND" [ref=f1e102] [cursor=pointer]:
            - /url: /politicians/c10f8d47-5ffa-47f0-9887-150a314d1426/
            - generic [ref=f1e103]: RAYPHAND, JAMES MICHAEL
            - generic [ref=f1e104]: IND
          - link "ATALIG, FELIPE QUITUGUA IND" [ref=f1e105] [cursor=pointer]:
            - /url: /politicians/d1383b79-003f-2d88-6871-9f68bf62bf21/
            - generic [ref=f1e106]: ATALIG, FELIPE QUITUGUA
            - generic [ref=f1e107]: IND
          - link "LIZAMA, JUAN TUDELA IND" [ref=f1e108] [cursor=pointer]:
            - /url: /politicians/1395d9a0-f316-a959-3f88-b79982100d0d/
            - generic [ref=f1e109]: LIZAMA, JUAN TUDELA
            - generic [ref=f1e110]: IND
          - link "HOFSCHNEIDER, LIANA SABLAN IND" [ref=f1e111] [cursor=pointer]:
            - /url: /politicians/d8961b1f-950e-55d1-04c6-079e362c1c44/
            - generic [ref=f1e112]: HOFSCHNEIDER, LIANA SABLAN
            - generic [ref=f1e113]: IND
          - link "BABAUTA, JUAN NEKAI REP" [ref=f1e114] [cursor=pointer]:
            - /url: /politicians/e15b9f66-57d6-0be9-f7d7-87e35a1101c0/
            - generic [ref=f1e115]: BABAUTA, JUAN NEKAI
            - generic [ref=f1e116]: REP
          - link "CAMACHO, JOSEPH JAMES NORITA OTH" [ref=f1e117] [cursor=pointer]:
            - /url: /politicians/e219b5be-e93e-c489-24f2-58f64f647582/
            - generic [ref=f1e118]: CAMACHO, JOSEPH JAMES NORITA
            - generic [ref=f1e119]: OTH
          - link "DEMAPAN, IGNACIA TUDELA REP" [ref=f1e120] [cursor=pointer]:
            - /url: /politicians/58b4c402-c054-2954-0435-c4c8b3574c27/
            - generic [ref=f1e121]: DEMAPAN, IGNACIA TUDELA
            - generic [ref=f1e122]: REP
        - generic [ref=f1e123]: Showing all 17 results
  - contentinfo [ref=f1e125]:
    - paragraph [ref=f1e126]:
      - link "elect.info" [ref=f1e127] [cursor=pointer]:
        - /url: https://us.elect.info/
      - text: "| Data from"
      - link "Federal Election Commission" [ref=f1e128] [cursor=pointer]:
        - /url: https://us.elect.info/datasources/fec.gov/
      - text: "| Generated 2026-10-23"
```

# Test source

```ts
  1  | import { test, expect } from '@playwright/test';
  2  | import { canonicalPath, toRelativePath } from './helpers';
  3  | 
  4  | // Release contract after the coordinated graph + PagePaths cutover (#462): all six
  5  | // delegates exist as current00 entities; the index and00 alias serve them, their
  6  | // live UUID pages canonicalize to00, and historical98 aliases redirect to00.
  7  | // This is intentionally red on the old98 graph / stale alias snapshot. The local
  8  | // district-categories fixture still proves98 rows keep safe current-UUID links;
  9  | // neither that fixture nor these inventory assertions may be skipped for missing rows.
  10 | for (const state of ['AS', 'GU', 'MP', 'VI', 'DC', 'PR']) {
  11 |   test(`${state} delegate district has a current00 canonical and historical98 redirect`, async ({ page, request }) => {
  12 |     const dataResponse = page.waitForResponse(response => {
  13 |       if (!response.url().includes('/api/graphql') || response.request().method() !== 'POST') return false;
  14 |       try {
  15 |         const body = response.request().postDataJSON();
  16 |         const variables = body?.variables;
  17 |         const filters = String(variables?.filter).split(',');
  18 |         return /\bbrowseEntities\s*\(/.test(body?.query || '') && variables?.entityType === 'District' &&
  19 |           filters.includes('district_type:cd') && filters.includes(`state:${state}`);
  20 |       } catch { return false; }
  21 |     });
  22 |     await page.goto(`/districts/?state=${state}&tab=congressional`);
  23 |     const payload = await (await dataResponse).json();
  24 |     expect(payload.errors, `${state}: current inventory query must succeed`).toBeUndefined();
  25 |     const inventory = payload.data?.browseEntities;
  26 |     expect(inventory?.total, `${state}: full congressional inventory must contain exactly one delegate`).toBe(1);
  27 |     expect(inventory?.hasMore, `${state}: delegate inventory must not be truncated`).toBe(false);
  28 |     const rows = inventory?.results;
  29 |     expect(rows, `${state}: exactly one delegate must remain in the graph`).toHaveLength(1);
  30 |     const row = rows[0];
  31 |     expect(row.state).toBe(state);
  32 |     expect(row.district).toBe('00');
  33 |     const metadata = JSON.parse(row.metadata || '{}');
  34 |     expect(metadata.district_type).toBe('cd');
  35 |     expect(metadata.district_slug.toLowerCase()).toBe(`${state.toLowerCase()}-00`);
  36 |     expect(row.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
  37 | 
  38 |     await expect(page.locator('#district-state-select')).toHaveValue(state);
  39 |     const result = page.locator('.entity-search-result');
  40 |     await expect(result).toHaveCount(1, { timeout: 15000 });
  41 |     await expect(result).toContainText(`${state}-00`);
  42 |     const canonical = `/districts/${state.toLowerCase()}-00/`;
  43 |     await expect(result).toHaveAttribute('href', canonical);
  44 |     const response = await page.goto(canonical);
  45 |     expect(response?.status(), `${state}:00 must serve, not redirect or miss`).toBe(200);
  46 |     await expect(page.locator('h1')).toBeVisible();
  47 |     expect(canonicalPath(await page.content())).toBe(canonical);
  48 | 
  49 |     const storage = await request.get(`/districts/${row.id}/`, { maxRedirects: 0 });
  50 |     expect(storage.status(), `${state}: graph-current UUID page must serve`).toBe(200);
  51 |     expect(canonicalPath(await storage.text()), `${state}: current UUID must share00 canonical`).toBe(canonical);
  52 |     const historical = await request.get(`/districts/${state.toLowerCase()}-98/`, { maxRedirects: 0 });
> 53 |     expect(historical.status(), `${state}:98 must redirect rather than retire or retain an old owner`).toBe(301);
     |                                                                                                        ^ Error: MP:98 must redirect rather than retire or retain an old owner
  54 |     expect(toRelativePath(historical.headers()['location'] || '')).toBe(canonical);
  55 |   });
  56 | }
  57 | 
```