* s3vectors: cover non-filterable key round-trip and nested filter rejection
The catalog writes the key list as a JSON string while older records
may still carry the array form; indexFromRecord must decode both. The
rejection path extracts field names through nested $and/$or filters, so
a blocked key deep in the tree still fails the query.
* s3vectors: factor the non-filterable rejection into a testable gate
Pull the blocked-key check out of handleQueryVectors into
nonFilterableField so the rejection itself is covered without standing
up the catalog stack; the handler now 400s on whatever the gate names.
* s3vectors: report the non-filterable match separately from the key
An empty metadata key in nonFilterableMetadataKeys collided with the
"no match" sentinel, so a filter on that key skipped rejection. Return
a match flag and cover the empty-key case in the test.