array_is_list(), and the encoder that guessed wrong

An API returning {"0": {...}, "1": {...}} instead of an array, because one filter had unset an element.

$rows = array_filter($rows, fn (Row $r) => $r->visible);

// keys are now 0, 2, 3 — not a list
json_encode($rows);   // {"0":...,"2":...,"3":...}

// the guard, and the fix
if (! array_is_list($rows)) {
    $rows = array_values($rows);
}

// or, in a test
self::assertTrue(array_is_list($payload['data']));

This has been a PHP API design hazard since JSON encoding existed, and array_is_list() makes the check explicit rather than a comparison against range(). Asserting it in the contract test for every collection endpoint is cheap and catches the case where a filter is added later — which is exactly how this one appeared, four years after the endpoint was written.