src/lightspeed@ops@nested_lifecycle_harness.erl

-module(lightspeed@ops@nested_lifecycle_harness).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/ops/nested_lifecycle_harness.gleam").
-export([pass_fail_label/1, run_scenario/1, run_matrix/0, lifecycle_contract_version_label/0, scenario_label/1, signature/1, scenario/1, deterministic/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 nested lifecycle conformance harness for M55.\n").

-type scenario() :: stable_child_identity_contracts |
    suspend_resume_independent_updates |
    scoped_event_routing_and_patch_targeting |
    subtree_failure_isolation |
    regression_gate_determinism.

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

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

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 442).
-spec count_nondeterministic(list(scenario_outcome())) -> integer().
count_nondeterministic(Outcomes) ->
    _pipe = Outcomes,
    _pipe@1 = gleam@list:filter(
        _pipe,
        fun(Outcome) -> not erlang:element(4, Outcome) end
    ),
    erlang:length(_pipe@1).

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 436).
-spec count_failed(list(scenario_outcome())) -> integer().
count_failed(Outcomes) ->
    _pipe = Outcomes,
    _pipe@1 = gleam@list:filter(
        _pipe,
        fun(Outcome) -> not erlang:element(3, Outcome) end
    ),
    erlang:length(_pipe@1).

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 94).
?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/nested_lifecycle_harness.gleam", 407).
-spec child_lifecycle_is(
    lightspeed@component@nested_lifecycle:runtime(),
    binary(),
    binary()
) -> boolean().
child_lifecycle_is(Runtime, Child_id, Expected) ->
    case lightspeed@component@nested_lifecycle:child(Runtime, Child_id) of
        {some, Node} ->
            lightspeed@component@nested_lifecycle:child_lifecycle_label(
                erlang:element(4, Node)
            )
            =:= Expected;

        none ->
            false
    end.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 326).
-spec evaluate_subtree_failure_isolation() -> {boolean(), binary()}.
evaluate_subtree_failure_isolation() ->
    {Runtime0, _} = lightspeed@component@nested_lifecycle:start(
        <<"parent-4"/utf8>>,
        <<"/rooms/4"/utf8>>
    ),
    {Runtime1, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime0,
        <<"child-a"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>a-0</article>"/utf8>>
    ),
    {Runtime2, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime1,
        <<"child-b"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>b-0</article>"/utf8>>
    ),
    {Runtime3, _} = lightspeed@component@nested_lifecycle:fail_child(
        Runtime2,
        <<"child-a"/utf8>>,
        <<"render_timeout"/utf8>>
    ),
    {Runtime4, Failed_route} = lightspeed@component@nested_lifecycle:route_event(
        Runtime3,
        lightspeed@component@nested_lifecycle:scoped_event(
            {child_scope, <<"child-a"/utf8>>},
            <<"tap"/utf8>>,
            <<"id=a-1"/utf8>>
        )
    ),
    {Runtime5, Sibling_patches} = lightspeed@component@nested_lifecycle:update_child(
        Runtime4,
        <<"child-b"/utf8>>,
        <<"<article>b-1</article>"/utf8>>
    ),
    Sibling_target_ok = case Sibling_patches of
        [Patch] ->
            lightspeed@diff:target(Patch) =:= lightspeed@component@nested_lifecycle:child_target(
                Runtime5,
                <<"child-b"/utf8>>
            );

        _ ->
            false
    end,
    Passed = (((lightspeed@component@nested_lifecycle:route_decision_label(
        Failed_route
    )
    =:= <<"rejected:child_failed:child-a:render_timeout"/utf8>>)
    andalso Sibling_target_ok)
    andalso lightspeed@component@nested_lifecycle:subtree_isolated(
        Runtime5,
        <<"child-a"/utf8>>
    ))
    andalso child_lifecycle_is(Runtime5, <<"child-b"/utf8>>, <<"mounted"/utf8>>),
    {Passed, lightspeed@component@nested_lifecycle:runtime_signature(Runtime5)}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 448).
-spec list_contains(list(binary()), binary()) -> boolean().
list_contains(Items, Expected) ->
    case Items of
        [] ->
            false;

        [Value | Rest] ->
            case Value =:= Expected of
                true ->
                    true;

                false ->
                    list_contains(Rest, Expected)
            end
    end.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 268).
