Skip to content

refactor(control): remove the priority and weighted modes - #1453

Merged
frahlg merged 3 commits into
masterfrom
refactor/remove-priority-weighted-modes
Sep 27, 2026
Merged

frahlg merged 3 commits into
masterfrom
refactor/remove-priority-weighted-modes

Conversation

@frahlg

@frahlg frahlg commented Sep 27, 2026

Copy link
Copy Markdown
Member

Contract-pair: srcfl/ftw-webapp@follow-core/modes-and-boost

Paired with srcfl/ftw-webapp#73, which drops the same two keys from its copy of contract/registry.yaml.

Round 2 of the multi-agent hardening and refactor review. A skeptic confirmed each finding against the code, and a second reviewer checked this diff and ran its tests. Removals follow the owner decisions of 2026-09-26.

Changes

  • docs: Lua-first driver authoring guide #7 Removed ModePriority/ModeWeighted, State.PriorityOrder and Weights, distributePriority/distributeWeighted, their revision.go hashing, the ModeCatalog entries, the contract/registry.yaml modes (contract_gen.go regenerated) and the HA select options, which come from AllModes. Also removed the never-read batteries..weight config key and its Settings > Batteries field, and deleted it from stored settings through DropRetiredSettings. At boot, restoreStoredMode (go/cmd/ftw/control_state.go) turns a stored 'priority' or 'weighted' into self_consumption, saves it and logs one Warn line. The API, HA and app refuse both modes through IsValidMode/ApplyMode. Dropped the 60 golden records for these modes: the seeded rotations keep their slots so every other record keeps its seed, and the diff is deletions only (611 to 551). The e2e target-following step now runs in self_consumption. …
    • Test: go/internal/api/api_test.go TestHandleSetModeRefusesRemovedModes (POST /api/mode priority/weighted returns 400 and is not persisted; before the fix it returned 200). go/cmd/ftw/control_state_test.go TestRestoreStoredModeMapsRemovedModesToSelfConsumption and …
  • telemetry: add DerEV type (EV charging Unit 1/5) #34 haCallbacks.SetMode now builds an appModes and calls appModes.SetMode. It goes through control.ApplyMode, logs a failed save instead of returning early, still applies ApplyExportFromMode, and replans in a goroutine instead of inside the paho handler. appModes' log line is now generic ('could not persist the mode').
    • Test: go/cmd/ftw/app_link_test.go TestHomeAssistantSetModeFinishesWhenTheModeCannotBeSaved. With a closed store, SetMode(planner_arbitrage) returns nil, applies the mode, clears the manual hold and sets battery export to allowed; SetMode('priority') is refused. The old code returned 'sql: database is …
  • control: fold live DerEV readings into the EV clamp (EV Unit 3/5) #36 Deleted the unread control.State.UseCascade field and its NewState initializer. Nothing stored it, so there was no stored state to handle.
    • Test: Removal only. go build ./..., go vet and the control tests pass.
  • ocpp: OCPP 1.6J Central System for EV chargers (EV Unit 4/5) #37 Removed Planner.UseEnergyDispatch. New go/internal/config/retired_control.go: Parse (YAML) and decodeStored (state.db JSON) turn planner.use_energy_dispatch into planner.legacy_dispatch = !value. The old key still wins over legacy_dispatch, as before. This adds one Retired notice, and DropRetiredSettings then deletes the key (and battery weights) from the stored document. A new energyDispatchEnabled(cfg) helper is used at boot and on hot reload, so a reload that removes the planner section no longer keeps the legacy path.
    • Test: go/internal/config/retired_control_test.go TestUseEnergyDispatchLoadsAsLegacyDispatch (4 cases) and TestStoredRetiredControlSettingsMigrateAndAreDeleted (stored doc migrated, rewritten without use_energy_dispatch/weight, legacy choice and soc_min kept, second drop is a no-op). …

Evidence

From /home/fredde/repos/ftw/.claude/worktrees/wf_8f55b108-a0d-3/go with the session toolchain (go1.26.8) and GOTMPDIR=/home/fredde/.cache/go-tmp:

  • gofmt -l on the changed non-test Go files: no output, PASS
  • go build ./...: PASS
  • go vet ./internal/control/ ./internal/config/ ./internal/api/ ./internal/appproto/... ./internal/ha/ ./cmd/ftw/ ./test/e2e/: PASS
  • go test ./internal/control/ ./internal/config/ ./internal/api/ ./internal/appproto/... ./internal/ha/ ./cmd/ftw/ -count=1: all ok
  • FTW_E2E=1 go test ./test/e2e -count=1 -timeout 300s: ok (28s). TestE2E_FullStack -v confirmed the self_consumption target-following step charges at +3000 W and moves toward discharge at -3000 W.
  • LANG=C LC_ALL=C npm test (repo root): 639 tests, 639 pass, 0 fail.
  • Golden check: re-recorded into scratch with FTW_GOLDEN_DUMP=1 FTW_GOLDEN_OUT=... Kept records match apart from existing float noise (-0 vs 0, 1e-13 W). The committed change removes only the 60 priority/weighted records (git diff --minimal: 1 added line for record_count, the rest deletions).

