-module(lightspeed@ops@chaos_harness).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/ops/chaos_harness.gleam").
-export([run_scenario/1, run_matrix/0, scenario_label/1, pass_fail_label/1, signature/1, deterministic/1, scenario/1, outcomes/1, failed_scenarios/1, nondeterministic_failures/1, report_signature/1, snapshot_signature/0, snapshot_report_markdown/0]).
-export_type([scenario/0, scenario_outcome/0, report/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Deterministic chaos, fuzz, and SLO-autopilot harness for M30.\n").
-type scenario() :: protocol_fuzz_corpus_regression |
runtime_fuzz_corpus_regression |
transport_chaos_fault_injection |
runtime_chaos_fault_injection |
storage_chaos_fault_injection |
slo_autopilot_audit_gate.
-type scenario_outcome() :: {scenario_outcome,
scenario(),
boolean(),
boolean(),
binary()}.
-type report() :: {report, list(scenario_outcome()), integer(), integer()}.
-file("src/lightspeed/ops/chaos_harness.gleam", 760).
-spec count_nondeterministic(list(scenario_outcome())) -> integer().
count_nondeterministic(Outcomes) ->
case Outcomes of
[] ->
0;
[Outcome | Rest] ->
case erlang:element(4, Outcome) of
true ->
count_nondeterministic(Rest);
false ->
1 + count_nondeterministic(Rest)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 749).
-spec count_failed(list(scenario_outcome())) -> integer().
count_failed(Outcomes) ->
case Outcomes of
[] ->
0;
[Outcome | Rest] ->
case erlang:element(3, Outcome) of
true ->
count_failed(Rest);
false ->
1 + count_failed(Rest)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 804).
-spec join_with(binary(), list(binary())) -> binary().
join_with(Separator, Values) ->
case Values of
[] ->
<<""/utf8>>;
[Value] ->
Value;
[Value@1 | Rest] ->
<<<<Value@1/binary, Separator/binary>>/binary,
(join_with(Separator, Rest))/binary>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 793).
-spec contains_substring(list(binary()), binary()) -> boolean().
contains_substring(Values, Target) ->
case Values of
[] ->
false;
[Value | Rest] ->
case gleam_stdlib:contains_string(Value, Target) of
true ->
true;
false ->
contains_substring(Rest, Target)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 735).
-spec count_decision(list(lightspeed@ops@slo_autopilot:audit_entry()), binary()) -> integer().
count_decision(Entries, Label) ->
case Entries of
[] ->
0;
[Entry | Rest] ->
case lightspeed@ops@slo_autopilot:decision_label(
erlang:element(4, Entry)
)
=:= Label of
true ->
1 + count_decision(Rest, Label);
false ->
count_decision(Rest, Label)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 445).
-spec evaluate_slo_autopilot_audit_gate() -> {boolean(), binary()}.
evaluate_slo_autopilot_audit_gate() ->
Runtime = lightspeed@ops@slo_autopilot:new(
lightspeed@ops@slo_autopilot:default_thresholds()
),
Warning_sample = lightspeed@ops@slo_autopilot:sample(
<<"edge"/utf8>>,
<<"availability"/utf8>>,
1200,
900,
<<"tenant-a"/utf8>>
),
{Runtime@1, Warning_status} = lightspeed@ops@slo_autopilot:evaluate(
Runtime,
Warning_sample,
<<"autopilot"/utf8>>,
10
),
Critical_sample = lightspeed@ops@slo_autopilot:sample(
<<"edge"/utf8>>,
<<"availability"/utf8>>,
2600,
1800,
<<"tenant-a"/utf8>>
),
{Runtime@2, Critical_status} = lightspeed@ops@slo_autopilot:evaluate(
Runtime@1,
Critical_sample,
<<"autopilot"/utf8>>,
20
),
Healthy_sample = lightspeed@ops@slo_autopilot:sample(
<<"edge"/utf8>>,
<<"availability"/utf8>>,
200,
100,
<<""/utf8>>
),
{Runtime@3, Healthy_status} = lightspeed@ops@slo_autopilot:evaluate(
Runtime@2,
Healthy_sample,
<<"autopilot"/utf8>>,
30
),
Audits = lightspeed@ops@slo_autopilot:audit_entries(Runtime@3),
Metrics = gleam@list:map(
Audits,
fun(Entry) ->
lightspeed@ops@telemetry:metric_line(
lightspeed@ops@slo_autopilot:audit_metric(Entry)
)
end
),
Applied = count_decision(Audits, <<"applied"/utf8>>),
Rolled_back = count_decision(Audits, <<"rolled_back"/utf8>>),
Active = gleam@list:map(
lightspeed@ops@slo_autopilot:active_controls(Runtime@3),
fun lightspeed@ops@slo_autopilot:control_label/1
),
Passed = (((((((lightspeed@ops@slo_autopilot:valid(Runtime@3) andalso (lightspeed@ops@slo_autopilot:status_label(
Warning_status
)
=:= <<"warning"/utf8>>))
andalso (lightspeed@ops@slo_autopilot:status_label(Critical_status) =:= <<"critical"/utf8>>))
andalso (lightspeed@ops@slo_autopilot:status_label(Healthy_status) =:= <<"healthy"/utf8>>))
andalso (Active =:= []))
andalso (Applied >= 3))
andalso (Rolled_back >= 3))
andalso contains_substring(
Metrics,
<<"counter lightspeed.slo.autopilot_control_total"/utf8>>
))
andalso contains_substring(Metrics, <<"decision=rolled_back"/utf8>>),
{Passed,
<<<<<<<<<<<<<<<<<<<<<<<<<<"statuses="/utf8,
(lightspeed@ops@slo_autopilot:status_label(
Warning_status
))/binary>>/binary,
","/utf8>>/binary,
(lightspeed@ops@slo_autopilot:status_label(
Critical_status
))/binary>>/binary,
","/utf8>>/binary,
(lightspeed@ops@slo_autopilot:status_label(
Healthy_status
))/binary>>/binary,
"|active="/utf8>>/binary,
(join_with(<<","/utf8>>, Active))/binary>>/binary,
"|applied="/utf8>>/binary,
(erlang:integer_to_binary(Applied))/binary>>/binary,
"|rolled_back="/utf8>>/binary,
(erlang:integer_to_binary(Rolled_back))/binary>>/binary,
"|runtime="/utf8>>/binary,
(lightspeed@ops@slo_autopilot:signature(Runtime@3))/binary>>}.
-file("src/lightspeed/ops/chaos_harness.gleam", 699).
-spec takeover_result_label(
{ok, lightspeed@cluster@durable_session:durable_session()} |
{error, lightspeed@cluster@durable_session:ownership_error()}
) -> binary().
takeover_result_label(Result) ->
case Result of
{ok, _} ->
<<"ok"/utf8>>;
{error, Error} ->
lightspeed@cluster@durable_session:ownership_error_label(Error)
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 364).
-spec evaluate_storage_chaos_fault_injection() -> {boolean(), binary()}.
evaluate_storage_chaos_fault_injection() ->
Base = begin
_pipe = lightspeed@cluster@durable_session:start(
<<"storage-1"/utf8>>,
<<"node-a"/utf8>>,
<<"/counter"/utf8>>,
{snapshot_journal, <<"snap"/utf8>>, <<"journal"/utf8>>, 2},
rehydrate,
0,
25,
0
),
_pipe@1 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe,
1,
3
),
_pipe@2 = lightspeed@cluster@durable_session:append_counter_delta(
_pipe@1,
1,
4
),
_pipe@3 = lightspeed@cluster@durable_session:crash(
_pipe@2,
<<"boom"/utf8>>
),
lightspeed@cluster@durable_session:restart(_pipe@3, 8)
end,
Invalid = begin
_pipe@4 = lightspeed@cluster@durable_session:request_takeover(
Base,
<<"node-b"/utf8>>,
2,
<<"wrong-token"/utf8>>,
10
),
takeover_result_label(_pipe@4)
end,
Takeover = case lightspeed@cluster@durable_session:request_takeover(
Base,
<<"node-b"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
<<"storage-1"/utf8>>,
<<"node-b"/utf8>>,
2
),
12
) of
{ok, Updated} ->
Updated;
{error, _} ->
Base
end,
Stale = begin
_pipe@5 = lightspeed@cluster@durable_session:request_takeover(
Takeover,
<<"node-a"/utf8>>,
1,
lightspeed@cluster@durable_session:expected_token(
<<"storage-1"/utf8>>,
<<"node-a"/utf8>>,
1
),
13
),
takeover_result_label(_pipe@5)
end,
Split = begin
_pipe@6 = lightspeed@cluster@durable_session:request_takeover(
Takeover,
<<"node-c"/utf8>>,
2,
lightspeed@cluster@durable_session:expected_token(
<<"storage-1"/utf8>>,
<<"node-c"/utf8>>,
2
),
14
),
takeover_result_label(_pipe@6)
end,
Continuity = begin
_pipe@7 = lightspeed@cluster@durable_session:continuity_report(
Takeover,
100,
140
),
lightspeed@cluster@durable_session:continuity_signature(_pipe@7)
end,
Passed = (((Invalid =:= <<"invalid_token:node-b:2"/utf8>>) andalso (Stale
=:= <<"stale_owner:2:1"/utf8>>))
andalso (Split =:= <<"split_brain:node-b:node-c:2"/utf8>>))
andalso gleam_stdlib:contains_string(Continuity, <<"met=false"/utf8>>),
{Passed,
<<<<<<<<<<<<<<"invalid="/utf8, Invalid/binary>>/binary, "|stale="/utf8>>/binary,
Stale/binary>>/binary,
"|split="/utf8>>/binary,
Split/binary>>/binary,
"|continuity="/utf8>>/binary,
Continuity/binary>>}.
-file("src/lightspeed/ops/chaos_harness.gleam", 771).
-spec count_label(list(binary()), binary()) -> integer().
count_label(Labels, Target) ->
case Labels of
[] ->
0;
[Value | Rest] ->
case Value =:= Target of
true ->
1 + count_label(Rest, Target);
false ->
count_label(Rest, Target)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 782).
-spec contains(list(binary()), binary()) -> boolean().
contains(Values, Target) ->
case Values of
[] ->
false;
[Value | Rest] ->
case Value =:= Target of
true ->
true;
false ->
contains(Rest, Target)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 716).
-spec replay_loop(
lightspeed@agent@session:session(),
binary(),
list(lightspeed@agent@session:inbox_event())
) -> lightspeed@agent@session:session().
replay_loop(Runtime, Owner, Events) ->
case Events of
[] ->
Runtime;
[Event | Rest] ->
replay_loop(
lightspeed@agent@session:handle(
Runtime,
{inbox_message, Owner, Event}
),
Owner,
Rest
)
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 708).
-spec replay_events(list(lightspeed@agent@session:inbox_event())) -> lightspeed@agent@session:session().
replay_events(Events) ->
replay_loop(
lightspeed@agent@session:start(
<<"chaos-runtime"/utf8>>,
<<"proc-a"/utf8>>,
rehydrate,
0,
50
),
<<"proc-a"/utf8>>,
Events
).
-file("src/lightspeed/ops/chaos_harness.gleam", 326).
-spec evaluate_runtime_chaos_fault_injection() -> {boolean(), binary()}.
evaluate_runtime_chaos_fault_injection() ->
Events = [{connect, <<"/counter"/utf8>>, <<"csrf"/utf8>>, 0},
increment,
{crash, <<"fault"/utf8>>},
increment,
{restart, 5},
{reconnect, <<"/counter"/utf8>>, 8},
{heartbeat, 9},
{tick, 200},
decrement],
Final = replay_events(Events),
Telemetry_labels = gleam@list:map(
lightspeed@agent@session:telemetry(Final),
fun lightspeed@agent@session:telemetry_label/1
),
Lifecycle = lightspeed@agent@typestate:lifecycle_to_string(
lightspeed@agent@session:lifecycle(Final)
),
Counter = lightspeed@agent@session:counter(Final),
Passed = ((((((Lifecycle =:= <<"draining"/utf8>>) andalso (Counter =:= 1))
andalso contains(Telemetry_labels, <<"session_crashed"/utf8>>))
andalso contains(Telemetry_labels, <<"session_restarted"/utf8>>))
andalso contains(Telemetry_labels, <<"session_rehydrated"/utf8>>))
andalso contains(Telemetry_labels, <<"heartbeat_timed_out"/utf8>>))
andalso (count_label(Telemetry_labels, <<"event_ignored"/utf8>>) >= 2),
{Passed,
<<<<<<<<<<"lifecycle="/utf8, Lifecycle/binary>>/binary,
"|counter="/utf8>>/binary,
(erlang:integer_to_binary(Counter))/binary>>/binary,
"|telemetry="/utf8>>/binary,
(join_with(<<","/utf8>>, Telemetry_labels))/binary>>}.
-file("src/lightspeed/ops/chaos_harness.gleam", 659).
-spec connect_result_label(lightspeed@transport@matrix:connect_result()) -> binary().
connect_result_label(Result) ->
case Result of
{connected, _, _} ->
<<"connected"/utf8>>;
{rejected, Error} ->
<<"rejected:"/utf8,
(lightspeed@transport@contract:error_to_string(Error))/binary>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 688).
-spec first_failure_reason(list(binary())) -> binary().
first_failure_reason(Frames) ->
case Frames of
[] ->
<<"none"/utf8>>;
[Frame | Rest] ->
case lightspeed@protocol:decode(Frame) of
{ok, {failure, _, Reason}} ->
Reason;
_ ->
first_failure_reason(Rest)
end
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 613).
-spec frame_tag(lightspeed@protocol:frame()) -> binary().
frame_tag(Frame) ->
case Frame of
{hello, _, _} ->
<<"hello"/utf8>>;
{event, _, _, _} ->
<<"event"/utf8>>;
{diff, _, _} ->
<<"diff"/utf8>>;
{ack, _} ->
<<"ack"/utf8>>;
{failure, _, _} ->
<<"failure"/utf8>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 675).
-spec frame_labels(list(binary())) -> binary().
frame_labels(Frames) ->
join_with(
<<","/utf8>>,
gleam@list:map(
Frames,
fun(Frame) -> case lightspeed@protocol:decode(Frame) of
{ok, Decoded} ->
frame_tag(Decoded);
{error, Error} ->
<<"decode_error:"/utf8,
(lightspeed@protocol:decode_error_to_string(Error))/binary>>
end end
)
).
-file("src/lightspeed/ops/chaos_harness.gleam", 623).
-spec connect_with_policy(integer(), binary(), integer(), integer(), integer()) -> {ok,
lightspeed@transport@matrix:adapter_state()} |
{error, binary()}.
connect_with_policy(
Now_ms,
Origin,
Max_payload_bytes,
Heartbeat_timeout_ms,
Reconnect_grace_ms
) ->
case lightspeed@transport@matrix:connect_with_policies(
lightspeed@agent@session:start(
<<"chaos-transport"/utf8>>,
<<"proc-a"/utf8>>,
rehydrate,
Now_ms,
100
),
{connect_request,
<<"/counter"/utf8>>,
<<"csrf"/utf8>>,
Origin,
Now_ms,
false},
web_socket_only,
lightspeed@transport@contract:allow_all(<<"proc-a"/utf8>>),
lightspeed@transport@contract:allow_protection(),
{security_policy, true, true, Max_payload_bytes},
{timeout_policy, Heartbeat_timeout_ms, Reconnect_grace_ms}
) of
{connected, State, _} ->
{ok, State};
{rejected, Error} ->
{error, lightspeed@transport@contract:error_to_string(Error)}
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 666).
-spec connect_attempt_label(
{ok, lightspeed@transport@matrix:adapter_state()} | {error, binary()}
) -> binary().
connect_attempt_label(Result) ->
case Result of
{ok, _} ->
<<"connected"/utf8>>;
{error, Reason} ->
<<"rejected:"/utf8, Reason/binary>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 227).
-spec evaluate_transport_chaos_fault_injection() -> {boolean(), binary()}.
evaluate_transport_chaos_fault_injection() ->
Insecure = connect_with_policy(0, <<"http://evil.test"/utf8>>, 64, 5, 10),
Insecure_label = connect_attempt_label(Insecure),
case connect_with_policy(0, <<"https://example.test"/utf8>>, 32, 2, 10) of
{error, Reason} ->
{false, <<"connect_error:"/utf8, Reason/binary>>};
{ok, State} ->
Oversized = lightspeed@transport@matrix:'receive'(
State,
lightspeed@protocol:encode(
{event,
<<"evt-1"/utf8>>,
<<"increment"/utf8>>,
<<"{\"blob\":\"1234567890123456789012345678901234567890\"}"/utf8>>}
),
1,
1
),
Oversized_reason = first_failure_reason(
erlang:element(3, Oversized)
),
Accepted = lightspeed@transport@matrix:'receive'(
erlang:element(2, Oversized),
lightspeed@protocol:encode(
{event,
<<"evt-2"/utf8>>,
<<"increment"/utf8>>,
<<"{}"/utf8>>}
),
2,
1
),
Accepted_labels = frame_labels(erlang:element(3, Accepted)),
Order_violation = lightspeed@transport@matrix:'receive'(
erlang:element(2, Accepted),
lightspeed@protocol:encode(
{event,
<<"evt-3"/utf8>>,
<<"decrement"/utf8>>,
<<"{}"/utf8>>}
),
3,
1
),
Order_reason = first_failure_reason(
erlang:element(3, Order_violation)
),
Timeout = lightspeed@transport@matrix:'receive'(
erlang:element(2, Order_violation),
lightspeed@protocol:encode({ack, <<"stale"/utf8>>}),
8,
2
),
Timeout_reason = first_failure_reason(erlang:element(3, Timeout)),
Reconnect_label = begin
_pipe = lightspeed@transport@matrix:reconnect(
erlang:element(2, Timeout),
{connect_request,
<<"/counter"/utf8>>,
<<"csrf"/utf8>>,
<<"https://example.test"/utf8>>,
30,
false},
lightspeed@transport@contract:allow_all(<<"proc-a"/utf8>>)
),
connect_result_label(_pipe)
end,
Passed = (((((Insecure_label =:= <<"rejected:protection_rejected:insecure_origin"/utf8>>)
andalso (Oversized_reason =:= <<"unsupported_client_frame:payload_too_large"/utf8>>))
andalso (Accepted_labels =:= <<"diff"/utf8>>))
andalso (Order_reason =:= <<"invalid_adapter_state:event_order_violation:last=1:incoming=1"/utf8>>))
andalso (Timeout_reason =:= <<"invalid_adapter_state:heartbeat_timeout"/utf8>>))
andalso (Reconnect_label =:= <<"rejected:invalid_adapter_state:reconnect_grace_exceeded"/utf8>>),
{Passed,
<<<<<<<<<<<<<<<<<<<<<<"insecure="/utf8, Insecure_label/binary>>/binary,
"|oversized="/utf8>>/binary,
Oversized_reason/binary>>/binary,
"|accepted="/utf8>>/binary,
Accepted_labels/binary>>/binary,
"|order="/utf8>>/binary,
Order_reason/binary>>/binary,
"|timeout="/utf8>>/binary,
Timeout_reason/binary>>/binary,
"|reconnect="/utf8>>/binary,
Reconnect_label/binary>>}
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 524).
-spec runtime_corpus() -> list({binary(), binary()}).
runtime_corpus() ->
Valid_replace = lightspeed@diff:encode_stream(
[{replace, <<"#app"/utf8>>, <<"<p>ok</p>"/utf8>>}]
),
Valid_upsert = lightspeed@diff:encode_stream(
[{upsert_keyed, <<"#items"/utf8>>, <<"a"/utf8>>, <<"<li>a</li>"/utf8>>}]
),
[{Valid_replace, <<"ok_ops:1:replace"/utf8>>},
{Valid_upsert, <<"ok_ops:1:upsert_keyed"/utf8>>},
{<<""/utf8>>, <<"error:empty_payload"/utf8>>},
{<<"ps|a|0|0"/utf8>>, <<"error:invalid_integer:a"/utf8>>},
{<<"ps|2|0|0"/utf8>>, <<"error:unsupported_version:2"/utf8>>},
{<<"ps|1|0|1|r,0,1"/utf8>>, <<"error:missing_dictionary_entry:0"/utf8>>},
{<<"ps|1|3|#app|fp|slot|1|u,0,1,1,2"/utf8>>,
<<"error:bad_field_count:dynamic_slots:2:1"/utf8>>},
{<<"ps|1|1|#app|1|z,0"/utf8>>, <<"error:malformed_operation:z,0"/utf8>>}].
-file("src/lightspeed/ops/chaos_harness.gleam", 602).
-spec runtime_case_label(binary()) -> binary().
runtime_case_label(Payload) ->
case lightspeed@diff:decode_stream(Payload) of
{ok, Patches} ->
<<<<<<"ok_ops:"/utf8,
(erlang:integer_to_binary(erlang:length(Patches)))/binary>>/binary,
":"/utf8>>/binary,
(join_with(
<<","/utf8>>,
gleam@list:map(Patches, fun lightspeed@diff:operation/1)
))/binary>>;
{error, Error} ->
<<"error:"/utf8,
(lightspeed@diff:decode_error_to_string(Error))/binary>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 571).
-spec evaluate_runtime_cases(
list({binary(), binary()}),
integer(),
integer(),
list(binary())
) -> {integer(), list(binary())}.
evaluate_runtime_cases(Cases, Index, Mismatches, Outcomes_rev) ->
case Cases of
[] ->
{Mismatches, lists:reverse(Outcomes_rev)};
[Entry | Rest] ->
{Payload, Expected} = Entry,
Actual = runtime_case_label(Payload),
Next_mismatches = case Actual =:= Expected of
true ->
Mismatches;
false ->
Mismatches + 1
end,
evaluate_runtime_cases(
Rest,
Index + 1,
Next_mismatches,
[<<<<(erlang:integer_to_binary(Index))/binary, ":"/utf8>>/binary,
Actual/binary>> |
Outcomes_rev]
)
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 213).
-spec evaluate_runtime_fuzz_corpus_regression() -> {boolean(), binary()}.
evaluate_runtime_fuzz_corpus_regression() ->
{Mismatches, Outcomes} = evaluate_runtime_cases(runtime_corpus(), 1, 0, []),
Passed = Mismatches =:= 0,
{Passed,
<<<<<<"mismatches="/utf8,
(erlang:integer_to_binary(Mismatches))/binary>>/binary,
"|cases="/utf8>>/binary,
(join_with(<<","/utf8>>, Outcomes))/binary>>}.
-file("src/lightspeed/ops/chaos_harness.gleam", 509).
-spec protocol_corpus() -> list({binary(), binary()}).
protocol_corpus() ->
[{<<"hello|lightspeed|1"/utf8>>, <<"ok:hello"/utf8>>},
{<<"hello|lightspeed|2"/utf8>>, <<"error:unsupported_version:2"/utf8>>},
{<<"hello|other|1"/utf8>>, <<"error:unsupported_protocol:other"/utf8>>},
{<<"event|r1|increment|{}"/utf8>>, <<"ok:event"/utf8>>},
{<<"diff|r1|<p>x</p>"/utf8>>, <<"ok:diff"/utf8>>},
{<<"ack|r1"/utf8>>, <<"ok:ack"/utf8>>},
{<<"failure|r1|boom"/utf8>>, <<"ok:failure"/utf8>>},
{<<"event|r1|increment|bad\\"/utf8>>,
<<"error:invalid_escape_sequence"/utf8>>},
{<<"ack"/utf8>>, <<"error:bad_field_count:ack:2:1"/utf8>>},
{<<"noop|x"/utf8>>, <<"error:unknown_frame_tag:noop"/utf8>>}].
-file("src/lightspeed/ops/chaos_harness.gleam", 595).
-spec protocol_case_label(binary()) -> binary().
protocol_case_label(Payload) ->
case lightspeed@protocol:decode(Payload) of
{ok, Frame} ->
<<"ok:"/utf8, (frame_tag(Frame))/binary>>;
{error, Error} ->
<<"error:"/utf8,
(lightspeed@protocol:decode_error_to_string(Error))/binary>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 547).
-spec evaluate_protocol_cases(
list({binary(), binary()}),
integer(),
integer(),
list(binary())
) -> {integer(), list(binary())}.
evaluate_protocol_cases(Cases, Index, Mismatches, Outcomes_rev) ->
case Cases of
[] ->
{Mismatches, lists:reverse(Outcomes_rev)};
[Entry | Rest] ->
{Payload, Expected} = Entry,
Actual = protocol_case_label(Payload),
Next_mismatches = case Actual =:= Expected of
true ->
Mismatches;
false ->
Mismatches + 1
end,
evaluate_protocol_cases(
Rest,
Index + 1,
Next_mismatches,
[<<<<(erlang:integer_to_binary(Index))/binary, ":"/utf8>>/binary,
Actual/binary>> |
Outcomes_rev]
)
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 199).
-spec evaluate_protocol_fuzz_corpus_regression() -> {boolean(), binary()}.
evaluate_protocol_fuzz_corpus_regression() ->
{Mismatches, Outcomes} = evaluate_protocol_cases(
protocol_corpus(),
1,
0,
[]
),
Passed = Mismatches =:= 0,
{Passed,
<<<<<<"mismatches="/utf8,
(erlang:integer_to_binary(Mismatches))/binary>>/binary,
"|cases="/utf8>>/binary,
(join_with(<<","/utf8>>, Outcomes))/binary>>}.
-file("src/lightspeed/ops/chaos_harness.gleam", 188).
-spec evaluate(scenario()) -> {boolean(), binary()}.
evaluate(Scenario) ->
case Scenario of
protocol_fuzz_corpus_regression ->
evaluate_protocol_fuzz_corpus_regression();
runtime_fuzz_corpus_regression ->
evaluate_runtime_fuzz_corpus_regression();
transport_chaos_fault_injection ->
evaluate_transport_chaos_fault_injection();
runtime_chaos_fault_injection ->
evaluate_runtime_chaos_fault_injection();
storage_chaos_fault_injection ->
evaluate_storage_chaos_fault_injection();
slo_autopilot_audit_gate ->
evaluate_slo_autopilot_audit_gate()
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 68).
?DOC(" Run one scenario twice and require deterministic parity.\n").
-spec run_scenario(scenario()) -> scenario_outcome().
run_scenario(Scenario) ->
{First_passed, First_signature} = evaluate(Scenario),
{Second_passed, Second_signature} = evaluate(Scenario),
Deterministic = (First_passed =:= Second_passed) andalso (First_signature
=:= Second_signature),
Passed = (First_passed andalso Second_passed) andalso Deterministic,
{scenario_outcome, Scenario, Passed, Deterministic, First_signature}.
-file("src/lightspeed/ops/chaos_harness.gleam", 48).
?DOC(" Run all M30 scenarios.\n").
-spec run_matrix() -> report().
run_matrix() ->
Outcomes = begin
_pipe = [protocol_fuzz_corpus_regression,
runtime_fuzz_corpus_regression,
transport_chaos_fault_injection,
runtime_chaos_fault_injection,
storage_chaos_fault_injection,
slo_autopilot_audit_gate],
gleam@list:map(_pipe, fun run_scenario/1)
end,
{report, Outcomes, count_failed(Outcomes), count_nondeterministic(Outcomes)}.
-file("src/lightspeed/ops/chaos_harness.gleam", 84).
?DOC(" Scenario label.\n").
-spec scenario_label(scenario()) -> binary().
scenario_label(Scenario) ->
case Scenario of
protocol_fuzz_corpus_regression ->
<<"protocol_fuzz_corpus_regression"/utf8>>;
runtime_fuzz_corpus_regression ->
<<"runtime_fuzz_corpus_regression"/utf8>>;
transport_chaos_fault_injection ->
<<"transport_chaos_fault_injection"/utf8>>;
runtime_chaos_fault_injection ->
<<"runtime_chaos_fault_injection"/utf8>>;
storage_chaos_fault_injection ->
<<"storage_chaos_fault_injection"/utf8>>;
slo_autopilot_audit_gate ->
<<"slo_autopilot_audit_gate"/utf8>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 96).
?DOC(" Stable pass/fail label.\n").
-spec pass_fail_label(scenario_outcome()) -> binary().
pass_fail_label(Outcome) ->
case erlang:element(3, Outcome) of
true ->
<<"pass"/utf8>>;
false ->
<<"fail"/utf8>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 104).
?DOC(" Scenario signature.\n").
-spec signature(scenario_outcome()) -> binary().
signature(Outcome) ->
erlang:element(5, Outcome).
-file("src/lightspeed/ops/chaos_harness.gleam", 109).
?DOC(" Determinism accessor.\n").
-spec deterministic(scenario_outcome()) -> boolean().
deterministic(Outcome) ->
erlang:element(4, Outcome).
-file("src/lightspeed/ops/chaos_harness.gleam", 114).
?DOC(" Scenario accessor.\n").
-spec scenario(scenario_outcome()) -> scenario().
scenario(Outcome) ->
erlang:element(2, Outcome).
-file("src/lightspeed/ops/chaos_harness.gleam", 119).
?DOC(" Report outcomes.\n").
-spec outcomes(report()) -> list(scenario_outcome()).
outcomes(Report) ->
erlang:element(2, Report).
-file("src/lightspeed/ops/chaos_harness.gleam", 124).
?DOC(" Failed scenario count.\n").
-spec failed_scenarios(report()) -> integer().
failed_scenarios(Report) ->
erlang:element(3, Report).
-file("src/lightspeed/ops/chaos_harness.gleam", 129).
?DOC(" Nondeterministic failure count.\n").
-spec nondeterministic_failures(report()) -> integer().
nondeterministic_failures(Report) ->
erlang:element(4, Report).
-file("src/lightspeed/ops/chaos_harness.gleam", 812).
-spec bool_label(boolean()) -> binary().
bool_label(Value) ->
case Value of
true ->
<<"true"/utf8>>;
false ->
<<"false"/utf8>>
end.
-file("src/lightspeed/ops/chaos_harness.gleam", 134).
?DOC(" Stable report signature.\n").
-spec report_signature(report()) -> binary().
report_signature(Report) ->
Entries = gleam@list:map(
erlang:element(2, Report),
fun(Outcome) ->
<<<<<<<<<<<<(scenario_label(erlang:element(2, Outcome)))/binary,
"="/utf8>>/binary,
(pass_fail_label(Outcome))/binary>>/binary,
":deterministic="/utf8>>/binary,
(bool_label(erlang:element(4, Outcome)))/binary>>/binary,
":"/utf8>>/binary,
(erlang:element(5, Outcome))/binary>>
end
),
join_with(<<";"/utf8>>, Entries).
-file("src/lightspeed/ops/chaos_harness.gleam", 150).
?DOC(" Deterministic snapshot signature for fixture drift gates.\n").
-spec snapshot_signature() -> binary().
snapshot_signature() ->
<<<<<<"m30.snapshot.v"/utf8, (erlang:integer_to_binary(1))/binary>>/binary,
"|"/utf8>>/binary,
(report_signature(run_matrix()))/binary>>.
-file("src/lightspeed/ops/chaos_harness.gleam", 158).
?DOC(" Deterministic markdown report for fixture scripts.\n").
-spec snapshot_report_markdown() -> binary().
snapshot_report_markdown() ->
Report = run_matrix(),
Failed = failed_scenarios(Report),
Nondeterministic = nondeterministic_failures(Report),
Status = case (Failed =:= 0) andalso (Nondeterministic =:= 0) of
true ->
<<"OK"/utf8>>;
false ->
<<"FAIL"/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"# Chaos Fixture Report\n\n"/utf8,
"snapshot_version: "/utf8>>/binary,
(erlang:integer_to_binary(
1
))/binary>>/binary,
"\n"/utf8>>/binary,
"status: "/utf8>>/binary,
Status/binary>>/binary,
"\n"/utf8>>/binary,
"failed_scenarios: "/utf8>>/binary,
(erlang:integer_to_binary(
Failed
))/binary>>/binary,
"\n"/utf8>>/binary,
"nondeterministic_failures: "/utf8>>/binary,
(erlang:integer_to_binary(Nondeterministic))/binary>>/binary,
"\n\n"/utf8>>/binary,
"snapshot_signature: "/utf8>>/binary,
(snapshot_signature())/binary>>/binary,
"\n\n"/utf8>>/binary,
"report_signature: "/utf8>>/binary,
(report_signature(Report))/binary>>/binary,
"\n"/utf8>>.