docs: v0.143.0 REPORT + CONTEXT + README (guest RAM resize UI, R-24; deployed + live-validated on demo)
This commit is contained in:
+16
-1
@@ -7,7 +7,22 @@
|
|||||||
>
|
>
|
||||||
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
||||||
|
|
||||||
Last updated: 2026-07-17 (v0.142.0 — offsite repo continuity: orphaned-repo guard + run-status auto-refresh)
|
Last updated: 2026-07-17 (v0.143.0 — guest RAM resize UI, R-24; MinAgent 0.90.0)
|
||||||
|
|
||||||
|
> **2026-07-17 — v0.143.0: guest RAM resize UI (R-24), LIVE on demo. MinAgent: 0.90.0.** The customer
|
||||||
|
> sees the guest's current memory + allowed range on the **Rendszer** settings page and resizes it
|
||||||
|
> ("Szerver memória (RAM)" card). The controller proxies + maps the agent's machine `code` to Hungarian;
|
||||||
|
> the AGENT (felhom-agent v0.90.0) enforces every bound and applies live (no reboot — R-24's old
|
||||||
|
> hub-desired-state framing is SUPERSEDED by Viktor's controller-direct ruling). agentapi
|
||||||
|
> `GuestMemory`/`ResizeMemory` (`*MemoryRefusedError` carries the code); capability
|
||||||
|
> `FeatureGuestMemoryResize` (featureMinAgent 0.90.0, probe type-asserts GuestMemory so the shared
|
||||||
|
> SupportProber/netAgent stay untouched); `POST /api/system/memory/resize`; JS confirm only on a shrink;
|
||||||
|
> agent-outdated hides the control, agent-unreachable falls back to the guest's `/proc/meminfo`. Deployed
|
||||||
|
> to BOTH demo guests (felhom-pve 9201 + nested demo-vm-felhom-4846bc 9201). **LIVE-validated** through the
|
||||||
|
> real endpoint on the nested demo (above_max + below_min refusals render the Hungarian message; the agent
|
||||||
|
> English never leaks; the capability gate resolves SupportYes via the 0.90.0 version header). A successful
|
||||||
|
> grow couldn't be shown on the tiny 4 GB nested host (max<current, correctly refused); the apply is
|
||||||
|
> Phase-0-proven at the agent layer. See REPORT.md.
|
||||||
|
|
||||||
> **2026-07-17 — v0.142.0: offsite repo continuity (Parts A + C), LIVE on demo.** Closes the
|
> **2026-07-17 — v0.142.0: offsite repo continuity (Parts A + C), LIVE on demo.** Closes the
|
||||||
> reinstall-orphaned-repo incident (a recreated data volume mints a new repo passphrase → the offsite
|
> reinstall-orphaned-repo incident (a recreated data volume mints a new repo passphrase → the offsite
|
||||||
|
|||||||
@@ -1,48 +1,67 @@
|
|||||||
# REPORT — most recent implementation
|
# REPORT — most recent implementation
|
||||||
|
|
||||||
## v0.142.0 — offsite repo continuity: orphaned-repo guard (A) + run-status auto-refresh (C) — 2026-07-17
|
## felhom-controller v0.143.0 — guest RAM resize UI (R-24) — 2026-07-17
|
||||||
|
|
||||||
**Baseline:** v0.141.0 (`1452dd2`) → **v0.142.0** (deployed live on demo 9201, healthy). Green:
|
**Baseline:** v0.142.0 (`f900c83`) → **v0.143.0** (`3286c7f`, pushed). **MinAgent: 0.90.0** (couples to
|
||||||
`go build ./... && go vet ./... && go test ./...` + template/emoji/native-confirm gates. Closes the
|
felhom-agent v0.90.0's `/guest/memory`). Deployed + LIVE-validated on the nested demo guest.
|
||||||
reinstall-orphaned-repo incident class (diagnosed 2026-07-17;
|
|
||||||
`documentation/audits/DIAGNOSE-offbox-repo-orphaned-2026-07-17.md`). Pairs with hub v0.60.0 (Part B).
|
|
||||||
|
|
||||||
### Part A — orphaned-repo guard (Scenarios A/B/C)
|
### What shipped
|
||||||
- **Classification** (`internal/backup/offbox.go` `classifyResticProbe`): `restic cat config` failure →
|
|
||||||
`wrong password or no key found` = **ORPHANED** (the definitive 07-17 signature) · no-repo = init ·
|
|
||||||
other (network/SFTP-auth) = unchanged error handling. `ensureOffboxRepo` acts on it.
|
|
||||||
- **State + card:** `OffboxTarget.RepoState="orphaned"` (+ `OrphanedAt`, `OrphanedRenamedTo`); on the
|
|
||||||
transition only, `offbox_repo_orphaned` fires and scheduled runs then SKIP (no nightly spam). The
|
|
||||||
remote page shows a calm Hungarian exception-color card (`backups_remote.html`), NOT the raw restic
|
|
||||||
banner (`LastError` is cleared for this case); the "Távoli mentés most" button is routed to the card.
|
|
||||||
- **Reset — move-aside, never delete:** UNCLAIMED box auto-resets on detection (Scenario B); CLAIMED
|
|
||||||
box gets an explicit reveal-then-confirm reset (Scenario C, `/backup/offbox/reset` + `confirm=1`).
|
|
||||||
Both do `mv <repo> <repo>.orphaned-<date>` (collision-suffixed `-2/-3`, over an ssh-exec seam) +
|
|
||||||
`restic init` + `offbox_repo_reset`. Restore paths never auto-reset (the auto-reset is run-only).
|
|
||||||
- **Red-proofs (run-fail-revert):** `TestOffbox_OrphanDetection_Claimed` (pre-fix = the incident: the
|
|
||||||
raw `wrong password` error surfaces, no state → FAIL; fixed: clean skip, one event, no nightly
|
|
||||||
re-fire, no raw banner) + `TestOffbox_OrphanDetection_UnclaimedAutoReset` (move-aside + both events,
|
|
||||||
un-orphaned) + `TestOffbox_ConfirmedReset` + `TestClassifyResticProbe`.
|
|
||||||
|
|
||||||
### Part C — run-status auto-refresh (Scenario E)
|
The customer sees the guest's current memory + the allowed range on the **Rendszer** settings page and
|
||||||
`GET /backup/offbox/status` (JSON: status/snapshots/last_error/orphaned) + a poll on
|
resizes it. The controller only proxies + maps the agent's machine `code` to Hungarian — the **agent**
|
||||||
`backups_remote.html`: while a run shows "Fut…" the page polls every 3 s and reloads once at the
|
(felhom-agent v0.90.0) enforces every bound and applies the change live (no reboot). Memory only.
|
||||||
terminal state (Rendben/Hiba + fresh numbers) — no manual reload; polling stops at terminal. Does not
|
|
||||||
touch the scheduled-run rendering. Test `TestOffboxStatusHandler` + `TestOffboxRun_RefusedWhenOrphaned`.
|
|
||||||
|
|
||||||
### Live leg (§13) — fallback taken, staged for the rehearsal
|
- **agentapi (`internal/agentapi/client.go`):** `GuestMemory` (GET) + `ResizeMemory` (POST). A ruled 412
|
||||||
The scratch-target live leg CANNOT run without disturbing live state: configuring a scratch offsite
|
surfaces `*MemoryRefusedError` (machine code + fresh bounds); a pre-0.90 agent 404s → typed `*StatusError`.
|
||||||
target resets `EscrowState` to `pending` (the offsite config carries the escrow state + the escrowed
|
- **Capability (`internal/agentapi/features.go`):** `FeatureGuestMemoryResize` + `featureMinAgent` **0.90.0**
|
||||||
password), the offbox RUN gates on `EscrowState=="escrowed"` (a scratch target needs its own
|
+ a `featureProbes` row. The probe TYPE-ASSERTS the one method it needs (`GuestMemory`), so the shared
|
||||||
customer-driven ceremony), and the live repo (customer zero's first snapshot) is untouchable (rule 2).
|
`SupportProber`/`netAgent` seams and their fakes are untouched (minimal-coupling choice — see Observations).
|
||||||
Per §13's explicit fallback: the mechanism is covered by the fake-based tests above (the classification
|
- **UI (`internal/web/system_memory_handlers.go` new; `templates/settings_system.html`):** a "Szerver
|
||||||
uses the EXACT restic stderr matched in the real 07-17 diagnosis), and the live leg is STAGED for
|
memória (RAM)" card; `POST /api/system/memory/resize` (mounted `/api/system/` in main.go) → capability
|
||||||
Viktor's planned delete/re-create rehearsal. Deploy verified: controller 0.142.0 live+healthy on 9201;
|
gate (SupportUnknown passes) → agent → response flash. JS confirm ONLY on a shrink. Code→Hungarian map;
|
||||||
the demo's healthy live repo was NOT spuriously flagged (settings `repo_state` absent = normal).
|
agent-outdated hides the control (+"rendszerfrissítése szükséges" note); agent-unreachable falls back to
|
||||||
|
the guest's own `/proc/meminfo` (control disabled, honest note; the page never 500s).
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
- agentapi: GuestMemory decode + 404-typed; ResizeMemory success + refusal-code (`*MemoryRefusedError`);
|
||||||
|
capability table (0.89→No / 0.90→Yes via the version fast-path; probe 404→No / ok→Yes).
|
||||||
|
- web handler: success maps to the Hungarian old→new line; below_usage_floor maps + **the agent's English
|
||||||
|
never leaks**; agent_outdated gate refuses with ResizeMemory NEVER called.
|
||||||
|
- Gates: `template_id_gate` + `emoji_gate` OK. `go build/vet/test` all pass (23 packages).
|
||||||
|
|
||||||
|
### Deploy + LIVE validation
|
||||||
|
|
||||||
|
Built + pushed `felhom-controller:0.143.0`; deployed to BOTH demo guests (guest 9201 on felhom-pve AND the
|
||||||
|
nested guest 9201 inside `demo-vm-felhom-4846bc`) — both `Up … (healthy)`.
|
||||||
|
|
||||||
|
**LIVE end-to-end through the REAL controller endpoint** (login → CSRF → POST) on the nested demo guest —
|
||||||
|
the exact pipeline the settings page drives (no server logic skipped; method: authenticated curl to the
|
||||||
|
controller container, browser bridge unavailable):
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/system/memory → {"allocated_mb":2890,"usage_mb":181,"host_total_mb":3914,"min_mb":2048,"max_mb":1866,"floor_mb":2048,"running":true}
|
||||||
|
POST /api/system/memory/resize {memory_mb:5000} → {"code":"above_max"} "A megengedett maximum 1866 MB (a gazdagép tartaléka miatt)."
|
||||||
|
POST /api/system/memory/resize {memory_mb:1024} → {"code":"below_min"} "A minimális memória 2048 MB."
|
||||||
|
```
|
||||||
|
|
||||||
|
The full chain is proven live: controller auth → capability gate resolving **SupportYes via the
|
||||||
|
X-Felhom-Agent-Version=0.90.0 header** → agentapi → agent enforcement → machine code → Hungarian mapping
|
||||||
|
(the agent's English is not shown). The lxcfs ripple (guest `/proc/meminfo` follows a real resize) is
|
||||||
|
Phase-0-proven at the agent layer.
|
||||||
|
|
||||||
|
### NOT yet live-validated
|
||||||
|
|
||||||
|
- A **successful** resize through the bounded endpoint could not be shown on the tiny 4 GB nested host: its
|
||||||
|
bounds are degenerate (`max_mb 1866 < current 2890`) so every target is correctly refused. The successful
|
||||||
|
live cgroup apply (2890→3146→2890, no reboot) is Phase-0-proven at the agent layer (agent REPORT §2). On a
|
||||||
|
normal-sized customer box a grow/shrink will succeed — folds into the rehearsal (S6 gains the resize touch).
|
||||||
|
- Full browser click-through of the card (the bridge attaches only to sessions started after it connected).
|
||||||
|
|
||||||
### Observations
|
### Observations
|
||||||
- Orphaned bytes vs quota: counted honestly in the usage bar; the card notes the set-aside copy; a
|
|
||||||
purge affordance is NOT built (Viktor purges the `.orphaned-<date>` dir manually — as in the 07-17 fix).
|
- The `featureProbes` type-assertion (vs. widening the shared `SupportProber`) keeps the memory feature from
|
||||||
- Other backup pages' refresh behavior unchanged (Part C is scoped to the remote-run status only).
|
coupling `netAgent` and every unrelated prober/fake to the memory surface. A prober that can't be asked →
|
||||||
- The controller cannot know the hub's superseded-blob count without cross-repo plumbing, so the card's
|
a non-404 error → SupportUnknown (fail-open), never a false "supported".
|
||||||
"recoverable with the recovery code" phrasing is unconditional (true going forward — Part B retains).
|
- The `memAgent` seam carries `NetVerifyStatus` + `AgentVersion` purely to satisfy the shared SupportProber /
|
||||||
|
version fast-path (production `*agentapi.Client` has them anyway) — the one small wart of reusing the cache.
|
||||||
|
|||||||
@@ -110,6 +110,16 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated
|
|||||||
JetBrains Mono, variable woff2, latin+latin-ext) and a 30-icon Lucide sprite are vendored in the
|
JetBrains Mono, variable woff2, latin+latin-ext) and a 30-icon Lucide sprite are vendored in the
|
||||||
binary** (`internal/web/static/fonts/` served at `/static/fonts/`; `templates/icons.html`) — no CDN,
|
binary** (`internal/web/static/fonts/` served at `/static/fonts/`; `templates/icons.html`) — no CDN,
|
||||||
no emoji. The setup wizard serves the same embedded stylesheet via `web.StyleCSS()`.
|
no emoji. The setup wizard serves the same embedded stylesheet via `web.StyleCSS()`.
|
||||||
|
- **Guest RAM resize (v0.143.0, R-24; MinAgent 0.90.0)** — the Rendszer page's "Szerver memória (RAM)"
|
||||||
|
card shows the guest's current/used memory + the allowed range and lets the customer resize it. The
|
||||||
|
controller only proxies + maps the agent's machine `code` to Hungarian; **the agent (felhom-agent
|
||||||
|
v0.90.0) enforces every bound and applies the change live via PVE SetConfig — no reboot** (min 2048 /
|
||||||
|
max host_total−2048 / a shrink is refused below max(2048, usage+512)). `systemPageData` calls
|
||||||
|
`memoryCardData` (a 2 s agent GET behind the `FeatureGuestMemoryResize` gate); `POST
|
||||||
|
/api/system/memory/resize` (`ServeSystemAPI`, `internal/web/system_memory_handlers.go`) →
|
||||||
|
`agentapi.ResizeMemory` → the code→Hungarian map. A JS confirm fires only on a shrink; an outdated agent
|
||||||
|
hides the control; an unreachable agent falls back to the guest's own `/proc/meminfo`. Memory only
|
||||||
|
(cores stay observation). The lxcfs ripple means the deploy-page memory math follows a resize for free.
|
||||||
- **Page IA (v0.97.0, TASK-D1)** — the settings monolith is split into four pages, each with its own
|
- **Page IA (v0.97.0, TASK-D1)** — the settings monolith is split into four pages, each with its own
|
||||||
data builder (`systemPageData`/`storagePageData`/`notificationsPageData`/`securityPageData`, sharing
|
data builder (`systemPageData`/`storagePageData`/`notificationsPageData`/`securityPageData`, sharing
|
||||||
`settingsBaseData`) and template. Routes: `/settings` (Rendszer), `/settings/notifications`
|
`settingsBaseData`) and template. Routes: `/settings` (Rendszer), `/settings/notifications`
|
||||||
|
|||||||
Reference in New Issue
Block a user