src/lightspeed@ops@quality_harness.erl

-module(lightspeed@ops@quality_harness).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/ops/quality_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]).
-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(" Quality parity harness for M10 compatibility and determinism gates.\n").

-type scenario() :: mount_conformance |
    bad_frame_fault |
    stale_ref_fault |
    throttled_client_fault |
    replay_reconnect_crash.

-type scenario_outcome() :: {scenario_outcome,
        scenario(),
        boolean(),
        boolean(),
        binary()}.

-type report() :: {report, list(scenario_outcome()), integer(), integer()}.

-file("src/lightspeed/ops/quality_harness.gleam", 495).
-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/quality_harness.gleam", 484).
-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/quality_harness.gleam", 442).
-spec lifecycle_label_from_session(lightspeed@agent@session:session()) -> binary().
lifecycle_label_from_session(State) ->
    _pipe = State,
    _pipe@1 = lightspeed@agent@session:lifecycle(_pipe),
    lightspeed@agent@typestate:lifecycle_to_string(_pipe@1).

-file("src/lightspeed/ops/quality_harness.gleam", 459).
-spec telemetry_labels(
    list(lightspeed@agent@session:telemetry_event()),
    list(binary())
) -> list(binary()).
telemetry_labels(Events, Labels_rev) ->
    case Events of
        [] ->
            lists:reverse(Labels_rev);

        [Event | Rest] ->
            telemetry_labels(
                Rest,
                [lightspeed@agent@session:telemetry_label(Event) | Labels_rev]
            )
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 513).
-spec join_with_loop(list(binary()), binary(), binary()) -> binary().
join_with_loop(Values, Separator, Acc) ->
    case Values of
        [] ->
            Acc;

        [Entry | Rest] ->
            join_with_loop(
                Rest,
                Separator,
                <<<<Acc/binary, Separator/binary>>/binary, Entry/binary>>
            )
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 506).
-spec join_with(list(binary()), binary()) -> binary().
join_with(Values, Separator) ->
    case Values of
        [] ->
            <<""/utf8>>;

        [First | Rest] ->
            join_with_loop(Rest, Separator, First)
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 448).
-spec session_signature(lightspeed@agent@session:session()) -> binary().
session_signature(State) ->
    <<<<<<<<<<<<<<"lifecycle="/utf8,
                                (lifecycle_label_from_session(State))/binary>>/binary,
                            ",counter="/utf8>>/binary,
                        (erlang:integer_to_binary(
                            lightspeed@agent@session:counter(State)
                        ))/binary>>/binary,
                    ",pending="/utf8>>/binary,
                (erlang:integer_to_binary(
                    erlang:length(
                        lightspeed@agent@session:pending_patches(State)
                    )
                ))/binary>>/binary,
            ",telemetry="/utf8>>/binary,
        (join_with(
            telemetry_labels(lightspeed@agent@session:telemetry(State), []),
            <<","/utf8>>
        ))/binary>>.

-file("src/lightspeed/ops/quality_harness.gleam", 308).
-spec replay_loop(
    lightspeed@agent@session:session(),
    binary(),
    list(lightspeed@agent@session:inbox_event())
) -> lightspeed@agent@session:session().
replay_loop(State, Owner, Events) ->
    case Events of
        [] ->
            State;

        [Event | Rest] ->
            replay_loop(
                lightspeed@agent@session:handle(
                    State,
                    {inbox_message, Owner, Event}
                ),
                Owner,
                Rest
            )
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 300).
-spec replay_events(list(lightspeed@agent@session:inbox_event())) -> lightspeed@agent@session:session().
replay_events(Events) ->
    replay_loop(
        lightspeed@agent@session:start(
            <<"replay-1"/utf8>>,
            <<"proc-a"/utf8>>,
            rehydrate,
            0,
            100
        ),
        <<"proc-a"/utf8>>,
        Events
    ).

