@@ -70,7 +70,10 @@ <h2>Failure Modes</h2>
7070 < td > HTTP 500</ td >
7171 < td >
7272 Returns a 500 error with
73- < code > {"error":{"message":"Chaos: request dropped","code":"chaos_drop"}}</ code >
73+ < code
74+ > {"error":{"message":"Chaos: request
75+ dropped","type":"server_error","code":"chaos_drop"}}</ code
76+ >
7477 </ td >
7578 </ tr >
7679 < tr >
@@ -205,7 +208,7 @@ <h2>Per-Request Headers</h2>
205208 < span class ="str "> "Content-Type"</ span > : < span class ="str "> "application/json"</ span > ,
206209 < span class ="str "> "x-aimock-chaos-disconnect"</ span > : < span class ="str "> "1.0"</ span > ,
207210 },
208- < span class ="prop "> body</ span > : < span class ="fn "> JSON.stringify</ span > ({ < span class ="prop "> model</ span > : < span class ="str "> "gpt-4"</ span > , < span class ="prop "> messages</ span > : [... ] }),
211+ < span class ="prop "> body</ span > : < span class ="fn "> JSON.stringify</ span > ({ < span class ="prop "> model</ span > : < span class ="str "> "gpt-4"</ span > , < span class ="prop "> messages</ span > : [{ < span class =" prop " > role </ span > : < span class =" str " > "user" </ span > , < span class =" prop " > content </ span > : < span class =" str " > "hello" </ span > } ] }),
209212});</ code > </ pre >
210213 </ div >
211214
@@ -218,7 +221,7 @@ <h2>CLI Flags</h2>
218221 < div class ="code-block-header ">
219222 CLI chaos flags < span class ="lang-tag "> shell</ span >
220223 </ div >
221- < pre > < code > $ npx -p @copilotkit/aimock llmock --fixtures ./fixtures \
224+ < pre > < code > $ npx -p @copilotkit/aimock aimock --fixtures ./fixtures \
222225 --chaos-drop 0.1 \
223226 --chaos-malformed 0.05 \
224227 --chaos-disconnect 0.02</ code > </ pre >
@@ -240,6 +243,55 @@ <h2>CLI Flags</h2>
240243 </ div >
241244 </ div >
242245
246+ < h2 > Proxy Mode</ h2 >
247+ < p >
248+ When aimock is configured as a record/replay proxy (< code > --record</ code > ), chaos applies
249+ to proxied requests too — so a staging environment pointed at real upstream APIs
250+ still sees the failure modes your tests expect. Chaos is rolled < em > once per request</ em > ,
251+ after fixture matching, with the same headers > fixture > server
252+ precedence.
253+ </ p >
254+ < table class ="endpoint-table ">
255+ < thead >
256+ < tr >
257+ < th > Mode</ th >
258+ < th > When upstream is contacted</ th >
259+ < th > What the client sees</ th >
260+ </ tr >
261+ </ thead >
262+ < tbody >
263+ < tr >
264+ < td > < code > drop</ code > </ td >
265+ < td > Never — upstream not contacted</ td >
266+ < td > HTTP 500 chaos body; upstream is not called</ td >
267+ </ tr >
268+ < tr >
269+ < td > < code > disconnect</ code > </ td >
270+ < td > Never — upstream not contacted</ td >
271+ < td > Connection destroyed; upstream is not called</ td >
272+ </ tr >
273+ < tr >
274+ < td > < code > malformed</ code > </ td >
275+ < td > Called — post-response</ td >
276+ < td >
277+ Request proxies normally; the upstream response is captured, then the body is
278+ replaced with invalid JSON before relay. The recorded fixture (if recording) keeps
279+ the real upstream response — chaos is a live-traffic decoration, not a fixture
280+ mutation.
281+ </ td >
282+ </ tr >
283+ </ tbody >
284+ </ table >
285+ < p >
286+ < strong > SSE bypass.</ strong > If upstream returns
287+ < code > Content-Type: text/event-stream</ code > , aimock streams chunks to the client
288+ progressively. By the time < code > malformed</ code > would fire, the bytes are already on the
289+ wire — the chaos action cannot be applied. This bypass is observable via the
290+ < code > aimock_chaos_bypassed_total</ code > counter (see Prometheus Metrics below) and a
291+ warning in the server log, so a configured chaos rate doesn't silently drop to 0% on SSE
292+ traffic. Streaming mutation is planned for a future phase.
293+ </ p >
294+
243295 < h2 > Journal Tracking</ h2 >
244296 < p >
245297 When chaos triggers, the journal entry includes a < code > chaosAction</ code > field recording
@@ -255,6 +307,7 @@ <h2>Journal Tracking</h2>
255307 "path": "/v1/chat/completions",
256308 "response": {
257309 "status": 500,
310+ "source": "fixture",
258311 "fixture": { "...": "elided for brevity" },
259312 "chaosAction": "drop"
260313 }
@@ -269,15 +322,31 @@ <h2>Journal Tracking</h2>
269322 < h2 > Prometheus Metrics</ h2 >
270323 < p >
271324 When metrics are enabled (< code > --metrics</ code > ), each chaos trigger increments the
272- < code > aimock_chaos_triggered_total</ code > counter with an < code > action</ code > label:
325+ < code > aimock_chaos_triggered_total</ code > counter, tagged with < code > action</ code > and
326+ < code > source</ code > . < code > source="fixture"</ code > means a fixture matched (or would have,
327+ before chaos intervened); < code > source="proxy"</ code > means the request was on the proxy
328+ dispatch path.
273329 </ p >
274330
275331 < div class ="code-block ">
276332 < div class ="code-block-header "> Metrics output < span class ="lang-tag "> text</ span > </ div >
277333 < pre > < code > # TYPE aimock_chaos_triggered_total counter
278- aimock_chaos_triggered_total{action="drop"} 3
279- aimock_chaos_triggered_total{action="malformed"} 1
280- aimock_chaos_triggered_total{action="disconnect"} 2</ code > </ pre >
334+ aimock_chaos_triggered_total{action="drop",source="fixture"} 3
335+ aimock_chaos_triggered_total{action="malformed",source="fixture"} 1
336+ aimock_chaos_triggered_total{action="disconnect",source="proxy"} 2</ code > </ pre >
337+ </ div >
338+
339+ < p >
340+ When a chaos action is rolled but can't be applied — today, only
341+ < code > malformed</ code > on an SSE proxy response — the bypass is recorded in a
342+ separate counter so operators can distinguish "chaos didn't roll" from "chaos rolled but
343+ was bypassed":
344+ </ p >
345+
346+ < div class ="code-block ">
347+ < div class ="code-block-header "> Bypass counter < span class ="lang-tag "> text</ span > </ div >
348+ < pre > < code > # TYPE aimock_chaos_bypassed_total counter
349+ aimock_chaos_bypassed_total{action="malformed",source="proxy",reason="sse_streamed"} 4</ code > </ pre >
281350 </ div >
282351 </ main >
283352 < aside class ="page-toc " id ="page-toc "> </ aside >
0 commit comments