v0.297.0: burn-down round 2 — 24 small rows (R-591 R-568 R-567 R-363 R-547 R-10 R-552 R-251 R-104 R-619 R-362 R-675 R-256 R-257 R-240 R-365 R-425 R-565 R-564 R-603 R-454 R-208 R-457-swept) + the banner countdown and deepCopyStack twins; MinAgent 0.131.0
gates / gates (push) Failing after 50s
gates / gates (push) Failing after 50s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -789,7 +789,7 @@ func main() {
|
||||
}
|
||||
if backupMgr != nil && cfg.Offsite.Enabled && cfg.Hub.URL != "" && cfg.Hub.APIKey != "" {
|
||||
bridge := &offsiteapply.Bridge{
|
||||
Cfg: cfg,
|
||||
Cfg: cfg,
|
||||
// Decision 69 (v0.289.0): the box sends its PUBLIC key to the hub's registrar, which pins it
|
||||
// append-only; the box never receives the sub-account password.
|
||||
Registrar: offsiteRegistrar,
|
||||
@@ -1507,13 +1507,18 @@ func main() {
|
||||
// every driveless app's recovery unit) were invisible, and it never reported a free-byte figure or
|
||||
// named a drive.
|
||||
//
|
||||
// CADENCE: DAILY, at 03:30. A fill is a slow-moving quantity — the thing that fills a disk is a
|
||||
// customer's photo library or a nightly backup, not a spike — so a shorter interval buys no
|
||||
// earlier warning and only costs statfs calls. 03:30 is deliberately BEFORE the nightly app-data
|
||||
// legs (db-dump / tier2 / offbox), so a customer who is about to lose a backup to lack of space
|
||||
// hears about it while there is still a night's margin, rather than after the failure.
|
||||
// The interval is NOT a cooldown: repeats are impossible because the check is edge-triggered per
|
||||
// filesystem, and the hub owns cooldown regardless.
|
||||
// CADENCE: every fillWatchInterval (10 min), PLUS the daily 03:30 run, PLUS once after startup.
|
||||
// The original reasoning was "a fill is slow-moving, so daily is enough"; two measurements proved
|
||||
// it wrong. R-363 (2026-08-21): a filesystem filled to 99% just after a daily run and the watcher
|
||||
// said nothing while the backup reserve was already refusing apps. R-547 (2026-09-17): a root
|
||||
// filesystem held at 96% for ten minutes raised no alarm of any kind. A daily sweep cannot carry
|
||||
// the word BEFORE; an interval no longer than the shortest measured window can. The cost is a
|
||||
// statfs per watched filesystem and one summary log line per run.
|
||||
// The interval is NOT a cooldown and adds no repeat mails: the check is edge-triggered against
|
||||
// PERSISTED bands with a hysteresis gap (fillwatch TestWarnsOnceThenIsSilent,
|
||||
// TestThresholdsKeepTheirHysteresisGap), and the hub owns cooldown regardless. The 03:30 run is
|
||||
// kept so the check still lands just before the nightly app-data legs. Pinned by
|
||||
// TestFillWatchRunsOnAnInterval.
|
||||
fillWatcher := fillwatch.New(
|
||||
filepath.Join(cfg.Paths.DataDir, "fillwatch-state.json"), logger,
|
||||
func() []fillwatch.Target { return fillTargets(cfg, sett) },
|
||||
@@ -1544,6 +1549,7 @@ func main() {
|
||||
// space the household can free on the kept-data list. Nothing is deleted by the box (D3).
|
||||
fillWatcher.SetExtra(func(t fillwatch.Target) string { return keptSpaceSentence(stackMgr, t.Path) })
|
||||
sched.Daily("fill-watch", "03:30", func(ctx context.Context) error { return fillWatcher.Check() })
|
||||
sched.Every("fill-watch-interval", fillWatchInterval, func(ctx context.Context) error { return fillWatcher.Check() })
|
||||
|
||||
// AND ONCE SHORTLY AFTER STARTUP. A box that BOOTS with a filesystem already over the line must
|
||||
// warn now, not up to 24 hours later — that is the R-100 shape, a real fault visible only after a
|
||||
@@ -2437,6 +2443,11 @@ func (s gatedAppStopStarter) StartStack(name string) error {
|
||||
// as unreadable (and be skipped, §8.4), never as a filesystem worth warning about.
|
||||
const fillWatchStartupDelay = 90 * time.Second
|
||||
|
||||
// fillWatchInterval is how often the fill check runs between the daily sweeps (R-363, R-547). It must
|
||||
// not exceed the shortest fill window that was measured going unannounced (ten minutes, R-547): any
|
||||
// window at least this long then contains a check. Pinned by TestFillWatchRunsOnAnInterval.
|
||||
const fillWatchInterval = 10 * time.Minute
|
||||
|
||||
// fillTargets is §8.1's watch list: the app-data volume, the system-data volume, and every
|
||||
// registered drive. Resolved at CHECK time, not at startup, so a drive added or decommissioned
|
||||
// between checks is picked up without a controller restart.
|
||||
|
||||
Reference in New Issue
Block a user