Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/stable-energyplan-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Use Energyplan by default on stable releases too, as betas already do. A beta box that moves to stable keeps the planner it has run, and a new stable install starts with Energyplan. Core DP still runs as shadow and fallback, and `planner.engine: core` still selects it.
4 changes: 2 additions & 2 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,11 @@ fleet_ping:
# ftw-drivers-2026-01: MX+j27UBkyM099hTyJlmMLK9qlTTDUJsaK/vH12fFKc=
# Refresh only updates the signed catalog. Install and activation stay explicit.

# Energyplan ships with Core and runs first in supported beta builds.
# Energyplan ships with Core and runs first in supported beta and stable builds.
# Core DP provides shadow comparisons and validated fallback plans.
# planner:
# enabled: true
# # engine: energyplan # beta default; core selects the Go planner
# # engine: energyplan # release default; core selects the Go planner
# mode: passive_arbitrage
# forecast_trust: balanced # cautious | balanced | bold (first boot; live value is SQLite)
# battery_export: unknown # unknown | not_allowed | allowed (unknown = no battery sale)
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,14 @@ remains explicit and atomic. See

## Optimizer

Beta releases use the bundled Energyplan worker when `planner.engine` is unset
Beta and stable releases use the bundled Energyplan worker when `planner.engine` is unset
on a supported host. It solves Core's downside PV forecast. Core validates its
plan before publishing it, then runs a bounded Core DP shadow on the same input.
A worker error, timeout or rejected plan invokes Core DP fallback. Core validates
fallback plans too; a failed validation leaves the prior plan in place.

`planner.engine: core` or `energyplan` selects an engine explicitly.
Stable and development builds default to Core. Older `engine: python` values
Development builds and other hosts default to Core. Older `engine: python` values
migrate to Energyplan; retired optimizer settings are ignored and omitted
when the configuration is saved.
Energyplan ships as compiled binaries with its own license; source and builds
Expand Down
7 changes: 4 additions & 3 deletions go/cmd/ftw/energyplan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"github.com/srcfl/ftw/go/internal/config"
)

