6be6c53e29
gates / gates (push) Successful in 25s
Red-proofs RP31-RP38. MinAgent 0.131.0 (unchanged). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
89 lines
3.2 KiB
Go
89 lines
3.2 KiB
Go
package settings
|
|
|
|
// ── Decision 50 (2026-09-30, R-720): a new app is in the off-site copy by default ──────────────────────
|
|
//
|
|
// The 2026-09-16 ruling turned the off-site tier ON for every new customer, but each app's own switch
|
|
// (`app_backup[<app>].offbox`) started OFF and only the backups page's „Bekapcsolás" set it. Measured on a
|
|
// fresh box 2026-09-29: three apps installed, every one „3. mentés Kikapcsolva", the night's off-site run
|
|
// „nincs kijelölt alkalmazás". The household was never told.
|
|
//
|
|
// DefaultOffboxOnForNewApp is called by the deploy-done hook (the one place a fresh install ends). It switches
|
|
// the app ON when, and only when:
|
|
// - an off-site target exists and is enabled (the customer has off-site — hub-provisioned or the
|
|
// household's own NAS), and
|
|
// - the app has NO per-app backup record yet. A record means someone already chose: an app removed
|
|
// WITHOUT deleting its backups keeps its record (R-474), so a reinstall keeps the household's earlier
|
|
// OFF. An app removed WITH its backups had its record deleted, so it is a new app again.
|
|
//
|
|
// It never turns anything OFF and never touches an app that is already installed (a release switches
|
|
// nothing by itself — the 2026-09-29 Part 0 rule).
|
|
// Pinned by internal/settings/offbox_default_test.go.
|
|
func (s *Settings) DefaultOffboxOnForNewApp(stackName string) (bool, string) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.Offbox == nil || !s.Offbox.Enabled || s.Offbox.Host == "" {
|
|
return false, "no off-site target"
|
|
}
|
|
if _, chosen := s.AppBackup[stackName]; chosen {
|
|
return false, "the app already has a backup choice"
|
|
}
|
|
if s.AppBackup == nil {
|
|
s.AppBackup = make(map[string]AppBackupPrefs)
|
|
}
|
|
s.AppBackup[stackName] = AppBackupPrefs{Offbox: true}
|
|
if err := s.save(); err != nil {
|
|
delete(s.AppBackup, stackName)
|
|
return false, "save failed: " + err.Error()
|
|
}
|
|
return true, ""
|
|
}
|
|
|
|
// AppsWithoutOffbox lists the given installed apps that are NOT in the off-site copy, when an off-site target
|
|
// exists (decision 50: the one-press offer for apps installed before the release). Empty when there is no
|
|
// target, or every app is on.
|
|
func (s *Settings) AppsWithoutOffbox(installed []string) []string {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
if s.Offbox == nil || !s.Offbox.Enabled || s.Offbox.Host == "" {
|
|
return nil
|
|
}
|
|
var out []string
|
|
for _, n := range installed {
|
|
if !s.AppBackup[n].Offbox {
|
|
out = append(out, n)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// EnableOffboxFor switches off-site ON for each named app in one save (the one-press offer).
|
|
func (s *Settings) EnableOffboxFor(apps []string) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.AppBackup == nil {
|
|
s.AppBackup = make(map[string]AppBackupPrefs)
|
|
}
|
|
for _, a := range apps {
|
|
p := s.AppBackup[a]
|
|
p.Offbox = true
|
|
s.AppBackup[a] = p
|
|
}
|
|
s.OffboxOfferDismissed = true // answered
|
|
return s.save()
|
|
}
|
|
|
|
// DismissOffboxOffer records the household's „Nem most".
|
|
func (s *Settings) DismissOffboxOffer() error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.OffboxOfferDismissed = true
|
|
return s.save()
|
|
}
|
|
|
|
// OffboxOfferDismissedValue reports whether the offer was answered.
|
|
func (s *Settings) OffboxOfferDismissedValue() bool {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return s.OffboxOfferDismissed
|
|
}
|