maven: fix test mocks for CalendarEvents interface (verification)

- Add CalendarEvents method to recordingAPI in auth_test.go
- Add CalendarEvents method to fakeCore in handlers_test.go

Co-Authored-By: opencode <opencode@anthropic.com>
This commit is contained in:
kami
2026-07-06 04:20:16 +04:00
parent 880715fad4
commit d52f60c54e
71 changed files with 287 additions and 280 deletions
+6 -6
View File
@@ -27,12 +27,12 @@ type RuleTrace struct {
// GateDetail — snapshot of the values the gate checked.
type GateDetail struct {
SnoozeUntil *time.Time `json:"snooze_until,omitempty"`
CooldownUntil *time.Time `json:"cooldown_until,omitempty"`
QuietHours bool `json:"quiet_hours"`
CalendarBusy bool `json:"calendar_busy"`
Presence string `json:"presence"` // "present"|"away"
InertKeysMissing []string `json:"inert_keys_missing,omitempty"`
SnoozeUntil *time.Time `json:"snooze_until,omitempty"`
CooldownUntil *time.Time `json:"cooldown_until,omitempty"`
QuietHours bool `json:"quiet_hours"`
CalendarBusy bool `json:"calendar_busy"`
Presence string `json:"presence"` // "present"|"away"
InertKeysMissing []string `json:"inert_keys_missing,omitempty"`
}
// ExplainGate runs the same checks as Gate() but records the first blocker.
+1 -1
View File
@@ -119,4 +119,4 @@ func ParseCooldownFact(f store.Fact) (time.Duration, bool) {
func MarshalCooldown(d time.Duration) string {
b, _ := json.Marshal(int64(d)) // int64 marshal never errors
return string(b)
}
}
+4 -4
View File
@@ -97,10 +97,10 @@ func TestFeedbackKeyMatchesRuleName(t *testing.T) {
func TestParseCooldownFactRoundTrip(t *testing.T) {
d := 45 * time.Minute
f := store.Fact{
Key: "cooldown:water",
Key: "cooldown:water",
Source: FeedbackSource,
Value: MarshalCooldown(d),
Ts: refTime(),
Value: MarshalCooldown(d),
Ts: refTime(),
}
got, ok := ParseCooldownFact(f)
if !ok {
@@ -149,4 +149,4 @@ func repeat(v string, n int) []string {
out[i] = v
}
return out
}
}
+1 -1
View File
@@ -242,4 +242,4 @@ func collapseReminders(due []store.Reminder) []store.Reminder {
Status: "pending",
Collapsed: due,
}}
}
}
+1 -1
View File
@@ -134,4 +134,4 @@ func CooldownFor(base time.Duration, lastSend time.Time) time.Time {
return time.Time{} // never sent → no cooldown active
}
return lastSend.Add(base)
}
}
+7 -7
View File
@@ -129,9 +129,9 @@ func TestTickCooldownSuppresses(t *testing.T) {
now := refTime()
// 4h since water (would fire) — but cooldown until now+10min. Suppressed.
s := State{
Now: now,
Presence: store.Present,
Facts: map[string]store.Fact{
Now: now,
Presence: store.Present,
Facts: map[string]store.Fact{
"water": factAt("water", "tap:water", `"250ml"`, now.Add(-4*time.Hour)),
},
CooldownUntil: map[string]time.Time{
@@ -197,9 +197,9 @@ func TestGateNoDataInertShutsUp(t *testing.T) {
// is missing in the snapshot — gate must still return false.
s := State{Now: refTime(), Presence: store.Present}
iwantfire := Rule{
Name: "x",
Severity: Sev1,
Predicate: func(State) bool { return true },
Name: "x",
Severity: Sev1,
Predicate: func(State) bool { return true },
InertWhenNoData: []string{"missing_key"},
}
if Gate(s, iwantfire) {
@@ -379,4 +379,4 @@ func TestGathererUsesFeedbackTunedCooldown(t *testing.T) {
if d, ok := ParseCooldownFact(fb); !ok || d != tuned {
t.Fatalf("ParseCooldownFact round-trip: want %v ok, got %v ok=%v", tuned, d, ok)
}
}
}
+21 -21
View File
@@ -15,10 +15,10 @@ import "time"
// auto-tuner scales it over time (mostly ignored → lengthen; acted → leave).
// Bounds belong at the daemon-config level; here we just carry the base.
type Rule struct {
Name string
Severity Severity
Cooldown // base cooldown + bounded-duration envelope for the auto-tuner
Predicate func(State) bool
Name string
Severity Severity
Cooldown // base cooldown + bounded-duration envelope for the auto-tuner
Predicate func(State) bool
// InertWhenNoData — most rules should be silent when their substrate key is
// missing (since(key)==null → don't fire). If the predicate already encodes
@@ -43,9 +43,9 @@ type Cooldown struct {
// Inert when no water fact exists at all (shuts up when uncertain).
func WaterRule() Rule {
return Rule{
Name: "water",
Severity: Sev1,
Cooldown: Cooldown{Base: 30 * time.Minute, Min: 15 * time.Minute, Max: 6 * time.Hour},
Name: "water",
Severity: Sev1,
Cooldown: Cooldown{Base: 30 * time.Minute, Min: 15 * time.Minute, Max: 6 * time.Hour},
InertWhenNoData: []string{"water"},
Predicate: func(s State) bool {
d, ok := s.Since("water")
@@ -60,16 +60,16 @@ func WaterRule() Rule {
// MealRule — sev1 care: if ≥6h since an `meal` fact, fire. Inert without data.
func MealRule() Rule {
return Rule{
Name: "meal",
Severity: Sev1,
Cooldown: Cooldown{Base: 60 * time.Minute, Min: 30 * time.Minute, Max: 8 * time.Hour},
Name: "meal",
Severity: Sev1,
Cooldown: Cooldown{Base: 60 * time.Minute, Min: 30 * time.Minute, Max: 8 * time.Hour},
InertWhenNoData: []string{"meal"},
Predicate: func(s State) bool {
d, ok := s.Since("meal")
if !ok {
return false
}
return d >= 6 * time.Hour
return d >= 6*time.Hour
},
}
}
@@ -79,9 +79,9 @@ func MealRule() Rule {
// Inert unless both exist — can't claim continuous activity without both anchors.
func BreakRule() Rule {
return Rule{
Name: "break",
Severity: Sev2,
Cooldown: Cooldown{Base: 45 * time.Minute, Min: 20 * time.Minute, Max: 4 * time.Hour},
Name: "break",
Severity: Sev2,
Cooldown: Cooldown{Base: 45 * time.Minute, Min: 20 * time.Minute, Max: 4 * time.Hour},
InertWhenNoData: []string{"desk_active", "break"},
Predicate: func(s State) bool {
dDesk, ok1 := s.Since("desk_active")
@@ -101,9 +101,9 @@ func BreakRule() Rule {
// a compromised poller writing under a different source can't forge the trigger.
func ServiceDownRule() Rule {
return Rule{
Name: "service_down",
Severity: Sev4,
Cooldown: Cooldown{Base: 15 * time.Minute, Min: 5 * time.Minute, Max: 1 * time.Hour},
Name: "service_down",
Severity: Sev4,
Cooldown: Cooldown{Base: 15 * time.Minute, Min: 5 * time.Minute, Max: 1 * time.Hour},
InertWhenNoData: []string{"service_down"},
Predicate: func(s State) bool {
f, ok := s.Fact("service_down")
@@ -123,9 +123,9 @@ func ServiceDownRule() Rule {
// the hard page. Provenance-scoped to poll:netdata.
func NetdataCriticalRule() Rule {
return Rule{
Name: "netdata_critical",
Severity: Sev3,
Cooldown: Cooldown{Base: 20 * time.Minute, Min: 10 * time.Minute, Max: 2 * time.Hour},
Name: "netdata_critical",
Severity: Sev3,
Cooldown: Cooldown{Base: 20 * time.Minute, Min: 10 * time.Minute, Max: 2 * time.Hour},
InertWhenNoData: []string{"netdata_alarm"},
Predicate: func(s State) bool {
f, ok := s.Fact("netdata_alarm")
@@ -148,4 +148,4 @@ func DefaultRules() []Rule {
ServiceDownRule(),
NetdataCriticalRule(),
}
}
}
+1 -1
View File
@@ -106,4 +106,4 @@ func (s State) Since(key string) (time.Duration, bool) {
return 0, true
}
return s.Now.Sub(f.Ts), true
}
}