Skip to content

feat(list_reservations): add expires_*/finalized_* fields + finalized_at_ms (0.2.6)#41

Merged
amavashev merged 2 commits into
mainfrom
feat/list-reservations-expires-finalized-filters
May 22, 2026
Merged

feat(list_reservations): add expires_*/finalized_* fields + finalized_at_ms (0.2.6)#41
amavashev merged 2 commits into
mainfrom
feat/list-reservations-expires-finalized-filters

Conversation

@amavashev
Copy link
Copy Markdown
Contributor

@amavashev amavashev commented May 22, 2026

Summary

Client-side companion to cycles-protocol-v0.yaml revision 2026-05-22 and cycles-server#163. Closes the Rust-client side of runcycles/cycles-server#162. Follow-up to v0.2.5 with the same shape — four more params on the request side, plus one new optional field on the response side.

What this PR does

Request side: ListReservationsParams

Four new Option<String> fields with skip_serializing_if:

pub expires_from: Option<String>,
pub expires_to: Option<String>,
pub finalized_from: Option<String>,
pub finalized_to: Option<String>,

Each pair binds to its target field (expires_at_ms, finalized_at_ms) independent of from/to and any sort_by. The three windows compose with AND. finalized_* excludes ACTIVE and EXPIRED rows per the spec (the field is absent on those rows; predicate fails).

Response side: ReservationSummary

New Option<u64> field with #[serde(default)]:

pub finalized_at_ms: Option<u64>,

Populated on COMMITTED and RELEASED rows; absent (None) on ACTIVE/EXPIRED rows and on pre-v0.1.25.21 servers. Back-compat preserved both ways via Option + #[serde(default)]. ReservationSummary is #[non_exhaustive] and Deserialize-only, so callers can't construct it directly — the new field is fully transparent to downstream code.

Regression tests

Three new tests in tests/client_test.rs:

  1. list_reservations_forwards_expires_and_finalized_windows — wiremock query_param matchers assert all four request-side fields land on the wire under spec names.
  2. list_reservations_deserializes_finalized_at_ms_on_summary — server emits the field on a COMMITTED row, client deserializes to Some(value).
  3. list_reservations_deserializes_absent_finalized_at_ms_as_none — server omits the field (pre-revision server or ACTIVE row), client deserializes to None. Locks the back-compat path.

Backward compatibility

  • ListReservationsParams: pure additive for callers using ..Default::default(). Exhaustive constructors break (need to add 4 more None initializers) — same as v0.2.5, not new to this PR. ListReservationsParams lacks #[non_exhaustive] per the existing repo convention.
  • ReservationSummary: #[non_exhaustive] + Deserialize-only, so the new optional field is transparent.

Verification

  • cargo test (full suite): 134 tests pass, 12 ignored (live-server, by design).
  • cargo clippy -- -W clippy::all: clean.

Out of scope (intentionally narrow)

ListReservationsParams has accumulated drift relative to the full v0.1.25 spec (missing workspace/workflow/toolset/sort_by/sort_dir/idempotency_key). Same out-of-scope note as v0.2.5. Worth a separate follow-up to bring the struct to full spec parity.

Test plan

  • CI green
  • (After merge) optional smoke against v0.1.25.21 cycles-server

Closes the Rust-client side of runcycles/cycles-server#162.

amavashev added 2 commits May 22, 2026 08:38
…_at_ms (0.2.6)

Client-side companion to cycles-protocol-v0.yaml revision 2026-05-22
(runcycles/cycles-protocol#98) and runcycles/cycles-server#163.
Closes the Rust-client side of issue #162. Follow-up to v0.2.5
with the same shape, just four more params on the request side
plus one new optional response-side field.

ListReservationsParams (request):

  Four new Option<String> fields, each with skip_serializing_if:
  expires_from, expires_to, finalized_from, finalized_to. Each
  pair binds to its target field independent of from/to and any
  sort_by. finalized_* excludes ACTIVE and EXPIRED rows
  (finalized_at_ms absent on those rows per the spec).

ReservationSummary (response):

  New Option<u64> field finalized_at_ms with #[serde(default)].
  Populated by servers on COMMITTED and RELEASED rows only;
  absent (None) on ACTIVE/EXPIRED rows and on pre-v0.1.25.21
  servers regardless of status. Back-compat preserved both ways
  by Option + serde default.

Regression tests in tests/client_test.rs:

  * list_reservations_forwards_expires_and_finalized_windows:
    wiremock query_param matchers assert all four request-side
    fields land on the wire under the spec names.
  * list_reservations_deserializes_finalized_at_ms_on_summary:
    server emits finalized_at_ms on a COMMITTED row, client
    deserializes to Some(value).
  * list_reservations_deserializes_absent_finalized_at_ms_as_none:
    server emits the row WITHOUT finalized_at_ms (pre-revision
    server or ACTIVE row), client deserializes to None. Locks
    the back-compat path.

No protocol or wire-format change beyond the optional response
field; servers older than v0.1.25.21 silently ignore the new
request params and don't emit the new response field. 134 tests
pass across integration + unit suites; doc-tests + clippy clean.

Out of scope (intentionally narrow, same as v0.2.5): pre-existing
drift on ListReservationsParams (missing workspace / workflow /
toolset / sort_by / sort_dir / idempotency_key fields relative to
full v0.1.25 spec parity) is not addressed here. Worth a follow-up.

Bumped to 0.2.6, refreshed Cargo.lock, updated AUDIT.md and
CHANGELOG.md.
@amavashev amavashev enabled auto-merge May 22, 2026 12:53
@amavashev amavashev merged commit cbfda53 into main May 22, 2026
8 checks passed
@amavashev amavashev deleted the feat/list-reservations-expires-finalized-filters branch May 22, 2026 12:57
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.

1 participant