Skip to content

v0.1.25.13 — hydration cap + enum wire annotations

Choose a tag to compare

@amavashev amavashev released this 17 Apr 01:52
· 333 commits to main since this release
c5ffb08

v0.1.25.13 — hydration cap + enum wire annotations

Two defensive fixes on the v0.1.25.12 sorted-list feature, ported from cycles-server-admin v0.1.25.24. No spec change, no wire-format change, no hot-path performance impact.

Fixed

  • P1 — listReservationsSorted hydration cap. The sorted path no longer hydrates an unbounded reservation population before the in-memory sort. SORTED_HYDRATE_CAP = 2000 mirrors the admin-plane pattern: a labeled break exits the SCAN loop once matching.size() >= cap, a WARN is logged naming the tenant + sort tuple, and the downstream sort/slice/cursor path operates on the capped slice. Page still fills, has_more + next_cursor still populate — the cap is a heap-safety bound, not a correctness bound. Legacy no-sort-params path intentionally uncapped (it streams page-by-page via the SCAN cursor).
  • P2 — Jackson wire annotations on ReservationSortBy + SortDirection. Both enums now carry @JsonValue getWire() + @JsonCreator fromWire(String) matching the admin plane's SortSpec/SortDirection contract. Wire form stays lowercase, parsing stays case-insensitive, null → null. Controller-level validation unchanged: unknown tokens still surface as HTTP 400 INVALID_REQUEST.

Operator guidance

Callers that outgrow the 2000-row cap should narrow filters (status, idempotency_key, scope segments: workspace/app/workflow/agent/toolset). The longer-term path is the deferred per-tenant ZSET index ADR at docs/deferred-optimizations/sorted-list-zset-indices.md, scheduled when a tenant crosses ~10k active reservations.

Tests

  • RedisReservationQueryTest#sortedHydrationStopsAtCap — mocks SCAN page with cap + 10 keys, asserts exactly 5 rows in ascending created_at_ms order and has_more=true, next_cursor != null.
  • EnumsTest (new, cycles-protocol-service-model) — 12 tests covering getWire lowercase emission, fromWire canonical+case-insensitive parsing, null pass-through, IllegalArgumentException on unknown tokens, round-trip identity.
  • Full build green: 358 (data) + 137 (api) = all tests passing; JaCoCo ≥ 95%.

Backward compatibility

Full. Behaviour-visible only for tenants whose sorted-list query previously returned >2000 matching rows — those rows beyond row 2000 in the capped slice are now unreachable without narrowing filters. Same trade-off the admin plane established in v0.1.25.24.

Docker image

ghcr.io/runcycles/cycles-server:0.1.25.13

[benchmark-skip] — no hot-path write changes. Reserve / commit / release / extend / decide / event paths byte-identical to v0.1.25.12. Sorted-list read path adds a bounds check (1 comparison per hydrated row) with no observable latency impact. Full benchmark sweep scheduled when the deferred ZSET optimization lands.