# 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/data-contracts.spec.ts >> graph data contracts >> the graph serves every scalar the schema declares (seeded sample per type)
- Location: tests/ui/data-contracts.spec.ts:81:7

# Error details

```
Error: postalCodes sample (offset 1000)

expect(received).toBeLessThan(expected)

Expected: < 500
Received:   504
```

# Test source

```ts
  44  |       );
  45  |       expect(data.tracts.length, `${c.name} (${geoid}) should have tracts`).toBeGreaterThan(0);
  46  |       expect(data.blocks.length, `${c.name} (${geoid}) should have blocks`).toBeGreaterThan(0);
  47  |     }
  48  |   });
  49  | 
  50  |   test('precincts join on the 5-digit county GEOID', async ({ request }) => {
  51  |     const data = await gql<{ precincts: unknown[] }>(
  52  |       request,
  53  |       `{ precincts(where: { county_fips: { eq: "48453" } }, limit: 1) { id } }`,
  54  |     );
  55  |     expect(data.precincts.length, 'Travis County (48453) should have precincts').toBeGreaterThan(0);
  56  |   });
  57  | 
  58  |   test('candidate ids are UUID5s and carry their FEC id', async ({ request }) => {
  59  |     const { candidates } = await gql<{ candidates: { id: string; fec_candidate_id: string | null }[] }>(
  60  |       request,
  61  |       // FEC-keyed candidates; the RDH ones without an FEC id are the schema-drift test's concern
  62  |       '{ candidates(where: { fec_candidate_id: { startsWith: "H" } }, limit: 50) { id fec_candidate_id } }',
  63  |     );
  64  |     expect(candidates.length).toBeGreaterThan(0);
  65  |     for (const c of candidates) {
  66  |       expect(c.id, `candidate ${c.fec_candidate_id} id`).toMatch(UUID);
  67  |       expect(c.fec_candidate_id ?? '', `candidate ${c.id} fec_candidate_id`).toMatch(/^[HSP][0-9A-Z]{8}$/);
  68  |     }
  69  |   });
  70  | 
  71  |   test('Party exposes its FEC code', async ({ request }) => {
  72  |     // Party.id is a UUID5; the FEC code the site and news chips use is party_code.
  73  |     const { parties } = await gql<{ parties: { id: string; party_code: string | null; party_name: string | null }[] }>(
  74  |       request,
  75  |       '{ parties(where: { party_code: { in: ["REP", "DEM"] } }) { id party_code party_name } }',
  76  |     );
  77  |     expect(parties.map(p => p.party_code).sort(), 'parties by party_code').toEqual(['DEM', 'REP']);
  78  |     for (const p of parties) expect(p.id, `${p.party_code} id`).toMatch(UUID);
  79  |   });
  80  | 
  81  |   test('the graph serves every scalar the schema declares (seeded sample per type)', async ({ request }) => {
  82  |     // End-to-end counterpart of api.elect.info's dist/check-schema.js (which gates
  83  |     // the API build), through the site's /api/graphql proxy. A declared non-null
  84  |     // field that is null ("Cannot return null for non-nullable field") fails the
  85  |     // whole query; a property
  86  |     // whose Neo4j type differs from the schema (a Date where it says String: "String
  87  |     // cannot represent value") fails its field, nullable or not. Sample each node
  88  |     // type at a seeded offset, asking for every scalar and every relationship-
  89  |     // property scalar. KNOWN lists accepted drift (with its ticket); anything else fails.
  90  |     test.setTimeout(240000);
  91  |     const KNOWN: Record<string, string[]> = {};
  92  |     const SAMPLE = 500;
  93  |     const REL_SAMPLE = 25;
  94  |     type TypeRef = { kind: string; name: string | null; ofType: TypeRef | null };
  95  |     type Field = { name: string; args: unknown[]; type: TypeRef };
  96  |     const named = (t: TypeRef | null): { kind: string; name: string | null } => {
  97  |       let x = t;
  98  |       while (x?.ofType) x = x.ofType;
  99  |       return { kind: x?.kind ?? '', name: x?.name ?? null };
  100 |     };
  101 |     const typeRef = 'type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }';
  102 |     const { __schema } = await gql<{ __schema: { queryType: { name: string }; types: { name: string; fields: Field[] | null }[] } }>(
  103 |       request, `{ __schema { queryType { name } types { name fields { name args { name } ${typeRef} } } } }`);
  104 |     const types = new Map(__schema.types.map(t => [t.name, t.fields ?? []]));
  105 |     const scalars = (typeName: string | null) => (types.get(typeName ?? '') ?? [])
  106 |       .filter(f => f.args.length === 0 && ['SCALAR', 'ENUM'].includes(named(f.type).kind))
  107 |       .map(f => f.name);
  108 |     // `<rel>Connection { edges { properties { ... } } }` for relationships that carry properties
  109 |     const relProps = (typeName: string | null) => (types.get(typeName ?? '') ?? [])
  110 |       .filter(f => f.name.endsWith('Connection'))
  111 |       .flatMap(f => {
  112 |         const edges = (types.get(named(f.type).name ?? '') ?? []).find(x => x.name === 'edges');
  113 |         const props = (types.get(named(edges?.type ?? null).name ?? '') ?? []).find(x => x.name === 'properties');
  114 |         const fields = scalars(named(props?.type ?? null).name);
  115 |         return fields.length ? [`${f.name}(first: 3) { edges { properties { ${fields.join(' ')} } } }`] : [];
  116 |       });
  117 |     const roots = (types.get(__schema.queryType.name) ?? [])
  118 |       .filter(f => {
  119 |         let x: TypeRef | null = f.type;
  120 |         const kinds: string[] = [];
  121 |         for (; x; x = x.ofType) kinds.push(x.kind);
  122 |         // Node lists only (they take limit/offset); custom list queries such as
  123 |         // entityFacets have their own arguments.
  124 |         const paged = (f.args as Array<{ name: string }>).some(a => a.name === 'limit');
  125 |         return kinds.join() === 'NON_NULL,LIST,NON_NULL,OBJECT' && paged && !f.name.startsWith('curation');
  126 |       })
  127 |       .map(f => ({ root: f.name, name: named(f.type).name }));
  128 | 
  129 |     const violations: string[] = [];
  130 |     const known: string[] = [];
  131 |     for (const { root, name } of roots) {
  132 |       const offset = getRandomItems([0, 1000, 5000, 20000, 50000], 1, `scalars:${name}`)[0];
  133 |       // Relationship properties on fewer nodes: a connection's first: 3 still reads
  134 |       // every edge (500 ZIPs' residents ran past the API's 60 s).
  135 |       const samples = [
  136 |         { selection: scalars(name), limit: SAMPLE },
  137 |         { selection: relProps(name), limit: REL_SAMPLE },
  138 |       ].filter(s => s.selection.length);
  139 |       for (const { selection, limit } of samples) {
  140 |         const res = await request.post('/api/graphql', {
  141 |           data: { query: `{ ${root}(limit: ${limit}, offset: ${offset}) { ${selection.join(' ')} } }` },
  142 |           headers: visitorHeaders(),
  143 |         });
> 144 |         expect(res.status(), `${root} sample (offset ${offset})`).toBeLessThan(500);
      |                                                                   ^ Error: postalCodes sample (offset 1000)
  145 |         const body = await res.json();
  146 |         for (const e of body.errors ?? []) {
  147 |           // field errors carry [root, index, field] or [root, index, conn, 'edges', index, 'properties', field]
  148 |           const segs = Array.isArray(e.path) ? e.path.slice(1).filter((p: unknown) => typeof p === 'string' && p !== 'edges' && p !== 'properties') : [];
  149 |           const field = segs.join('.');
  150 |           const where = field ? `${name}.${field}` : `${name}: ${String(e.message).slice(0, 120)}`;
  151 |           if (field && KNOWN[name ?? '']?.includes(field)) known.push(where);
  152 |           else violations.push(`${where}: ${String(e.message).replace(/value: .*/, 'value').slice(0, 80)} (${root} offset ${offset})`);
  153 |         }
  154 |       }
  155 |     }
  156 |     if (known.length) {
  157 |       test.info().annotations.push({ type: 'known schema/graph drift', description: [...new Set(known)].join(', ') });
  158 |     }
  159 |     expect([...new Set(violations)], 'schema fields the graph cannot serve').toEqual([]);
  160 |   });
  161 | 
  162 |   test('entity counts stay above the accepted baseline', async ({ request }) => {
  163 |     const keys = Object.keys(baseline.counts);
  164 |     const { entityCounts } = await gql<{ entityCounts: Record<string, number> }>(
  165 |       request,
  166 |       `{ entityCounts { ${keys.join(' ')} } }`,
  167 |     );
  168 |     const low = keys
  169 |       .map(k => ({ k, got: entityCounts[k], floor: Math.floor(baseline.counts[k] * baseline.floorRatio) }))
  170 |       .filter(({ got, floor }) => !(got >= floor));
  171 |     expect(
  172 |       low.map(({ k, got, floor }) => `${k} ${got} < floor ${floor} (baseline ${baseline.counts[k]})`),
  173 |       'entity counts below baseline floor (update baseline-counts.json only for an accepted drop)',
  174 |     ).toEqual([]);
  175 |   });
  176 | });
  177 | 
```