Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
5.8 KiB
felhom.eu — task reports
Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md; the scripts history lives in scripts/CHANGELOG.md.
TASK — hub v0.43.0: remote app-log diagnostics (copyable issues + context + on-demand log tails) — 2026-07-10
Pairs with controller v0.111.0. Deployed via GitOps (image 0.43.0, manifest bump, ArgoCD hard-refresh
- sync): Synced/Healthy, rollout complete, clean startup log. Motivated live: Peti's CWA issue was tooltip-only unreadable and context-free, with no remote way to see the app's logs.
What shipped (Parts A, C, D-hub, F, G, H of the spec)
- A — readable/copyable issues (
app_detail.html): Known Issues rows click-to-expand — full message in a wrapping monospace<pre>+ Copy button (clipboard API + execCommand fallback); fingerprint, severity, first/last seen, and the explicit affected-customers list (linked) in the body. Tooltip truncation killed. - C — context store/render (
store/telemetry.go): additivecontext+context_customercolumns;upsertAppIssuestores context on INSERT, adopts a later one ONLY while the stored one is empty (first capture wins). Rendered as "Context around first occurrence — from ", copyable. Nil-safe with pre-v0.111 reports. - D — on-demand log tail (pull-based, hub half): per-app Request log tail button on the customer
page (+ "tail pending" badge) →
log_tail_requests(one per (customer,app), re-click refreshes) + a customer-visiblelog_tail_requestedevent (transparency). Report ACK advertiseslog_tail_requests: [app…](same additive omit-when-empty pattern as escrow); the arrivinglog_tailsare stored inapp_log_tails(transient, last 2 per app), request cleared in the same tx (consume-once). Ordered viewer with line numbers (log_tail.html) + Download .log; reads are customer-scoped (cross-customer → 404). NO hub→controller push channel. - F — bug fix: the 24h/7d/30d selector now filters Known Issues too —
GetAppIssuesgained the samesincecutoff the Memory Trend uses (it previously had NO time filter at all). - G — deletion → dismissal. Diagnosis recorded (spec asked a/b): the delete handler was NOT
broken —
DeleteAppIssues/ByIDsexecute correct SQL. Deletion is futile because the controller re-scans a rolling 15-minute log window every report and re-upserts any still-occurring fingerprint with a fresh scan-timelast_seenminutes later → cause (b). Implementeddismissed_at: Dismiss Selected/All, dismissed rows out of the default view ("Show dismissed" toggle shows them dimmed + badged), and un-dismiss ONLY onexcluded.last_seen > dismissed_at(a re-sent old window stays hidden; a genuinely new occurrence resurfaces — recurrence is never silently swallowed). - H — per-customer scoping:
?customer=<id>filters Known Issues byaffected_customersmembership (header: "filtered: "; period links carry the filter); the customer page's App Telemetry rows link to that filtered view (the drill-down). Fleet view unchanged; count column labeled "Occurrences (all customers)" (per-customer counts noted as a future refinement, not built).
Tests + red-proofs (all four failed exactly as designed; restored green)
- G: dismissal guard replaced with unconditional clear →
old-window re-report RESURRECTED the dismissed issue→ FAIL. - F: range predicate neutered →
10d-old issue visible in the 24h view→ FAIL. - C: first-capture-wins CASE replaced with overwrite →
empty-context upsert clobbered the stored context: []string(nil)→ FAIL. - D consume-once: request-DELETE removed from
SaveAppLogTail→ store test AND the API ACK round-trip both FAILED (request survived fulfillment — the controller would ship tails every cycle). - Non-hollow coverage: late-context adoption; warn-no-context; occurrence counting; tail request/refresh/fulfill/prune-to-2/cross-customer-scoping; ACK omit-when-empty baseline + full round-trip; render tests (expanded row incl. full message + context + provenance + dismiss controls + "filtered:" header; customer page request button/pending badge/tails section via the REAL handler; ordered tail view + text/plain attachment download + cross-customer 404).
Live validation (demo, operator-free legs)
Synthetic error injected into the demo controller container's log stream (neighbor lines +
password=hunter2 + an ERROR: … LC0111 … line). On the next report cycle (14:22:34Z, 3.7KB vs the
2.5KB baseline) the hub DB showed the row in app_log_issues: severity error,
context_customer=demo-felhom, and an exactly-ordered 11-line context containing
diag: connecting with password=[REDACTED] to fake backend — live proof the secret never left the
box and that capture/wire/store all work end-to-end. (Method: report-cycle → /api/v1/report ingest →
hub DB read via kubectl cp; DB copy deleted after. The UI click-path is render-tested — the hub operator
password is Viktor-only, CC cannot log in.)
Operator follow-up (1 click)
- Live tail round-trip: on
hub.felhom.eu/customers/demo-felhom→ App Telemetry → Request log tail on thefelhom-controllerrow; the ordered tail + Download .log appears within ≤2 report cycles (≤30 min), and the "tail pending" badge clears (consume-once). The mechanism is fully red-proof-tested on both repos; only the click itself is operator-gated. - Per spec: do NOT request tails from Peti's box in this task — Viktor's call once he's read this. Peti's CWA issues are now fully readable (full message + context) on the next report cycles.