diff --git a/.agents/distributed-state.md b/.agents/distributed-state.md index b38e5dd34..5936636ea 100644 --- a/.agents/distributed-state.md +++ b/.agents/distributed-state.md @@ -44,9 +44,9 @@ Examples: `failover.targets` and `failover.chains` are ephemeral live-health state with no `Store`, republished by the leader every 10 s. -**Gotcha:** `Reconcile` with neither a `Store` nor a `Loader` re-hydrates the -map **empty** on a reconnect or a late join — there is nothing for it to pull -from. If your map has no durable backing, a leader (or another privileged +**Gotcha:** `Reconcile` with neither a `Store` nor a `Loader` does **nothing** +— there is nothing for it to pull from, so it cannot help a late joiner catch +up. If your map has no durable backing, a leader (or another privileged writer) must republish its live state after a reconnect instead of relying on `Reconcile` to recover it. diff --git a/core/services/failover/distsync/distsync.go b/core/services/failover/distsync/distsync.go index 349aef14f..f7bb3dfce 100644 --- a/core/services/failover/distsync/distsync.go +++ b/core/services/failover/distsync/distsync.go @@ -25,9 +25,9 @@ var ( // PinStore is given) so a late joiner hydrates every pin from the DB on // Start, not just from whatever peers happen to broadcast afterwards. // - failover.targets and failover.chains are ephemeral live-health state, -// NATS-only with no Store and no Reconcile: there is nothing durable to -// hydrate from, and a Reconcile tick would re-hydrate them empty and wipe -// live state clean off a running frontend. A late joiner instead catches +// NATS-only with no Store and no Reconcile: with neither set, a Reconcile +// tick's hydrate is a no-op (nothing durable to pull from), so it could +// never help a late joiner catch up anyway. A late joiner instead catches // up from the leader's periodic Republish (see failover.Manager.Republish). type Sync struct { pins *syncstate.SyncedMap[string, PinRecord] diff --git a/docs/content/features/model-failover.md b/docs/content/features/model-failover.md index 39b4b20bc..6defb123d 100644 --- a/docs/content/features/model-failover.md +++ b/docs/content/features/model-failover.md @@ -236,11 +236,11 @@ continue. On a single LocalAI instance, a restart removes the pin. In - The model editor's template picker has a **Failover Chain** template that starts a new model with two empty targets. Any model can also add a `failover.targets` field directly: each row picks a target model and a - **warm** toggle, with move up/down and remove controls. The warm toggle is - disabled, with an explanation, for a target on a remote (`localai-proxy` or - `cloud-proxy`) backend, since `warm` has no effect there. The field flags - fewer than two targets, a duplicate target, and the chain naming itself as - one of its own targets. + **warm** toggle, with move up/down and remove controls. The toggle is + available on every row; `warm` has no effect on a remote (`localai-proxy` or + `cloud-proxy`) target, and LocalAI logs a warning when it loads a chain with + one set. The field flags fewer than two targets, a duplicate target, and the + chain naming itself as one of its own targets. - Opening an existing chain in the model editor shows a health strip: the chain's status pill, its active target and how long it has been active, and a table of every target with its kind, warm flag, status, last probe diff --git a/docs/superpowers/specs/2026-09-26-failover-distributed-proxy-ui-design.md b/docs/superpowers/specs/2026-09-26-failover-distributed-proxy-ui-design.md index 208fa1f7f..7ae52561b 100644 --- a/docs/superpowers/specs/2026-09-26-failover-distributed-proxy-ui-design.md +++ b/docs/superpowers/specs/2026-09-26-failover-distributed-proxy-ui-design.md @@ -70,8 +70,9 @@ below applies when distributed mode is on. maps. The manager does not import NATS or gorm directly. - A peer delta is applied through `OnApply`, which changes local state without publishing again (no echo loops). -- The NATS-only maps have no `Store`, so `Reconcile` would re-hydrate them - empty. Instead the leader republishes every target and chain snapshot every +- The NATS-only maps have no `Store`, so a `Reconcile` tick's hydrate would be + a no-op — nothing durable to pull from, so it could never help a late + joiner. Instead the leader republishes every target and chain snapshot every 10 s. A frontend that joins late converges within 10 s and uses its own state until then.