v0.90.0 — guest RAM resize (R-24) + fast-tick-until-convergence (R-28)
MinAgent coupling: felhom-controller v0.143.0 gates its guest-memory-resize UI on this agent (FeatureGuestMemoryResize, MinAgent 0.90.0). R-24 guest RAM resize (internal/localapi/guestmemory.go): self-scoped GET/POST /guest/memory. Agent enforces every bound FRESH per request (min 2048, max host_total-2048, shrink floor max(2048, usage+512)); applies via PVE SetConfig — live cgroup apply, no reboot (Phase-0 proven on the nested demo box). Verify-after-apply re-reads maxmem before claiming success. New narrow MemoryOps seam (GuestAPI untouched); Options.Memory nil -> 503. Memory only. R-28 fast-tick (internal/fasttick): while any desired-state item is unapplied - including the pre-tunnel window a hub poke can't reach - pulse the shared out-of-band trigger every 30s, self-disarm on convergence. Four cached sources (desired-gen==0, reconcile Planned-Pending>0, pbsdr waiting_secret only, wgtunnel desired-not-operational); LOUD pbsdr states + pending_signature excluded. Seams: reconcile.Engine.LastResult() + wgtunnel.Manager.TunnelConvergence() (cached, no per-tick exec). Guests-0/0: hypothesis REFUTED live (9201 IS a pool member; 0/0 was the pre-provision window; PoolAddVMID re-assert already covers restore-over-existing). No code change; the fast-tick mitigates the window. Tests + red-proofs (i floor guard, ii max guard, iii always-pulse) all restored green.
This commit is contained in:
@@ -1,3 +1,48 @@
|
||||
## v0.90.0 — agent train: guest RAM resize (R-24) + fast-tick-until-convergence (R-28) (2026-07-17)
|
||||
|
||||
**MinAgent coupling:** felhom-controller v0.143.0 gates its guest-memory-resize UI on this agent
|
||||
(`FeatureGuestMemoryResize`, MinAgent 0.90.0). One train, one floor raise (Viktor's ruling).
|
||||
Green: `go build ./... && go vet ./... && go test ./...` all pass.
|
||||
|
||||
- **Item 1 — guest RAM resize (R-24, controller-direct)** (`internal/localapi/guestmemory.go`, new):
|
||||
a new self-scoped local-API surface — `GET /guest/memory` (current allocation, live usage, and the
|
||||
enforced bounds, all agent-computed in MB) and `POST /guest/memory` (bounded resize). The agent is
|
||||
the security boundary: every bound is recomputed FRESH per request from a live read (the UI's numbers
|
||||
are decoration). Ruled bounds — min **2048 MB**; max **host_total − 2048 MB** (host reserve); a SHRINK
|
||||
is refused below **max(2048, usage + 512 MB)** with `below_usage_floor` (stop apps first). Applies via
|
||||
the PVE API `SetConfig` — a **live cgroup apply, no reboot** (Phase-0 PROVEN on the nested demo box:
|
||||
maxmem moves with the guest running, `/proc/meminfo` ripples via lxcfs). Verify-after-apply: the new
|
||||
maxmem is re-read and must equal the target before success is claimed (a pending/reboot outcome is a
|
||||
502, never a false success). Refusals return a machine `code` (below_min/above_max/below_usage_floor)
|
||||
+ fresh bounds at 412; SetConfig is never called on a refusal path. Single-flight per host. Optional
|
||||
`Options.Memory` (nil → 503 "not configured"); a NEW narrow `MemoryOps` interface (does not touch the
|
||||
shared `GuestAPI`). Wired in `main.go` from the existing proxmox client. Memory only; cores stay
|
||||
observation.
|
||||
- **Item 2 — fast-tick-until-first-convergence (R-28)** (`internal/fasttick/`, new): the agent-plane
|
||||
immediacy SECONDARY. While ANY desired-state item is unapplied — most importantly the **pre-tunnel
|
||||
WG-registration window a hub poke cannot reach** — it pulses the SAME out-of-band report trigger the
|
||||
watchdog/poke use, every **30 s**, and **self-disarms emergently** the instant everything converges.
|
||||
State-based by ruling: nothing to journal, no timer to leak. Four cached sources (no exec/network per
|
||||
tick): desired-generation == 0 (never fetched); reconcile `LastResult` actionable drift
|
||||
(`Planned − Pending > 0` — a destructive `pending_signature` is EXPECTED, excluded); pbsdr
|
||||
`waiting_secret` ONLY (the LOUD `consumed_failed`/`verify_failed` are excluded so a stuck box never
|
||||
hammers); wgtunnel block-desired-but-not-operational. Supporting seams: `reconcile.Engine.LastResult()`
|
||||
(mutex-recorded per pass) and `wgtunnel.Manager.TunnelConvergence()` (cached snapshot refreshed at each
|
||||
Apply — the fast-tick never execs `wg`/`systemctl`). A perma-unconverged box fast-ticks at ~2 small
|
||||
reports/min (bounded, documented; timers were deliberately rejected).
|
||||
- **Guests-0/0 (diagnosis passenger):** REFUTED the pool-membership hypothesis on the live nested box —
|
||||
guest 9201 IS a pool member, the agent token sees it (VM.Audit comes from the `/pool/felhom` grant),
|
||||
hub reports 1/1. The observed 0/0 was the legitimate **pre-provision reporting window** (no guest
|
||||
existed yet); the existing `PoolAddVMID` re-assert (bringup.go:498) already covers the known
|
||||
restore-over-existing edge (campaign-2 R2). Item 2's fast-tick is exactly the window's mitigation.
|
||||
No code change.
|
||||
- **Tests + red-proofs (run-fail-restore):** localapi memory (grow/shrink, the three refusals each with
|
||||
a **SetConfig-count == 0** assertion, cross-guest 403, fresh-bounds-per-request, verify-not-reflected
|
||||
502, nil-config 503) — red-proofs (i) floor guard removed → below_usage_floor fails; (ii) max guard
|
||||
removed → above_max fails. fasttick (pulse-while-unconverged, silent-when-converged, the ruled
|
||||
disarm-on-convergence, full-channel non-blocking drop, first-reason) — red-proof (iii) always-pulse →
|
||||
the silent + disarm tests fail. `Engine.LastResult` effect + pre-first-run ok=false. All restored green.
|
||||
|
||||
## v0.89.0 — agent train: PBS-DR self-grant (R-22) + escrow config live-reload + agent-plane poke listener (2026-07-16)
|
||||
|
||||
Three bundled agent-plane items. Green: `go build ./... && go vet ./... && go test ./...` all pass.
|
||||
|
||||
Reference in New Issue
Block a user