Releases: runcycles/cycles-server
Release list
v0.1.25.59 — authoritative reservation TTL
Authoritative reservation TTL
- Emit
remaining_ttl_mson reservation create and extend responses. - Recompute the field on idempotent replays; finalized reservations report zero.
- Keep the timing hint outside signed evidence payloads.
- Stabilize replay assertions for the documented dynamic-field carve-out.
- Align generated and runtime schemas on a non-negative TTL.
v0.1.25.58 — direct-event replay metrics
Direct-event replay metrics
This release closes the remaining replay-observability asymmetry: successful keyed direct-event replays now appear in the domain request counter without double-counting mutation-only effects.
Observability
- Records successful keyed
POST /v1/eventsreplays ascycles_events_total{decision="APPLIED",reason="IDEMPOTENT_REPLAY"}. - Keeps fresh event applications tagged
reason="OK". - Preserves exactly-once
cycles_overdraft_incurred_totalaccounting when an event replay follows an original debt-incurring mutation. - Clarifies that domain event counters cover repository-handled outcomes and documents the operations that expose replay tags.
Compatibility and validation
- Metrics-only behavior change: no protocol schema, HTTP body/status, Redis command, Lua script, ledger state, idempotency storage, evidence, or runtime-event behavior changed.
- Production and full-stack Compose files pin
ghcr.io/runcycles/cycles-server:0.1.25.58. - Targeted repository tests passed: 30/30.
- Real-Redis metrics integration tests passed: 14/14.
- Full integration-profile reactor discovered 1,207 tests with zero failures or errors.
- Protocol operation coverage remains 11/11.
- JaCoCo line coverage: data 95.14%, API 95.56%.
- All merge CI, integration, CodeQL, container, and supply-chain checks passed.
[benchmark-skip]: the replay path adds one in-memory Micrometer counter increment; foreground Redis and ledger paths are unchanged.
Full details: CHANGELOG.md [0.1.25.58], AUDIT.md, BENCHMARKS.md, and PR #249.
v0.1.25.57 — Redis recovery and rolling-upgrade matrices
Redis recovery and rolling-upgrade matrices
This test/documentation-only release makes Redis lost-response recovery and supported rolling-upgrade storage compatibility executable in CI, without changing production behavior.
Recovery coverage
- Adds deterministic lost-response tests for reserve, commit, release, direct event, dry-run, and decide.
- Retries every discarded successful response and asserts byte-identical bodies plus exactly-once ledger, evidence, runtime-event, reservation, event, and TTL-index side effects.
- Uses a FIFO executor barrier for deterministic asynchronous event draining rather than timing sleeps.
Upgrade compatibility
- Adds frozen legacy Redis fixtures for lifecycle fast-body rows, pre-snapshot rows, pre-v0.1.25.52 event storage, the pre-v0.1.25.51 dry-run namespace, and reservations created before the optional created-at index.
- Pins replay, mismatch, snapshot-backfill, no-second-debit, and index-backfill behavior against the current reader.
- Strengthens fixtures so storage-field drift cannot make compatibility tests pass vacuously.
Compatibility and validation
- No production source, protocol wire shape, Redis layout, or foreground command path changed.
- Production and full-stack Compose files pin
ghcr.io/runcycles/cycles-server:0.1.25.57. - 1,206 tests passed: 31 model, 575 data, 600 API; zero failures, errors, or skips.
- Protocol operation coverage 11/11.
- JaCoCo line coverage: data 95.14%, API 95.56%.
- All merge CI, integration, CodeQL, container, and supply-chain checks passed.
[benchmark-skip]: this release changes tests and documentation only.
Full details: CHANGELOG.md [0.1.25.57], AUDIT.md, BENCHMARKS.md, issue #247, and PR #248.
v0.1.25.56 — leased scheduled Redis maintenance
Leased scheduled Redis maintenance
This release coordinates all five Redis-backed scheduled maintenance jobs across runtime replicas without changing protocol behavior, ledger semantics, job cadence, or foreground request paths.
Reliability and operations
- Adds per-job Redis
SET NX PXleases for reservation expiry, audit retention, event retention, created-at index repair, and created-at index sweeping. - Renews and releases leases only when the owner token still matches, preventing an old process from extending or deleting a successor lease.
- Uses a bounded heartbeat executor plus local overlap guards; abandoned leases recover automatically after TTL.
- Keeps every maintenance job idempotent and isolates action, Redis, renewal, release, and metrics failures from the scheduler.
- Adds
cycles_maintenance_runs_total{job,outcome}andcycles_maintenance_duration_seconds{job,outcome}with structurally bounded tags. - Warns at startup when the renewal interval exceeds one-third of the lease TTL and documents renewal head-of-line timeout margin.
Compatibility
- No protocol schema, HTTP request/response, ledger Lua, authoritative Redis row, maintenance cadence, or foreground request-path change.
- New
cycles:maintenance:lease:*keys are short-lived internal coordination state. - Mixed fleets remain idempotent but do not provide single-run guarantees until every runtime pod is upgraded.
- Production and full-stack Compose files pin
ghcr.io/runcycles/cycles-server:0.1.25.56.
Validation
- 1,195 tests passed: 31 model, 575 data, 589 API; zero failures, errors, or skips.
- Protocol operation coverage 11/11.
- JaCoCo line coverage: data 95.14%, API 95.56%.
- Real-Redis tests cover two-runner exclusion, heartbeat renewal, stale-owner release protection, abandoned-lease recovery, Redis/type/action/metrics failures, and all five scheduler delegations.
- All PR CI, integration, CodeQL, Trivy, and container checks passed.
[benchmark-skip]: production changes are confined to background maintenance and bounded metrics; no HTTP or ledger hot path changed.
Full details: CHANGELOG.md [0.1.25.56], AUDIT.md, BENCHMARKS.md, issue #245, and PR #246.
v0.1.25.55 — typed reservation-query boundary
Typed reservation-query boundary
This release reduces the highest remaining change-risk concentration in cycles-server without changing protocol, Redis, cursor, filtering, ordering, or performance behavior.
Internal architecture
- Introduces immutable
ReservationListQuerygroups for scope filters, inclusive time windows, sort state, cursors, limits, and optional projections. - Moves SCAN pagination, sorted fallback, and completeness-gated created-at traversal into
RedisReservationQueryRepository. - Centralizes Redis hash projections, filter matching, finalized-time resolution, and detail/list hydration in
ReservationHashMapper. - Retains both public
RedisReservationRepository.listReservations(...)signatures as the compatibility facade. - Shares exact scope-segment matching between reservation and balance queries while preserving the existing first-occurrence behavior.
Correctness safeguards
- Adds a real-Redis query matrix that executes through both a READY created-at index and the authoritative SCAN fallback.
- Asserts identical rows, stable ordering, page boundaries, exact cursor bytes, and error code/status/message across both paths.
- Pins the
tenant,reservation_id, andcreated_atconsistency fields in listing projections. - Preserves the established filter-hash argument order so in-flight sorted cursors remain valid across the upgrade.
Compatibility
- No protocol schema, HTTP signature, response shape, Redis key, Lua script, Redis command sequence, cursor encoding, filter, ordering, index readiness, or feature-flag change.
- Production and full-stack Compose files pin
ghcr.io/runcycles/cycles-server:0.1.25.55.
Validation
- 1,182 tests passed: 31 model, 562 data, 589 API; zero failures, errors, or skips.
- Protocol operation coverage 11/11.
- JaCoCo line coverage: data 95.22%, API 95.56%.
- Real-Redis created-at index suite 24/24, including explicit INDEX and SCAN_DISABLED parity coverage.
- Three paired candidate and three v0.1.25.54 baseline benchmark trials completed all 17 cases with zero errors.
- Sorted-list p50 remained 17.0 ms at 1,000 rows and moved from 16.9 ms to 17.6 ms (+4.1%) at 10,000 rows, classified as performance-neutral.
- All PR CI, integration, CodeQL, Trivy, and container checks passed.
Full details: CHANGELOG.md [0.1.25.55], AUDIT.md, BENCHMARKS.md, issue #243, and PR #244.
v0.1.25.54 — bounded created-at reservation listing
Bounded created-at reservation listing
This release makes the default created_at_ms reservation listing population-independent while preserving reservation hashes as the authority and retaining the complete full-SCAN fallback whenever index completeness is uncertain.
Performance
- Adds a per-tenant
created_at_msZSET, atomically dual-written by reservation creation. - Serves the default sorted query in bounded, tie-safe candidate batches only after READY/count validation succeeds.
- Reduces same-host p50 from 22.5 ms to 10.7 ms at 1,000 rows and from 164.9 ms to 11.1 ms at 10,000 rows.
- Leaves the other six sort keys on the authoritative full-SCAN implementation.
Reliability and rollout
- Uses restartable backfill, expected-count validation before and after hydration, lazy stale cleanup, and a nightly authoritative sweep.
- Invalidates readiness on malformed authoritative rows and repairs exclusively owned wrong-type index keys without creating complete-looking omissions.
- Isolates scheduled maintenance on a bounded four-thread pool and backs off deterministic malformed-row reconciliation failures for one hour.
- Validates sorted cursor boundaries before Redis work so indexed and fallback paths return the same
400 INVALID_REQUEST. - Defaults the read/backfill switch off in the application and both production Compose files; enable
RESERVATION_CREATED_AT_INDEX_ENABLEDonly after every writer runs v0.1.25.54 or newer.
Compatibility
- No protocol schema, response body, filtering, ordering, or cursor-format change.
- Disabling the feature flag immediately restores the previous full-SCAN read path.
- Production and full-stack Compose files pin
ghcr.io/runcycles/cycles-server:0.1.25.54.
Validation
- 1,181 tests passed: 31 model, 561 data, 589 API; zero failures, errors, or skips.
- Protocol operation coverage 11/11.
- JaCoCo line coverage: data 95.10%, API 95.56%.
- Real-Redis coverage includes 10,000-row traversal, 300-way timestamp ties, rollout/readiness races, malformed cursors, corruption fallback, wrong-type repair, sweep isolation, and repair backoff.
- Three local benchmark trials completed all 17 cases with zero errors; the release workflow will independently enforce the rolling 25% regression gate.
- Production Compose configurations render successfully.
Full details: CHANGELOG.md [0.1.25.54], AUDIT.md, BENCHMARKS.md, and PR #242.
v0.1.25.53 — sorted reservation scaling baseline
Sorted reservation scaling baseline
This benchmark-only release establishes the pre-index comparison point for cycles-server#240 without changing production request, Lua, Redis-storage, or wire behavior.
Added
- end-to-end
GET /v1/reservationssorted-list benchmarks at 1,000 and 10,000 total reservation hashes - a 50/50 authenticated-tenant/unrelated-tenant fixture that exposes the current global SCAN and hydration cost
list_sorted_1k_p50_msandlist_sorted_10k_p50_msin benchmark parsing, three-trial medians, nightly history, and release regression gating- a revised completeness-safe Phase B design: one default-sort index, explicit post-rollout readiness, expected-count validation, restartable backfill, stale cleanup, stable tie pagination, and full-SCAN fallback
Baseline
Three same-host medians against the unchanged v0.1.25.52 runtime:
- 1,000 total / 500 tenant rows: 22.5 ms p50, 40.9 ms p95, 48.3 ms p99
- 10,000 total / 5,000 tenant rows: 164.9 ms p50, 210.2 ms p95, 232.0 ms p99
Validation
- 1,144 tests; zero failures, errors, or skips
- protocol operation coverage 11/11
- JaCoCo line coverage: data 95.12%, API 95.56%
- release benchmark profile 17/17 with all nine headline metrics parsed
- production Compose configurations validated
v0.1.25.52 — event replay storage and ledger helper cleanup
This release removes keyed-event replay storage amplification and consolidates the protocol's per-scope over-limit rule without changing public behavior.
Event replay storage
- Stores one canonical response body for new idempotent events in the 30-day event hash instead of duplicating it in a seven-day fast-response key.
- Reads the immutable snapshot directly on normal replay, preserving one body lookup while removing one response-sized write, expiring key, and memory copy per keyed event.
- Retains byte-identical replay for pre-v0.1.25.52 rows through the legacy fast-key fallback and opportunistic
HSETNXsnapshot backfill. - Uses a protected hash read so an incompatible legacy event-key type does not prevent replay while the canonical legacy response still exists.
Ledger maintainability
- Replaces four hand-synchronized commit/event over-limit marking loops with one shared
mark_uncovered_scopesimplementation. - Keeps exact signed-int64 arithmetic side-effect-free in
int64-helpers.lua; Redis mutations live in the separateledger-helpers.luaprelude. - Adds composition tests that enforce one helper definition per loaded ledger script and prevent Redis writes from returning to the arithmetic prelude.
Compatibility
- No request, response, or successful replay shape changes.
- Pre-v0.1.25.52 event rows remain replayable while their legacy response key exists; missing event hashes are not recreated and existing snapshots are never overwritten.
- Production and full-stack compose defaults pin
ghcr.io/runcycles/cycles-server:0.1.25.52.
Validation
- 1,144 tests passed: 31 model, 534 data, 579 API; zero failures, errors, or skips.
- Protocol contract coverage 11/11; JaCoCo line coverage 95.12% data and 95.56% API.
- Real-Redis coverage includes snapshot-only replay, legacy backfill, wrong-type legacy fallback, and both capped-charge policies' hierarchical scope marking.
- Three benchmark-profile trials passed all 15 cases with zero concurrency errors; every headline delta remained below the 25% regression threshold.
Full details: CHANGELOG.md [0.1.25.52], AUDIT.md, BENCHMARKS.md, and PR #239.
v0.1.25.51 — protocol idempotency and replay hardening
This release hardens protocol idempotency, replay integrity, hierarchical budget attribution, and corrupt-expiry observability without changing the public schema.
Protocol correctness
- Shares the reserve endpoint idempotency namespace between live and dry-run requests, returning
409 IDEMPOTENCY_MISMATCHwhen the same key changes request form or payload. - Makes slow, uncontested non-persisting evaluations publish safely after claim expiry while preventing overwrite by a newer winner.
- Preserves pre-upgrade dry-run results through the legacy namespace bridge and detects independently lost companion hashes by value shape.
- Marks only scopes that individually fail to cover capped commit/event charges as over-limit.
Replay and expiry hardening
- Stores immutable event response snapshots and repairs missing fast response caches without re-dispatching webhooks or synthesizing changed bodies.
- Opportunistically backfills pre-snapshot event rows while their canonical response remains available.
- Quarantines malformed expiry rows with durable reason/timestamp metadata, WARN logging, and bounded
cycles.reservations.quarantinedmetrics. - Normalizes missing/non-textual quarantine tenants to the existing
UNKNOWNmetric tag.
Compatibility
- No request or successful-response schema changes.
- Mixed-version deployments may return a transient retriable 500 from an older pod while a new dry-run marker is live (at most 60 seconds); the documented production topology remains single-instance.
- Production and full-stack compose defaults pin
ghcr.io/runcycles/cycles-server:0.1.25.51.
Validation
- 1,140 tests passed: 31 model, 531 data, 578 API; zero failures, errors, or skips.
- Protocol contract coverage 11/11; JaCoCo line coverage 95.11% data and 95.56% API.
- Focused adversarial Redis suite 64/64, including three-state CAS and bidirectional value-shape mismatch cases.
- Three benchmark-profile trials completed with zero concurrent errors and no measurable regression.
Full details: CHANGELOG.md [0.1.25.51], AUDIT.md, BENCHMARKS.md, and PR #238.
v0.1.25.50 — runtime correctness, replay integrity, and int64 fidelity
Rolls up the v0.1.25.49 runtime hardening and the v0.1.25.50 replay/int64 follow-up. This release keeps the public protocol schema unchanged while closing correctness, liveness, and scaling gaps in reservation lifecycle processing.
Correctness and replay integrity
- Stores immutable reserve/commit/release response snapshots inside their atomic Redis mutations and repairs missing fast caches without synthesizing a potentially different response.
- Uses a PENDING → BASE/EVIDENCE state machine so concurrent replay repair cannot overwrite a canonical evidence-bearing response.
- Preserves exact signed-int64 ledger arithmetic and response values across reserve, commit, release, expiry, direct events, and extend through one shared Lua decimal helper.
- Saturates only the commit-level debt observability aggregate at
Long.MAX_VALUE; per-scope debts and balances remain exact. - Restores commit/release replay metrics with
IDEMPOTENT_REPLAYwhile avoiding overdraft double-counting.
Expiry and audit hardening
- Emits expiry events only for a true
status=EXPIREDtransition and hydrates the correct timestamp fields. - Quarantines reservations with missing, malformed, or negative estimate data outside the bounded TTL sweep index, leaving state and budgets untouched for operator reconciliation and logging a WARN.
- Makes admin-release audit persistence part of the same Lua transaction and centralizes audit-entry preparation with fail-closed tenant validation.
Performance and operations
- Releases Redis connections before BCrypt verification.
- Replaces hot reservation
HGETALLcalls with explicitHMGETprojections, shares name-keyed projection mapping, and hoists projection arrays. - Adds resilient event/delivery pointer retention cleanup and fixes jqwik configuration discovery.
- Updates production and full-stack compose defaults to
ghcr.io/runcycles/cycles-server:0.1.25.50.
Compatibility
- No public schema or successful-response shape changes.
- Finalized reservations created before immutable snapshots existed still replay through their canonical body cache; if both that cache and a snapshot are absent, the server returns the existing retriable 500 rather than a non-identical reconstruction.
Validation
- 1,111 tests: 31 model, 525 data, 555 API; zero failures, errors, or skips.
- Contract coverage 11/11; JaCoCo line coverage 95.09% data and 95.56% API.
- Real-Redis regressions cover
2^53 + 1,10^14 + 1, andLong.MAX_VALUEledger/refund/replay cases. - Same-host benchmark medians: reserve/commit/release p50 14.5/13.7/14.3 ms and 698.2 ops/s at 32 threads, with no regression signal versus v0.1.25.49.
Full details: CHANGELOG.md [0.1.25.49] and [0.1.25.50], AUDIT.md 2026-07-12/13 entries, PRs #235 and #237, issue #236.