-file("src/lightspeed/ops/quality_harness.gleam", 276).
-spec evaluate_replay_reconnect_crash() -> {boolean(), binary()}.
evaluate_replay_reconnect_crash() ->
    Events = [{connect, <<"/counter"/utf8>>, <<"csrf"/utf8>>, 0},
        increment,
        increment,
        {crash, <<"boom"/utf8>>},
        {restart, 5},
        {reconnect, <<"/counter"/utf8>>, 10},
        increment,
        {ack, <<"stale-ref"/utf8>>}],
    First = replay_events(Events),
    Second = replay_events(Events),
    Signature_1 = session_signature(First),
    Signature_2 = session_signature(Second),
    Passed = ((Signature_1 =:= Signature_2) andalso (lifecycle_label_from_session(
        First
    )
    =:= <<"live"/utf8>>))
    andalso (lightspeed@agent@session:counter(First) =:= 3),
    {Passed, Signature_1}.

-file("src/lightspeed/ops/quality_harness.gleam", 423).
-spec first_failure_reason(list(binary())) -> binary().
first_failure_reason(Frames) ->
    case Frames of
        [] ->
            <<"missing_failure"/utf8>>;

        [Payload | Rest] ->
            case lightspeed@protocol:decode(Payload) of
                {ok, {failure, _, Reason}} ->
                    Reason;

                {ok, _} ->
                    first_failure_reason(Rest);

                {error, Error} ->
                    <<"frame_decode_error:"/utf8,
                        (lightspeed@protocol:decode_error_to_string(Error))/binary>>
            end
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 324).
-spec connect_default(integer()) -> {ok,
        {lightspeed@transport@wisp_websocket:adapter_state(), list(binary())}} |
    {error, binary()}.
