## TL;DR

A cold-cache warning fires on the first load before the batch window fills; it says nothing about whether batching worked. Verify the batch function actually ran once with all N keys, and that the database saw a single query. If both hold, the alert is a false positive and the detector needs an exemption for verified-batched dataloader paths.

## The query

```text
agent flagged an N+1 from a GraphQL dataloader cold-cache warning even though the loader batched correctly
```

## Steps

### 1. Find the batch function and instrument its invocations

Locate the dataloader's batch load function for the flagged field. Add a counter (or check existing metrics) for how many times the batch function runs per request and how many keys each invocation receives.

Expected: visibility into batch invocations per request: count and keys per call.

### 2. Reproduce the flagged request and read the counter

Replay the request that triggered the alert. Read the batch invocation counter.

Expected: the batch function ran once (or once per batch window) receiving all N keys in a single call.

### 3. Confirm the database saw one round trip

Check the database's query counters for the request window (pg_stat_statements calls, slow query log, or the driver's execute events). You are looking for a single query carrying the N keys, typically an IN clause.

Expected: one query, N keys, matching the single batch invocation.

### 4. Confirm the warning is cold-cache-only

Run the same request a second time with a warm cache. The batch function should not run at all and no warning should appear.

Expected: second run shows zero batch invocations and no warning, proving the warning was a first-load artifact.

### 5. Exempt verified-batched loader paths from the detector

Change the N+1 detector so dataloader paths with a verified single batch per window do not alert. Alert only when batch invocations scale with N (many small batches), which is the actual failure mode.

Expected: the same workload re-run produces no alert; a genuinely unbatched resolver still alerts.

## Use this when

- The N+1 evidence is a dataloader cache warning, not measured queries
- The batch function demonstrably ran once with all keys
- The alert appeared on first load and vanished on repeat requests
- The detector flags resolver fields without checking batch behavior

## Not for this skill when

- The batch function ran N times with one key each (real batching failure)
- The loader has no batch function at all (plain per-row resolver N+1)
- The duplicates are retry storms or instrumentation queries
- Cache is disabled in the test environment and every load is cold

## Variant phrasings

### dataloader N+1 false positive

Same check: batch invocation count per request is the ground truth, not the warning text.

### batch loader warning on first request

Expected behavior on cold cache. The warning describes the cache, not the query pattern.

### GraphQL resolver flagged though batched

Verify at the batch function (step 1), not at the resolver log lines, which fire per field by design.

## Why it happens

Dataloader warnings are written for developers debugging cache behavior, and they mention cache misses in alarming language. An agent reading the warning text pattern-matches "cache miss on every key" to "N+1" without checking whether the keys were fetched in one batch. The warning was never evidence of a query problem; the agent treated a cache observation as a query measurement.

## Edge cases

- Batch window too small: if max batch size splits N keys into many small batches, that is a real inefficiency. Tune the batch size rather than exempting the path.
- Per-key errors breaking the batch: one failing key can abort batching in some implementations. Check error handling before exempting.
- Cache disabled in staging: every request looks like a first load. Fix the environment, not the detector.
- Multiple loaders for the same field: make sure you instrumented the loader that actually served the request.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_h2Vd7xvJ5yVB0FdX0gKsZg
