docs(shares): R-7b v0.145.0 — CHANGELOG, CONTEXT, REUSE, README; caveats cleared

The samba_classify.go SCOPE NOTE and the README KNOWN GAP both described a gap that
R-7b closes; both now describe the sibling-shares-source execution instead.
This commit is contained in:
2026-07-18 13:06:41 +02:00
parent 900c870212
commit 3b70a9e9ab
5 changed files with 146 additions and 11 deletions
+26 -4
View File
@@ -2374,10 +2374,32 @@ main mux behind `RequireAuth`+`CsrfProtect` (the `/api/` subtree is routed there
no `.felhom.yml` and its binds are absolute share paths). Per-share `Felhőmentés` ON → `mandatory`
(offsite + tier-2); OFF → `optional` (tier-2 only). smb.conf/passdb are never classified.
> **KNOWN GAP (design fork, deliberately not improvised).** The seam is correct, but share data is not
> yet in a live tier-2/offsite RUN: `backup.RunTier2` short-circuits on a missing recovery unit before
> it reaches `GetStackClassifiedBinds`, and the offsite runner enumerates `settings.GetOffboxApps()`.
> Both engines are recovery-unit shaped, which a share-only infra stack has not. See root `REPORT.md`.
#### Share backup EXECUTION — the sibling shares source (R-7b, v0.145.0)
The earlier KNOWN GAP is **closed**: share data is in both live tiers. It did not get there through
`GetStackClassifiedBinds`the engines are recovery-unit shaped and Model B deliberately left every
per-app path byte-identical. Instead `internal/backup` runs a **sibling shares source** off the same
registry, applying the same per-share class rule:
| Tier | Entry point | Shape |
|---|---|---|
| 2 (cross-drive) | `RunSharesTier2` — after the per-stack loop in `RunAllTier2` | legs grouped by SOURCE DRIVE → `backups/secondary/_shares/<driveKey>/<share>` + `_payload/`, layout marker LAST |
| 3 (offsite) | `runOffboxSharesLeg` — after the per-app loop, before retention | ONE `restic backup --tag felhom-offbox --tag _shares` = manifest staging dir + every MANDATORY share |
| restore | `RestoreSharesScratch``PlaceSharesRestore` | scratch first, then a missing-only merge, each destination prefix-asserted against LIVE storage roots |
The **payload** (`shares_payload.go`) is what makes a restore give back a working feature rather than
loose files: a byte-deterministic `_shares-manifest.json` of the definitions plus a best-effort,
secret-bearing `passdb.tar`. Definitions protection is the floor — a quota-blocked offsite push
degrades to the manifest alone, never to nothing.
`_shares` is a **reserved key** (restic tag, dest root, status record). `ValidateSMBShareName` refuses
a leading underscore, and both run loops skip a `_shares` stack loudly. It never reaches a customer
surface: `backup.DisplayStackName` maps it to „Megosztások" at the notification and prose boundaries,
while the persisted set, the tag and the paths keep the raw key.
**Liveness:** `monitor.EffectiveProtected` adds `infra.SambaContainerName` exactly while sharing is
on, so a dead sharing service raises the standard protected-container issue → alert → degradation
e-mail. Note the container name is NOT the stack name (`samba` vs `felhom-samba`).
---
+10 -6
View File
@@ -18,12 +18,16 @@ import (
//
// The smb.conf / passdb mounts are deliberately NOT emitted — they are config, not customer data.
//
// SCOPE NOTE (the reported design fork, see REPORT.md): making this seam correct does NOT by itself
// put share data into a live tier-2/offsite run. Both engines are structured around a per-app
// RECOVERY UNIT — backup.RunTier2 short-circuits on `os.Stat(unitDir)` before it ever calls
// GetStackClassifiedBinds, and the offsite runner enumerates settings.GetOffboxApps(). A share-only
// infra stack has neither, and teaching them about one is more than an enumeration tweak, so per the
// task's STOP clause it was reported rather than improvised inside the engines.
// EXECUTION (R-7b, v0.145.0 — the gap this note used to describe is CLOSED). Share data now reaches
// BOTH live tiers, but not through this seam: the engines remain structured around a per-app recovery
// unit (backup.RunTier2 still short-circuits on `os.Stat(unitDir)`; the offsite runner still
// enumerates settings.GetOffboxApps()), and Model B deliberately left those paths byte-identical.
// Instead the backup package runs a SIBLING shares source off the SAME registry this file reads —
// backup.RunSharesTier2 and backup.runOffboxSharesLeg — applying the identical rule below.
//
// So this function and the shares sources agree by construction on WHAT each share's class is, while
// the sources own WHERE it goes. Keep the rule here in sync with internal/backup/shares_payload.go's
// classifiedShares if it ever changes.
func (m *Manager) sambaClassifiedBinds() ([]appbackup.ClassifiedBind, bool) {
if m.settings == nil {
return nil, false