Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ab8f5ac
fix(mpc): surplus-only EV can take leftover PV beside battery grid-ch…
cursoragent Aug 18, 2026
cc7fa4a
refactor(mpc): treat EV as site power, not a harness mapper
cursoragent Aug 18, 2026
7e27199
fix(mpc): speak 0-1 SoC after si-core-units rebase
frahlg Aug 19, 2026
9a24495
fix(loadpoint): live surplus hides PV-soak even when EV made the mete…
cursoragent Aug 19, 2026
cd07ddc
feat(ev): the Manual tab follows the charger after Charge now
frahlg Sep 6, 2026
aea554e
fix(ev): apply controls directly and show charger feedback
frahlg Sep 6, 2026
6ee9212
Keep EV goals and solar rules in one session view
frahlg Sep 6, 2026
c459d15
Notify phones on confirmed charger connections
frahlg Sep 6, 2026
5801b4d
fix(settings): keep unchanged drivers running on charger saves
frahlg Sep 6, 2026
8c33446
fix(ev): expose unconfirmed battery levels after restart
frahlg Sep 6, 2026
c0c5bfb
fix(ev): keep manual sessions while waiting for first telemetry
frahlg Sep 6, 2026
212b045
fix(ev): remove the active target when its goal is removed
frahlg Sep 6, 2026
51ce2f2
fix(ev): show charging on home and make the first goal selectable
frahlg Sep 6, 2026
46d04a7
fix(ev): clear the goal saving progress after confirmation
frahlg Sep 6, 2026
ecc4460
Merge existing EV surplus allocation work into the charging candidate
frahlg Sep 6, 2026
99371b8
Resolve portable driver paths before applying settings
frahlg Sep 6, 2026
135c6d5
docs(api): clarify removal of the active charging goal
frahlg Sep 6, 2026
9bbc69d
fix(ev): retain confirmed levels only for the same charger session
frahlg Sep 6, 2026
f9e9eca
fix(ev): resume planning when a car accepts energy again
frahlg Sep 6, 2026
5e01da8
fix(ev): distinguish pause confirmation and expose battery size
frahlg Sep 6, 2026
2391dd1
fix(update): keep restart images and restore portable managed drivers
frahlg Sep 6, 2026
2e01f7f
feat(ev): save battery size through a narrow configuration route
frahlg Sep 6, 2026
008ba8c
fix(ev): name charger limits separately from the main fuse
frahlg Sep 6, 2026
e115b78
fix(ev): clear prior vehicle state after an unseen reconnect
frahlg Sep 6, 2026
51024e6
fix(ev): enforce pause and limits with honest command confirmation
frahlg Sep 6, 2026
27bf915
fix(ev): bind restored manual charging to hardware and session
frahlg Sep 6, 2026
87a7e80
fix(ev): distinguish stored battery size from the active car
frahlg Sep 6, 2026
21943ce
fix(ev): restore manual choices only after session identity is known
frahlg Sep 6, 2026
a8eb067
fix(ev): explain unmatched restart and pending current changes
frahlg Sep 6, 2026
488c91d
fix(ev): stop old manual power when a session binding changes
frahlg Sep 6, 2026
8241ca1
fix(ev): pin the verified Easee session driver
frahlg Sep 6, 2026
3b66faf
fix(updater): persist optimizer update and rollback pins
frahlg Sep 6, 2026
7085724
fix(ev): show when charging intent could not be saved
frahlg Sep 6, 2026
324c6c5
docs(update): use the configured Core service name
frahlg Sep 6, 2026
c9c07c2
fix(ev): report failed manual saves and retry on fresh telemetry
frahlg Sep 6, 2026
7a31411
fix(ev): retain entered battery level when charging verifies session
frahlg Sep 6, 2026
cca809c
fix(ev): keep previous charging goal when storage fails
frahlg Sep 6, 2026
b67f07b
fix(ev): reject solar preference changes when storage fails
frahlg Sep 6, 2026
8f3b6b5
fix(ev): keep fuse budgets below feasible charge steps
frahlg Sep 6, 2026
7a7024b
fix(ev): reject manual requests across unverified session resets
frahlg Sep 6, 2026
0fe4c9b
fix(ev): acknowledge only the current manual choice
frahlg Sep 6, 2026
2e730b7
fix(ev): preserve newer manual requests during automatic release
frahlg Sep 6, 2026
040ad25
docs(ev): describe manual request timestamps
frahlg Sep 6, 2026
42b347e
fix(ev): retain the reason when site telemetry pauses charging
frahlg Sep 6, 2026
7e6dc2e
fix(ev): guide the first charger connection and clarify saves
frahlg Sep 6, 2026
19cdb4d
fix(ev): describe the saved goal while the car is unplugged
frahlg Sep 6, 2026
c9ab3b4
fix(ev): confirm an unplugged goal only when one exists
frahlg Sep 6, 2026
987ffef
fix(ev): avoid guessing connection status from the catalog
frahlg Sep 6, 2026
7806f79
fix(api): cancel savings reads with app requests
frahlg Sep 6, 2026
21bcdc1
fix(ci): preflight optimizer package writes before release
frahlg Sep 6, 2026
f73cd99
fix(ev): acknowledge saved settings before replanning
frahlg Sep 6, 2026
a4979e5
fix(mpc): stop old dispatch after a failed replacement plan
frahlg Sep 6, 2026
b5b0eae
test(ev): verify capacity restart and lost session proof
frahlg Sep 6, 2026
08e117d
fix(ev): persist pause before charger identity arrives
frahlg Sep 6, 2026
fad1e80
fix(drivers): pin reviewed Easee session proof
frahlg Sep 6, 2026
cf41766
fix(ev): recover OCPP identity and retain safe intent across reconnects
frahlg Sep 6, 2026
e7edd06
fix(web): explain unconfirmed charger connections
frahlg Sep 6, 2026
6843ddd
fix(ocpp): bind callbacks and commands to their socket
frahlg Sep 6, 2026
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/driver-config-numbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep unchanged drivers running when settings pass through the web API. Compare numeric values from JSON and YAML equally, including nested driver settings. Bound charger settings requests so a missing reply leads to a visible retry state.
5 changes: 5 additions & 0 deletions .changeset/easee-session-driver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Use Easee session evidence to retain a confirmed battery level across a restart only when the same active session is verified.
9 changes: 9 additions & 0 deletions .changeset/ev-battery-session-truth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"ftw": patch
---

Keep a confirmed EV battery level across restart only when fresh charger telemetry identifies the same hardware and charging session. Show when the level cannot be retained or the disk write failed. Changing battery capacity preserves the current level and its confidence.

Treat a car declining current as a separate charging status. It no longer changes the estimated battery level to the target or sends a completed notification. Completion needs a fresh matched vehicle battery reading.

A higher goal, an explicit retry or measured charging lets the planner resume after a prior refusal.
5 changes: 5 additions & 0 deletions .changeset/ev-battery-size-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Let the charging view save the usual car’s usable battery size without replacing other settings. Apply a saved size through the shared config path and keep the current charge level steady. A failed save leaves the previous size in use.
5 changes: 5 additions & 0 deletions .changeset/ev-charger-limit-words.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Explain when the charger’s own current limit reduces a request, without blaming the main fuse.
5 changes: 5 additions & 0 deletions .changeset/ev-client-readiness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Add Pause charging and Resume plan beside Charge now, with status that waits for the charger to stop. Let users change battery size beside the current level. Explain whether that level survives a restart, and never call a car that declined charge full. Keep the request deadline active until the response body arrives.
5 changes: 5 additions & 0 deletions .changeset/ev-command-acknowledgement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep a changed charging request pending until the controller processes that choice and receives a fresh charger reading. An earlier command cannot confirm a new current or pause.
5 changes: 5 additions & 0 deletions .changeset/ev-connected-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Notify subscribed phones when a car is plugged in. Ignore first readings and recovery after an outage. Charging notifications carry the charger identity so the app can open its status and controls.
5 changes: 5 additions & 0 deletions .changeset/ev-connection-confirmation-copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Explain when charging needs a new choice because the charger or connection could not be confirmed, including after reconnecting. Keep the message separate from confirmation that current has stopped.
5 changes: 5 additions & 0 deletions .changeset/ev-effective-capacity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Show when the current car uses a different battery size from the usual size just saved.
5 changes: 5 additions & 0 deletions .changeset/ev-failed-plan-dispatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Stop dispatching an old plan when its replacement fails, so a removed charging goal cannot keep charging the car. Keep the current plan during normal recalculation, require a successful new plan after failure, and preserve manual Start and Pause with the usual safety limits.
9 changes: 9 additions & 0 deletions .changeset/ev-feedback-and-direct-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"ftw": patch
---

Add a charger without inventing an ID or pressing Save again. Charger settings apply on change, with errors and a retry beside the form. OCPP setup stays separate from cloud chargers.

Charging feedback separates the FTW request, the charger's reported limit and measured power. Old charger readings cannot claim current charging. Manual current changes apply on release; Return to plan names the action that ends a manual hold. Charge level and schedule writes run in order, and failed requests stay visible.

Keep the charging goal and solar rule together, with no mode tabs. Show when Charge now overrides them. Show the current slider only while manual charging is active. Opening goal settings does not send a command.
5 changes: 5 additions & 0 deletions .changeset/ev-first-connection-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Guide the first charger connection from Chargers into the charger catalog and back after saving the connection. Hide the unrelated global Save button for charger autosave; keep explicit saves beside OCPP and shared-car settings.
5 changes: 5 additions & 0 deletions .changeset/ev-first-session-level.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep the battery level entered while waiting when the same charger first verifies its session at charging start. Count newly delivered energy from that level and save it once the session is verified.
5 changes: 5 additions & 0 deletions .changeset/ev-fuse-ceiling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep EV power below the fuse budget when the budget falls between charging steps or below the minimum.
5 changes: 5 additions & 0 deletions .changeset/ev-goal-save-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Save charging goals before applying them. If storage fails, keep the previous goal and return a clear error for both goal edits and removals. A successful retry applies and saves the new goal together.
7 changes: 7 additions & 0 deletions .changeset/ev-manual-hold-session-restore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"ftw": patch
---

Bind a saved manual charging request to its charger hardware and verified charging session. Keep a saved pause on the same charger. When a prior positive request cannot be verified, pause and ask the owner to confirm instead of resuming automatic charging. Preserve explicit Start or Clear actions that arrive before the first charger reading.

A running request also stops if the charger, session or loadpoint binding changes. A clear issued before telemetry survives another immediate restart, and concurrent Set/Clear writes preserve the order shown by the controller.
5 changes: 5 additions & 0 deletions .changeset/ev-manual-save-feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Show when a charging choice applies now but could not be saved for restart. Retry its save when fresh charger data arrives and clear the message only after storage confirms it.
5 changes: 5 additions & 0 deletions .changeset/ev-missing-reading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Preserve manual charging while the charger driver starts or has no reading. An absent reading no longer counts as an unplug. A confirmed unplug still ends the manual session.
5 changes: 5 additions & 0 deletions .changeset/ev-ocpp-reconnect-proof.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Ask OCPP chargers for fresh hardware identity after reconnecting, with bounded retries for missing replies and a safe fallback when the request is unsupported. Pause an older manual Start when hardware identity is lost, keep an explicit Pause, and allow a new Start to bind to the next verified identity. Keep cable status unknown during a network interruption, and preserve the reconnect boundary even when it falls between control ticks.
5 changes: 5 additions & 0 deletions .changeset/ev-ocpp-socket-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep OCPP messages and command replies bound to the connection they came from. A delayed status or BootNotification from an older connection can no longer clear Pause or replace the current charger's identity. Check capabilities again after reconnecting.
5 changes: 5 additions & 0 deletions .changeset/ev-owner-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Show the connected car and its next action on the home screen, with a direct route to charging controls. Keep stale status visible until a fresh reading confirms unplugging. Let the user choose the displayed first goal without changing its time or battery target.
5 changes: 5 additions & 0 deletions .changeset/ev-pause-and-limits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep a manual pause until the user resumes or unplugs. Show when a pause is waiting for the charger and when it is confirmed. Keep manual charging available without a planner and enforce charger and installation limits on every manual request.
5 changes: 5 additions & 0 deletions .changeset/ev-release-current-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Apply an automatic charging stop only if the manual request has not changed since the controller checked it. Keep a newer Pause, Start or slider change, and give each explicit retry a fresh wait for the car to draw current.
5 changes: 5 additions & 0 deletions .changeset/ev-remove-goal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Remove the active derived target when a charging goal is removed. The old deadline no longer drives the planner after the UI says the goal is gone. A separate Charge now request continues unchanged.
5 changes: 5 additions & 0 deletions .changeset/ev-restart-choice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Ask how to continue when an earlier charge request cannot be matched after restart. Offer Charge now, Resume plan and Pause charging without calling it a user pause. Keep actual power visible until a changed current limit reaches the charger.
5 changes: 5 additions & 0 deletions .changeset/ev-save-before-planning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Confirm saved charging settings before calculating the plan. Show that planning is in progress and keep old charging windows out of that state.
5 changes: 5 additions & 0 deletions .changeset/ev-soc-confirmation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Mark the default EV battery level as unconfirmed. Ask for the car's level after a box restart instead of presenting a calculation from the default as a confirmed estimate. An entered level still applies on slider release and survives a settings reload.
5 changes: 5 additions & 0 deletions .changeset/ev-solar-save-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Save the solar charging choice before applying it. If storage fails, keep the previous choice and reject the change in both the box UI and Webapp. A retry can save and apply the choice once storage recovers.
5 changes: 5 additions & 0 deletions .changeset/ev-unbound-manual-pause.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep an explicit charging pause across restart even before the charger reports hardware identity. A prior Start without matching session proof restores only a pause that needs confirmation. Use the current OCPP connection's boot identity, and retry failed saves when charger data returns.
5 changes: 5 additions & 0 deletions .changeset/ev-unverified-session-reset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Pause a prior manual request when a session counter resets, including when the previous session had no verified ID. Keep an explicit Start when the same uninterrupted session gains its first verified ID.
7 changes: 7 additions & 0 deletions .changeset/manual-charge-feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"ftw": patch
---

EV modal, Manual tab: after Charge now the line under the button follows the charger instead of repeating the request. It says that the amps were sent and the box is waiting for the charger to confirm, that the charger has taken the limit and the car has not started drawing, that the car is charging, that the charger offers the current but the car is not drawing it (with the charger's own reason, such as "EV not accepting current"), that the command stalled, or that the main fuse limits the charge right now — each with the time elapsed. The plan strip above the tabs says the same while a manual charge runs, so the charger's reason is no longer hidden behind the manual sentence. A refused Start (403, 404, 409) now reads as a failure with the server's reason instead of "Charging at 16 A".

`GET /api/loadpoints` carries this as `manual` per loadpoint: `state` (`sent`, `accepted`, `charging`, `not_drawing`, `stalled`, `limited`), `started_at_ms`, `since_ms`, requested and commanded watts and amps, the charger's reported limit and reason. `POST …/manual_hold` answers with `started_at_ms`, and an Update of the amps keeps the first press as the start. `commanded_since_ms` says when the box's current order was first given.
5 changes: 5 additions & 0 deletions .changeset/portable-managed-driver-backups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Full backups now include managed drivers whose active links use absolute paths inside the data directory. The archive stores relative links so restore works at a new path. Links that escape the data directory or form cycles remain blocked.
5 changes: 5 additions & 0 deletions .changeset/quiet-optimizer-pins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep the selected optimizer image after updates and rollbacks by saving and checking its Compose pin. Report a failed pin write instead of a successful update, preserve other host settings and file permissions, and keep shell payloads containing credentials out of updater logs.
5 changes: 5 additions & 0 deletions .changeset/restart-keeps-running-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Restart restarts the existing container and keeps its exact image, including local test builds. It never pulls or recreates from a stale Compose tag. Core refuses the unsafe restart path on older updaters and explains how to update the updater.
5 changes: 5 additions & 0 deletions .changeset/savings-request-cancellation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Stop savings database reads when an app request times out or is canceled, so the request releases its place for later app reads. Keep canceled calculations out of the daily savings cache.
5 changes: 5 additions & 0 deletions .changeset/settings-driver-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

Keep driver paths consistent when settings are saved. Adding a charger no longer restarts other drivers with paths that fail to load.
7 changes: 7 additions & 0 deletions .changeset/surplus-only-ev-pv-beside-battery-grid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"ftw": patch
---

A surplus-only EV can take leftover PV while the home battery buys from the grid. Surplus-only is an EV policy, not a site-wide import ban: the car still cannot import, and the home battery still cannot feed the car.

Ship a new optimizer image with this core. HiGHS still plans under the leftover constraint; an old optimizer image will keep idling the car on cheap sun and never produce the combo ValidatePlan now accepts.
49 changes: 46 additions & 3 deletions .github/workflows/optimizer-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,42 @@ on:
description: Optimizer SemVer without prefix (for example 1.3.2-beta.1 or 1.3.2)
required: true
type: string
dry_run:
description: Check package access and run tests without building images, tagging or publishing
required: true
type: boolean
default: true

permissions:
contents: write
packages: write
contents: read

concurrency:
group: optimizer-${{ inputs.channel }}-${{ inputs.version }}
cancel-in-progress: false

jobs:
registry:
name: verify optimizer package write access
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Verify canonical optimizer package writes
env:
GHCR_USERNAME: ${{ github.actor }}
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
bash scripts/check-ghcr-write-access.sh srcfl/ftw-optimizer
echo 'Optimizer package write preflight passed; no image or tag was published.'

validate:
name: validate independent optimizer version
needs: registry
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.version.outputs.release_tag }}
Expand Down Expand Up @@ -167,8 +191,11 @@ jobs:
publish:
name: build optimizer image
needs: [validate, test]
if: needs.validate.outputs.image_exists != 'true'
if: ${{ !inputs.dry_run && needs.validate.outputs.image_exists != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -206,11 +233,14 @@ jobs:
if: >-
${{
always() &&
!inputs.dry_run &&
needs.validate.result == 'success' &&
needs.test.result == 'success' &&
(needs.publish.result == 'success' || needs.publish.result == 'skipped')
}}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -239,3 +269,16 @@ jobs:
if [ "${CHANNEL}" = beta ]; then prerelease=(--prerelease); fi
gh release create "${TAG}" --repo "${GITHUB_REPOSITORY}" \
--title "FTW optimizer ${TAG#optimizer-}" --generate-notes --latest=false "${prerelease[@]}"

dry-run:
name: confirm optimizer dry run
needs: [registry, validate, test]
if: ${{ inputs.dry_run }}
runs-on: ubuntu-latest
steps:
- name: Record validation result
env:
RELEASE_TAG: ${{ needs.validate.outputs.release_tag }}
run: |
printf 'Optimizer dry run passed for %s at %s. Package write access and tests passed. No image was built or published, and no git tag or release was created.\n' \
"${RELEASE_TAG}" "${GITHUB_SHA}" | tee -a "${GITHUB_STEP_SUMMARY}"
3 changes: 3 additions & 0 deletions contract/push-catalogue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# lost every notification that mattered.
version: 1
events:
- kind: charging.connected
title: Car plugged in
body: "Open to see charging status, check the battery level and set a ready time."
- kind: charging.session_complete
title: Car charged
body: "{kwh} kWh delivered — ready to go."
Expand Down
5 changes: 5 additions & 0 deletions docs/backup-and-restore.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ FTW:
4. hashes every file, verifies the finished archive and runs SQLite
`quick_check` before publishing it.

Managed-driver links that point inside the persistent directory become relative
links in the archive. Restore can therefore move the data to another directory
or machine. Backup never follows these links to copy a host file; verification
rejects link chains that escape the data directory or form a cycle.

Choose **Download**, save the `.ftwbak` file on another computer or USB disk,
and keep at least one older known-good copy. **Verify** rechecks the server copy;
it does not prove that a download exists elsewhere.
Expand Down
21 changes: 19 additions & 2 deletions docs/self-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ restored Core fails health. See [backup-and-restore.md](backup-and-restore.md).

Optimizer-only updates use `optimizer-vX.Y.Z[-beta.N]`, recreate and
health-check only `ftw-optimizer`, and never replace Core. Failure restores the
previous Optimizer image while Core continues on its Go fallback.
previous Optimizer image while Core continues on its Go fallback. After health
succeeds, both update and rollback save `FTW_OPTIMIZER_IMAGE_TAG` in the host
project's `.env` and check it before reporting success. Other settings, file
owner and mode stay intact. A pin write failure is reported as a failed
operation even if the optimizer is healthy; repair the host project and retry.
The host Compose image must use `${FTW_OPTIMIZER_IMAGE_TAG}` (an optional default
is allowed), or the operation stops before replacing the optimizer.

A Driver update downloads one signed artifact, verifies hash, metadata and host
API compatibility, then atomically activates exactly that version. Core puts
Expand Down Expand Up @@ -120,7 +126,18 @@ The version badge selects `stable` or `beta`, checks availability and starts
an update. Changing channel does not deploy anything. A skipped version remains
hidden only until a newer version appears.

For manual Core + updater operation:
**Restart** stops and starts the existing Core container, then checks its health.
It keeps that container's image and environment, even if `.env` or Compose now
names a different release. It does not apply changes to Compose; use the update
flow for a new image. Core sends `restart_existing` so an older updater refuses
before it can pull or replace anything. If FTW reports that safe restart needs a
newer updater, update Core and updater together using the paired commands below.
A normal Core update also asks the updater to replace itself with the same tag
after Core passes its health check.

For manual Core + updater operation, first set `FTW_IMAGE_TAG` and
`FTW_UPDATER_IMAGE_TAG` in the project's `.env` to the same published immutable
tag. Run these commands with the Core service name from your Compose file:

```bash
cd ~/ftw
Expand Down
2 changes: 1 addition & 1 deletion drivers/BUNDLED_SOURCE.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"for coverage. Run scripts/sync-bundled-drivers.sh to update."
],
"repository": "srcfl/device-drivers",
"commit": "f98d5c5f3519fa90f010a69573aa8fcf8595c8b0",
"commit": "3890ca922a627fe0eee5df825a4fefe95cefd1b9",
"source_dir": "drivers/lua",
"drivers": [
"ambibox_v2x", "ctek", "ctek_hybrid", "ctek_v2", "deye", "easee_cloud",
Expand Down
Loading