docs: interactive resilience demo pages#109
Merged
Merged
Conversation
Move brk.res() from unconditional-per-landing to the terminal (non-retried) branch only, and skip it when the landing was cut short by AsyncTimeout. Per architecture/resilience.md the breaker sits outside retry and counts one outcome per fully-exhausted retry sequence, not per attempt; a deadline-cancelled operation surfaces as the outer TimeoutError and the inner breaker never sees a counted outcome for it. Only observable once a page combines circuitBreaker with retry/timeout (task 5's full-stack page); verified byte-for-byte no regression on circuit-breaker.md/retry.md/bulkhead.md/timeout.md.
Composes all four resilience patterns (timeout, circuitBreaker, bulkhead, retry) on one page against a 16s multi-phase incident. Deviates from the drafted scenario in one number: hard-down fault latency 3.0s -> 0.3s. At 3.0s every hard-down attempt already exceeds the 2.0s AsyncTimeout on attempt 0, so (per the composition fix) the breaker never receives a real outcome and never trips -- the page's own third and fourth coach stops become unreachable. 0.3s lets real failures land and trip the breaker within the hard-down window; see .superpowers/sdd/task-5-report.md for the full numeric trace.
Flesh out the demos index with links to all five pages and a faithful-model note, cross-link resilience.md to the demos, and correct the circuit-breaker comment describing how the async breaker handles an outer-timeout cancellation (it does see the CancelledError via except BaseException, it just doesn't count it as an outcome).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… spike phase latB was a hardcoded 40ms even on timeout/full-stack pages, contradicting elapsedB as it climbed toward the deadline. Derive it from the same bounded-latency measure as elapsedB when a timeout is configured; leave it untouched (40ms) elsewhere. computeOutageWindow only flagged hard failures, so full-stack's decorative outage bar silently dropped the 2-5s latency-spike phase. Also flag high-latency ok samples (ms >= 1.0, matching updateUI's existing `slow` threshold), falling back to a generic "degraded" label when a window mixes down and slow phases.
- inherit mkdocs-material font instead of a hardcoded system stack - fill the content column (drop 760px centering that left a stray margin) - keep the timeline outage label on one line (nowrap + vertical center) - plain-client p99 reflects the in-flight latency tail, so it stays high in a brownout instead of flickering to 40ms and contradicting the callout - derive the flow-diagram breaker/pool/elapsed boxes from the scenario chain and auto-select the first scenario, so first paint shows a coherent state Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a Demos section to the docs site: five self-contained, browser-based pages that animate httpware's resilience patterns under load, so a reader viscerally sees the failure each pattern prevents. One page per pattern (CircuitBreaker, Retry + RetryBudget, Bulkhead, AsyncTimeout) plus a composed full-stack page.
Full rationale, design, and decisions:
planning/changes/2026-07-18.02-resilience-demo-pages.md.What it is
docs/demos/engine.js): virtual clock, seeded PRNG, backend/fault model, one faithful model per pattern, a flow+counters renderer, and a hand-rolled guided-tour driver (spotlight + placed coach-marks). Each page is a markdown file with a mount<div>+ a small config.Faithfulness
The whole point is that the models match real httpware — verified against
src/httpware/middleware/resilience/*.py: RetryBudget (ceil + two-sided ttl-purged window), CircuitBreaker (consecutive-failure, lazy half-open, OPEN no-op, records once per exhausted retry sequence, timed-out requests don't feed it), Bulkhead (semaphore fast-reject, slot held across retries), AsyncTimeout (outermost total deadline). Fidelity constants live in one cited block inengine.js.Constraints honored
prefers-reduced-motion; outcomes not by color alone (dots differ by shape).Verification
just docs-build --strictclean; all six demo routes build.🤖 Generated with Claude Code