Show & Tell: Designing the Three-Layer CognitiveCycle Fault Tolerance Stack #142
web3guru888
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
The Full Resilience Stack: Retry Budget → Circuit Breaker → Graceful Degradation
With #137 (circuit breaker) and #139 (retry budget manager) now designed, the CognitiveCycle has a three-layer fault tolerance architecture. I want to walk through the complete call stack so the design rationale is clear.
Why three layers?
Failures in a real-time cognitive loop come in three flavors:
A single mechanism can't handle all three well. Retrying a permanently broken module wastes budget. Skipping a transiently slow module loses valid data. Serving stale data forever erodes confidence without notice.
So we have three nested layers:
Layer 1: Retry Budget
Defined in #139. Key design constraints:
Not all exceptions are transient. Only
TransientModuleErrorandasyncio.TimeoutErrorare retried. APermanentModuleError(bad config, invariant violation) skips straight to the circuit breaker.Safety tier gets max_attempts=1. We don't retry safety checks. If the safety gate fails, the correct response is immediate escalation, not a second attempt that might pass due to timing luck.
Budget accounts for total wall clock. A 250ms budget for 3 attempts means attempt 3 only gets whatever time is left — not a fresh 250ms slice.
Layer 2: Circuit Breaker
Defined in #137. Tracks persistent failures across ticks using
ModuleHealthRecord.The key insight: the circuit breaker operates at tick granularity, not attempt granularity. A
RetryBudgetExhaustedis one failure event for the breaker — it doesn't matter that the module failed 3 times internally.State transitions:
Emergency mode for Tier 0 (safety): if the safety module's circuit opens, the cycle enters emergency mode and skips Tiers 1-4 entirely. An unsafe action is worse than no action.
Layer 3: Graceful Degradation
When a module's circuit is OPEN, the tick still needs to proceed. Downstream modules expect inputs. The solution: serve the last known good value from the Blackboard cache:
When
reasoningis OPEN andlast_good["reasoning.result"]exists:source: "last_good"andstale: TrueCycleProfilerrecordsdegraded_keys: ["reasoning.result"]in the tick summaryreasoning.result = NoneThe full tick flow (annotated)
Open questions
Tier 0 emergency mode — should the cycle publish a
CYCLE_EMERGENCYevent and terminate, or continue with a degraded mode that skips planning/execution only?last_goodTTL strategy — fixed TTL per module (e.g.,reasoning=10s,bio_inspired=30s) vs. dynamic TTL based on how frequently the module typically writes?Retry sleep in async context —
await asyncio.sleep(delay_ms/1000)inrun_with_retry()yields the event loop, allowing other tier tasks to make progress. This is actually helpful for fairness but could cause surprising ordering. Worth documenting explicitly.The wiki page at Fault-Tolerance has the complete implementation reference including all three layers.
All reactions