docs: hub v0.43.0 CHANGELOG + REUSE entries (log-tail pull pattern, upsert guards)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -83,6 +83,8 @@
|
||||
| `copyFile` | hub/internal/assets/assets.go (~L259) | `(src, dst) error` | THE atomic file write (tmp + rename) in the hub | Copy this shape for any new on-disk write. |
|
||||
| `fileSHA256` | hub/internal/assets/assets.go (~L244) | `(path) (string, error)` | Streaming sha256 of a file | — |
|
||||
| `(*Store).SaveEvent` | hub/internal/store/store.go (~L1003) | `(...) (int64, error)` | Persisting ANY event (controller or hub source) | Pair with dispatcher/`onEvent` — saving alone never notifies. |
|
||||
| `(*Store).RequestLogTail` / `GetPendingLogTailRequests` / `SaveAppLogTail` | hub/internal/store/logtail.go | pending-intent + consume-once fulfillment | THE ACK-flag pull pattern for hub→box requests (copy for any new one) | SaveAppLogTail clears the request in the SAME tx (consume-once) + prunes to last 2 per (customer,app); the hub NEVER connects into a box |
|
||||
| `upsertAppIssue` dismissal/context semantics | hub/internal/store/telemetry.go | ON CONFLICT CASE guards | Issue dismissal + first-capture-wins context | Un-dismiss ONLY on `excluded.last_seen > dismissed_at`; context adopted only while stored one is empty — do not "simplify" either CASE (red-proofed) |
|
||||
| `store.GuestID` | hub/internal/store/store.go (~L1268) | `(hostID string, vmid int) string` | Canonical guest primary key | Never hand-concatenate host+vmid. |
|
||||
| `scheduleDaily` | hub/cmd/hub/main.go (~L449) | `(ctx, name, "HH:MM", fn, logger)` | Daily jobs in Europe/Budapest (prune etc.) | Blocking — run as goroutine. `parseHM` returns 0,0 (midnight) on bad input. |
|
||||
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# Felhom Hub — Changelog
|
||||
|
||||
## v0.43.0 — Remote app-log diagnostics: copyable issues + error context + on-demand log tails (2026-07-10)
|
||||
|
||||
Pairs with controller v0.111.0. Motivated live: Peti's CWA NFS issue was visible in Known Issues but
|
||||
tooltip-only unreadable and context-free, and there was no way to see the app's actual logs without box
|
||||
access. The hub still never connects into a guest — everything rides the existing report + ACK.
|
||||
|
||||
- **Part A — readable, copyable issues** (`templates/app_detail.html`): Known Issues rows are
|
||||
click-to-expand — full message in a wrapping monospace `<pre>` + **Copy** button (clipboard API with
|
||||
execCommand fallback), fingerprint/severity/first-last-seen in the body. Tooltip-only truncation killed.
|
||||
- **Part C — context stored + rendered** (`store/telemetry.go`): `app_log_issues` gains `context`
|
||||
(JSON array) + `context_customer` (provenance); `upsertAppIssue` stores context on INSERT and adopts a
|
||||
later one ONLY while the stored context is empty (**first capture wins** — stable repro, no churn).
|
||||
Rendered in the expanded row as "Context around first occurrence — from <customer>", copyable.
|
||||
Nil-safe with pre-v0.111 reports.
|
||||
- **Part D — on-demand ordered log tail (pull-based)**: per-app **"Request log tail"** button on the
|
||||
customer page → `log_tail_requests` row (one active per app; re-click refreshes) + a customer-visible
|
||||
`log_tail_requested` event (transparency by default). The report ACK advertises
|
||||
`log_tail_requests: [app…]` (same additive omit-when-empty pattern as escrow); the controller's next
|
||||
report ships `log_tails` → stored in `app_log_tails` (transient, **last 2 per app kept**) and the
|
||||
request is **cleared (consume-once)**. Ordered tail view with line numbers (`log_tail.html`) +
|
||||
**Download .log**; tail reads are customer-scoped.
|
||||
- **Part F fix — the 24h/7d/30d selector now filters Known Issues**: `GetAppIssues` gained the same
|
||||
`since` cutoff the Memory Trend uses (it had NO time filter — a 24h view showed 25-day-old rows).
|
||||
- **Part G — deletion → dismissal**: diagnosis = the delete handler was NOT broken; deletion is futile
|
||||
because the controller re-scans its rolling 15-minute window every report and re-upserts a still-
|
||||
occurring fingerprint with fresh `last_seen` minutes later. Replaced with `dismissed_at`:
|
||||
Dismiss Selected/All (buttons renamed), dismissed rows out of the default view ("Show dismissed"
|
||||
toggle), and `upsertAppIssue` un-dismisses ONLY on `excluded.last_seen > dismissed_at` — a re-sent
|
||||
old window stays hidden, a genuinely NEW occurrence resurfaces (recurrence never silently swallowed).
|
||||
- **Part H — per-customer scoping**: `?customer=<id>` on the app detail page filters Known Issues to
|
||||
rows whose `affected_customers` contains the id (header shows "filtered: <customer>"); the customer
|
||||
page's App Telemetry rows link there (the drill-down). The fleet view stays; the expanded row lists
|
||||
the affected customers explicitly (linked) and the count column is labeled
|
||||
"Occurrences (all customers)".
|
||||
- **Tests + red-proofs (all four failed exactly as designed, restored green):** dismissal guard dropped
|
||||
→ old-window re-report resurrected the row → FAIL; range predicate neutered → 10d-old issue visible
|
||||
at 24h → FAIL; first-capture-wins dropped → empty-context upsert clobbered stored context → FAIL;
|
||||
consume-once DELETE removed → request survived fulfillment (store test + API ACK round-trip both) →
|
||||
FAIL. Plus: late-context adoption, warn-no-context, occurrence counting, tail request/fulfill/prune-
|
||||
to-2/cross-customer-404, ACK omit-when-empty baseline, render tests (expanded row content, customer
|
||||
page sections, ordered tail view + download headers).
|
||||
|
||||
## v0.42.0 — Remote "Debug mód" toggle on the customer config editor (2026-07-10)
|
||||
|
||||
Lets an operator flip the controller's debug mode (verbose log + the `/debug` menu, which the controller
|
||||
|
||||
Reference in New Issue
Block a user