Spec-conformance audit (2026-07-04 fleet sweep) against protocol spec v0.1.25.12. Enum tolerance is exemplary (#[serde(other)] Unknown everywhere, no deny_unknown_fields) — findings are mostly error-path ergonomics plus one latent panic.
Bugs / latent breaks
- Additive
Decision value → panic in reserve() (client.rs:186-189): a non-Deny unknown decision bypasses is_denied() and hits .expect("reservation_id ... must be present when decision is ALLOW"). The #[serde(other)] forward-compat is undercut by control flow — treat non-ALLOW/ALLOW_WITH_CAPS as an error instead of expecting.
retry_after hard-coded None on all error paths (client.rs:436,445): ErrorResponse has no retry_after_ms field and no Retry-After header parse, so Error::is_retryable() (error.rs:71) classifies every BudgetExceeded (and future 429 LIMIT_EXCEEDED) as non-retryable. The 200-body deny path DOES surface retry_after_ms — same server condition, different error richness.
- 410 Gone unhandled; 409
IdempotencyMismatch/ReservationFinalized unclassified — all fall to generic Error::Api (client.rs:423-438); 409 path also discards affected_scopes.
Spec-currency gaps
ErrorCode lacks LIMIT_EXCEEDED (spec v0.1.25.12) — tolerated as Unknown today.
- Evidence surface (
cycles_evidence response fields, GET /v1/evidence/{id}, JWKS) unmodeled; silently dropped. ReservationSummary also lacks committed/metadata/committed_metadata/evidence projections (include=, spec 2026-06-19/22 revisions); ListReservationsParams has the window filters ✓ but no sort_by/sort_dir/include.
validate_extend_by_ms (validation.rs:40) defined but never called on the extend path; retry engine is dead_code ("future release") while guard commit failures propagate directly — either wire or remove.
ListReservationsParams not #[non_exhaustive] (request.rs:142) — every additive param bump is a source-breaking change (already bit v0.2.5/v0.2.6 per CHANGELOG).
Context
Same sweep: spec PRs runcycles/cycles-protocol#120/#121/#122 and fixes across the server fleet. Full inventory details available on request.
Spec-conformance audit (2026-07-04 fleet sweep) against protocol spec v0.1.25.12. Enum tolerance is exemplary (
#[serde(other)] Unknowneverywhere, nodeny_unknown_fields) — findings are mostly error-path ergonomics plus one latent panic.Bugs / latent breaks
Decisionvalue → panic inreserve()(client.rs:186-189): a non-Deny unknown decision bypassesis_denied()and hits.expect("reservation_id ... must be present when decision is ALLOW"). The#[serde(other)]forward-compat is undercut by control flow — treat non-ALLOW/ALLOW_WITH_CAPS as an error instead of expecting.retry_afterhard-codedNoneon all error paths (client.rs:436,445):ErrorResponsehas noretry_after_msfield and noRetry-Afterheader parse, soError::is_retryable()(error.rs:71) classifies everyBudgetExceeded(and future 429LIMIT_EXCEEDED) as non-retryable. The 200-body deny path DOES surfaceretry_after_ms— same server condition, different error richness.IdempotencyMismatch/ReservationFinalizedunclassified — all fall to genericError::Api(client.rs:423-438); 409 path also discardsaffected_scopes.Spec-currency gaps
ErrorCodelacksLIMIT_EXCEEDED(spec v0.1.25.12) — tolerated asUnknowntoday.cycles_evidenceresponse fields,GET /v1/evidence/{id}, JWKS) unmodeled; silently dropped.ReservationSummaryalso lackscommitted/metadata/committed_metadata/evidenceprojections (include=, spec 2026-06-19/22 revisions);ListReservationsParamshas the window filters ✓ but nosort_by/sort_dir/include.validate_extend_by_ms(validation.rs:40) defined but never called on the extend path; retry engine isdead_code("future release") whileguardcommit failures propagate directly — either wire or remove.ListReservationsParamsnot#[non_exhaustive](request.rs:142) — every additive param bump is a source-breaking change (already bit v0.2.5/v0.2.6 per CHANGELOG).Context
Same sweep: spec PRs runcycles/cycles-protocol#120/#121/#122 and fixes across the server fleet. Full inventory details available on request.