# 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: schema fields the graph cannot serve

expect(received).toEqual(expected) // deep equality

- Expected  -  1
+ Received  + 12

- Array []
+ Array [
+   "Candidate.affiliatedWithPartiesConnection.cycle: Cannot return null for non-nullable field AffiliatedWithProperties.cycle. (candidates offset 5000)",
+   "Committee.affiliatedWithPartiesConnection.cycle: Cannot return null for non-nullable field AffiliatedWithProperties.cycle. (committees offset 5000)",
+   "Employer.first_contribution: String cannot represent value (employers offset 0)",
+   "Employer.last_contribution: String cannot represent value (employers offset 0)",
+   "Individual.first_contribution: String cannot represent value (individuals offset 20000)",
+   "Tract.inCountyCountiesConnection.geoid: Cannot return null for non-nullable field InCountyProperties.geoid. (tracts offset 20000)",
+   "Stage.election_year: Cannot return null for non-nullable field Stage.election_year. (stages offset 1000)",
+   "State.candidatesResidesInConnection.cycles: Cannot return null for non-nullable field ResidesInProperties.cycles. (states offset 0)",
+   "Vendor.first_payment: String cannot represent value (vendors offset 1000)",
+   "Vendor.last_payment: String cannot represent value (vendors offset 1000)",
+ ]
```

# Test source

```ts
  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  |     type TypeRef = { kind: string; name: string | null; ofType: TypeRef | null };
  94  |     type Field = { name: string; args: unknown[]; type: TypeRef };
  95  |     const named = (t: TypeRef | null): { kind: string; name: string | null } => {
  96  |       let x = t;
  97  |       while (x?.ofType) x = x.ofType;
  98  |       return { kind: x?.kind ?? '', name: x?.name ?? null };
  99  |     };
  100 |     const typeRef = 'type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }';
  101 |     const { __schema } = await gql<{ __schema: { queryType: { name: string }; types: { name: string; fields: Field[] | null }[] } }>(
  102 |       request, `{ __schema { queryType { name } types { name fields { name args { name } ${typeRef} } } } }`);
  103 |     const types = new Map(__schema.types.map(t => [t.name, t.fields ?? []]));
  104 |     const scalars = (typeName: string | null) => (types.get(typeName ?? '') ?? [])
  105 |       .filter(f => f.args.length === 0 && ['SCALAR', 'ENUM'].includes(named(f.type).kind))
  106 |       .map(f => f.name);
  107 |     // `<rel>Connection { edges { properties { ... } } }` for relationships that carry properties
  108 |     const relProps = (typeName: string | null) => (types.get(typeName ?? '') ?? [])
  109 |       .filter(f => f.name.endsWith('Connection'))
  110 |       .flatMap(f => {
  111 |         const edges = (types.get(named(f.type).name ?? '') ?? []).find(x => x.name === 'edges');
  112 |         const props = (types.get(named(edges?.type ?? null).name ?? '') ?? []).find(x => x.name === 'properties');
  113 |         const fields = scalars(named(props?.type ?? null).name);
  114 |         return fields.length ? [`${f.name}(first: 3) { edges { properties { ${fields.join(' ')} } } }`] : [];
  115 |       });
  116 |     const roots = (types.get(__schema.queryType.name) ?? [])
  117 |       .filter(f => {
  118 |         let x: TypeRef | null = f.type;
  119 |         const kinds: string[] = [];
  120 |         for (; x; x = x.ofType) kinds.push(x.kind);
  121 |         return kinds.join() === 'NON_NULL,LIST,NON_NULL,OBJECT' && !f.name.startsWith('curation');
  122 |       })
  123 |       .map(f => ({ root: f.name, name: named(f.type).name }));
  124 | 
  125 |     const violations: string[] = [];
  126 |     const known: string[] = [];
  127 |     for (const { root, name } of roots) {
  128 |       const selection = [...scalars(name), ...relProps(name)];
  129 |       if (!selection.length) continue;
  130 |       const offset = getRandomItems([0, 1000, 5000, 20000, 50000], 1, `scalars:${name}`)[0];
  131 |       const res = await request.post('/api/graphql', {
  132 |         data: { query: `{ ${root}(limit: ${SAMPLE}, offset: ${offset}) { ${selection.join(' ')} } }` },
  133 |       });
  134 |       const body = await res.json();
  135 |       for (const e of body.errors ?? []) {
  136 |         // field errors carry [root, index, field] or [root, index, conn, 'edges', index, 'properties', field]
  137 |         const segs = Array.isArray(e.path) ? e.path.slice(1).filter((p: unknown) => typeof p === 'string' && p !== 'edges' && p !== 'properties') : [];
  138 |         const field = segs.join('.');
  139 |         const where = field ? `${name}.${field}` : `${name}: ${String(e.message).slice(0, 120)}`;
  140 |         if (field && KNOWN[name ?? '']?.includes(field)) known.push(where);
  141 |         else violations.push(`${where}: ${String(e.message).replace(/value: .*/, 'value').slice(0, 80)} (${root} offset ${offset})`);
  142 |       }
  143 |     }
  144 |     if (known.length) {
  145 |       test.info().annotations.push({ type: 'known schema/graph drift', description: [...new Set(known)].join(', ') });
  146 |     }
> 147 |     expect([...new Set(violations)], 'schema fields the graph cannot serve').toEqual([]);
      |                                                                              ^ Error: schema fields the graph cannot serve
  148 |   });
  149 | 
  150 |   test('entity counts stay above the accepted baseline', async ({ request }) => {
  151 |     const keys = Object.keys(baseline.counts);
  152 |     const { entityCounts } = await gql<{ entityCounts: Record<string, number> }>(
  153 |       request,
  154 |       `{ entityCounts { ${keys.join(' ')} } }`,
  155 |     );
  156 |     const low = keys
  157 |       .map(k => ({ k, got: entityCounts[k], floor: Math.floor(baseline.counts[k] * baseline.floorRatio) }))
  158 |       .filter(({ got, floor }) => !(got >= floor));
  159 |     expect(
  160 |       low.map(({ k, got, floor }) => `${k} ${got} < floor ${floor} (baseline ${baseline.counts[k]})`),
  161 |       'entity counts below baseline floor (update baseline-counts.json only for an accepted drop)',
  162 |     ).toEqual([]);
  163 |   });
  164 | });
  165 | 
```