# REPORT — v0.115.0: version-aware Supports (agent version channel) + DSM-validated NAS guidance **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). ## Baselines → shipped | 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 | ## What shipped (files) `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). ## Tests + red-proofs (mutation → predicted failure → reverted → green) | Test | Red-proof mutant | Observed failure | |---|---|---| | `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 | Green gate `go build && go vet && go test ./...` PASS; `template_id_gate.py` + `emoji_gate.py` green. ## Deployed + verified 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). ## Part A (DSM spike) — the guidance edits landed here 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/`); 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`. ## NOT live-validated - The `agent_outdated`/held branches on a real