Deterministic canary rollout planner and blast-radius simulator for MoonBit
moon add EJJ-ai-nb/canaryringfn main {
let plan = @canaryring.example_plan()
let users = @canaryring.example_users()
let metrics = @canaryring.healthy_metrics()
let report = @canaryring.simulate_rollout(plan, users, metrics)
println(report.to_markdown())
}moon run examples/basic
moon run cmd/mainmoon check --deny-warn
moon build
moon test --deny-warn
moon fmt --check
moon docpub(all) struct ControlEvaluation {
rule_id : String
domain : ControlDomain
status : Severity
score : Int
title : String
message : String
repair : String
} derive(Eq, Debug)pub(all) struct ControlReview {
verdict : String
score : Int
passed : Int
warned : Int
failed : Int
evaluations : Array[ControlEvaluation]
} derive(Eq, Debug)pub(all) struct ControlRule {
id : String
domain : ControlDomain
title : String
check_text : String
evidence_text : String
repair_text : String
weight : Int
} derive(Eq, Debug)fn ControlRule::ControlRule(id? : String, domain? : ControlDomain, title? : String, check_text? : String, evidence_text? : String, repair_text? : String, weight? : Int) -> ControlRulepub(all) struct EvidenceReport {
score : Int
verdict : String
findings : Array[RolloutFinding]
} derive(Eq, Debug)pub(all) struct ExposureDecision {
enabled : Bool
bucket_bp : Int
mode : RolloutMode
phase_name : String
reason : String
} derive(Eq, Debug)pub(all) struct ForecastReport {
verdict : String
peak_users : Int
peak_traffic_units : Int
peak_risk_score : Int
steps : Array[ForecastStep]
} derive(Eq, Debug)pub(all) struct GateResult {
decision : GateDecision
severity : Severity
score : Int
reasons : Array[String]
} derive(Eq, Debug)pub(all) struct IncidentReport {
title : String
minute : Int
impact : ImpactLevel
decision : GateDecision
severity : Severity
affected_users : Int
affected_traffic_units : Int
primary_reason : String
actions : Array[String]
} derive(Eq, Debug)fn IncidentReport::IncidentReport(title? : String, minute? : Int, impact? : ImpactLevel, decision? : GateDecision, severity? : Severity, affected_users? : Int, affected_traffic_units? : Int, primary_reason? : String, actions? : Array[String]) -> IncidentReportfn MetricsSnapshot::MetricsSnapshot(minute? : Int, sample_count? : Int, error_per_million? : Int, latency_p95_ms? : Int, saturation_bp? : Int, synthetic_pass? : Bool, dependency_failures? : Int) -> MetricsSnapshotpub(all) struct PhaseRecommendation {
next_percent_bp : Int
next_mode : RolloutMode
decision : GateDecision
title : String
rationale : String
action_items : Array[String]
} derive(Eq, Debug)pub(all) struct PlanChange {
field : String
kind : PlanChangeKind
before : String
after : String
severity : Severity
detail : String
} derive(Eq, Debug)fn PlanChange::PlanChange(field? : String, kind? : PlanChangeKind, before? : String, after? : String, severity? : Severity, detail? : String) -> PlanChangepub(all) struct PlanDiff {
verdict : String
risk_delta : Int
changes : Array[PlanChange]
} derive(Eq, Debug)pub(all) struct ReleaseEvidence {
applicant_name : String
github_owner : String
repository_name : String
mooncakes_package : String
version : String
ci_status : String
issue_records : Array[String]
test_records : Array[String]
release_notes : String
design_notes : String
license : String
} derive(Eq, Debug)fn ReleaseEvidence::ReleaseEvidence(applicant_name? : String, github_owner? : String, repository_name? : String, mooncakes_package? : String, version? : String, ci_status? : String, issue_records? : Array[String], test_records? : Array[String], release_notes? : String, design_notes? : String, license? : String) -> ReleaseEvidencefn RiskBudget::RiskBudget(max_error_per_million? : Int, max_latency_p95_ms? : Int, min_samples? : Int, max_saturation_bp? : Int, max_blast_radius_bp? : Int, require_synthetic_pass? : Bool, max_dependency_failures? : Int) -> RiskBudgetpub(all) struct RolloutFinding {
id : String
kind : ValidationKind
severity : Severity
title : String
detail : String
repair : String
evidence : String
penalty : Int
} derive(Eq, Debug)pub(all) struct RolloutPhase {
name : String
start_minute : Int
duration_minutes : Int
percent_bp : Int
mode : RolloutMode
require_manual_approval : Bool
} derive(Eq, Debug)fn RolloutPhase::RolloutPhase(name? : String, start_minute? : Int, duration_minutes? : Int, percent_bp? : Int, mode? : RolloutMode, require_manual_approval? : Bool) -> RolloutPhasepub(all) struct RolloutPlan {
name : String
salt : String
segments : Array[SegmentRule]
phases : Array[RolloutPhase]
budget : RiskBudget
owner : String
repository : String
package_name : String
} derive(Eq, Debug)fn RolloutPlan::RolloutPlan(name? : String, salt? : String, segments? : Array[SegmentRule], phases? : Array[RolloutPhase], budget? : RiskBudget, owner? : String, repository? : String, package_name? : String) -> RolloutPlanpub(all) struct RunbookRecord {
id : String
kind : RunbookRecordKind
state : RunbookState
title : String
evidence : String
owner : String
minute : Int
action : String
} derive(Eq, Debug)fn RunbookRecord::RunbookRecord(id? : String, kind? : RunbookRecordKind, state? : RunbookState, title? : String, evidence? : String, owner? : String, minute? : Int, action? : String) -> RunbookRecordpub(all) struct RunbookReport {
score : Int
verdict : String
records : Array[RunbookRecord]
findings : Array[RolloutFinding]
owner_count : Int
metric_count : Int
rollback_count : Int
approval_count : Int
release_count : Int
} derive(Eq, Debug)fn SegmentRule::SegmentRule(name? : String, include_regions? : Array[Region], exclude_regions? : Array[Region], include_tiers? : Array[UserTier], exclude_tiers? : Array[UserTier], require_tags? : Array[String], exclude_tags? : Array[String], min_version? : String, max_bucket_bp? : Int) -> SegmentRulepub(all) struct SimulationReport {
plan_name : String
verdict : String
score : Int
findings : Array[RolloutFinding]
steps : Array[SimulationStep]
final_gate : GateResult
blast_radius : BlastRadius
} derive(Eq, Debug)pub(all) struct SimulationStep {
minute : Int
phase_name : String
exposed_users : Int
exposed_traffic_units : Int
gate : GateResult
} derive(Eq, Debug)pub(all) struct TimelineEvent {
minute : Int
phase_name : String
kind : TimelineEventKind
mode : RolloutMode
percent_bp : Int
note : String
} derive(Eq, Debug)fn TimelineEvent::TimelineEvent(minute? : Int, phase_name? : String, kind? : TimelineEventKind, mode? : RolloutMode, percent_bp? : Int, note? : String) -> TimelineEventfn TrafficForecast::TrafficForecast(base_users? : Int, base_traffic_units? : Int, growth_bp_per_hour? : Int, peak_multiplier_bp? : Int, safety_margin_bp? : Int) -> TrafficForecastfn UserProfile::UserProfile(id? : String, region? : Region, tier? : UserTier, version? : String, tags? : Array[String], staff? : Bool, traffic_units? : Int) -> UserProfilefn blast_radius_for_users(plan : RolloutPlan, users : Array[UserProfile], minute : Int) -> BlastRadiusfn cohort_distribution(users : Array[UserProfile], salt : String, ring_count : Int) -> Array[String]fn compare_recommendations(left : PhaseRecommendation, right : PhaseRecommendation) -> PhaseRecommendationfn evaluate_control_rule(rule : ControlRule, plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> ControlEvaluationfn exposed_users(plan : RolloutPlan, users : Array[UserProfile], minute : Int) -> Array[UserProfile]fn in_percent_bucket(user_id : String, salt : String, percent_bp : Int) -> Boolfn incident_report(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot], minute : Int) -> IncidentReportfn matching_segment_names(user : UserProfile, segments : Array[SegmentRule], salt? : String) -> Array[String]fn metric_trend_gate(budget : RiskBudget, previous : MetricsSnapshot, current : MetricsSnapshot, blast : BlastRadius) -> GateResultfn metric_window(metrics : Array[MetricsSnapshot], start_minute : Int, end_minute : Int) -> MetricWindowfn metric_window_gate(budget : RiskBudget, previous : MetricWindow, current : MetricWindow, blast : BlastRadius) -> GateResultfn plan_report_json(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> Stringfn plan_report_markdown(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> Stringfn recommend_next_phase(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot], minute : Int) -> PhaseRecommendationfn review_controls(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> ControlReviewfn simulate_rollout(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> SimulationReportfn simulation_json(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> Stringfn simulation_markdown(plan : RolloutPlan, users : Array[UserProfile], metrics : Array[MetricsSnapshot]) -> StringInstall
Download zipDeterministic canary rollout planner and blast-radius simulator for MoonBit