-spec evaluate_scoped_event_routing_and_patch_targeting() -> {boolean(),
    binary()}.
evaluate_scoped_event_routing_and_patch_targeting() ->
    {Runtime0, _} = lightspeed@component@nested_lifecycle:start(
        <<"parent-3"/utf8>>,
        <<"/rooms/3"/utf8>>
    ),
    {Runtime1, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime0,
        <<"child-a"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>a-0</article>"/utf8>>
    ),
    {Runtime2, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime1,
        <<"child-b"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>b-0</article>"/utf8>>
    ),
    {Runtime3, Parent_decision} = lightspeed@component@nested_lifecycle:route_event(
        Runtime2,
        lightspeed@component@nested_lifecycle:scoped_event(
            parent_scope,
            <<"refresh"/utf8>>,
            <<""/utf8>>
        )
    ),
    {Runtime4, Child_decision} = lightspeed@component@nested_lifecycle:route_event(
        Runtime3,
        lightspeed@component@nested_lifecycle:scoped_event(
            {child_scope, <<"child-a"/utf8>>},
            <<"tap"/utf8>>,
            <<"id=a-1"/utf8>>
        )
    ),
    {Runtime5, Missing_decision} = lightspeed@component@nested_lifecycle:route_event(
        Runtime4,
        lightspeed@component@nested_lifecycle:scoped_event(
            {child_scope, <<"child-missing"/utf8>>},
            <<"tap"/utf8>>,
            <<"id=missing"/utf8>>
        )
    ),
    {Runtime6, _} = lightspeed@component@nested_lifecycle:update_child(
        Runtime5,
        <<"child-a"/utf8>>,
        <<"<article>a-1</article>"/utf8>>
    ),
    Patch_targets = gleam@list:map(
        lightspeed@component@nested_lifecycle:patches(Runtime6),
        fun lightspeed@diff:target/1
    ),
    Passed = ((((lightspeed@component@nested_lifecycle:route_decision_label(
        Parent_decision
    )
    =:= <<"routed_to_parent"/utf8>>)
    andalso (lightspeed@component@nested_lifecycle:route_decision_label(
        Child_decision
    )
    =:= <<"routed_to_child:child-a"/utf8>>))
    andalso (lightspeed@component@nested_lifecycle:route_decision_label(
        Missing_decision
    )
    =:= <<"rejected:unknown_child:child-missing"/utf8>>))
    andalso list_contains(
        Patch_targets,
        lightspeed@component@nested_lifecycle:child_target(
            Runtime6,
            <<"child-a"/utf8>>
        )
    ))
    andalso lightspeed@component@nested_lifecycle:authority_invariants(Runtime6),
    {Passed, lightspeed@component@nested_lifecycle:runtime_signature(Runtime6)}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 426).
-spec latest_patch_from_list(
    list(lightspeed@diff:patch()),
    lightspeed@diff:patch()
) -> gleam@option:option(lightspeed@diff:patch()).
latest_patch_from_list(Patches, Latest) ->
    case Patches of
        [] ->
            {some, Latest};

        [Patch | Rest] ->
            latest_patch_from_list(Rest, Patch)
    end.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 419).
-spec latest_patch(lightspeed@component@nested_lifecycle:runtime()) -> gleam@option:option(lightspeed@diff:patch()).
latest_patch(Runtime) ->
    case lightspeed@component@nested_lifecycle:patches(Runtime) of
        [] ->
            none;

        [Patch | Rest] ->
            latest_patch_from_list(Rest, Patch)
    end.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 231).
