You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Remaining event data gaps:** None. All EventData fields now fully populated for runtime-emitted events.
40
40
41
+
### 2026-04-08 — v0.1.25.5: Fix duplicate budget state events (cycles-server-events#15)
42
+
43
+
**Bug:**`budget.exhausted`, `budget.over_limit_entered`, and `budget.debt_incurred` events fired on every operation where the post-state matched the condition, not only on state *transitions*. For example, a reserve that depleted a budget emitted `budget.exhausted`, then the subsequent commit (with remaining still at 0) emitted it again.
44
+
45
+
**Root cause:**`EventEmitterService.emitBalanceEvents()` checked post-mutation state only (e.g., `remaining == 0`). No transition detection.
46
+
47
+
**Fix:** Lua scripts (reserve, commit, event) now include `pre_remaining` and `pre_is_over_limit` per scope in balance snapshots. Java emits only on transitions:
**Performance:** No extra Redis calls. reserve.lua caches pre-state from existing validation HMGET. commit.lua caches from existing overage-path reads (ALLOW_IF_AVAILABLE/ALLOW_WITH_OVERDRAFT); delta <= 0 paths skip (remaining can only increase). event.lua folds `is_over_limit` into existing HMGET.
**Write-path analysis:** All operations consistent with v0.1.25.4. Reserve (7.2ms vs 5.7ms), Commit (5.8ms vs 4.7ms), Release (6.0ms vs 4.8ms), Extend (9.0ms vs 7.6ms), Decide (6.3ms vs 5.5ms), Event (6.2ms vs 5.1ms) — all within normal container/JVM warmth variance across benchmark sessions. The pre-state caching in Lua adds zero extra Redis calls: reserve.lua caches from its existing validation HMGET, commit.lua from existing overage-path reads, event.lua folds is_over_limit into its existing HMGET. No regressions.
41
+
42
+
### Single-Threaded Read-Path Latency
43
+
44
+
| Operation | p50 | p95 | p99 | min | max | mean |
**Read-path analysis:** No read-path code was changed. All operations consistent with v0.1.25.4 (GET reservation 3.5ms vs 3.8ms, GET balances 3.6ms vs 4.0ms). No regressions.
**Concurrency analysis:** Throughput at 32 threads is 2,520 ops/s — within 5% of v0.1.25.4's 2,655 ops/s. The scaling ratio from 8→32 threads is 3.3x (753 → 2,520), consistent with prior versions (v0.1.25.4: 3.4x, v0.1.25.3: 3.5x). p99 at 32 threads (34.5ms) is comparable to v0.1.25.4's 29.8ms. Zero errors at all concurrency levels. The transition fix adds no measurable overhead — pre-state caching piggybacks on existing Lua reads with zero extra Redis calls. Earlier runs on this day showed degraded numbers (~725 ops/s) due to TuneupUI background processes consuming CPU; after termination, normal throughput restored.
Copy file name to clipboardExpand all lines: cycles-protocol-service/cycles-protocol-service-api/src/main/java/io/runcycles/protocol/api/controller/EventController.java
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -47,7 +47,9 @@ public ResponseEntity<EventCreateResponse> create(
Copy file name to clipboardExpand all lines: cycles-protocol-service/cycles-protocol-service-api/src/main/java/io/runcycles/protocol/api/controller/ReservationController.java
+9-4Lines changed: 9 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -81,8 +81,11 @@ public ResponseEntity<ReservationCreateResponse> create(
81
81
.build(),
82
82
null, null);
83
83
}
84
-
// Emit budget state events from post-operation balances
Copy file name to clipboardExpand all lines: cycles-protocol-service/cycles-protocol-service-data/src/main/java/io/runcycles/protocol/data/repository/RedisReservationRepository.java
+44Lines changed: 44 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -130,6 +130,8 @@ public ReservationCreateResponse createReservation(ReservationCreateRequest requ
Copy file name to clipboardExpand all lines: cycles-protocol-service/cycles-protocol-service-data/src/main/java/io/runcycles/protocol/data/service/EventEmitterService.java
+23-11Lines changed: 23 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -86,32 +86,44 @@ public void emit(EventType type, String tenantId, String scope, Actor actor,
0 commit comments