v0.217.0: prefill from the app's own backup, where-the-data-goes on deploy, bounded inventory fan-out
gates / gates (push) Successful in 10s
gates / gates (push) Successful in 10s
Completes R-351 and ships R-352's visibility half. Gates 11/11 OK, suite 28 packages ok, go vet clean, -race clean on the changed package - all run and read BEFORE this commit. PART 2 SCENARIO A - the deploy page prefills the address and data folder from the app's OWN backup. backup.RecordedUnitForStack scans every readable namespace root (the app is NOT installed in this case, so there is no own drive to ask) and reads manifest.json plus the captured compose/app.yaml. Local file reads only: no network, no restic, no restore. RecordedAddress.Known() requires BOTH halves on purpose - an absent SUBDOMAIN makes the live deploy path substitute the CATALOG default (stacks/deploy.go:88-90), and offering that back as "what your backup says" would be a fabricated fact. The prefill is labelled as coming from the backup and stays editable: a memory, not a lock. PART 1 VISIBILITY (R-352) - the deploy page now states where the app's data will live before the button is pressed. Measured 2026-08-21: 13 of 53 catalogue templates declare a storage field; the other 40 have none and their data goes to the system drive, which no screen said. Metadata.HasDeployField answers "does this app have somewhere to PUT a recorded value?" - for the 40-class a recorded placement is a fact to state, never a value written into a field that does not exist. NO PLACEMENT CHANGED. NOTHING MIGRATED. The rest is a filed specification. PART 4 - measured before theorising, on the live off-site target: snapshots --json 2605 ms once; stats 2697 ms PER APP, sequential, 5 app tags => 2605 + 5*2697 = ~16.1 s, matching the reported ten-to-fifteen seconds. The cause is the shape already on file, so the per-app size calls now run concurrently, BOUNDED TO 4. The bound is the safety property, not the speed one: the repository is a Hetzner Storage Box with a session cap, and a refused size call returns SizeBytes 0 - a silent UNDER-REPORT of the customer's data rather than a visible failure. Peak-in-flight is asserted. OffsiteInventoryList had no test at all before this. TEMPLATE SAFETY - every Restore* key is set UNCONDITIONALLY in the deploy handler, because a template doing index/eq against an undefined key errors at RENDER time: green build, green vet, green suite, 500 on the page. Four render tests, one per branch, because the existing deploy render test only renders AutoFields and never reaches these blocks. RED-PROOFS, mutation asserted applied then reverted to 0: A three template guards dropped (count asserted 3) -> the blank form returned P4 inventorySizeConcurrency = 1 -> "peak in flight was 1", elapsed 282ms = sequential DOCS: CHANGELOG v0.217.0 (MinAgent 0.129.0 unchanged), CONTEXT (the restore's own memory + what is next), controller/README.md (Backup System), REUSE.md (4 new rows), REPORT.md overwritten - the previous REPORT preserved to audits/REPORT-v0.216.0-2026-08-14.md first. NOT fixed here, filed as R-353 and named the next session's first item: a restore whose unit carries no db_dumps and no volume_dumps still reports a bare completion.
This commit is contained in:
@@ -455,6 +455,32 @@
|
||||
{{end}}
|
||||
|
||||
<form id="deploy-form" class="deploy-form">
|
||||
{{/* R-351 SCENARIO A — the values below came from this app's OWN backup, so a reinstall does
|
||||
not ask the customer to remember what the backup already recorded. Stated, never silent:
|
||||
a prefilled field whose origin is unexplained is indistinguishable from a default. */}}
|
||||
{{if and (not .AlreadyDeployed) .RestoreHasRecord}}
|
||||
<div class="alert alert-info" style="margin-bottom:1rem">
|
||||
<svg class="ico ico-sm"><use href="#i-info"/></svg>
|
||||
Ennek az alkalmazásnak van korábbi mentése, ezért az alábbi mezőket a saját mentése alapján töltöttük ki.
|
||||
{{if .RestoreRecordedAddress}}Korábbi webcím: <strong>{{.RestoreRecordedAddress}}</strong>.{{end}}
|
||||
{{if .RestoreRecordedDrive}}Az adatai itt voltak: <strong>{{.RestoreRecordedDrive}}</strong>.{{end}}
|
||||
Ha most máshová szeretnéd telepíteni, nyugodtan átírhatod — a visszaállítás előtt jelezni fogjuk az eltérést.
|
||||
</div>
|
||||
{{end}}
|
||||
{{/* R-351 / Part 1 — WHERE THE DATA WILL LIVE, before the button is pressed. Measured
|
||||
2026-08-21: 13 of 53 catalog templates declare a storage field; the other 40 have none and
|
||||
their data goes to the system drive, which no screen said. This states it. It changes no
|
||||
placement — that is a separate ruling and a separate session. */}}
|
||||
{{if not .AlreadyDeployed}}
|
||||
<div class="form-hint" style="margin-bottom:1rem">
|
||||
{{if .RestoreRecordedDeclaresPath}}
|
||||
Az alkalmazás adatai az alább kiválasztott adatmeghajtóra kerülnek.
|
||||
{{else}}
|
||||
<strong>Hol lesznek az adatok:</strong> ennél az alkalmazásnál nincs külön adatmeghajtó-választás,
|
||||
ezért az adatai a rendszermeghajtóra kerülnek (<code>{{.SystemDataPath}}</code>). A mentései így is elkészülnek.
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .DockerBelowReserve}}
|
||||
<div class="alert alert-warning" style="margin-bottom:1rem">
|
||||
<svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg> Nincs elég szabad tárhely a telepítéshez. Jelenleg {{.DockerFreeHuman}} szabad, és a rendszer
|
||||
@@ -521,7 +547,9 @@
|
||||
<div class="subdomain-input-group">
|
||||
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
||||
class="form-control subdomain-input"
|
||||
value="{{if and $.AlreadyDeployed $.DeployedFieldValues}}{{index $.DeployedFieldValues .EnvVar}}{{else}}{{.Default}}{{end}}"
|
||||
{{/* R-351: a reinstall offers the address the customer's own backup recorded,
|
||||
ahead of the catalog default. Editable — a domain can legitimately change. */}}
|
||||
value="{{if and $.AlreadyDeployed $.DeployedFieldValues}}{{index $.DeployedFieldValues .EnvVar}}{{else if index $.RestoreFieldValues .EnvVar}}{{index $.RestoreFieldValues .EnvVar}}{{else}}{{.Default}}{{end}}"
|
||||
placeholder="aldomain"
|
||||
pattern="[a-z0-9]([a-z0-9-]*[a-z0-9])?"
|
||||
required
|
||||
@@ -578,7 +606,11 @@
|
||||
{{range $.StoragePaths}}
|
||||
<option value="{{.Path}}" data-free-percent="{{printf "%.0f" .FreePercent}}"
|
||||
{{if .NotAllowed}}disabled{{end}}
|
||||
{{if $.AlreadyDeployed}}{{if eq .Path $.CurrentHDDPath}}selected{{end}}{{else if and .IsDefault (not .NotAllowed)}}selected{{end}}>
|
||||
{{/* R-351: on a reinstall the drive the BACKUP recorded wins over the
|
||||
configured default — it is where this app's data actually lived, and
|
||||
restoring into a different drive is the mismatch the restore then has
|
||||
to stop and name. The customer can still pick another. */}}
|
||||
{{if $.AlreadyDeployed}}{{if eq .Path $.CurrentHDDPath}}selected{{end}}{{else if $.RestorePrefillHDDPath}}{{if and (eq .Path $.RestorePrefillHDDPath) (not .NotAllowed)}}selected{{end}}{{else if and .IsDefault (not .NotAllowed)}}selected{{end}}>
|
||||
{{.Label}} — {{.FreeHuman}} szabad{{if .NotAllowed}} ({{.NotAllowedNote}}){{else if .IsDefault}} (alapértelmezett){{end}}
|
||||
</option>
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user