connect_default(Now_ms) ->
    Result = lightspeed@transport@wisp_websocket:connect(
        lightspeed@agent@session:start(
            <<"s-1"/utf8>>,
            <<"proc-a"/utf8>>,
            rehydrate,
            0,
            100
        ),
        {web_socket_request,
            <<"/counter"/utf8>>,
            <<"csrf"/utf8>>,
            <<"https://example.test"/utf8>>,
            Now_ms},
        lightspeed@transport@contract:allow_all(<<"proc-a"/utf8>>)
    ),
    case Result of
        {connected, State, Outbound_frames} ->
            {ok, {State, Outbound_frames}};

        {rejected, Error} ->
            {error, lightspeed@transport@contract:error_to_string(Error)}
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 250).
-spec evaluate_throttled_client_fault() -> {boolean(), binary()}.
evaluate_throttled_client_fault() ->
    case connect_default(0) of
        {error, Reason} ->
            {false, <<"connect_error:"/utf8, Reason/binary>>};

        {ok, {State, _}} ->
            Result = lightspeed@transport@wisp_websocket:receive_with_hooks(
                State,
                lightspeed@protocol:encode(
                    {event, <<"e-1"/utf8>>, <<"increment"/utf8>>, <<"{}"/utf8>>}
                ),
                5,
                lightspeed@transport@contract:deny_rate_limit(
                    <<"throttled"/utf8>>,
                    120
                )
            ),
            Reason@1 = first_failure_reason(erlang:element(3, Result)),
            Counter = lightspeed@agent@session:counter(
                lightspeed@transport@wisp_websocket:session_state(
                    erlang:element(2, Result)
                )
            ),
            Passed = (Reason@1 =:= <<"rate_limited:throttled:120"/utf8>>)
            andalso (Counter =:= 0),
            {Passed,
                <<<<<<"reason="/utf8, Reason@1/binary>>/binary,
                        ",counter="/utf8>>/binary,
                    (erlang:integer_to_binary(Counter))/binary>>}
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 470).
-spec count_telemetry_label(
    list(lightspeed@agent@session:telemetry_event()),
    binary()
) -> integer().
count_telemetry_label(Events, Label) ->
    case Events of
        [] ->
            0;

        [Event | Rest] ->
            case lightspeed@agent@session:telemetry_label(Event) =:= Label of
                true ->
                    1 + count_telemetry_label(Rest, Label);

                false ->
                    count_telemetry_label(Rest, Label)
            end
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 218).
-spec evaluate_stale_ref_fault() -> {boolean(), binary()}.
evaluate_stale_ref_fault() ->
    case connect_default(0) of
        {error, Reason} ->
            {false, <<"connect_error:"/utf8, Reason/binary>>};

        {ok, {State, _}} ->
            Stale = lightspeed@transport@wisp_websocket:'receive'(
                State,
                lightspeed@protocol:encode({ack, <<"stale-ref"/utf8>>}),
                1
            ),
            Session_state = lightspeed@transport@wisp_websocket:session_state(
                erlang:element(2, Stale)
            ),
            Pending = erlang:length(
                lightspeed@agent@session:pending_patches(Session_state)
            ),
            Emitted = erlang:length(erlang:element(3, Stale)),
            Ignored = count_telemetry_label(
                lightspeed@agent@session:telemetry(Session_state),
                <<"event_ignored"/utf8>>
            ),
            Passed = ((Pending =:= 1) andalso (Emitted =:= 0)) andalso (Ignored
            >= 1),
            {Passed,
                <<<<<<<<<<"pending="/utf8,
                                    (erlang:integer_to_binary(Pending))/binary>>/binary,
                                ",outbound_frames="/utf8>>/binary,
                            (erlang:integer_to_binary(Emitted))/binary>>/binary,
                        ",ignored="/utf8>>/binary,
                    (erlang:integer_to_binary(Ignored))/binary>>}
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 198).
-spec evaluate_bad_frame_fault() -> {boolean(), binary()}.
evaluate_bad_frame_fault() ->
    case connect_default(0) of
        {error, Reason} ->
            {false, <<"connect_error:"/utf8, Reason/binary>>};

        {ok, {State, _}} ->
            Result = lightspeed@transport@wisp_websocket:'receive'(
                State,
                <<"event|1|save|abc\\"/utf8>>,
                1
            ),
            Failure_reason = first_failure_reason(erlang:element(3, Result)),
            Counter = lightspeed@agent@session:counter(
                lightspeed@transport@wisp_websocket:session_state(
                    erlang:element(2, Result)
                )
            ),
            Passed = (Failure_reason =:= <<"protocol_decode_failed:invalid_escape_sequence"/utf8>>)
            andalso (Counter =:= 0),
            {Passed,
                <<<<<<"reason="/utf8, Failure_reason/binary>>/binary,
                        ",counter="/utf8>>/binary,
                    (erlang:integer_to_binary(Counter))/binary>>}
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 436).
-spec lifecycle_label(lightspeed@transport@wisp_websocket:adapter_state()) -> binary().
lifecycle_label(State) ->
    _pipe = State,
    _pipe@1 = lightspeed@transport@wisp_websocket:session_state(_pipe),
    lifecycle_label_from_session(_pipe@1).

-file("src/lightspeed/ops/quality_harness.gleam", 404).
-spec first_diff_operation(list(binary())) -> binary().
first_diff_operation(Frames) ->
    case Frames of
        [] ->
            <<"missing_diff"/utf8>>;

        [Payload | Rest] ->
            case lightspeed@protocol:decode(Payload) of
                {ok, {diff, _, Html}} ->
                    case lightspeed@diff:decode(Html) of
                        {ok, Patch} ->
                            lightspeed@diff:operation(Patch);

                        {error, Error} ->
                            <<"diff_decode_error:"/utf8,
                                (lightspeed@diff:decode_error_to_string(Error))/binary>>
                    end;

                {ok, _} ->
                    first_diff_operation(Rest);

                {error, Error@1} ->
                    <<"frame_decode_error:"/utf8,
                        (lightspeed@protocol:decode_error_to_string(Error@1))/binary>>
            end
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 394).
-spec frame_label(lightspeed@protocol:frame()) -> binary().
frame_label(Frame) ->
    case Frame of
        {hello, _, _} ->
            <<"hello"/utf8>>;

        {event, _, _, _} ->
            <<"event"/utf8>>;

        {diff, _, _} ->
            <<"diff"/utf8>>;

        {ack, _} ->
            <<"ack"/utf8>>;

        {failure, _, _} ->
            <<"failure"/utf8>>
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 376).
-spec decode_frames(list(binary()), list(lightspeed@protocol:frame())) -> list(lightspeed@protocol:frame()).
decode_frames(Frames, Decoded_rev) ->
    case Frames of
        [] ->
            lists:reverse(Decoded_rev);

        [Payload | Rest] ->
            case lightspeed@protocol:decode(Payload) of
                {ok, Frame} ->
                    decode_frames(Rest, [Frame | Decoded_rev]);

                {error, _} ->
                    decode_frames(
                        Rest,
                        [{failure, <<""/utf8>>, <<"decode_error"/utf8>>} |
                            Decoded_rev]
                    )
            end
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 369).
-spec frame_labels(list(binary())) -> binary().
frame_labels(Frames) ->
    _pipe = Frames,
    _pipe@1 = decode_frames(_pipe, []),
    _pipe@2 = gleam@list:map(_pipe@1, fun frame_label/1),
    join_with(_pipe@2, <<","/utf8>>).

