hub v0.120.0: app_update_undone/held reach the household, per app, in its language
gates / gates (push) Successful in 26s

Allowlisted, not operator-only, seeded for new households and added
once (add-only) to every existing enabled_events row. mail.event entries
in hu and en name the app from details.stack_name. Per-app cooldown on
both the operator and the household leg.

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:
2026-09-23 13:47:13 +02:00
parent 05ea21e918
commit d3b284863e
22 changed files with 563 additions and 5 deletions
+5
View File
@@ -233,6 +233,11 @@ var defaultSeedEvents = []string{
"host_disk_critical",
"storage_fill_critical",
"offbox_repo_orphaned",
// v0.120.0 (`09` §3 decision 15): the household is told ONCE when an update is undone, and when
// it (or its undo) failed and the app is held. Existing households get them by the one-time,
// add-only store.SeedEventTypesOnce.
"app_update_undone",
"app_update_held",
}
// MarkClaimed records a controller-reported successful claim and sends the one-time confirmation
+14
View File
@@ -76,3 +76,17 @@ func TestMarkClaimed_EmptyEmail_NoRow_ClaimSucceeds(t *testing.T) {
t.Fatalf("idempotent re-claim: %v", err)
}
}
// v0.120.0 — a NEW household hears about an undone or held update from day one.
// RED-PROOF (REPORT.md): drop app_update_undone from defaultSeedEvents → this fails naming it.
func TestDefaultSeedIncludesTheUpdateOutcomes(t *testing.T) {
have := map[string]bool{}
for _, e := range defaultSeedEvents {
have[e] = true
}
for _, et := range []string{"app_update_undone", "app_update_held"} {
if !have[et] {
t.Fatalf("defaultSeedEvents must include %s", et)
}
}
}