-spec evaluate_suspend_resume_independent_updates() -> {boolean(), binary()}.
evaluate_suspend_resume_independent_updates() ->
    {Runtime0, _} = lightspeed@component@nested_lifecycle:start(
        <<"parent-2"/utf8>>,
        <<"/rooms/2"/utf8>>
    ),
    {Runtime1, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime0,
        <<"child-a"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>a-0</article>"/utf8>>
    ),
    {Runtime2, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime1,
        <<"child-b"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>b-0</article>"/utf8>>
    ),
    Runtime3 = lightspeed@component@nested_lifecycle:suspend_child(
        Runtime2,
        <<"child-a"/utf8>>
    ),
    {Runtime4, _} = lightspeed@component@nested_lifecycle:update_child(
        Runtime3,
        <<"child-b"/utf8>>,
        <<"<article>b-1</article>"/utf8>>
    ),
    Runtime5 = lightspeed@component@nested_lifecycle:resume_child(
        Runtime4,
        <<"child-a"/utf8>>
    ),
    Target_ok = case latest_patch(Runtime5) of
        {some, Patch} ->
            lightspeed@diff:target(Patch) =:= lightspeed@component@nested_lifecycle:child_target(
                Runtime5,
                <<"child-b"/utf8>>
            );

        none ->
            false
    end,
    Child_a_ok = child_lifecycle_is(
        Runtime5,
        <<"child-a"/utf8>>,
        <<"mounted"/utf8>>
    ),
    Child_b_ok = child_lifecycle_is(
        Runtime5,
        <<"child-b"/utf8>>,
        <<"mounted"/utf8>>
    ),
    Passed = ((Target_ok andalso Child_a_ok) andalso Child_b_ok) andalso (lightspeed@component@nested_lifecycle:parent_mount_count(
        Runtime5
    )
    =:= 1),
    {Passed, lightspeed@component@nested_lifecycle:runtime_signature(Runtime5)}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 201).
-spec evaluate_stable_child_identity_contracts() -> {boolean(), binary()}.
evaluate_stable_child_identity_contracts() ->
    {Runtime0, _} = lightspeed@component@nested_lifecycle:start(
        <<"parent-1"/utf8>>,
        <<"/rooms/1"/utf8>>
    ),
    {Runtime1, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime0,
        <<"child-a"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>a-0</article>"/utf8>>
    ),
    {Runtime2, _} = lightspeed@component@nested_lifecycle:mount_child(
        Runtime1,
        <<"child-b"/utf8>>,
        <<"child/v1"/utf8>>,
        <<"<article>b-0</article>"/utf8>>
    ),
    {Runtime3, _} = lightspeed@component@nested_lifecycle:update_child(
        Runtime2,
        <<"child-a"/utf8>>,
        <<"<article>a-1</article>"/utf8>>
    ),
    Runtime4 = lightspeed@component@nested_lifecycle:suspend_child(
        Runtime3,
        <<"child-a"/utf8>>
    ),
    Runtime5 = lightspeed@component@nested_lifecycle:resume_child(
        Runtime4,
        <<"child-a"/utf8>>
    ),
    Passed = (lightspeed@component@nested_lifecycle:stable_child_identity(
        Runtime5
    )
    andalso (lightspeed@component@nested_lifecycle:parent_mount_count(Runtime5)
    =:= 1))
    andalso lightspeed@component@nested_lifecycle:authority_invariants(Runtime5),
    Signature = lightspeed@component@nested_lifecycle:runtime_signature(
        Runtime5
    ),
    {Passed, Signature}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 371).
-spec evaluate_regression_gate_determinism() -> {boolean(), binary()}.
evaluate_regression_gate_determinism() ->
    Identity = run_scenario(stable_child_identity_contracts),
    Suspend_resume = run_scenario(suspend_resume_independent_updates),
    Routing = run_scenario(scoped_event_routing_and_patch_targeting),
    Isolation = run_scenario(subtree_failure_isolation),
    Signature = <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"identity="/utf8,
                                                                (pass_fail_label(
                                                                    Identity
                                                                ))/binary>>/binary,
                                                            ":"/utf8>>/binary,
                                                        (erlang:element(
                                                            5,
                                                            Identity
                                                        ))/binary>>/binary,
                                                    "|suspend_resume="/utf8>>/binary,
                                                (pass_fail_label(Suspend_resume))/binary>>/binary,
                                            ":"/utf8>>/binary,
                                        (erlang:element(5, Suspend_resume))/binary>>/binary,
                                    "|routing="/utf8>>/binary,
                                (pass_fail_label(Routing))/binary>>/binary,
                            ":"/utf8>>/binary,
                        (erlang:element(5, Routing))/binary>>/binary,
                    "|isolation="/utf8>>/binary,
                (pass_fail_label(Isolation))/binary>>/binary,
            ":"/utf8>>/binary,
        (erlang:element(5, Isolation))/binary>>,
    {((((((erlang:element(3, Identity) andalso erlang:element(4, Identity))
        andalso erlang:element(3, Suspend_resume))
        andalso erlang:element(4, Suspend_resume))
        andalso erlang:element(3, Routing))
        andalso erlang:element(4, Routing))
        andalso erlang:element(3, Isolation))
        andalso erlang:element(4, Isolation),
        Signature}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 189).
