Active black-box Mealy model learning and replay-confirmed behavioral compatibility checks.
///|
import {
"CaptainK-65/moon-statelens" @lens,
}///|
test "saved assertions and successful-event safety rules" {
let model = @lens.Machine::new(["logout", "request"], [
[{ target: 0, output: "ok", }, { target: 0, output: "denied", }],
])
let suite = model.regression_suite(profile="wp", state_bound=1)
let imported = @lens.RegressionSuite::from_json(Json(suite))
assert_true(imported.plan().validate())
let report = imported
.plan()
.run(@lens.Experiment::new(model.system(), model.alphabet()))
guard report is { "passed": True, .. } else { fail("regression") }
let rule = @lens.BehaviorRule::new(
"logged-out-denial",
{ input: "request", output: "allowed", },
kind="after",
trigger={ input: "logout", output: "ok", },
)
assert_true(rule.search(model).witness is None)
assert_eq(rule.check_trace(["logout", "request"], ["ok", "allowed"]), Some(1))
}///|
test "quick start learns a resettable session" {
let active = [false]
let target = @lens.System::new(reset=() => active[0] = false, step=input => {
match input {
"login" => {
active[0] = true
"ok"
}
"logout" => {
active[0] = false
"ok"
}
"request" => if active[0] { "allowed" } else { "denied" }
_ => raise @lens.UnknownInput(input)
}
})
let experiment = @lens.Experiment::new(target, ["login", "logout", "request"])
let result = @lens.learn(experiment, @lens.Oracle::w_method(2))
assert_true(result.status is Supported(ConditionalStateBound(2)))
let model = result.model.unwrap()
assert_eq(model.state_count(), 2)
assert_eq(model.trace(["login", "logout", "request"]), ["ok", "ok", "denied"])
assert_true(
@lens.distinguish(model, @lens.decode_model(model.encode())) is None,
)
}///|
test "quick start preserves an inconclusive query budget" {
let target = @lens.System::new(reset=() => (), step=_ => "ok")
let experiment = @lens.Experiment::new(target, ["x"], max_queries=0)
let result = @lens.learn(experiment, @lens.Oracle::w_method(1))
assert_true(result.status is Inconclusive("physical-queries"))
assert_true(result.model is None)
}pub struct BehaviorRule {
// private fields
}impl ToJson for BehaviorRulefn BehaviorRule::check_trace(self : BehaviorRule, inputs : Array[String], outputs : Array[String]) -> Int? raise LensErrorfn BehaviorRule::finding(self : BehaviorRule, search : RuleSearch, actual : Array[String]?) -> Json raisefn BehaviorRule::new(id : String, forbidden : RuleEvent, kind? : String, trigger? : RuleEvent, release? : RuleEvent) -> BehaviorRule raise LensErrorfn BehaviorRule::search(self : BehaviorRule, model : Machine, max_pairs? : Int) -> RuleSearch raise LensErrorfn BehaviorRule::verify(self : BehaviorRule, model : Machine, experiment : Experiment, max_pairs? : Int) -> Json raisepub(all) struct CompatibilityResult {
status : CompatibilityStatus
left : LearningResult
right : LearningResult
left_statistics : Statistics
right_statistics : Statistics
refinements : Int
spurious_inputs : Array[Array[String]]
} derive(Debug)pub(all) enum CompatibilityStatus {
ConfirmedDifference(Difference)
NoDifferenceBetweenHypotheses
Inconclusive(String)
ReplayUnstable(side~ : String, word~ : Array[String], expected~ : Array[String], actual~ : Array[String])
} derive(Debug)pub struct Experiment {
// private fields
}fn Experiment::new(system : System, alphabet : Array[String], max_queries? : Int, max_steps? : Int, max_word_length? : Int, max_cache_nodes? : Int, max_output_code_units? : Int, use_cache? : Bool, recheck_every? : Int) -> Experiment raise LensErrorfn Experiment::query(self : Experiment, requested_word : Array[String], bypass_cache? : Bool) -> Array[String] raisepub struct LearningDriver {
// private fields
}fn LearningDriver::new(algorithm : Algorithm, alphabet : Array[String], max_states? : Int, max_rounds? : Int, max_table_cells? : Int, max_table_symbols? : Int, max_prefixes? : Int) -> LearningDriver raisefn LearningDriver::refine(self : LearningDriver, requested : Array[String], actual : Array[String]) -> Unit raisefn LearningDriver::result(self : LearningDriver, statistics : Statistics, status : LearningStatus) -> LearningResultpub(all) struct LearningResult {
model : Machine?
status : LearningStatus
statistics : Statistics
rounds : Array[LearningRound]
counterexamples : Array[Difference]
} derive(Debug)impl ToJson for LearningResultfn Machine::regression_suite(self : Machine, profile? : String, state_bound? : Int, max_candidates? : Int, max_symbols? : Int, max_work? : Int) -> RegressionSuite raisepub(all) struct ModelDiagnosis {
differences : Array[Difference]
complete : Bool
visited_pairs : Int
checked_edges : Int
reason : String?
} derive(ToJson, Debug)pub struct Oracle {
// private fields
}fn Oracle::evaluate(self : Oracle, hypothesis : Machine, experiment : Experiment) -> CheckResult raisepub struct QuerySession {
// private fields
}fn QuerySession::accept_output(self : QuerySession, id : Int, output : String) -> Unit raise LensErrorfn QuerySession::new(alphabet : Array[String], max_queries? : Int, max_steps? : Int, max_word_length? : Int, max_cache_nodes? : Int, max_output_code_units? : Int, use_cache? : Bool, recheck_every? : Int) -> QuerySession raise LensErrorfn QuerySession::start(self : QuerySession, requested : Array[String], bypass_cache? : Bool) -> QueryStart raise LensErrorpub struct RegressionExecution {
// private fields
}fn RegressionExecution::abort(self : RegressionExecution, reason : String, unstable? : Bool) -> Unitpub struct RegressionPlan {
// private fields
}fn RegressionPlan::execution(self : RegressionPlan, stability_rechecks? : Int) -> RegressionExecution raisefn RegressionPlan::run(self : RegressionPlan, experiment : Experiment, stability_rechecks? : Int) -> Json raisepub struct RegressionSuite {
// private fields
}impl ToJson for RegressionSuitepub struct System {
// private fields
}pub struct VerificationCursor {
// private fields
}fn VerificationCursor::new(plan : VerificationPlan, hypothesis : Machine) -> VerificationCursor raisefn VerificationCursor::submit(self : VerificationCursor, id : Int, outputs : Array[String]) -> Unit raisepub(all) enum VerificationPlan {
Exact(Machine)
Exhaustive(depth~ : Int, max_tests~ : Int)
RandomWords(seed~ : UInt, max_length~ : Int, tests~ : Int)
WMethod(bound~ : Int, max_tests~ : Int, max_work~ : Int)
WpMethod(bound~ : Int, max_tests~ : Int, max_work~ : Int)
Replay(Array[Array[String]])
Chain(Array[VerificationPlan])
} derive(Debug)fn compare(left : Experiment, right : Experiment, left_oracle : Oracle, right_oracle : Oracle, max_states? : Int, max_refinements? : Int) -> CompatibilityResult raisefn confirm_difference(left : Experiment, right : Experiment, inputs : Array[String]) -> Difference? raisefn diagnose_models(left : Machine, right : Machine, max_pairs? : Int, max_findings? : Int, max_edges? : Int) -> ModelDiagnosis raise LensErrorfn learn(experiment : Experiment, oracle : Oracle, max_states? : Int, max_rounds? : Int, max_table_cells? : Int, max_table_symbols? : Int, max_prefixes? : Int) -> LearningResult raisefn learn_with(experiment : Experiment, oracle : Oracle, algorithm : Algorithm, max_states? : Int, max_rounds? : Int, max_table_cells? : Int, max_table_symbols? : Int, max_prefixes? : Int) -> LearningResult raiseInstall
Download zipActive black-box Mealy model learning and replay-confirmed behavioral compatibility checks.