R-304 option C (hub half): recovery_older_package allowlisted and operator-only; design + row updated
gates / gates (push) Successful in 4m13s

Unreleased; ships with tomorrow's hub release.

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-10-08 10:09:20 +02:00
parent 83e6167145
commit 5beedcce1a
7 changed files with 43 additions and 4 deletions
+5 -1
View File
@@ -1,9 +1,13 @@
## Unreleased (2026-10-08) — an alarm when a box never backs up off-site because its escrow is pending (R-243; `09` §3 decision 179); a deleted customer's audit rows go after 1 year (R-901; decision 181) — ships with tomorrow's hub release
## Unreleased (2026-10-08) — an alarm when a box never backs up off-site because its escrow is pending (R-243; `09` §3 decision 179); a deleted customer's audit rows go after 1 year (R-901; decision 181); the operator's older-recovery-package mail (R-304; decision 183) — ships with tomorrow's hub release
**Operator action on deploy: none.** Expect ONE `offsite_escrow_pending` mail for **Tester 2** on the first sweep after
the deploy: its latest report (2026-10-04) says off-site ON, escrow `pending`, no successful run ever — the state the
operator believes it is in (decision 170).
- **R-304 option C (decision 183):** new event type `recovery_older_package` (sent by the controller of the same day when
a household's code opens, or may open, an older sealed escrow package): in `allowedEventTypes` and
`notify.operatorOnlyEvents`, no household text. Test `TestR304_RecoveryOlderPackageIsAllowlistedAndOperatorOnly`
(red-proved: without the allowlist line „the controller's push would 400").
- **R-901 (operator ruling 2026-10-08 09:04, decision 181):** after a customer is DELETED, its `events` and
`notification_log` rows are deleted 1 year after the deletion — a new daily step in `pruneAll`
(`store.PruneDeletedCustomerAudit`). A deletion is a `customer_resets` journal row with leg `customer_delete` = ok and
+3
View File
@@ -2169,6 +2169,9 @@ var allowedEventTypes = map[string]bool{
// R-243 — the hub raises these itself (monitor/offsite_escrow_pending.go); allowlisted like the line above.
"offsite_escrow_pending": true,
"offsite_escrow_pending_cleared": true,
// R-304 option C — controller (same day) sends it on an unlock that opens / may open an older package. Operator-only
// (notify.operatorOnlyEvents); NO customerMessages entry.
"recovery_older_package": true,
// controller v0.289.0 (decision 69): the customer-chosen deletion of set-aside history is deferred
// to the operator — the box's append-only key cannot delete. Operator-only (notify.operatorOnlyEvents).
"offbox_abandon_deferred": true,
@@ -0,0 +1,19 @@
package api
import (
"testing"
"gitea.dooplex.hu/admin/felhom-hub/internal/notify"
)
// R-304 option C (decision 183): the controller's recovery_older_package must be accepted (or POST /event 400s — R-77)
// and must reach only the operator. RED-PROOF: drop it from allowedEventTypes → "must be in allowedEventTypes".
func TestR304_RecoveryOlderPackageIsAllowlistedAndOperatorOnly(t *testing.T) {
et := "recovery_older_package"
if !allowedEventTypes[et] {
t.Fatalf("%s must be in allowedEventTypes — the controller's push would 400", et)
}
if !notify.IsOperatorOnly(et) {
t.Fatalf("%s must be operator-only — reopening old history is the operator's (R-312)", et)
}
}
+3
View File
@@ -707,6 +707,9 @@ var operatorOnlyEvents = map[string]bool{
// the reminder on every page; this is the operator's „they have not acted" line. Listed in the SAME commit.
"offsite_escrow_pending": true,
"offsite_escrow_pending_cleared": true,
// R-304 option C (2026-10-08, decision 183): a household's recovery code opens — or may open — an OLDER sealed
// escrow package; reopening old history is operator-only (R-312), so only the operator is told. Same commit.
"recovery_older_package": true,
// v0.127.0 (decisions 68–69, R-820/R-822). The off-site key registrar, its daily check and the
// clean-up window: custody facts about key lines and fingerprints — the household can take no
// action on any of them. Listed in the SAME commit that mints them.
@@ -6,7 +6,8 @@ import "testing"
// on every page, and a missing customerMessages entry would mail them raw operator English. Red-proof: delete either
// line from operatorOnlyEvents and this fails naming it.
func TestR243_EscrowPendingIsOperatorOnly(t *testing.T) {
for _, e := range []string{"offsite_escrow_pending", "offsite_escrow_pending_cleared"} {
// R-304 option C's recovery_older_package is pinned here too (same reason: operator-only, no household text).
for _, e := range []string{"offsite_escrow_pending", "offsite_escrow_pending_cleared", "recovery_older_package"} {
if !operatorOnlyEvents[e] {
t.Errorf("%s is not operator-only", e)
}