voltweave

    Offline household energy scheduling and outage resilience simulation

    energy
    scheduler
    simulation
    wasm
    moonbit
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    last month
    Downloads
    7

    #VoltWeave(伏织)

    CI License MoonBit

    VoltWeave 是一个以 MoonBit 为主要实现语言、可离线运行的家庭用能调度与停电韧性仿真器。它把分时电价、碳排强度、屋顶光伏、家庭电池、固定或柔性电器以及停电事件放进同一套确定性模型,输出可执行计划、逐时能源流、风险区间和机器可读的决策解释。

    项目不控制真实电气设备,也不代替电工安全评估;它的边界是“规划、比较和仿真”。所有内置场景均在本地计算,无需云服务或外部 API。

    #为什么做 VoltWeave

    常见家庭能源项目偏向设备接入或实时看板;VoltWeave 专注于一个更明确的空白:在同一个离线内核中,同时处理电器时间窗、连续/可中断任务、配电功率上限、电池安全边界、停电保供优先级和不确定性复现,并给出稳定原因码。它不是 MoonBit 编译器、编辑器或包管理工具。

    #核心能力

    • 整数定点数据模型:功率 W、能量 Wh、金额微单位、效率千分比,跨后端结果可复现。
    • 约束调度:支持固定、可移峰、可中断、可放弃任务及四级保供优先级。
    • 储能调度:约束容量、充放电功率、效率、备用电量与停电期间的放电策略。
    • 多目标方案:费用、碳排、舒适度、韧性和电池损耗可配置,支持策略集与 Pareto 前沿。
    • 风险仿真:使用固定种子的确定性 PRNG 扰动光伏、基础负载及停电时段,输出分位数和风险等级。
    • 独立审计:重新检查数组形状、供需平衡、配电上限、停电约束、电池边界和任务时间窗。
    • 可解释输出:Markdown、CSV、ASCII 曲线、JSON 以及稳定的校验/审计原因码。
    • 双入口演示:MoonBit CLI 与浏览器 Wasm-GC 仪表盘,浏览器端不上传输入数据。

    #快速开始

    需要 MoonBit 工具链;本项目已用 moon 0.1.20260803 验证。

    git clone https://github.com/suqinxi/suqinxi.git cd suqinxi moon check --deny-warn moon test -p sujy123456/voltweave --deny-warn moon run cmd/voltweave -- demo

    常用命令:

    moon run cmd/voltweave -- compact # 紧凑公寓场景 moon run cmd/voltweave -- outage # 风暴停电场景 moon run cmd/voltweave -- compare # 五种目标策略比较 moon run cmd/voltweave -- simulate # 64 次确定性不确定性仿真 moon run cmd/voltweave -- validate # 输入校验报告 moon run cmd/voltweave -- json # JSON 计划结果 moon run cmd/voltweave -- input # JSON 示例输入 moon run cmd/voltweave -- chart # 终端功率曲线

    #浏览器 Wasm 演示

    moon build web/engine --target wasm-gc --release cp _build/wasm-gc/release/build/web/engine/engine.wasm web/app/voltweave.wasm python -m http.server 8765 --directory web/app

    访问 http://127.0.0.1:8765。Windows PowerShell 可用:

    Copy-Item _build/wasm-gc/release/build/web/engine/engine.wasm web/app/voltweave.wasm python -m http.server 8765 --directory web/app

    仓库提交了一个可直接演示的 Wasm 构建产物;源代码仍是唯一可信来源,发布前应重新执行上述构建。

    #项目结构

    domain.mbt 领域类型、JSON 合约与单位约定 validation.mbt 输入校验、稳定错误码与建议 optimizer.mbt 候选搜索、任务调度、电池能源流和 Pareto 比较 simulation.mbt 可复现采样、分布统计与敏感性分析 analytics.mbt 独立结果审计、资源充足性与方案差异 report.mbt Markdown、CSV、ASCII 报告 examples.mbt 三组可运行场景 cmd/voltweave/ MoonBit CLI web/engine/ Wasm-GC 外部接口 web/app/ 离线单页演示 docs/ 架构、使用、测试和发布文档

    #测试与构建

    moon fmt --check moon check --deny-warn moon test -p sujy123456/voltweave --deny-warn moon build cmd/voltweave --target wasm --release moon check web/engine --target wasm-gc --deny-warn moon build web/engine --target wasm-gc --release moon publish --dry-run

    目前包含 46 个可运行测试,覆盖模型序列化、校验、任务放置、电池流、停电约束、仿真可复现性、分位数、报告以及独立审计。为什么测试命令显式限定根包,见 docs/TESTING.md

    #文档与发布

    #功能边界与限制

    • 当前求解器是确定性有界搜索与启发式调度,不声称得到全局最优解。
    • 输入时间序列必须使用同一时间粒度;内置示例为 60 分钟、24 个时段。
    • 仿真结果用于比较相对风险,不是天气预测、财务承诺或电气安全证明。
    • 浏览器演示公开的是预编译内置场景;完整自定义 JSON 流程通过 MoonBit 库和 CLI 完成。

    #许可证

    Copyright 2026 苏琴茜。项目按 Apache License 2.0 开源。当前运行时代码没有第三方包依赖;许可证与素材核验结果见 docs/OPEN_SOURCE_REVIEW.md

    AdequacyProfile

    pub(all) struct AdequacyProfile {
    total_demand_wh : Int
    total_solar_wh : Int
    usable_battery_wh : Int
    outage_demand_wh : Int
    outage_solar_wh : Int
    outage_storage_margin_wh : Int
    peak_requested_w : Int
    weakest_supply_margin_w : Int
    weakest_supply_slot : Int
    critical_task_energy_wh : Int
    flexible_task_energy_wh : Int
    risk_codes : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Capacity and outage adequacy indicators computed before optimization.

    AdequacyProfile::to_json_string

    fn AdequacyProfile::to_json_string(self : AdequacyProfile) -> String

    AuditFinding

    pub(all) struct AuditFinding {
    code : String
    severity : AuditSeverity
    subject : String
    message : String
    slot : Int?
    expected : Int?
    actual : Int?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A stable, machine-readable audit result. Codes are intentionally kept separate from prose so downstream applications do not parse messages.

    AuditFinding::new

    fn AuditFinding::new(code : String, severity : AuditSeverity, subject : String, message : String, slot? : Int, expected? : Int, actual? : Int) -> AuditFinding

    AuditSeverity

    pub(all) enum AuditSeverity {
    AuditInfo
    AuditWarning
    AuditError
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Severity used by the independent result auditor.

    AuditSeverity::label

    fn AuditSeverity::label(self : AuditSeverity) -> String

    AuditSummary

    pub(all) struct AuditSummary {
    passed : Bool
    error_count : Int
    warning_count : Int
    info_count : Int
    maximum_balance_residual_w : Int
    maximum_grid_excess_w : Int
    minimum_battery_state_wh : Int
    maximum_battery_state_wh : Int
    findings : Array[AuditFinding]
    balances : Array[EnergyBalanceRow]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    AuditSummary::has_code

    fn AuditSummary::has_code(self : AuditSummary, code : String) -> Bool

    AuditSummary::to_json_string

    fn AuditSummary::to_json_string(self : AuditSummary) -> String

    BatterySpec

    pub(all) struct BatterySpec {
    name : String
    capacity_wh : Int
    initial_wh : Int
    reserve_wh : Int
    minimum_wh : Int
    maximum_wh : Int
    maximum_charge_w : Int
    maximum_discharge_w : Int
    charge_efficiency_permille : Int
    discharge_efficiency_permille : Int
    cycle_cost_micro_per_kwh : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Battery characteristics use watt-hours, watts, and permille efficiencies.

    BatterySpec::clamp_state

    fn BatterySpec::clamp_state(self : BatterySpec, state_wh : Int) -> Int

    BatterySpec::new

    fn BatterySpec::new(name : String, capacity_wh : Int, initial_wh : Int, reserve_wh : Int, maximum_charge_w : Int, maximum_discharge_w : Int) -> BatterySpec

    BatterySpec::state_permille

    fn BatterySpec::state_permille(self : BatterySpec, state_wh : Int) -> Int

    BatterySpec::usable_wh

    fn BatterySpec::usable_wh(self : BatterySpec) -> Int

    BatteryStep

    pub(all) struct BatteryStep {
    slot : Int
    state_before_wh : Int
    power_w : Int
    state_after_wh : Int
    source : String
    reason : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Positive battery power means charging; negative means discharging.

    BatteryStep::charged_wh

    fn BatteryStep::charged_wh(self : BatteryStep) -> Int

    BatteryStep::discharged_wh

    fn BatteryStep::discharged_wh(self : BatteryStep) -> Int

    CandidatePlacement

    pub(all) struct CandidatePlacement {
    task_id : String
    start_slot : Int
    end_slot : Int
    energy_cost_component : Int
    carbon_component : Int
    comfort_component : Int
    resilience_component : Int
    capacity_excess_w : Int
    solar_overlap_wh : Int
    total_score : Int
    feasible : Bool
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Diagnostic score for a candidate task placement.

    CandidatePlacement::duration_slots

    fn CandidatePlacement::duration_slots(self : CandidatePlacement) -> Int

    DispatchResult

    type DispatchResult derive(
    Debug
    )

    DistributionSummary

    pub(all) struct DistributionSummary {
    minimum : Int
    p10 : Int
    median : Int
    p90 : Int
    p95 : Int
    maximum : Int
    mean : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    EnergyBalanceRow

    pub(all) struct EnergyBalanceRow {
    slot : Int
    demand_w : Int
    served_demand_w : Int
    grid_w : Int
    solar_w : Int
    battery_charge_w : Int
    battery_discharge_w : Int
    unserved_w : Int
    supply_w : Int
    accounted_use_w : Int
    residual_w : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Per-slot reconstruction of supply, demand, storage, and residual energy.

    EnergyBalanceRow::is_balanced

    fn EnergyBalanceRow::is_balanced(self : EnergyBalanceRow, tolerance_w? : Int) -> Bool

    Explanation

    pub(all) struct Explanation {
    code : String
    severity : String
    subject : String
    message : String
    slot : Int?
    evidence : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A machine-readable explanation tied to a plan decision.

    Explanation::info

    fn Explanation::info(code : String, subject : String, message : String, slot? : Int) -> Explanation

    Explanation::warning

    fn Explanation::warning(code : String, subject : String, message : String, slot? : Int) -> Explanation

    IntSeries

    pub(all) struct IntSeries {
    name : String
    unit : String
    slot_minutes : Int
    values : Array[Int]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A regular time grid represented using integer values.

    Values are deliberately unit-agnostic so the same type can carry prices, carbon intensity, solar power, or a capacity limit.

    IntSeries::at

    fn IntSeries::at(self : IntSeries, slot : Int) -> Int

    IntSeries::average

    fn IntSeries::average(self : IntSeries) -> Int

    IntSeries::copy_values

    fn IntSeries::copy_values(self : IntSeries) -> Array[Int]

    IntSeries::length

    fn IntSeries::length(self : IntSeries) -> Int

    IntSeries::maximum

    fn IntSeries::maximum(self : IntSeries) -> Int

    IntSeries::minimum

    fn IntSeries::minimum(self : IntSeries) -> Int

    IntSeries::new

    fn IntSeries::new(name : String, unit : String, slot_minutes : Int, values : Array[Int]) -> IntSeries

    IntSeries::scale_permille

    fn IntSeries::scale_permille(self : IntSeries, factor_permille : Int) -> IntSeries

    IntSeries::sum

    fn IntSeries::sum(self : IntSeries) -> Int

    IntSeries::with_value

    fn IntSeries::with_value(self : IntSeries, slot : Int, value : Int) -> IntSeries

    IssueLevel

    pub(all) enum IssueLevel {
    Error
    Warning
    Advice
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    IssueLevel::label

    fn IssueLevel::label(self : IssueLevel) -> String

    LoadTask

    pub(all) struct LoadTask {
    id : String
    name : String
    mode : TaskMode
    priority : Priority
    power_w : Int
    duration_slots : Int
    earliest_start : Int
    latest_end : Int
    preferred_start : Int
    fixed_start : Int
    minimum_run_slots : Int
    maximum_interruptions : Int
    comfort_penalty_per_slot : Int
    skip_penalty : Int
    tags : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A schedulable household load.

    LoadTask::energy_wh

    fn LoadTask::energy_wh(self : LoadTask, slot_minutes : Int) -> Int

    LoadTask::fixed

    fn LoadTask::fixed(id : String, name : String, power_w : Int, duration_slots : Int, fixed_start : Int, priority? : Priority) -> LoadTask

    LoadTask::interruptible

    fn LoadTask::interruptible(id : String, name : String, power_w : Int, duration_slots : Int, earliest_start : Int, latest_end : Int, preferred_start : Int, maximum_interruptions : Int, priority? : Priority) -> LoadTask

    LoadTask::is_required

    fn LoadTask::is_required(self : LoadTask) -> Bool

    LoadTask::latest_start

    fn LoadTask::latest_start(self : LoadTask) -> Int

    LoadTask::optional

    fn LoadTask::optional(id : String, name : String, power_w : Int, duration_slots : Int, earliest_start : Int, latest_end : Int, preferred_start : Int, priority? : Priority) -> LoadTask

    LoadTask::shiftable

    fn LoadTask::shiftable(id : String, name : String, power_w : Int, duration_slots : Int, earliest_start : Int, latest_end : Int, preferred_start : Int, priority? : Priority) -> LoadTask

    LoadTask::window_slots

    fn LoadTask::window_slots(self : LoadTask) -> Int

    LoadTask::with_tag

    fn LoadTask::with_tag(self : LoadTask, tag : String) -> LoadTask

    ObjectiveWeights

    pub(all) struct ObjectiveWeights {
    cost : Int
    carbon : Int
    comfort : Int
    resilience : Int
    battery_wear : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Integer weights make scoring deterministic across all MoonBit backends.

    ObjectiveWeights::balanced

    ObjectiveWeights::for_policy

    ObjectiveWeights::normalized

    ObjectiveWeights::total

    fn ObjectiveWeights::total(self : ObjectiveWeights) -> Int

    OutageEvent

    pub(all) struct OutageEvent {
    id : String
    start_slot : Int
    end_slot : Int
    grid_limit_w : Int
    reserve_override_wh : Int?
    description : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    An interval where the public grid is unavailable or capped.

    OutageEvent::blackout

    fn OutageEvent::blackout(id : String, start_slot : Int, end_slot : Int, description? : String) -> OutageEvent

    OutageEvent::contains

    fn OutageEvent::contains(self : OutageEvent, slot : Int) -> Bool

    OutageEvent::duration_slots

    fn OutageEvent::duration_slots(self : OutageEvent) -> Int

    PlanComparison

    pub(all) struct PlanComparison {
    baseline : PlanResult
    optimized : PlanResult
    cost_saving_micro : Int
    carbon_saving_g : Int
    peak_reduction_w : Int
    resilience_gain_permille : Int
    recommendation : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    PlanDelta

    pub(all) struct PlanDelta {
    baseline_title : String
    candidate_title : String
    cost_delta_micro : Int
    carbon_delta_g : Int
    peak_delta_w : Int
    unserved_delta_wh : Int
    critical_unserved_delta_wh : Int
    resilience_delta_permille : Int
    comfort_delta : Int
    completed_task_delta : Int
    candidate_dominates : Bool
    baseline_dominates : Bool
    tradeoff_count : Int
    summary : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A compact comparison between two valid optimizer outputs.

    PlanDelta::to_json_string

    fn PlanDelta::to_json_string(self : PlanDelta) -> String

    PlanMetrics

    pub(all) struct PlanMetrics {
    imported_energy_wh : Int
    exported_energy_wh : Int
    solar_used_wh : Int
    solar_curtailed_wh : Int
    battery_charged_wh : Int
    battery_discharged_wh : Int
    cost_micro : Int
    export_credit_micro : Int
    carbon_g : Int
    comfort_penalty : Int
    unserved_energy_wh : Int
    critical_unserved_wh : Int
    completed_tasks : Int
    skipped_tasks : Int
    peak_grid_w : Int
    resilience_permille : Int
    score : Int64
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Aggregate objective values. Money is stored in micro currency units.

    PlanMetrics::empty

    fn PlanMetrics::empty() -> PlanMetrics

    PlanMetrics::net_cost_micro

    fn PlanMetrics::net_cost_micro(self : PlanMetrics) -> Int

    PlanMetrics::served_energy_wh

    fn PlanMetrics::served_energy_wh(self : PlanMetrics) -> Int

    PlanResult

    pub(all) struct PlanResult {
    title : String
    status : PlanStatus
    slot_minutes : Int
    horizon_slots : Int
    schedule : Array[ScheduleEntry]
    battery_steps : Array[BatteryStep]
    load_w : Array[Int]
    grid_w : Array[Int]
    solar_used_w : Array[Int]
    unserved_w : Array[Int]
    battery_state_wh : Array[Int]
    skipped_task_ids : Array[String]
    metrics : PlanMetrics
    explanations : Array[Explanation]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Full optimizer output used by the CLI, web demo, and JSON API.

    PlanResult::empty

    fn PlanResult::empty(title : String, slots : Int, slot_minutes : Int) -> PlanResult

    PlanResult::entry_for

    fn PlanResult::entry_for(self : PlanResult, task_id : String) -> ScheduleEntry?

    PlanResult::grid_peak_slot

    fn PlanResult::grid_peak_slot(self : PlanResult) -> Int

    PlanResult::is_task_scheduled

    fn PlanResult::is_task_scheduled(self : PlanResult, task_id : String) -> Bool

    PlanResult::to_json_string

    fn PlanResult::to_json_string(self : PlanResult) -> String

    PlanResult::total_unserved_wh

    fn PlanResult::total_unserved_wh(self : PlanResult) -> Int

    PlanStatus

    pub(all) enum PlanStatus {
    Feasible
    FeasibleWithCurtailment
    Infeasible
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    PlanStatus::label

    fn PlanStatus::label(self : PlanStatus) -> String

    PlanningInput

    pub(all) struct PlanningInput {
    title : String
    slot_minutes : Int
    horizon_slots : Int
    tariff_micro_per_kwh : IntSeries
    carbon_g_per_kwh : IntSeries
    solar_w : IntSeries
    base_load_w : IntSeries
    grid_limit_w : IntSeries
    tasks : Array[LoadTask]
    battery : BatterySpec?
    outages : Array[OutageEvent]
    weights : ObjectiveWeights
    allow_grid_export : Bool
    export_credit_micro_per_kwh : Int
    random_seed : UInt
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Complete input contract for the optimizer.

    PlanningInput::empty

    fn PlanningInput::empty(title : String, slots : Int) -> PlanningInput

    PlanningInput::grid_limit_at

    fn PlanningInput::grid_limit_at(self : PlanningInput, slot : Int) -> Int

    PlanningInput::has_outage_at

    fn PlanningInput::has_outage_at(self : PlanningInput, slot : Int) -> Bool

    PlanningInput::to_json_string

    fn PlanningInput::to_json_string(self : PlanningInput) -> String

    PlanningInput::total_solar_energy_wh

    fn PlanningInput::total_solar_energy_wh(self : PlanningInput) -> Int

    PlanningInput::total_task_energy_wh

    fn PlanningInput::total_task_energy_wh(self : PlanningInput) -> Int

    PlanningInput::with_outage

    fn PlanningInput::with_outage(self : PlanningInput, outage : OutageEvent) -> PlanningInput

    PlanningInput::with_task

    fn PlanningInput::with_task(self : PlanningInput, task : LoadTask) -> PlanningInput

    PlanningPolicy

    pub(all) enum PlanningPolicy {
    Balanced
    LowestCost
    LowestCarbon
    HighestComfort
    HighestResilience
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Policy used when several valid plans are available.

    PlanningPolicy::label

    fn PlanningPolicy::label(self : PlanningPolicy) -> String

    Priority

    pub(all) enum Priority {
    Critical
    High
    Normal
    Low
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Relative importance of a task during normal and outage operation.

    Priority::label

    fn Priority::label(self : Priority) -> String

    Priority::rank

    fn Priority::rank(self : Priority) -> Int

    RiskBand

    pub(all) enum RiskBand {
    LowRisk
    ModerateRisk
    HighRisk
    CriticalRisk
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    RiskBand::label

    fn RiskBand::label(self : RiskBand) -> String

    ScenarioSample

    pub(all) struct ScenarioSample {
    index : Int
    seed : UInt
    solar_factor_permille : Int
    base_load_factor_permille : Int
    tariff_factor_permille : Int
    largest_spike_slot : Int
    largest_spike_w : Int
    outage_start_slots : Array[Int]
    outage_duration_slots : Array[Int]
    input : PlanningInput
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    ScheduleEntry

    pub(all) struct ScheduleEntry {
    task_id : String
    task_name : String
    start_slot : Int
    end_slot : Int
    power_w : Int
    energy_wh : Int
    priority : Priority
    reason : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A chosen execution interval. Interruptible tasks may have several entries.

    ScheduleEntry::contains

    fn ScheduleEntry::contains(self : ScheduleEntry, slot : Int) -> Bool

    ScheduleEntry::duration_slots

    fn ScheduleEntry::duration_slots(self : ScheduleEntry) -> Int

    SensitivityCase

    pub(all) struct SensitivityCase {
    id : String
    label : String
    changed_parameter : String
    change_permille : Int
    status : PlanStatus
    metrics : PlanMetrics
    delta_cost_micro : Int
    delta_carbon_g : Int
    delta_unserved_wh : Int
    delta_resilience_permille : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    SimulationRun

    pub(all) struct SimulationRun {
    index : Int
    seed : UInt
    solar_factor_permille : Int
    base_load_factor_permille : Int
    tariff_factor_permille : Int
    largest_spike_slot : Int
    largest_spike_w : Int
    outage_duration_slots : Array[Int]
    status : PlanStatus
    metrics : PlanMetrics
    scheduled_tasks : Int
    explanation_count : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    SimulationRun::from_sample

    fn SimulationRun::from_sample(sample : ScenarioSample, result : PlanResult) -> SimulationRun

    SimulationSummary

    pub(all) struct SimulationSummary {
    title : String
    requested_runs : Int
    completed_runs : Int
    feasible_runs : Int
    infeasible_runs : Int
    risk_band : RiskBand
    cost_micro : DistributionSummary
    carbon_g : DistributionSummary
    unserved_energy_wh : DistributionSummary
    critical_unserved_wh : DistributionSummary
    peak_grid_w : DistributionSummary
    resilience_permille : DistributionSummary
    worst_run_index : Int
    best_run_index : Int
    runs : Array[SimulationRun]
    recommendations : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    SimulationSummary::feasibility_permille

    fn SimulationSummary::feasibility_permille(self : SimulationSummary) -> Int

    SimulationSummary::to_json_string

    fn SimulationSummary::to_json_string(self : SimulationSummary) -> String

    SolverConfig

    pub(all) struct SolverConfig {
    maximum_candidates_per_task : Int
    prefer_solar : Bool
    allow_grid_charging : Bool
    preserve_reserve_outside_outage : Bool
    capacity_violation_penalty : Int
    outage_violation_penalty : Int
    optional_skip_threshold : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Runtime limits and deterministic heuristics for the scheduler.

    SolverConfig::default

    fn SolverConfig::default() -> SolverConfig

    TaskMode

    pub(all) enum TaskMode {
    Fixed
    Shiftable
    Interruptible
    Optional
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Scheduling semantics for a household task.

    TaskMode::is_flexible

    fn TaskMode::is_flexible(self : TaskMode) -> Bool

    TaskMode::label

    fn TaskMode::label(self : TaskMode) -> String

    TaskMode::may_skip

    fn TaskMode::may_skip(self : TaskMode) -> Bool

    UncertaintyConfig

    pub(all) struct UncertaintyConfig {
    solar_min_permille : Int
    solar_max_permille : Int
    base_load_min_permille : Int
    base_load_max_permille : Int
    tariff_min_permille : Int
    tariff_max_permille : Int
    outage_start_jitter_slots : Int
    outage_duration_jitter_slots : Int
    temporary_spike_probability_permille : Int
    temporary_spike_min_w : Int
    temporary_spike_max_w : Int
    correlated_signal_permille : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Bounds for deterministic uncertainty sampling, expressed in permille.

    UncertaintyConfig::conservative

    fn UncertaintyConfig::conservative() -> UncertaintyConfig

    UncertaintyConfig::none

    UncertaintyConfig::typical

    ValidationCode

    pub(all) enum ValidationCode {
    InvalidHorizon
    InvalidSlotMinutes
    SeriesLengthMismatch
    SeriesSlotMismatch
    NegativeSeriesValue
    InvalidTaskId
    DuplicateTaskId
    InvalidTaskPower
    InvalidTaskDuration
    InvalidTaskWindow
    FixedTaskOutsideWindow
    InvalidInterruptionRule
    InvalidBatteryCapacity
    InvalidBatteryState
    InvalidBatteryPower
    InvalidBatteryEfficiency
    InvalidBatteryReserve
    InvalidOutageWindow
    InvalidGridLimit
    InvalidObjectiveWeights
    ImpossibleRequiredTask
    PeakCapacityRisk
    MissingTariffVariation
    MissingCarbonVariation
    ExportWithoutCredit
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Stable validation codes suitable for CLI and web clients.

    ValidationCode::label

    fn ValidationCode::label(self : ValidationCode) -> String

    ValidationIssue

    pub(all) struct ValidationIssue {
    code : ValidationCode
    level : IssueLevel
    path : String
    message : String
    hint : String
    slot : Int?
    task_id : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    ValidationIssue::advice

    fn ValidationIssue::advice(code : ValidationCode, path : String, message : String, hint : String) -> ValidationIssue

    ValidationIssue::at_slot

    fn ValidationIssue::at_slot(self : ValidationIssue, slot : Int) -> ValidationIssue

    ValidationIssue::error

    fn ValidationIssue::error(code : ValidationCode, path : String, message : String, hint? : String) -> ValidationIssue

    ValidationIssue::for_task

    fn ValidationIssue::for_task(self : ValidationIssue, task_id : String) -> ValidationIssue

    ValidationIssue::warning

    fn ValidationIssue::warning(code : ValidationCode, path : String, message : String, hint? : String) -> ValidationIssue

    ValidationReport

    pub(all) struct ValidationReport {
    issues : Array[ValidationIssue]
    checked_tasks : Int
    checked_slots : Int
    estimated_required_peak_w : Int
    estimated_required_energy_wh : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    ValidationReport::advice_count

    fn ValidationReport::advice_count(self : ValidationReport) -> Int

    ValidationReport::empty

    ValidationReport::error_count

    fn ValidationReport::error_count(self : ValidationReport) -> Int

    ValidationReport::has_code

    fn ValidationReport::has_code(self : ValidationReport, code : ValidationCode) -> Bool

    ValidationReport::is_valid

    fn ValidationReport::is_valid(self : ValidationReport) -> Bool

    ValidationReport::messages

    fn ValidationReport::messages(self : ValidationReport) -> Array[String]

    ValidationReport::warning_count

    fn ValidationReport::warning_count(self : ValidationReport) -> Int

    apply_safe_defaults

    fn apply_safe_defaults(input : PlanningInput) -> PlanningInput

    Return a repaired copy for safe, explicitly documented defaults. Structural errors such as impossible windows are intentionally not hidden.

    assess_adequacy

    fn assess_adequacy(input : PlanningInput) -> AdequacyProfile

    Estimate resource adequacy before scheduling. This deliberately reports a conservative envelope rather than claiming that aggregate energy guarantees a feasible schedule.

    audit_markdown

    fn audit_markdown(summary : AuditSummary) -> String

    audit_plan

    fn audit_plan(input : PlanningInput, result : PlanResult, balance_tolerance_w? : Int) -> AuditSummary

    Independently audit a plan against its original input. The auditor does not call the optimizer and therefore also catches regression defects in solve().

    built_in_examples

    fn built_in_examples() -> Array[(String, PlanningInput)]

    All built-in examples with stable identifiers.

    candidate_placements

    fn candidate_placements(input : PlanningInput, task : LoadTask, current_load_w : Array[Int], config? : SolverConfig) -> Array[CandidatePlacement]

    capability_summary

    fn capability_summary() -> String

    Short capability summary used by smoke tests and package documentation.

    compact_apartment_example

    fn compact_apartment_example() -> PlanningInput

    Small apartment without solar or storage.

    compare_plans

    fn compare_plans(baseline : PlanResult, candidate : PlanResult) -> PlanDelta

    Compare plans using decision-facing deltas rather than their weighted score, because scores from different objective policies are not directly comparable.

    compare_with_baseline

    fn compare_with_baseline(input : PlanningInput, config? : SolverConfig) -> PlanComparison

    comparison_markdown

    fn comparison_markdown(comparison : PlanComparison) -> String

    evaluate_candidate

    fn evaluate_candidate(input : PlanningInput, task : LoadTask, start_slot : Int, current_load_w : Array[Int], config? : SolverConfig) -> CandidatePlacement

    Evaluate a contiguous placement against the current provisional load.

    example_by_id

    fn example_by_id(id : String) -> PlanningInput?

    format_energy_wh

    fn format_energy_wh(value : Int) -> String

    format_money_micro

    fn format_money_micro(value : Int) -> String

    format_slot

    fn format_slot(slot : Int, slot_minutes : Int) -> String

    home_day_example

    fn home_day_example() -> PlanningInput

    Full household example used by the CLI, README, and web engine.

    most_influential_case

    fn most_influential_case(cases : Array[SensitivityCase]) -> SensitivityCase?

    pareto_frontier

    fn pareto_frontier(results : Array[(PlanningPolicy, PlanResult)]) -> Array[(PlanningPolicy, PlanResult)]

    Remove policy results that are worse on every reported objective.

    plan_ascii_chart

    fn plan_ascii_chart(result : PlanResult, width? : Int) -> String

    plan_csv

    fn plan_csv(result : PlanResult) -> String

    plan_markdown

    fn plan_markdown(result : PlanResult) -> String

    Render a complete review-friendly Markdown plan report.

    plan_result_from_json

    fn plan_result_from_json(source : String) -> PlanResult raise

    plan_timeline

    fn plan_timeline(result : PlanResult) -> String

    planning_input_from_json

    fn planning_input_from_json(source : String) -> PlanningInput raise

    project_name

    let project_name : String

    Human-readable project name.

    reconstruct_energy_balance

    fn reconstruct_energy_balance(result : PlanResult) -> Array[EnergyBalanceRow]

    sample_scenario

    fn sample_scenario(input : PlanningInput, config : UncertaintyConfig, index : Int) -> ScenarioSample

    Generate a single reproducible uncertainty sample.

    sensitivity_analysis

    fn sensitivity_analysis(input : PlanningInput) -> Array[SensitivityCase]

    Evaluate transparent one-at-a-time changes for key planning assumptions.

    simulate

    fn simulate(input : PlanningInput, runs? : Int, uncertainty? : UncertaintyConfig, solver_config? : SolverConfig) -> SimulationSummary

    Run reproducible scenario analysis. Each sample is derived from the input seed.

    simulation_markdown

    fn simulation_markdown(summary : SimulationSummary) -> String

    solve

    fn solve(original_input : PlanningInput, config? : SolverConfig) -> PlanResult

    Produce a deterministic energy plan for a validated input.

    solve_policy_set

    fn solve_policy_set(input : PlanningInput, config? : SolverConfig) -> Array[(PlanningPolicy, PlanResult)]

    Solve the same scenario for all supported policies.

    solve_preferred_baseline

    fn solve_preferred_baseline(input : PlanningInput) -> PlanResult

    Create a simple preferred-time baseline without changing the input contract.

    storm_outage_example

    fn storm_outage_example() -> PlanningInput

    Household storm scenario with a six-hour evening blackout.

    summarize_distribution

    fn summarize_distribution(values : Array[Int]) -> DistributionSummary

    validate

    fn validate(input : PlanningInput) -> ValidationReport

    Validate a complete planning request without modifying it.

    validation_markdown

    fn validation_markdown(report : ValidationReport) -> String

    version

    let version : String

    Semantic version exposed by the library and CLI.