func TestEnergyplanBetaSelection(t *testing.T) {
func TestEnergyplanReleaseSelection(t *testing.T) {
for _, tc := range []struct{ version, engine, want string }{
{"v2.15.0-beta.1", "", "energyplan"},
{"v2.15.0", "", "core"},
{"v2.15.0", "", "energyplan"},
{"v0.140.1-dev.83867213", "", "core"},
{"dev", "", "core"},
{"dev-beta.invalid", "", "core"},
{"v2.15.0-beta.1", "core", "core"},
Expand Down Expand Up @@ -64,7 +65,7 @@ func TestBuildMPCBatterylessEngineAdmission(t *testing.T) {
want bool
}{
{"explicit Core in beta", "v3.1.0-beta.1", "core", false},
{"stable default", "v3.1.0", "", false},
{"stable default", "v3.1.0", "", energyplanSupported(runtime.GOOS, runtime.GOARCH)},
{"development default", "dev", "", false},
{"invalid beta default", "dev-beta.invalid", "", false},
{"explicit Energyplan", "v3.1.0", "energyplan", true},
Expand Down
9 changes: 8 additions & 1 deletion go/internal/api/api_mpc_unavailable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"runtime"
"testing"

"github.com/srcfl/ftw/go/internal/config"
Expand All @@ -12,6 +13,12 @@ import (

func TestMPCDisabledEndpointsNameTheSkipReason(t *testing.T) {
t.Parallel()
// Releases default to Energyplan where the worker ships, and Energyplan
// plans without a battery; elsewhere the default is Core DP.
stableDefault := mpc.ReasonNoBatteryCapacity
if config.SupportsBundledEnergyplan(runtime.GOOS, runtime.GOARCH) {
stableDefault = ""
}
cases := []struct {
name string
deps *Deps
Expand Down Expand Up @@ -47,7 +54,7 @@ func TestMPCDisabledEndpointsNameTheSkipReason(t *testing.T) {
Planner: &config.Planner{Enabled: true},
Price: &config.Price{Provider: "elprisetjustnu"},
}},
want: mpc.ReasonNoBatteryCapacity,
want: stableDefault,
},
{
name: "batteryless development default",
Expand Down
2 changes: 1 addition & 1 deletion go/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ const (
PlannerEngineEnergyplan = "energyplan"
)

// EngineName resolves an explicit engine. The launcher applies beta defaults
// EngineName resolves an explicit engine. The launcher applies release defaults
// before calling this method; an unset value here keeps Core for other callers.
func (p *Planner) EngineName() string {
if p == nil {
Expand Down
6 changes: 4 additions & 2 deletions go/internal/config/planner_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
"strings"
)

var plannerBetaVersion = regexp.MustCompile(`^v[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+$`)
var plannerReleaseVersion = regexp.MustCompile(`^v[0-9]+\.[0-9]+\.[0-9]+(-beta\.[0-9]+)?$`)

// EngineForBuild applies the same release default for planner admission and
// API diagnostics. Explicit choices, including legacy aliases, take precedence.
// Beta and stable releases default to the bundled Energyplan worker on a
// supported host; development builds default to Core.
Comment on lines +12 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the remaining docs for the stable default

This stable-default change leaves go/internal/config/config.go:693 saying an unset engine uses Energyplan only in betas, while optimizer/native/README.md:53-56 still explicitly says stable builds default to Core. Maintainers following either description can unintentionally select Energyplan on a stable Linux installation, so both references should be updated with the other documentation in this commit.

AGENTS.md reference: AGENTS.md:L274-L275

Useful? React with 👍 / 👎.

func (p *Planner) EngineForBuild(version, goos, goarch string) string {
if p != nil && strings.TrimSpace(p.Engine) != "" {
return p.EngineName()
}
if plannerBetaVersion.MatchString(version) && SupportsBundledEnergyplan(goos, goarch) {
if plannerReleaseVersion.MatchString(version) && SupportsBundledEnergyplan(goos, goarch) {
return PlannerEngineEnergyplan
}
return PlannerEngineCore
Expand Down
6 changes: 5 additions & 1 deletion go/internal/config/planner_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ func TestPlannerEngineForBuild(t *testing.T) {
{"v3.1.0-beta.1", "", "windows", "amd64", PlannerEngineCore},
{"v3.1.0-beta.1", "", "linux", "arm", PlannerEngineCore},
{"v3.1.0-beta.1", "core", "linux", "arm64", PlannerEngineCore},
{"v3.1.0", "", "linux", "arm64", PlannerEngineCore},
{"v3.1.0", "", "linux", "arm64", PlannerEngineEnergyplan},
{"v0.140.1", "", "linux", "amd64", PlannerEngineEnergyplan},
{"v0.140.1", "", "darwin", "arm64", PlannerEngineCore},
{"v0.140.1", "core", "linux", "arm64", PlannerEngineCore},
{"v0.140.1-dev.83867213", "", "linux", "arm64", PlannerEngineCore},
{"dev", "", "linux", "arm64", PlannerEngineCore},
{"dev-beta.invalid", "", "linux", "arm64", PlannerEngineCore},
{"v3.1.0-beta.", "", "linux", "arm64", PlannerEngineCore},
Expand Down
2 changes: 1 addition & 1 deletion web/settings/tabs/planner.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
var options = [["", "Automatic (release default)"], ["energyplan", "Energyplan"],
["core", "Core DP"]];
return '<label for="planner-engine">Engine ' +
help("Automatic uses Energyplan in supported beta builds and Core DP elsewhere. Energyplan runs Core DP as a shadow and uses it as fallback. Changing the engine requires a restart.") +
help("Automatic uses Energyplan in supported beta and stable builds and Core DP elsewhere. Energyplan runs Core DP as a shadow and uses it as fallback. Changing the engine requires a restart.") +
'</label><select id="planner-engine" data-path="planner.engine">' +
options.map(function (option) {
return '<option value="' + option[0] + '"' + (selected === option[0] ? ' selected' : '') + '>' + option[1] + '</option>';
Expand Down
Loading