Files
felhom-controller/REPORT.md
T
admin cf9ce01917 .fab exclusion scoping: classes in the manual export (Task 4, v0.136.0)
SQ6 over-capture FIXED for classified apps: the userdata root tar is exclude-scoped (keeps only
ancestors/descendants of a SELECTED bind relpath — R1-C, the tier2Reconcile keep-rule); no selected
userdata bind → no root tar (radarr state-only). New appbackup.ComputeFabBuckets (shared
resolveGuardCollapse pipeline; class buckets; guards over ALL classes; no cross-bucket containment).
appexport/fabplan.go: computeFabPlan + tarDirectoryExcluding + fabEstimateSplit. ExportRequest gains
DeselectOptional/OptInExcluded (both start handlers — two-call-site); mandatory is a server-side
floor. Manifest v1 + import UNTOUCHED; legacy apps byte-identical to v0.130.0. Estimate additive
class split; export UI: locked-mandatory/optional-checkboxes/excluded-opt-in + two-number warning.
All 6 §10 red-proofs verified. 6D Accept #1 now runs against this shape.
2026-07-15 11:28:40 +02:00

72 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# REPORT — `.fab` exclusion scoping (Task 4) — controller v0.136.0
## Summary
Task 4: the `.fab` column of the matrix (SQ5 verdict + ruling #1 + Viktor's R1-C). **The SQ6
over-capture is fixed for classified apps** — a manual export's userdata root tar is now
exclude-scoped (keeps only ancestors/descendants of a selected bind), so sibling apps' content no
longer rides along; an all-excluded app produces no userdata tar at all. Mechanics unchanged from
v0.130.0 (one root tar + per-mount skip), so the **manifest stays v1 and the import side is
untouched**; **legacy apps export byte-identically**. Mandatory is a server-side floor; optional is a
pre-selected checkbox; excluded is opt-in behind the two-number warning.
## Baselines (live-verified at session start)
| Repo | `main` @ start | Version | → |
|---|---|---|---|
| felhom-controller | `5f21613` | v0.135.0 | **v0.136.0** |
## Files
- **mod** `internal/appbackup/captureset.go` — extracted `resolveGuardCollapse` (shared pipeline); new `ComputeFabBuckets` + `FabBuckets`.
- **new** `internal/appexport/fabplan.go``fabPlan`, `computeFabPlan`, `fabUserdataExcludes` + `classifyFabRel`, `tarDirectoryExcluding`, `fabEstimateSplit`.
- **mod** `internal/appexport/export.go``ExportRequest` += `DeselectOptional`/`OptInExcluded`; `dirLister` seam; `exportHDDData` consumes the plan; `tarDirectory` → thin wrapper.
- **mod** `internal/appexport/estimate.go``ExportEstimate` class-split fields (additive); `FabItem`.
- **mod** `internal/appexport/provider.go` + `cmd/controller/main.go``GetStackClassifiedBinds` on the export seam + adapter.
- **mod** `internal/web/handler_export.go` + `handler_export_download.go` — both start handlers carry the selections (two-call-site).
- **mod** `internal/web/templates/app_export.html` — the class-selection UI.
- **tests** new `fabbuckets_test.go`, `fabplan_test.go`, `fabexport_test.go`, `fab_export_test.go`; provider fakes updated.
- CHANGELOG / REPORT / CONTEXT / README.
Untouched (§5/§12): `manifest.go`, `validate.go`, `restore.go`, every import handler, `ExportDataMounts` — the verdict rests on the import side staying byte-identical.
## Tests — results
`go build ./... && go vet ./... && go test ./...`**green.** New: bucket/guard/no-containment
(`ComputeFabBuckets`); plan scenarios AF + §8 (unmatched-mount-kept, skip-when-none, mandatory floor,
nested excludes); `tarDirectoryExcluding` FS-level; export-level bundle tests (exclude-scoped tar,
legacy full-root, all-excluded no-tar); the two-call-site bundle test across BOTH start pipelines.
### §10 red-proofs (mutate → FAIL → revert), all verified
| ID | Mutation | Test |
|---|---|---|
| A | legacy routed through the classified plan (drop short-circuit) | `FabExport_LegacyFullRoot` (userdata tar skipped) |
| B | always-tar the userdata root | `FabExport_AllExcludedNoUserdataTar` (tar present) |
| C | invert the keep-rule | `FabExport_ExcludeScopedUserdataTar` (mandatory excluded) |
| D3 | drop the server-side mandatory floor | `FabPlan_MandatoryFloor` (mandatory deselected) |
| E | skip guards for excluded buckets | `ComputeFabBuckets_GuardsAllClasses` (traversal enters a bucket) |
| F | drop selection fields from one start handler | `Fab_SelectionsRideBothStartPipelines/download` (opted-in content absent) |
All reverted; post-revert full suite green; no residue.
## Deploy / verify
`<filled after deploy>`
## §13 live validation
`<filled after the live legs>`
## 6D-pending
`<updated after §13>`
## Observations
- `ComputeCaptureSet` was refactored to share `resolveGuardCollapse` with `ComputeFabBuckets` (no
duplicate pipeline); its existing tests stayed green through the refactor.
- The estimate split is in the shared `EstimateExport`, so both estimate pipelines surface it by
construction; the genuine two-call-site risk (and the F red-proof) is on the START selections, which
the bundle test exercises per-handler.