1. Secret apply conflict: secret.yaml is a raw `kubectl get -o yaml` dump
that includes the live resourceVersion/uid/creationTimestamp at capture
time. Applying a stale resourceVersion trips optimistic-concurrency
control ("the object has been modified") on effectively every restore,
since normal cluster activity keeps bumping it. Strip those three
volatile fields before `kubectl apply`.
2. Wrong re-seed source for Nextcloud: the re-seed step added for the PVC
exclusion fix assumed both Mautic and Nextcloud bake their excluded dirs
in at their own PVC mount path (/var/www/html), copying from
pvc_path/$dir. True for Mautic, wrong for Nextcloud — its image keeps
the shipped source tree at /usr/src/nextcloud, completely separate from
/var/www/html (empty in the raw image at that path). Caught in testing
("cp: cannot stat '/var/www/html/apps'") because the reseed_failed gate
from the previous fix did its job and left the app at 0 replicas instead
of booting broken — but still required a live manual fix to bring
Nextcloud back after the failed test. New RECONSTRUCT_SRC table makes
the copy source explicit and independently verified per app instead of
assumed by analogy: confirmed /usr/src/nextcloud/{apps,core,dist,
3rdparty,lib} exist in a bare nextcloud:32 pod with no volume mounted
before relying on it.
Verified end-to-end after both fixes: fresh Nextcloud backup -> restore ->
data/ intact (184M, 89 files, unchanged) -> occ status installed/healthy ->
200 on /status.php, via the actual script run (not just the manual
recovery), confirming the automated path works, not just my live fix.