v0.7: compound failures and synthetic adversarial responses
Available in 0.7.0. Core installation remains standalone. Run the offline
resilience example with
uv run python examples/advanced/resilience.py.
Cascades
from agentic_chaos import cascade, chaos_call, chaos_session
from agentic_chaos import RateLimitStormFault, TokenTimeoutFault
fault = cascade(first=RateLimitStormFault(burst_count=3),
then=TokenTimeoutFault(hang_seconds=0), delay_between=0.1)
with chaos_session([fault]) as session:
# Your retrying application calls chaos_call() on each attempt.
# The first three attempts raise 429s, the fourth times out, then calls pass.
pass
A cascade schedules stages across calls, rather than executing the target twice
in one call. Rate-limit stages exhaust their positive burst count; other stages
fire once. Skipped probability/eligibility leaves the stage pending. Delay is a
minimum interval from the previous stage's completion to the next injection;
there is no background timer. Child events retain their native fault type and ID
and add detail.cascade_id and zero-based detail.cascade_stage.
Use fresh instances per sequential campaign; concurrent calls sharing one cascade
are unsupported. Nested cascades are rejected. Use chaos_call or chaos_acall,
not streaming-only faults. Circuit-breaker checks apply before stage dispatch,
and each child event consumes one injection. Dry-run plans use the cascade name
and advance private stage state without sleeping or changing real faults; target
calls still execute, as with all Chaos previews.
Breaking-point search
from agentic_chaos import RateLimitStormFault, find_breaking_point
result = find_breaking_point(my_retrying_app, fault=RateLimitStormFault,
param="burst_count", range=(1, 20))
print(result.breaking_point, result.trials)
The inclusive integer search requires deterministic, monotonic recovery: success
at lower severity and failure at higher severity. It records (severity, passed)
trials, returns None when no tested threshold fails, and takes logarithmically
many trials. Every trial has a fresh fault/session; reset application/external
state yourself and supply seeds through fault_kwargs. An exception from the
application counts as failure; setup and recovered(output) predicate errors
propagate. Without a predicate, returning normally means recovery. This is a
measured threshold under the stated assumptions, not proof of monotonicity or a
production capacity guarantee. Keep target calls bounded with their own timeouts.
Response poisoning and containment evidence
PoisonedResponseFault(strategy=..., payload=..., seed=...) supports:
| Strategy | Synthetic transformation |
|---|---|
confident_wrong |
Replace text with a confident wrong answer |
partial_hallucination |
Append a fabricated reference |
format_violation |
Replace text with malformed JSON |
prompt_injection |
Replace text with an instruction override |
policy_bypass |
Replace text with an approval-bypass request |
Strings and content/text envelopes use the existing degradation adapter.
Unsupported envelopes raise TypeError; expose text through your own adapter
for provider-specific shapes. Default payloads are deterministic templates, not
model-generated fact-aware attacks. seed controls probability selection and is
recorded along with the exact strategy and payload in event detail. Payloads may
be sensitive if customized; native reports contain them. Embedded instructions
are data: Chaos never dispatches them.
The offline example publishes a synthetic policy version, seed, payload, expected protected/bypassed outcomes and observed dispatch list. Its deliberately bypassed negative control must fail containment. This validates only that isolated toy boundary; injection, timeout, task recovery and output quality alone do not prove real Sidecar/MCP containment. Cross-framework containment remains future work.
Explicit cost estimates
agentic-chaos estimate my_app.py --fault rate_limit_storm --retries 3 \
--calls 1 --cost-per-call-usd 0.04
Emits JSON: baseline $0.04, extra $0.12, total $0.16. The scenario path is only a label: no file is read, imported or executed. The caller supplies price and retry assumptions; every retry is modeled as a fully billed call. Provider 429s may cost nothing, so this is a budget scenario, not inferred billing or a forecast.
Evidence and ecosystem compatibility
No new shared schema is introduced. Existing ChaosReport, calls, contracts and
AIOS Run exports continue to work. Child cascade and poisoning provenance travels
in event detail and exported native evidence. Lens consumes native chaos events;
Tower counts native outcomes independently of deployment health. MCP discovers
poisoned_response through the existing registry and can run a trusted local
script using these APIs; hosted HTTP still rejects script execution. Cascades and
search are Python orchestration APIs, not newly exposed MCP tools. Sidecar needs
0.8.3 for an optional-extra range admitting Chaos 0.7. Evals retains ownership of
scores and release gates. AIOS mappings document these producer-local extensions;
no normative schema change or conformance promotion is implied.