Review

The removal is correct. The four findings are fixed, and the only thing blocking the merge is the unpaired webapp contract change.

#7: ModePriority, ModeWeighted, PriorityOrder, Weights, distributePriority, distributeWeighted, their revision hashing, the catalog and registry entries and the generated contract are all gone. A grep over go/, web/, docs/, scripts/, contract/ and config.example.yaml finds no references apart from the migration and its tests. restoreStoredMode (go/cmd/ftw/control_state.go) turns a stored priority or weighted into self_consumption, saves it and logs one Warn line. It runs before the planner-prefs resolution and the planner_arbitrage-to-passive migration, so boot order is right. Any other unknown value keeps the old behaviour. The API, HA and the app all refuse both modes through IsValidMode/ApplyMode. The HA select options come from AllModes. The golden corpus lost only records; the seeded rotations keep empty slots, so every surviving record keeps its seed, and the replay passes. TestMeterClampRespectsNonZeroGridTarget now uses self_consumption, which its own comment already described.

#34: haCallbacks.SetMode now goes through appModes.SetMode and …

Open points:

  • [should-fix] contract/registry.yaml:149: The paired ftw-webapp change does not exist yet. srcfl/ftw-webapp main still lists { key: weighted, tier: hidden } and priority in contract/registry.yaml, and it is byte-identical to origin/master's copy. It also has a hand-written 'weighted' mode in src/lib/sim/box.ts and src/lib/format/plan.test.ts. The required contract CI job in .github/workflows/test.yml diffs the two copies, so it will fail until a paired ftw-webapp PR removes both lines and this PR's body carries Contract-pair: srcfl/ftw-webapp@<ref>. The author disclosed this. It blocks the merge, but the code here is correct.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

- #7 priority/weighted: remove ModePriority and ModeWeighted, State.PriorityOrder
  and Weights, distributePriority/distributeWeighted, their revision hashing,
  catalogue, contract registry and HA select entries, and the never-read
  batteries.<name>.weight setting and its Settings field. Priority held every
  battery at its measured power because nothing set its order. A stored
  priority or weighted mode boots as self_consumption, is saved back and
  logged once; the API, HA and the app refuse both. Their 60 golden records
  are dropped (611 -> 551, deletions only) and the e2e target-following step
  runs in self_consumption.
- #34 HA mode: haCallbacks.SetMode now calls appModes.SetMode, so it goes
  through control.ApplyMode, only logs a failed save, still applies the export
  preference and replans without blocking the MQTT handler.
- #36 UseCascade: delete the unread control.State field and its initializer.
- #37 use_energy_dispatch: drop the deprecated key. Loading YAML or stored
  settings turns it into planner.legacy_dispatch (the old key still wins),
  DropRetiredSettings deletes it and battery weights from state.db, and one
  energyDispatchEnabled helper serves boot and hot reload, which no longer
  keeps the legacy path after the planner section is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf64b0b477

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread go/cmd/ftw/main.go Outdated
mpcSvc.SetMode(ctx, mm)
}
return nil
return modes.SetMode(ctx, control.Mode(m))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Serialize planner updates from Home Assistant mode changes

When Home Assistant sends two planner-mode commands close together, this now routes both through appModes.SetMode, which acknowledges each command before launching mpc.SetMode in independent goroutines. Those goroutines need not start in command order, so the older command can run last and overwrite the planner mode and plan while ctrl.Mode and the persisted value contain the newer selection; for example, selecting active and then passive arbitrage can leave the planner exporting under active arbitrage. Serialize or coalesce these MPC updates, or verify that the requested mode is still current before replanning.

AGENTS.md reference: AGENTS.md:L28-L30

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-27T06:36:14.346407Z bf64b0b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

frahlg and others added 2 commits September 27, 2026 09:04
…ority-weighted-modes

# Conflicts:
#	go/cmd/ftw/main.go
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7
@frahlg
frahlg merged commit a71f777 into master Sep 27, 2026
15 checks passed
@frahlg
frahlg deleted the refactor/remove-priority-weighted-modes branch September 27, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant