Add event history TTL controls#30
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ab53dc9ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
9 issues found across 41 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 633768bed4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
1 issue found across 12 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ce80a1ea40
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3be16898b4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7dc5ad236
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b853527548
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 19218ee6ee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
5 issues found across 14 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6f99c69488
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 380ad88736
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ) | ||
| ): | ||
| self.event_history.trim_event_history(owner_label=str(self)) | ||
| if not include_ttl or not self._has_ttl_cleanup_sources(): |
There was a problem hiding this comment.
Honor per-event TTLs without bus defaults
When a bus has no bus-level TTLs and no registered handler TTLs, but a completed event itself sets event_ttl or event_result_ttl, this guard returns before scanning history and resolving those per-event overrides. A later natural trim therefore never removes the event or its results, so per-event TTLs only work when some unrelated bus/handler TTL is configured; track per-event TTL sources or inspect retained history before skipping the scan.
Useful? React with 👍 / 👎.
| }) | ||
| } | ||
|
|
||
| if (!include_ttl || !this._hasTTLCleanupSources()) { |
There was a problem hiding this comment.
Honor per-event TTLs without bus defaults
When an event carries event_ttl or event_result_ttl but the TS bus itself has both TTL defaults unset and no handler currently has handler_result_ttl, this early return skips the only loop that resolves the event-level TTLs. In that configuration, a subsequent emit/trim pass leaves completed events and results retained indefinitely despite the event override; the skip condition needs to include TTLs present on retained events/results.
Useful? React with 👍 / 👎.
| if b.EventHistory.MaxHistorySize != nil && (*b.EventHistory.MaxHistorySize == 0 || b.EventHistory.MaxHistoryDrop) { | ||
| b.EventHistory.TrimEventHistory(nil) | ||
| } | ||
| if !includeTTL || !b.hasTTLCleanupSources() { |
There was a problem hiding this comment.
Honor per-event TTLs without bus defaults
For a Go bus with no bus-level TTL defaults and no registered handler TTLs, a completed event can still have EventTTL or EventResultTTL set on the event, but this guard returns before the history scan that resolves those fields. The next natural trim pass then never prunes that event or its results, so event-level TTL overrides are silently ignored unless an unrelated bus/handler TTL is configured.
Useful? React with 👍 / 👎.
| if let Some(max_size) = self.runtime.max_history_size { | ||
| self.trim_history_to_capacity(max_size, false); | ||
| } | ||
| if !include_ttl || !self.has_ttl_cleanup_sources() { |
There was a problem hiding this comment.
Honor per-event TTLs without bus defaults
If a Rust bus has no bus-level TTL defaults and no handler TTLs, completed events can still carry event_ttl or event_result_ttl, but this return prevents trim_event_history from ever examining those per-event values. A later natural trim therefore retains expired events/results forever in that common override-only configuration; the cleanup source check should account for TTLs stored in history.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
4 issues found across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 954af21dec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
3 issues found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="abxbus/event_bus.py">
<violation number="1" location="abxbus/event_bus.py:2265">
P2: The sorted `_ttl_deadline_queue` optimization means completed events are only re-evaluated when their precomputed deadline is reached. If a bus, event, or handler TTL is shortened at runtime after an event has already completed, the old (longer) deadline remains in the queue and the event will not be pruned until that stale future time. The previous scan-based trim loop honored updated TTLs on the next pass for all history, but the new queue-only inspection loses that behavior for events whose original deadline has not yet arrived. Consider retracking or recomputing deadlines for affected events when a bus-level or handler-level TTL is mutated, or document this limitation if runtime TTL adjustment is no longer supported.</violation>
</file>
<file name="abxbus-go/event_bus.go">
<violation number="1" location="abxbus-go/event_bus.go:822">
P2: The queue-based TTL pruning removes the previous full-history scan, which introduces a blind spot for already-completed events after runtime TTL changes. Events that finished while `EventTTL` or handler TTLs were unset are never added to `ttlDeadlineQueue`; if those fields are tightened later, existing history events silently remain unpruned. Consider adding an occasional fallback scan or a backfill hook when TTL config changes so that previously untracked events can still be evaluated against current settings.</violation>
</file>
<file name="abxbus-ts/src/EventBus.ts">
<violation number="1" location="abxbus-ts/src/EventBus.ts:523">
P2: The TTL deadline is indexed before event results are relinked to canonical bus handlers in `fromJSON`. `_earliestTTLDeadline` depends on `result.handler.handler_result_ttl`, but `_linkEventResultHandlers` replaces `result.handler` after the queue is built. If the canonical handler has a smaller TTL than the deserialized stub, the stored deadline is too late and pruning is delayed until that incorrect timestamp. Move `_trackEventTTLDeadline` to after the `_linkEventResultHandlers` loop, or re-track deadlines once relinking is complete.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="abxbus-go/tests/eventbus_timeout_test.go">
<violation number="1" location="abxbus-go/tests/eventbus_timeout_test.go:151">
P2: The new test creates three separate EventBus instances and calls Destroy() only at the end of each sub-section without defer or t.Cleanup. If any t.Fatal/t.Fatalf assertion in a sub-section fires before reaching the Destroy() call — for example, the assertion on line ~139 checking that the event remains before runtime changes — the test exits immediately and the bus resources (goroutines, channels) for that bus are leaked. All other tests in this file consistently use defer bus.Destroy() or t.Cleanup(bus.Destroy) right after each bus is created. Consider adding defer right after each bus creation to match the established pattern and ensure cleanup on early failure.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1824ec6e98
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 255025a7b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
1 issue found across 8 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d98916206
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
1 issue found across 15 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b37225e3ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ce24e3de1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return completed_at.astimezone(UTC).timestamp() | ||
|
|
||
| def _resolve_event_ttl(self, event: BaseEvent[Any]) -> float | None: | ||
| return event.event_ttl if event.event_ttl is not None else self.event_ttl |
There was a problem hiding this comment.
Validate mutable Python event TTLs before resolving
Because BaseEvent disables assignment validation and EventBus exposes mutable TTL attributes, a caller can set event.event_ttl = -2 or bus.event_ttl = -2 after construction and then emit/trim the event. This resolver returns that invalid value directly, and the trim path treats negative TTLs as “retain forever”, so the new >= -1 TTL contract is bypassed for runtime edits; validate the resolved TTL (and the analogous result TTL path) before using it.
Useful? React with 👍 / 👎.
| const jsonSchemaDraft202012 = jsonschema.Draft202012 | ||
|
|
||
| func validateOptionalSecondsAtLeastMinusOne(name string, value *float64) error { | ||
| if value != nil && *value < -1 { |
There was a problem hiding this comment.
Reject non-finite Go TTL values
When Go callers pass math.NaN() or math.Inf(1) for a TTL option or restored TTL field, this check accepts it because the < -1 comparison is false for NaN and true infinities pass the lower-bound test. Those values later produce inconsistent retention behavior in deadline tracking/trimming instead of being rejected under the finite seconds contract used by the other runtimes; check math.IsNaN/math.IsInf here before accepting the value.
Useful? React with 👍 / 👎.
Summary
Adds event history retention controls consistently across Python, TypeScript, Go, and Rust:
event_ttlfor dropping completed events from a bus historyevent_result_ttlfor pruning a bus's completed event results after the parent event completeshandler_result_ttlfor handler-level result retention overridesThe implementation keeps default hydration late and follows the existing timeout/slow-warning precedence model: bus defaults, event overrides, and handler overrides where applicable.
null/undefinedinherits defaults,-1means retain indefinitely,0prunes on the next natural trim pass, and values below-1are rejected.Implementation Notes
Validation
uv run pytest tests/test_eventbus_timeout.py tests/test_eventbus_forwarding.py tests/test_eventbus_dispatch_defaults.py -qgo test ./tests -run 'TTL|TypedEventConfigDefaultsPopulateBaseEventFields|TypedEventPointerZeroTTLsAreExplicitOverrides|CompletedForwardedEventWithPrunedTargetResults' -count=1cargo fmt --manifest-path abxbus-rust/Cargo.toml --checkcargo test --manifest-path abxbus-rust/Cargo.toml ttl -- --nocapturecargo test --manifest-path abxbus-rust/Cargo.toml typed_event_config_defaults -- --nocapturecargo test --manifest-path abxbus-rust/Cargo.toml completed_forwarded_event_with_pruned_target_results -- --nocapturenpm run typecheckNODE_OPTIONS='--expose-gc' node --expose-gc --test --import tsx tests/EventBus_timeout.test.ts tests/EventBus_forwarding.test.ts tests/EventBus_dispatch_defaults.test.tsSummary by cubic
Adds TTL controls for event/result history and an option-aware event reset across Python, TypeScript, Go, and Rust. Also hardens completed-event handling, forwarding, and restore/validate logic, fixes TTL validation/retracking (including a Rust lock-order fix), and enforces nonnegative execution timeouts across runtimes.
New Features
event_ttl,event_result_ttl,handler_result_ttlwith precedence (bus → event → handler). Semantics: inherit on null/undefined; keep forever on -1; prune on 0 at natural trim; reject < -1.handler_result_ttlis serialized inEventResult.event_created_atand TTL defaults, and clears status/timestamps/results; added read-only payload accessors; TypeScript exportsEventPayloadFieldsandEventResetOptions.Bug Fixes
Written for commit 5ce24e3. Summary will update on new commits.