Skip to content

Commit 62f3475

Browse files
authored
Merge pull request #98 from runcycles/docs/changelog-and-operations
docs: add CHANGELOG.md + OPERATIONS.md
2 parents 53cb43b + 38847d6 commit 62f3475

8 files changed

Lines changed: 605 additions & 40 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ cycles-protocol-service/cycles-protocol-service-model/.classpath
4848
cycles-protocol-service/cycles-protocol-service-model/.project
4949
.flattened-pom.xml
5050
.claude/settings.local.json
51+
52+
# Claude Code local state (not for commit)
53+
.claude/scheduled_tasks.lock

BENCHMARKS.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ Results are environment-dependent. Use for relative comparison across versions o
77

88
Run benchmarks: `mvn test -Pbenchmark` (requires Docker).
99

10+
### Release coverage
11+
12+
Benchmarks are captured when a release contains **hot-path code changes**
13+
(Lua scripts, repository methods, controller logic). They are deliberately
14+
skipped for releases whose changes are wire-format-neutral or test-only —
15+
running them would only measure environmental noise. Skipped releases:
16+
17+
- **v0.1.25.8** — admin-on-behalf-of dual-auth (new auth filter, no
18+
change to the reserve/commit/release hot path).
19+
- **v0.1.25.9** — test additions only, no production code changes.
20+
- **v0.1.25.10** — metrics instrumentation (Micrometer counter
21+
increments on success/failure paths; no Redis/Lua changes). The
22+
`ReservationExpiryService` prefix fix is off the request hot path
23+
(runs in the background sweep).
24+
25+
Last benchmarked release: **v0.1.25.7**.
26+
1027
---
1128

1229
## v0.1.25.7 — Typed `Enums.ReasonCode` refactor + flaky test fix

