docs: REPORT + CONTEXT for v0.116.0/v0.116.1 (deployed 9201, live-validated at info level)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
+20
-1
@@ -7,7 +7,26 @@
|
||||
>
|
||||
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
||||
|
||||
Last updated: 2026-07-11 (v0.115.0 — version-aware Supports + DSM-validated guidance; pairs with agent v0.82.0 + hub v0.45.0)
|
||||
Last updated: 2026-07-11 (v0.116.1 — observability pass; pairs with agent v0.83.0 + hub v0.46.0)
|
||||
|
||||
> **2026-07-11 — v0.116.0/0.116.1: OBSERVABILITY PASS (LIVE on 9201; agent v0.83.0 + hub v0.46.0).
|
||||
> MinAgent: 0.81.0 unchanged.** The debug ring (`LogBuffer`) now ALWAYS exists — logger =
|
||||
> `MultiWriter(LevelFilterWriter(stdout, logging.level), ring)`, so DEBUG detail is remotely
|
||||
> readable on an `info` box while docker logs keep the configured level. New `internal/logx`
|
||||
> leveled helpers = the sweep standard (netstorage_job phases/verdicts/durations, netprobe,
|
||||
> validation refusals, orphan WARN, `SupportsWithSource` gate line, agentapi per-call DEBUG,
|
||||
> migrate phases, tier2/offbox unswallowed persists). Report ACK gains `controller_log_requested` →
|
||||
> next report ships `controller_log_tail` (selftail.go, consume-once, 128 KB; the customer-visible
|
||||
> `operator log pull served` INFO rides in the tail; app-tail wire byte-compatible). Debug page:
|
||||
> `Vezérlő | Ügynök` tabs — the agent tab proxies agent `GET /debug/logs` (`Client.DebugLogs`;
|
||||
> typed-404 → the "after the agent's next update" notice). **v0.116.1 (found by live validation):
|
||||
> `/debug` + `/api/debug/*` + the nav item were STILL gated on logging.level=debug — ungated (auth
|
||||
> unchanged), the incident's actual blind spot.** Live-proven at info: a real refused NAS add is
|
||||
> fully reconstructable on both tabs (capability gate w/ source=version, phase lines, 502+duration,
|
||||
> category). Conventions: `felhom.eu/documentation/runbooks/logging-conventions.md`. OPEN: operator
|
||||
> clicks the hub's two "Request logs" buttons (hub UI password-gated) to close the live bundle
|
||||
> round-trip; legacy `isDebug()` emission sites left for incremental migration. NOT published —
|
||||
> Peti stays 0.113/0.81.
|
||||
|
||||
> **2026-07-11 — v0.115.0: version-aware Supports + DSM-validated NAS guidance (LIVE on 9201, pairs
|
||||
> with agent v0.82.0 + hub v0.45.0). MinAgent: 0.81.0.** Capability detection now compares the agent
|
||||
|
||||
@@ -1,61 +1,69 @@
|
||||
# REPORT — v0.115.0: version-aware Supports (agent version channel) + DSM-validated NAS guidance
|
||||
# REPORT — v0.116.0/v0.116.1: observability pass (always-on debug ring + agent tab + self-log pull + sweep)
|
||||
|
||||
**Date:** 2026-07-11 · **Version:** controller v0.115.0 (from v0.114.0) · **MinAgent:** 0.81.0 (the
|
||||
version channel FALLS BACK to the probe — agent 0.82 is NOT required). Pairs with agent v0.82.0 +
|
||||
hub v0.45.0. Part B of the NAS/coupling backlog-clear task (composite A–F; this repo = B).
|
||||
**Date:** 2026-07-11 · **Version:** controller v0.116.1 (from v0.115.0; 0.116.1 = the debug-surface
|
||||
ungate found by live validation) · **MinAgent:** 0.81.0 unchanged · **Deployed:** guest 9201
|
||||
(`0.116.1` healthy) · **NOT published/vouched** — Peti stays 0.113.0; this reaches him with the next
|
||||
publish train. Pairs with agent v0.83.0 + hub v0.46.0. Task-wide record: this file + each repo's
|
||||
CHANGELOG + `felhom.eu/documentation/runbooks/logging-conventions.md` (the codified conventions).
|
||||
|
||||
## Baselines → shipped
|
||||
## Motivating incident → root causes closed
|
||||
|
||||
| Repo | main @ start | → shipped | Version |
|
||||
|---|---|---|---|
|
||||
| felhom-controller | `ac6adaaa` (v0.114.0) | `b6842a4` | **v0.115.0** — live on 9201 |
|
||||
| felhom-agent | `1e60e88` (v0.81.0) | `fa9c7fe` | v0.82.0 — demo-deploy (version channel) |
|
||||
| felhom.eu | `4eaabb2` | (A findings + hub train) | DSM spike + hub v0.45.0 |
|
||||
A NAS-verify refusal on an `info` box showed NOTHING remotely. Three stacked causes, all fixed:
|
||||
1. the `LogBuffer` ring only EXISTED at `logging.level=debug` (setupLogger) → now always built;
|
||||
stdout respects the level via `LevelFilterWriter` (docker logs unchanged);
|
||||
2. the new flows emitted few lines → the leveled `internal/logx` sweep (phases, verdicts, durations);
|
||||
3. **the `/debug` page + `/api/debug/*` 404'd at info** (found live — v0.116.1): the viewer is now
|
||||
available at any level, still session-authed (RequireAuth + CSRF); the nav link always renders.
|
||||
|
||||
## What shipped (files)
|
||||
## What shipped
|
||||
|
||||
`internal/agentapi/client.go` (`noteAgentVersion` on all four Do sites — passive capture even on
|
||||
404/errors; strict bare-semver validation; `AgentVersion()`), `internal/agentapi/features.go`
|
||||
(`featureMinAgent` table + `AgentVersionReporter` + version-first `Supports`, probe fallback
|
||||
unchanged), NEW `internal/util/version.go` (THE one comparator, moved verbatim from selfupdate which
|
||||
now aliases it), `internal/selfupdate/version.go` (aliases), `internal/web/templates/storage_network.html`
|
||||
(DSM-validated NFS guidance from Part A). Tests: `internal/agentapi/features_version_test.go`,
|
||||
`storage_network_template_test.go` (unchanged content check).
|
||||
- **Capture layer**: always-on 1000-entry ring; `MultiWriter(LevelFilterWriter(stdout, level), ring)`;
|
||||
`logx.Debugf/Infof/Warnf/Errorf` (caller-attributed); legacy `isDebug()` emission sites untouched.
|
||||
- **Report self-log pull** (`report/selftail.go`): ACK `controller_log_requested` → next report ships
|
||||
`controller_log_tail` (128 KB, consume-once, the v0.111.0 logtail.go shape; the customer-visible
|
||||
`operator log pull served` INFO rides IN the tail). App-tail wire byte-compatible (schema-tested).
|
||||
- **Debug page tabs**: `Vezérlő | Ügynök`; the agent tab proxies agent `GET /debug/logs` via the new
|
||||
`Client.DebugLogs` (typed-404 → "Az ügynök naplónézete az ügynök következő frissítése után érhető
|
||||
el."; non-404 stays an honest error). Template gates green.
|
||||
- **Sweep**: netstorage_job (start + per-phase transitions + verdicts + rollback outcomes +
|
||||
durations), netprobe exec/result, handler validation refusals (which check), orphan-share WARN,
|
||||
capability gate line now carries the SOURCE (`SupportsWithSource`: version/probe-cache/probe),
|
||||
agentapi per-call DEBUG (`SetLogger` on the memoized client) + version-change line, migrate
|
||||
per-phase + duration, tier2/offbox run-start + previously swallowed status-persist errors → WARN.
|
||||
|
||||
## Tests + red-proofs (mutation → predicted failure → reverted → green)
|
||||
## Red-proofs (demonstrated, restored)
|
||||
|
||||
| Test | Red-proof mutant | Observed failure |
|
||||
| Scenario | Reverted shape | Failure seen |
|
||||
|---|---|---|
|
||||
| `TestSupports_VersionKnown_ComparesWithoutProbe` (0.82/0.81/1.0/0.100→Yes; 0.79/0.80.9→No, no probe) | version short-circuit dropped | `version-known path must NOT probe (ver=0.82.0, probes=1)` |
|
||||
| `TestSupports_GarbageOrNoVersion_ProbeFallback` (`""`/dev/`0.82`/rc1/`evil;`… → exactly one probe, cached) | trust unparseable header as "too old" | `unusable version "dev" must fall back to EXACTLY one probe, got 0` |
|
||||
| `TestSupports_NonReporterProber_Unchanged` | — | (non-reporter probers keep v0.114.0 behavior) |
|
||||
| `TestVersionComparator_Table` (numeric-not-lexicographic, v-prefix, pre-release rejected) | — | — |
|
||||
| `TestClient_VersionHeaderWins_WireLevel` / `TestClient_GarbageHeaderIgnored_WireLevel` (real pinned client) | — | header wins over a routeless agent; garbage ignored at capture |
|
||||
| S1 | LevelFilterWriter pass-through | `stdout carries the DEBUG line at level info` |
|
||||
| S2 | self-tail drain removed | `second build shipped again — consume-once broken` |
|
||||
| S7 | probe-verdict line dropped | `phase line "probe verdict: ok=true" missing` |
|
||||
|
||||
Green gate `go build && go vet && go test ./...` PASS; `template_id_gate.py` + `emoji_gate.py` green.
|
||||
(S3 schema + S6 both-polarity notice tests pass; their traps are asserted structurally.)
|
||||
|
||||
## Deployed + verified
|
||||
## Live validation (9201, `logging.level: info`, 2026-07-11 ~17:10 CEST — via the exact endpoints the UI invokes; rendering-only residual)
|
||||
|
||||
9201 (golden/bootstrap): `felhom-controller:0.115.0 Up (healthy)`. Live check (real add endpoint,
|
||||
agent 0.82 = the SUPPORTED branch): a bogus-export add returned the categorized `nfs_export`
|
||||
failure + full rollback, and the debug log shows `capability gate: netstorage_verify=yes` — the
|
||||
verdict now sourced from the **version compare** (agent 0.82 header), zero probe calls. The probe
|
||||
fallback is regression-tested (T3/non-reporter) and is Peti's live path (his agent stays 0.81, no
|
||||
header → probe).
|
||||
- Real NAS add (`POST /api/storage/netstorage/add`, unreachable endpoint 192.168.0.199) → job
|
||||
`failed` with `category=unreachable` + the exact §3.2 Hungarian message in ~2 s.
|
||||
- **Vezérlő tab** (`/api/debug/logs?level=DEBUG`) at info shows the whole flow: capability gate
|
||||
`netstorage_verify=yes (source=version)` ← the 0.82/0.83 version channel live, add started INFO,
|
||||
`[agentapi] POST /netstorage/add -> 502 (2001ms)`, failed WARN with category+duration.
|
||||
- **Ügynök tab** (`/api/debug/agent-logs`) proxies the agent ring (201 entries) incl.
|
||||
`POST /netstorage/add status=502 duration_ms=2001`.
|
||||
|
||||
## Part A (DSM spike) — the guidance edits landed here
|
||||
## NOT live-validated (expected + why)
|
||||
|
||||
Real DSM 7.2 (virtual-dsm) validated the consumer recipes end-to-end through the v0.114 pipeline:
|
||||
NFS "Map all users to admin" = Route A PASS (hardlink incl.); squash-off = `not_writable` refusal;
|
||||
plain-user SMB PASS **with working hardlinks** (the Q5 caveat CLOSED for Synology); wrong-password/
|
||||
wrong-share classify identically (`smb_auth`/`smb_share`). The NFS guidance gained the verified
|
||||
Synology menu path (File Services → NFS → **NFSv4.1**; NFS Permissions rule; `/volume1/<share>`);
|
||||
the "útmutató készül" caveat narrowed to **QNAP only** (no emulator — nothing fabricated). Record:
|
||||
`felhom.eu/documentation/audits/SPIKE-nas-dsm-2026-07-11.md`.
|
||||
- **Hub bundle round-trip (button → pending → bundle → download):** the hub UI is operator-password-
|
||||
gated and no logged-in browser session was available — **operator follow-up: click "Request
|
||||
controller logs" + "Request agent logs" on hub.felhom.eu/hosts/<demo host> and download both.**
|
||||
The full round-trip incl. consume-once + S6 stays-pending is proven by hub API tests.
|
||||
- **Blocked-secret branch live:** deliberately test-level only (no real secret is ever planted live).
|
||||
|
||||
## NOT live-validated
|
||||
## Observations
|
||||
|
||||
- The `agent_outdated`/held branches on a real <MinAgent agent (no such box exists — test-proven).
|
||||
- Q1c restart survival: tested in Part E and **FAILED** (empty-dir; not a controller bug) — the fix
|
||||
is felhom-agent's, spec'd at `felhom.eu/documentation/backlog/FOLLOWUP-nas-automount-guest-reboot-reassert.md`.
|
||||
A controller follow-on (health cross-check the GUEST-visible mount) is noted there.
|
||||
- Legacy `isDebug()` call sites left in place per spec — their DEBUG detail still doesn't exist at
|
||||
info (only NEW logx lines do). Future sweeps can migrate them incrementally.
|
||||
- Swallowed-error branches found + fixed with a WARN (not more): tier2 `SetCrossDriveConfig` ×3,
|
||||
offbox `UpdateOffboxStatus` ×2. The offbox stats persist (best-effort, stale-safe) left as-is.
|
||||
- The guest's local-API token was incidentally printed to the operator terminal during config
|
||||
inspection (never into a file/commit); rotating it is cheap if desired.
|
||||
|
||||
Reference in New Issue
Block a user