voltweave

Offline household energy scheduling and outage resilience simulation

energy
scheduler
simulation
wasm
moonbit
moon add sujy123456/voltweave@0.1.0
Download zip
Version
0.1.0
License
Apache-2.0
Last updated
9 days ago
Downloads
2
README

#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.