CHANGELOG.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# Changelog
2+
3+
All notable changes to `cycles-server` are recorded here. Format follows [Keep a
4+
Changelog](https://keepachangelog.com/en/1.1.0/); versions use
5+
[Semantic-ish Versioning](https://semver.org/) with a fourth "patch-of-patch"
6+
segment for same-day follow-ups.
7+
8+
This file is for **downstream consumers** — people pulling the Docker image or
9+
JAR. For internal engineering history (root cause analyses, rejected
10+
alternatives, test-strategy decisions) see [`AUDIT.md`](AUDIT.md).
11+
12+
Wire format is considered stable within a minor version (`0.1.x`). Breaking
13+
changes to request/response bodies or Lua-script semantics would require a
14+
minor bump. "Internal signature changes" (e.g. Java method parameters) are
15+
called out but are not breaking to API clients.
16+
17+
## [0.1.25.10] — 2026-04-14
18+
19+
### Added
20+
21+
- Seven domain-level Prometheus counters under the `cycles_*` namespace. See
22+
[`OPERATIONS.md`](OPERATIONS.md) for the full list, tag semantics, and
23+
alerting recipes. Short summary:
24+
- `cycles_reservations_reserve_total`
25+
- `cycles_reservations_commit_total`
26+
- `cycles_reservations_release_total`
27+
- `cycles_reservations_extend_total`
28+
- `cycles_reservations_expired_total`
29+
- `cycles_events_total`
30+
- `cycles_overdraft_incurred_total`
31+
- Configuration flag `cycles.metrics.tenant-tag.enabled` (default `true`) —
32+
set to `false` in deployments with many thousands of tenants to keep
33+
Prometheus cardinality bounded.
34+
- `RedisDisconnectResilienceIntegrationTest` — exercises the paused-Redis
35+
failure mode end-to-end and guards against silent-failure regressions.
36+
37+
### Fixed
38+
39+
- `ReservationExpiryService` was silently no-op'ing event emission on every
40+
expiry since v0.1.25.3 because it looked up the wrong Redis key prefix
41+
(`reservation:<id>` instead of `reservation:res_<id>`). The
42+
`reservation.expired` webhook now actually fires. If your downstream
43+
webhook consumer assumed expiries would never emit an event, update it
44+
before upgrading.
45+
46+
### Wire format
47+
48+
Unchanged. Upgrading from v0.1.25.9 requires no client changes.
49+
50+
### Notes for upgraders
51+
52+
- New counters appear on your next Prometheus scrape. No config change
53+
needed to emit them; they are on by default.
54+
- The `reservation.expired` webhook fix will start delivering events you
55+
weren't receiving before. Confirm your webhook endpoint handles them.
56+
57+
## [0.1.25.9] — 2026-04-14
58+
59+
### Added
60+
61+
- Seven new test classes landing the second-wave coverage plan
62+
(overdraft property tests, `expire.lua` direct conformance, admin-release
63+
vs agent-commit race, multi-scope attribution under contention,
64+
idempotency-cache expiry, clock-skew resilience, audit-log completeness).
65+
See [`AUDIT.md`](AUDIT.md) for the full strategy.
66+
67+
### Wire format
68+
69+
Unchanged. Test-only release.
70+
71+
## [0.1.25.8] — 2026-04-13
72+
73+
### Added
74+
75+
- **Admin-on-behalf-of release** (spec revision 2026-04-13). Dual-auth
76+
endpoint: `POST /v1/reservations/{id}/release` now accepts either a
77+
tenant `X-Cycles-API-Key` or a server-configured `X-Admin-API-Key` via
78+
`AdminApiKeyAuthenticationFilter`. Admin-driven releases write an audit
79+
entry with `metadata.actor_type=admin_on_behalf_of` to the shared
80+
`audit:log:*` Redis store, surfacing in the governance dashboard.
81+
- `admin.api-key` application property for configuring the admin key.
82+
83+
### Security
84+
85+
- Admin key comparison uses `MessageDigest.isEqual` (constant-time on
86+
equal-length inputs). Deployments should rotate to fixed-length keys.
87+
- CR/LF injection guarded in audit-log `reason` field.
88+
89+
## [0.1.25.7] — 2026-04-11
90+
91+
### Added
92+
93+
- `Enums.ReasonCode` as a typed enum (previously stringly-typed on the
94+
wire). Drop-in Jackson round-trip-compatible with existing clients.
95+
96+
### Fixed
97+
98+
- Flaky `EventEmitterServiceTest` on CI. Replaced `Thread.sleep(200)` +
99+
`verify()` racing with `Mockito.timeout()` / `after()`.
100+
101+
## [0.1.25.6] — 2026-04-10
102+
103+
### Changed
104+
105+
- Reserve/event/decide now distinguish `UNIT_MISMATCH` from
106+
`BUDGET_NOT_FOUND`. Previously a wrong-unit request surfaced as "budget
107+
not found" which was misleading when the scope had a budget under a
108+
different unit. The scripts now probe alternate units and emit
109+
`UNIT_MISMATCH` with the set of configured units.
110+
111+
## [0.1.25.5] — 2026-04-08
112+
113+
### Fixed
114+
115+
- Duplicate emission of budget-state transition events
116+
(`budget.approaching_limit`, `budget.at_limit`,
117+
`budget.over_limit`, `debt.incurred`) on multi-scope operations. Closes
118+
`cycles-server-events#15`.
119+
120+
## [0.1.25.4] — 2026-04-07
121+
122+
### Changed
123+
124+
- Event-data payloads now include all fields the webhook consumers
125+
require for correct dedup/ordering (`reservation_id`, `scope`, `unit`,
126+
`actor`, timestamps). Previously some events arrived with missing
127+
fields that forced webhook consumers to re-query the server.
128+
129+
## [0.1.25.3] — 2026-04-03
130+
131+
### Added
132+
133+
- Runtime event emission: `reservation.reserved`, `reservation.committed`,
134+
`reservation.released`, `reservation.expired`, `reservation.extended`,
135+
`event.applied`, and the budget-state transitions. Events land on a
136+
Redis stream consumed by `cycles-server-events` for webhook fan-out.
137+
- `PROTOCOL_VERSION` constant correctly set to `v0.1.25`.
138+
139+
## [0.1.25.2] — 2026-04-02
140+
141+
### Fixed
142+
143+
- `getBalances` and `listReservations` now lowercase the stored scope
144+
before segment matching, so operator-curated budgets with mixed-case
145+
scope paths are findable. Writes were already lowercase; this was a
146+
read-side defensive fix. Closes
147+
`cycles-openclaw-budget-guard#70`, `cycles-server-admin#54`.
148+
149+
## [0.1.25.1] — 2026-04-01
150+
151+
### Added
152+
153+
- Webhook event emission from the runtime server. Reserve/commit/release/
154+
extend and decide now emit events to the shared Redis dispatch queue
155+
for `cycles-server-events` to fan out to configured subscribers.
156+
Events include `reservation.denied` (on DENY decisions) and
157+
`reservation.commit_overage` (when committed `actual > estimate`).
158+
- `EventEmitterService` with async, non-blocking emission on a
159+
dedicated daemon thread pool (`CompletableFuture.runAsync`). The
160+
request thread never waits on event writes.
161+
- TTL retention: event keys expire after 90 days, delivery keys after
162+
14 days. Configurable via `EVENT_TTL_DAYS` / `DELIVERY_TTL_DAYS`.
163+
164+
### Performance
165+
166+
- Event save (SET + EXPIRE + 2× ZADD) and subscription lookup
167+
(2× SMEMBERS) batched into one Redis pipeline round-trip (was 6
168+
sequential). Near-zero overhead on non-event paths; commit p50
169+
recovered from 13.4ms to 5.6ms after the fix below.
170+
171+
### Fixed
172+
173+
- Commit overage event was firing on every commit, not just true
174+
overages. Now emits only when `actual > estimateAmount`.
175+
176+
---
177+
178+
## Archive
179+
180+
v0.1.x and earlier versions predating this changelog: see `AUDIT.md`.
181+
182+
[0.1.25.10]: https://github.com/runcycles/cycles-server/compare/v0.1.25.9...v0.1.25.10
183+
[0.1.25.9]: https://github.com/runcycles/cycles-server/compare/v0.1.25.8...v0.1.25.9
184+
[0.1.25.8]: https://github.com/runcycles/cycles-server/compare/v0.1.25.7...v0.1.25.8
185+
[0.1.25.7]: https://github.com/runcycles/cycles-server/compare/v0.1.25.6...v0.1.25.7
186+
[0.1.25.6]: https://github.com/runcycles/cycles-server/compare/v0.1.25.5...v0.1.25.6
187+
[0.1.25.5]: https://github.com/runcycles/cycles-server/compare/v0.1.25.4...v0.1.25.5
188+
[0.1.25.4]: https://github.com/runcycles/cycles-server/compare/v0.1.25.3...v0.1.25.4
189+
[0.1.25.3]: https://github.com/runcycles/cycles-server/compare/v0.1.25.2...v0.1.25.3
190+
[0.1.25.2]: https://github.com/runcycles/cycles-server/compare/v0.1.25.1...v0.1.25.2
191+
[0.1.25.1]: https://github.com/runcycles/cycles-server/releases/tag/v0.1.25.1

0 commit comments

Comments
 (0)