-spec evaluate(scenario()) -> {boolean(), binary()}.
evaluate(Scenario) ->
    case Scenario of
        stable_child_identity_contracts ->
            evaluate_stable_child_identity_contracts();

        suspend_resume_independent_updates ->
            evaluate_suspend_resume_independent_updates();

        scoped_event_routing_and_patch_targeting ->
            evaluate_scoped_event_routing_and_patch_targeting();

        subtree_failure_isolation ->
            evaluate_subtree_failure_isolation();

        regression_gate_determinism ->
            evaluate_regression_gate_determinism()
    end.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 61).
?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/nested_lifecycle_harness.gleam", 42).
?DOC(" Run all M55 scenarios.\n").
-spec run_matrix() -> report().
run_matrix() ->
    Outcomes = begin
        _pipe = [stable_child_identity_contracts,
            suspend_resume_independent_updates,
            scoped_event_routing_and_patch_targeting,
            subtree_failure_isolation,
            regression_gate_determinism],
        gleam@list:map(_pipe, fun run_scenario/1)
    end,
    {report, Outcomes, count_failed(Outcomes), count_nondeterministic(Outcomes)}.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 77).
?DOC(" M55 lifecycle contract version label.\n").
-spec lifecycle_contract_version_label() -> binary().
lifecycle_contract_version_label() ->
    <<"m55.lifecycle.v"/utf8, (erlang:integer_to_binary(1))/binary>>.

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

        suspend_resume_independent_updates ->
            <<"suspend_resume_independent_updates"/utf8>>;

        scoped_event_routing_and_patch_targeting ->
            <<"scoped_event_routing_and_patch_targeting"/utf8>>;

        subtree_failure_isolation ->
            <<"subtree_failure_isolation"/utf8>>;

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

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 102).
?DOC(" Scenario signature accessor.\n").
-spec signature(scenario_outcome()) -> binary().
signature(Outcome) ->
    erlang:element(5, Outcome).

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 107).
?DOC(" Scenario accessor.\n").
-spec scenario(scenario_outcome()) -> scenario().
scenario(Outcome) ->
    erlang:element(2, Outcome).

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 112).
?DOC(" Scenario determinism accessor.\n").
-spec deterministic(scenario_outcome()) -> boolean().
deterministic(Outcome) ->
    erlang:element(4, Outcome).

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

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 122).
?DOC(" Failed scenario count.\n").
-spec failed_scenarios(report()) -> integer().
failed_scenarios(Report) ->
    erlang:element(3, Report).

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 127).
?DOC(" Nondeterministic scenario count.\n").
-spec nondeterministic_failures(report()) -> integer().
nondeterministic_failures(Report) ->
    erlang:element(4, Report).

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

        [First | Rest] ->
            gleam@list:fold(
                Rest,
                First,
                fun(Accumulator, Value) ->
                    <<<<Accumulator/binary, Separator/binary>>/binary,
                        Value/binary>>
                end
            )
    end.

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

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

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 132).
?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/nested_lifecycle_harness.gleam", 148).
?DOC(" Deterministic snapshot signature for M55 fixture drift gates.\n").
-spec snapshot_signature() -> binary().
snapshot_signature() ->
    <<<<<<"m55.snapshot.v"/utf8, (erlang:integer_to_binary(1))/binary>>/binary,
            "|"/utf8>>/binary,
        (report_signature(run_matrix()))/binary>>.

-file("src/lightspeed/ops/nested_lifecycle_harness.gleam", 156).
?DOC(" Deterministic markdown report for M55 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,
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"# Nested Lifecycle Fixture Report\n\n"/utf8,
                                                                                        "snapshot_version: "/utf8>>/binary,
                                                                                    (erlang:integer_to_binary(
                                                                                        1
                                                                                    ))/binary>>/binary,
                                                                                "\n"/utf8>>/binary,
                                                                            "lifecycle_contract_version: "/utf8>>/binary,
                                                                        (lifecycle_contract_version_label(
                                                                            
                                                                        ))/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>>.