-file("src/lightspeed/ops/quality_harness.gleam", 346).
-spec reconnect_default(
    lightspeed@transport@wisp_websocket:adapter_state(),
    integer()
) -> {ok, {lightspeed@transport@wisp_websocket:adapter_state(), list(binary())}} |
    {error, binary()}.
reconnect_default(State, Now_ms) ->
    Result = lightspeed@transport@wisp_websocket:reconnect(
        State,
        {web_socket_request,
            <<"/counter"/utf8>>,
            <<"csrf"/utf8>>,
            <<"https://example.test"/utf8>>,
            Now_ms},
        lightspeed@transport@contract:allow_all(<<"proc-a"/utf8>>)
    ),
    case Result of
        {connected, State@1, Outbound_frames} ->
            {ok, {State@1, Outbound_frames}};

        {rejected, Error} ->
            {error, lightspeed@transport@contract:error_to_string(Error)}
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 148).
-spec evaluate_mount_conformance() -> {boolean(), binary()}.
evaluate_mount_conformance() ->
    Connect_result = connect_default(0),
    case Connect_result of
        {error, Reason} ->
            {false, <<"connect_error:"/utf8, Reason/binary>>};

        {ok, {State, Frames}} ->
            Connect_labels = frame_labels(Frames),
            Connect_patch_op = first_diff_operation(Frames),
            Connect_live = lifecycle_label(State),
            Reconnect_result = reconnect_default(State, 10),
            case Reconnect_result of
                {error, Reason@1} ->
                    {false, <<"reconnect_error:"/utf8, Reason@1/binary>>};

                {ok, {Reconnected, Reconnect_frames}} ->
                    Reconnect_labels = frame_labels(Reconnect_frames),
                    Reconnect_patch_op = first_diff_operation(Reconnect_frames),
                    Reconnect_live = lifecycle_label(Reconnected),
                    Passed = (((((Connect_labels =:= <<"hello,diff"/utf8>>)
                    andalso (Connect_patch_op =:= <<"replace_segments"/utf8>>))
                    andalso (Connect_live =:= <<"live"/utf8>>))
                    andalso (Reconnect_labels =:= <<"hello,diff"/utf8>>))
                    andalso (Reconnect_patch_op =:= <<"replace_segments"/utf8>>))
                    andalso (Reconnect_live =:= <<"live"/utf8>>),
                    {Passed,
                        <<<<<<<<<<<<<<<<<<<<<<"connect_labels="/utf8,
                                                                    Connect_labels/binary>>/binary,
                                                                ",connect_op="/utf8>>/binary,
                                                            Connect_patch_op/binary>>/binary,
                                                        ",connect_lifecycle="/utf8>>/binary,
                                                    Connect_live/binary>>/binary,
                                                ",reconnect_labels="/utf8>>/binary,
                                            Reconnect_labels/binary>>/binary,
                                        ",reconnect_op="/utf8>>/binary,
                                    Reconnect_patch_op/binary>>/binary,
                                ",reconnect_lifecycle="/utf8>>/binary,
                            Reconnect_live/binary>>}
            end
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 138).
-spec evaluate(scenario()) -> {boolean(), binary()}.
evaluate(Scenario) ->
    case Scenario of
        mount_conformance ->
            evaluate_mount_conformance();

        bad_frame_fault ->
            evaluate_bad_frame_fault();

        stale_ref_fault ->
            evaluate_stale_ref_fault();

        throttled_client_fault ->
            evaluate_throttled_client_fault();

        replay_reconnect_crash ->
            evaluate_replay_reconnect_crash()
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 59).
?DOC(" Run one scenario twice and require stable signature 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/quality_harness.gleam", 41).
?DOC(" Run all M10 scenarios.\n").
-spec run_matrix() -> report().
run_matrix() ->
    Scenarios = [mount_conformance,
        bad_frame_fault,
        stale_ref_fault,
        throttled_client_fault,
        replay_reconnect_crash],
    Outcomes = gleam@list:map(Scenarios, fun run_scenario/1),
    {report, Outcomes, count_failed(Outcomes), count_nondeterministic(Outcomes)}.

-file("src/lightspeed/ops/quality_harness.gleam", 75).
?DOC(" Scenario label.\n").
-spec scenario_label(scenario()) -> binary().
scenario_label(Scenario) ->
    case Scenario of
        mount_conformance ->
            <<"mount_conformance"/utf8>>;

        bad_frame_fault ->
            <<"fault_bad_frame"/utf8>>;

        stale_ref_fault ->
            <<"fault_stale_ref"/utf8>>;

        throttled_client_fault ->
            <<"fault_throttled_client"/utf8>>;

        replay_reconnect_crash ->
            <<"replay_reconnect_crash"/utf8>>
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 86).
?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/quality_harness.gleam", 94).
?DOC(" Scenario signature.\n").
-spec signature(scenario_outcome()) -> binary().
signature(Outcome) ->
    erlang:element(5, Outcome).

-file("src/lightspeed/ops/quality_harness.gleam", 99).
?DOC(" Whether scenario result was deterministic across repeated runs.\n").
-spec deterministic(scenario_outcome()) -> boolean().
deterministic(Outcome) ->
    erlang:element(4, Outcome).

-file("src/lightspeed/ops/quality_harness.gleam", 104).
?DOC(" Outcome scenario id.\n").
-spec scenario(scenario_outcome()) -> scenario().
scenario(Outcome) ->
    erlang:element(2, Outcome).

-file("src/lightspeed/ops/quality_harness.gleam", 109).
?DOC(" Report outcomes.\n").
-spec outcomes(report()) -> list(scenario_outcome()).
outcomes(Report) ->
    erlang:element(2, Report).

-file("src/lightspeed/ops/quality_harness.gleam", 114).
?DOC(" Number of failed scenarios.\n").
-spec failed_scenarios(report()) -> integer().
failed_scenarios(Report) ->
    erlang:element(3, Report).

-file("src/lightspeed/ops/quality_harness.gleam", 119).
?DOC(" Number of nondeterministic scenarios.\n").
-spec nondeterministic_failures(report()) -> integer().
nondeterministic_failures(Report) ->
    erlang:element(4, Report).

-file("src/lightspeed/ops/quality_harness.gleam", 525).
-spec bool_label(boolean()) -> binary().
bool_label(Value) ->
    case Value of
        true ->
            <<"true"/utf8>>;

        false ->
            <<"false"/utf8>>
    end.

-file("src/lightspeed/ops/quality_harness.gleam", 124).
?DOC(" Stable report summary suitable for CI signatures.\n").
-spec report_signature(report()) -> binary().
report_signature(Report) ->
    _pipe = erlang:element(2, Report),
    _pipe@1 = gleam@list:map(
        _pipe,
        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(_pipe@1, <<";"/utf8>>).