Skip to content

fix(zig): harden 0.2.0 release blockers - #409

Merged
ajroetker merged 5 commits into
antflydb:codex/e2e-publish-split-racesfrom
dovinmu:fix/pr371-release-hardening
Jul 29, 2026
Merged

fix(zig): harden 0.2.0 release blockers#409
ajroetker merged 5 commits into
antflydb:codex/e2e-publish-split-racesfrom
dovinmu:fix/pr371-release-hardening

Conversation

@dovinmu

@dovinmu dovinmu commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a stacked release-hardening change for #371. It addresses the black-box Go-v-Zig findings and the related lifecycle paths identified in the Zig white-box investigation.

Release blockers

  • reject unsupported transform operators atomically instead of acknowledging a no-op; narrow the OpenAPI contract to the implemented operators
  • stop detached LSM maintenance jobs from immediately resubmitting a positive-but-non-actionable maintenance hint, eliminating the external dense/sparse index idle CPU loop
  • fold finalized split/merge records into desired topology during authority handoff so automatic splits can finish
  • fix HA E2E readiness probing to use /readyz
  • bind the serverless health listener to the configured serverless host

API and CLI hardening

  • normalize uncaught request errors into safe JSON 400/413/500 responses for HTTP/1 and HTTP/2
  • add the default JSON Content-Type for successful API responses
  • percent-decode generated query parameters exactly once, including backup locations
  • return missing-table index-list requests immediately instead of entering the five-second status retry path
  • make --document the canonical insert flag while retaining --value as an alias
  • make table list compact by default, with detail behind --verbose or --output json
  • add friendlier startup error messages
  • remove the unsupported metadata --join flag from help
  • update Lite format documentation from revision 1 to revision 2

Root causes

The external-index CPU burn was an LSM maintenance lifecycle loop: a detached job could observe a positive maintenance score, find no valid work, and immediately resubmit itself indefinitely. The split stall was a handoff gap where a durable finalized transition could be visible before projected topology caught up, but desired topology only rehydrated active intents.

Validation

  • make zig-build ZIG_BUILD_FLAGS=-j1
  • generated OpenAPI/docs regenerated twice with identical output
  • zig build lib-httpx-test -j1
  • focused DB transform, LSM maintenance, and metadata finalized-split tests
  • external dense-index create → ready → idle → drop soak: 0.3–0.5% CPU after this patch (the same repro was ~140% before the LSM fix)
  • E2E: automatic split finalization
  • E2E: both HA standby tests
  • E2E: unsupported transform rejection without partial mutation (all seven advertised-but-unimplemented operators)
  • E2E: normally percent-encoded backup location validation
  • E2E: missing-table index-list latency
  • E2E: CLI compact/JSON table listing and --document insert
  • E2E: external embedding index ingest/query

The broad aggregate test target on the #371 base is not green independently of this patch (existing metadata expectation/contract failures, stale no-match test filters, and restore-test initializer compile errors), so validation here uses the relevant focused targets and E2E reproductions.

@ajroetker

Copy link
Copy Markdown
Contributor

[codex]

Review findings:

  1. [P1] Decoded query parameters leak per request. queryDecoded allocates using the long-lived server allocator, but Context.deinit does not free the returned buffers, and generated handlers never free them. Every supplied query parameter now leaks one request-controlled allocation. Track these buffers in the context, use a request arena, or generate corresponding frees.

  2. [P2] A transient bulk-ingest window can permanently strand maintenance debt. clearMaintenanceJobInFlight(made_progress) suppresses rescheduling whenever runMaintenanceStep returns false, including when it is temporarily blocked by active bulk ingest. When that session is aborted, abortBulkIngestSessionLocked merely decrements the counter, leaving positive debt with no job until an unrelated write occurs. Reschedule when the last bulk session ends or aborts, while retaining no-resubmit behavior for genuinely non-actionable plans.

  3. [P2] Generic HTTP/1 errors are mislabeled as internal failures. routeErrorBody maps every status except 400 and 413 to INTERNAL_ERROR, but sendError is also used for 404, 408, and 431. An unknown HTTP/1 route therefore returns status 404 with an internal-server-error body. Add status-specific envelopes or restrict this helper to 400/413/500.

@ajroetker
ajroetker marked this pull request as ready for review July 29, 2026 00:46
@ajroetker
ajroetker merged commit fa2d3f8 into antflydb:codex/e2e-publish-split-races Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants