Skip to content

CustomZoneQueryPhase races CloudKit's query index — integration suite fails at Phase 18 #445

Description

@leogdion

Summary

mistdemo test-private fails at Phase 18 (Query records in a custom zone) with Verification failed: zone query did not return both created records, aborting Phases 19-26. This is a test race, not a library bugrecords/query with a zoneID works correctly.

Evidence

CustomZoneQueryPhase (Examples/MistDemo/Sources/MistDemoKit/Integration/Phases/CustomZoneQueryPhase.swift:93-104) calls queryRecords immediately after modifyRecords. CloudKit's query index is eventually consistent, so the records are not yet visible to a query even though they exist.

Reproduced directly against iCloud.com.brightdigit.MistDemo / development / private DB with raw HTTP:

Step Result
records/modify — create 2 records with zoneID HTTP 200, both created
records/query with same zoneID, immediately HTTP 200, 0 records
same query, +3s later HTTP 200, both records
records/lookup by name with zoneID HTTP 200, both returned immediately

lookup (a direct read) sees the records right away; query (index-backed) does not. So the zoneID request plumbing added in #426 / #146 is correct — the phase's timing assumption is not.

Why it wasn't caught

The phase already anticipates one eventual-consistency case — a NOT_FOUND branch treated as non-fatal at :126-134 ("schema may not be indexed yet"). But an empty-but-successful result is a different shape and falls through to the hard guard at :99.

Phase 17 ("Query with request options") passes because it queries 30 pre-existing records rather than freshly written ones.

Suggested fix

Poll with a bounded retry instead of asserting on the first response — e.g. retry the query until expectedNames.isSubset(of: foundNames) or a ~15-30s deadline, then fail. 3s was enough in this reproduction, but that is not a guarantee; CI runners may be slower, which likely explains intermittent failures beyond the expired-token issue.

Worth auditing the other query-after-write phases for the same assumption while in there.

Note on the run that found this

Phases 1-17 all passed, including the four new change-tracking phases from #429. The previously reported AUTHENTICATION_REQUIRED (HTTP 421) failures in the MistDemo Integration workflow were purely an expired CLOUDKIT_WEB_AUTH_TOKEN; with a fresh token, auth is fine and this race is the only remaining failure.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions