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
8 changes: 8 additions & 0 deletions .changeset/remove-ask-why.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"ftw": minor
---

Ask why is removed: the Plan card question box, the header chip, the Settings
fieldset and the `/api/assistant/*` routes. On first start, Core deletes the
stored Ask why settings and OpenRouter key. Old conversations stay unused in
state.db. The help report is unchanged and is again the one button under the plan.
5 changes: 0 additions & 5 deletions .github/ISSUE_TEMPLATE/ask_why.md

This file was deleted.

11 changes: 0 additions & 11 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,17 +229,6 @@ fleet_ping:
enabled: true
# endpoint: https://relay.ftw.energy/fleet

# Ask why — optional. Paste an OpenRouter key (free account, no card) and
# the Plan card can explain the live help report and draft a GitHub issue.
# Off until enabled. The key is stored on this box and sent only as a
# bearer token to the API you set. Default model openrouter/free stays on
# free models. The helper never issues driver commands.
# assistant:
# enabled: true
# api_key: sk-or-v1-...
# model: openrouter/free
# # base_url: https://openrouter.ai/api/v1

# Independently distributed Lua drivers. The signed stable catalog is refreshed
# by default, but refresh never downloads, activates, or restarts a driver.
# Add `device_repository: { enabled: false }` to opt out. The expanded form is:
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ change does not prove the currently pinned recovery bundle passes.
| Daily charging | [The webapp panel](https://github.com/srcfl/ftw-webapp/blob/ff7af033fa3fcdeb38882e3ff365e8d6d7aba75a/src/views/EvPanel.svelte) already saves SoC on slider release, changes schedules without a Save button and supports Charge now. | [Now](https://github.com/srcfl/ftw-webapp/blob/ff7af033fa3fcdeb38882e3ff365e8d6d7aba75a/src/views/Now.svelte) normally opens that panel after a charger tap or notification link. Bring the relevant SoC action directly into the post-plug-in entry experience. Complete the goal → plan → delivered-energy flow on real chargers, including offline cars and restarts. |
| Notifications | Core and the webapp implement subscription, charging connection/completion/interruption events and device alerts. See the [shared push catalogue](../contract/push-catalogue.yaml) and [rule defaults](../go/internal/notifications/service.go). | There is no dedicated predicted-missed-departure event in that catalogue. Add an actionable goal-risk notification and make activation clear during charging setup, with user consent. Verify delivery while the app is closed; an interrupted-session alert alone does not cover a future shortfall. |
| Live trust and expert access | Flow exists. [LivePanel](https://github.com/srcfl/ftw-webapp/blob/ff7af033fa3fcdeb38882e3ff365e8d6d7aba75a/src/views/LivePanel.svelte) already puts a recent one-second trace behind each energy bubble and freezes it on silence. Core stores [structured v2 command results](../go/internal/state/driver_command_results.go), plan diagnostics and issued forecasts. | Join request, accepted intent, command response and measured effect in the normal experience and a structured analysis API, including legacy drivers and different sample cadences. Current result records and live watts are useful parts, not a complete proof of causality. Measure response time on a target box. |
| External control and agents | [Protocol command IDs and authorization leases](../go/internal/appproto/command.go), scoped operations, [bounded battery holds](../go/internal/api/api_battery_manual.go), schedule APIs and encrypted sessions exist. [HASS callbacks](../go/cmd/ftw/main.go) persist modes and grid targets. The built-in [Ask why tools](../go/internal/api/api_assistant_tools.go) are read-only. | Define renewable external control separately from durable goals. Losing HASS does not currently expire its saved mode. Existing authorization leases do not supply that policy. Build structured agent reads first, then permitted schedule/plan writes and a cloud MCP endpoint using the same Core checks. |
| External control and agents | [Protocol command IDs and authorization leases](../go/internal/appproto/command.go), scoped operations, [bounded battery holds](../go/internal/api/api_battery_manual.go), schedule APIs and encrypted sessions exist. [HASS callbacks](../go/cmd/ftw/main.go) persist modes and grid targets. | Define renewable external control separately from durable goals. Losing HASS does not currently expire its saved mode. Existing authorization leases do not supply that policy. Build structured agent reads first, then permitted schedule/plan writes and a cloud MCP endpoint using the same Core checks. |
| Savings | [The API](../go/internal/api/api_savings.go) explicitly reports `site_total` against `no_pv_no_battery_vehicle_energy_at_daily_average`. Actual import cost and export revenue are available. | Make the scope clear on each surface that says “saved”. Then add and validate the same-hardware self-consumption counterfactual, including EV behaviour and stored-energy accounting. Do not relabel the current figure as FTW's incremental benefit. |
| Heat and settings | Thermal contracts and an [explicitly opted-in solar feed](../go/cmd/ftw/solar_feed_send.go) already exist. The on-box [planner settings](../web/settings/tabs/planner.js) and webapp use different levels of technical language; the on-box minimum SoC still says “House reserve”. | Keep existing opt-ins explicit while phase one uses heat data for planning. Align basic controls around user goals and distinguish operating limits from forecast caution. Audit stored settings before removing or hiding them. Active tank/hot-water optimization remains a later bounded outcome. |

Expand Down
3 changes: 1 addition & 2 deletions go/cmd/ftw/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import (
const (
httpReadHeaderTimeout = 10 * time.Second
httpReadTimeout = 15 * time.Second
// WriteTimeout must outlast assistant.Timeout (90s): Ask why streams SSE
// on this listener, and a shorter write ceiling would cut the reply off.
// WriteTimeout bounds how long one response may take to a slow client.
httpWriteTimeout = 2 * time.Minute
httpIdleTimeout = 60 * time.Second
)
Expand Down
5 changes: 5 additions & 0 deletions go/cmd/ftw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,11 @@ func main() {
slog.Error("initialize config database", "err", err)
os.Exit(1)
}
if dropped, err := config.DropRetiredSettings(st, *configPath, cfg); err != nil {
slog.Warn("could not remove retired Ask why settings", "err", err)
} else if dropped {
slog.Info("Ask why has been removed; its settings and API key were deleted")
}

if cfg.State != nil && cfg.State.ColdRetentionDays != 0 {
slog.Warn("state.cold_retention_days is retired; fixed EMS history retention applies", "previous_days", cfg.State.ColdRetentionDays)
Expand Down
11 changes: 0 additions & 11 deletions go/internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,6 @@ type Deps struct {
Bundle *components.Bundle

Version string

// AssistantHTTP is the outbound client for Ask why. Nil uses a
// client with assistant.Timeout. Tests inject httptest.Server's client.
AssistantHTTP *http.Client
}

// Server wraps the http.ServeMux and adds shared middleware (logging,
Expand Down Expand Up @@ -281,7 +277,6 @@ type Server struct {
versionUpdateMu sync.Mutex
driverUpdateMu sync.Mutex
backupMu sync.Mutex
assistantAskMu sync.Mutex

// Timers that put a driver back after an edit has been tried for its
// window. The record on disk is what survives a restart; these only make
Expand Down Expand Up @@ -447,12 +442,6 @@ func (s *Server) routes() {
s.handle("GET /api/support/dump", Local, s.handleSupportDump)
s.handle("GET /api/ocpp/chargers", Local, s.handleOCPPChargers)
s.handle("GET /api/support/report", Local, s.handleSupportReport)
s.handle("GET /api/assistant/status", Read, s.handleAssistantStatus)
s.handle("POST /api/assistant/ask", Local, s.handleAssistantAsk)
s.handle("GET /api/assistant/threads", Read, s.handleAssistantThreads)
s.handle("GET /api/assistant/threads/{id}", Read, s.handleAssistantThread)
s.handle("DELETE /api/assistant/threads/{id}", Configure, s.handleAssistantThreadDelete)
s.handle("DELETE /api/assistant/threads", Configure, s.handleAssistantThreadsClear)
s.handle("POST /api/drivers/{name}/control", Actuate, s.handleDriverControl)
s.handle("DELETE /api/drivers/{name}/control", Actuate, s.handleDriverControlRelease)
s.handle("POST /api/drivers/{name}/restart", Configure, s.handleDriverRestart)
Expand Down
291 changes: 0 additions & 291 deletions go/internal/api/api_assistant.go

This file was deleted.

Loading
Loading