Packages

LiveView-style runtime for Gleam.

Current section

Files

Jump to
lightspeed src lightspeed ops app_platform_harness.gleam
Raw

src/lightspeed/ops/app_platform_harness.gleam

//// Deterministic app-platform conformance harness for M38.
import gleam/int
import gleam/list
import lightspeed/platform/foundation
pub const snapshot_version = 1
/// M38 conformance scenarios.
pub type Scenario {
ReferenceCompositionPatterns
IntegrationSeamOverrides
LifecycleWorkflowConformance
WorkflowWithoutFrameworkPatching
}
/// One M38 scenario outcome.
pub type ScenarioOutcome {
ScenarioOutcome(
scenario: Scenario,
passed: Bool,
deterministic: Bool,
signature: String,
)
}
/// Full M38 report.
pub type Report {
Report(
outcomes: List(ScenarioOutcome),
failed_scenarios: Int,
nondeterministic_failures: Int,
)
}
/// Run all M38 scenarios.
pub fn run_matrix() -> Report {
let outcomes =
[
ReferenceCompositionPatterns,
IntegrationSeamOverrides,
LifecycleWorkflowConformance,
WorkflowWithoutFrameworkPatching,
]
|> list.map(run_scenario)
Report(
outcomes: outcomes,
failed_scenarios: count_failed(outcomes),
nondeterministic_failures: count_nondeterministic(outcomes),
)
}
/// Run one scenario twice and require deterministic parity.
pub fn run_scenario(scenario: Scenario) -> ScenarioOutcome {
let #(first_passed, first_signature) = evaluate(scenario)
let #(second_passed, second_signature) = evaluate(scenario)
let deterministic =
first_passed == second_passed && first_signature == second_signature
let passed = first_passed && second_passed && deterministic
ScenarioOutcome(
scenario: scenario,
passed: passed,
deterministic: deterministic,
signature: first_signature,
)
}
/// Scenario label.
pub fn scenario_label(scenario: Scenario) -> String {
case scenario {
ReferenceCompositionPatterns -> "reference_composition_patterns"
IntegrationSeamOverrides -> "integration_seam_overrides"
LifecycleWorkflowConformance -> "lifecycle_workflow_conformance"
WorkflowWithoutFrameworkPatching -> "workflow_without_framework_patching"
}
}
/// Stable pass/fail label.
pub fn pass_fail_label(outcome: ScenarioOutcome) -> String {
case outcome.passed {
True -> "pass"
False -> "fail"
}
}
/// Scenario signature accessor.
pub fn signature(outcome: ScenarioOutcome) -> String {
outcome.signature
}
/// Scenario accessor.
pub fn scenario(outcome: ScenarioOutcome) -> Scenario {
outcome.scenario
}
/// Scenario determinism accessor.
pub fn deterministic(outcome: ScenarioOutcome) -> Bool {
outcome.deterministic
}
/// Report outcomes accessor.
pub fn outcomes(report: Report) -> List(ScenarioOutcome) {
report.outcomes
}
/// Failed scenario count.
pub fn failed_scenarios(report: Report) -> Int {
report.failed_scenarios
}
/// Nondeterministic scenario count.
pub fn nondeterministic_failures(report: Report) -> Int {
report.nondeterministic_failures
}
/// Stable report signature.
pub fn report_signature(report: Report) -> String {
let entries =
list.map(report.outcomes, fn(outcome) {
scenario_label(outcome.scenario)
<> "="
<> pass_fail_label(outcome)
<> ":deterministic="
<> bool_label(outcome.deterministic)
<> ":"
<> outcome.signature
})
join_with(";", entries)
}
/// Deterministic snapshot signature for M38 fixture drift gates.
pub fn snapshot_signature() -> String {
"m38.snapshot.v"
<> int.to_string(snapshot_version)
<> "|"
<> report_signature(run_matrix())
}
/// Deterministic markdown report for M38 fixture scripts.
pub fn snapshot_report_markdown() -> String {
let report = run_matrix()
let failed = failed_scenarios(report)
let nondeterministic = nondeterministic_failures(report)
let status = case failed == 0 && nondeterministic == 0 {
True -> "OK"
False -> "FAIL"
}
"# App Platform Fixture Report\n\n"
<> "snapshot_version: "
<> int.to_string(snapshot_version)
<> "\n"
<> "status: "
<> status
<> "\n"
<> "failed_scenarios: "
<> int.to_string(failed)
<> "\n"
<> "nondeterministic_failures: "
<> int.to_string(nondeterministic)
<> "\n\n"
<> "snapshot_signature: "
<> snapshot_signature()
<> "\n\n"
<> "report_signature: "
<> report_signature(report)
<> "\n"
}
fn evaluate(scenario: Scenario) -> #(Bool, String) {
case scenario {
ReferenceCompositionPatterns -> evaluate_reference_composition_patterns()
IntegrationSeamOverrides -> evaluate_integration_seam_overrides()
LifecycleWorkflowConformance -> evaluate_lifecycle_workflow_conformance()
WorkflowWithoutFrameworkPatching ->
evaluate_workflow_without_framework_patching()
}
}
fn evaluate_reference_composition_patterns() -> #(Bool, String) {
let profiles = foundation.reference_profiles()
let signatures = list.map(profiles, foundation.signature)
let passed = list.length(profiles) == 3 && profiles_all_valid(profiles)
#(passed, join_with(";", signatures))
}
fn evaluate_integration_seam_overrides() -> #(Bool, String) {
let profiles = foundation.reference_profiles()
let entries =
list.map(profiles, fn(profile) {
foundation.name(profile)
<> ":"
<> foundation.seam_contract_signature(profile)
})
let passed = profiles_all_have_explicit_overrides(profiles)
#(passed, join_with(";", entries))
}
fn evaluate_lifecycle_workflow_conformance() -> #(Bool, String) {
let profiles = foundation.reference_profiles()
let entries = list.map(profiles, foundation.workflow_matrix_signature)
let required = foundation.required_workflows()
let passed = profiles_support_required_workflows(profiles, required)
#(passed, join_with(";", entries))
}
fn evaluate_workflow_without_framework_patching() -> #(Bool, String) {
let profiles = foundation.reference_profiles()
let required = foundation.required_workflows()
let passed = profiles_run_without_framework_patching(profiles, required)
let entries =
list.map(profiles, fn(profile) {
foundation.name(profile)
<> ":patching_required="
<> bool_label(foundation.requires_framework_internal_patching(profile))
})
#(passed, join_with(";", entries))
}
fn profiles_all_valid(profiles: List(foundation.AppProfile)) -> Bool {
case profiles {
[] -> True
[profile, ..rest] -> foundation.valid(profile) && profiles_all_valid(rest)
}
}
fn profiles_all_have_explicit_overrides(
profiles: List(foundation.AppProfile),
) -> Bool {
case profiles {
[] -> True
[profile, ..rest] ->
foundation.explicit_override_points(profile)
&& profiles_all_have_explicit_overrides(rest)
}
}
fn profiles_support_required_workflows(
profiles: List(foundation.AppProfile),
required_workflows: List(foundation.LifecycleWorkflow),
) -> Bool {
case profiles {
[] -> True
[profile, ..rest] ->
profile_supports_workflows(profile, required_workflows)
&& profiles_support_required_workflows(rest, required_workflows)
}
}
fn profile_supports_workflows(
profile: foundation.AppProfile,
required_workflows: List(foundation.LifecycleWorkflow),
) -> Bool {
case required_workflows {
[] -> True
[workflow, ..rest] ->
foundation.supports_workflow(profile, workflow)
&& profile_supports_workflows(profile, rest)
}
}
fn profiles_run_without_framework_patching(
profiles: List(foundation.AppProfile),
required_workflows: List(foundation.LifecycleWorkflow),
) -> Bool {
case profiles {
[] -> True
[profile, ..rest] ->
!foundation.requires_framework_internal_patching(profile)
&& profile_workflows_run_without_patching(profile, required_workflows)
&& profiles_run_without_framework_patching(rest, required_workflows)
}
}
fn profile_workflows_run_without_patching(
profile: foundation.AppProfile,
required_workflows: List(foundation.LifecycleWorkflow),
) -> Bool {
case required_workflows {
[] -> True
[workflow, ..rest] ->
foundation.workflow_runs_without_internal_patching(profile, workflow)
&& profile_workflows_run_without_patching(profile, rest)
}
}
fn count_failed(outcomes: List(ScenarioOutcome)) -> Int {
case outcomes {
[] -> 0
[outcome, ..rest] ->
case outcome.passed {
True -> count_failed(rest)
False -> 1 + count_failed(rest)
}
}
}
fn count_nondeterministic(outcomes: List(ScenarioOutcome)) -> Int {
case outcomes {
[] -> 0
[outcome, ..rest] ->
case outcome.deterministic {
True -> count_nondeterministic(rest)
False -> 1 + count_nondeterministic(rest)
}
}
}
fn bool_label(value: Bool) -> String {
case value {
True -> "true"
False -> "false"
}
}
fn join_with(separator: String, values: List(String)) -> String {
case values {
[] -> ""
[value] -> value
[value, ..rest] -> value <> separator <> join_with(separator, rest)
}
}