Claim chat autosend periods as list_ready:chat:YYYY-MM-DD (F20-01)
CI / ci (push) Successful in 7m36s
CI / ci (pull_request) Successful in 7m21s

The shopping_chat_autosend schedule now claims its schedule_runs period
under AutosendKey of the coming week's Monday instead of the ISO week key.
Schedule gains an optional PeriodKey hook that replaces the rule's key;
Register rejects a schedule setting both Key and PeriodKey. The fake-clock
tests assert the stored period keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 16:11:51 -04:00
co-authored by Claude Opus 5.5
parent 7f48a67ad4
commit 9ff50fd558
4 changed files with 30 additions and 13 deletions
+14 -3
View File
@@ -209,6 +209,11 @@ type Schedule struct {
// colon ("start:2026-10-14"), so two schedules of one Name claim
// different periods. Name and Key together are unique.
Key string
// PeriodKey, when set, gives the period key claimed for p in place of
// the rule's, such as "list_ready:chat:2026-10-19" for the week p.Week;
// p.Key is the rule's key. It must give each period its own key. A
// schedule sets Key or PeriodKey, not both.
PeriodKey func(p Period) string
// Rule returns when the schedule fires under settings. It is called
// again after every settings change.
Rule func(settings household.Settings) Rule
@@ -293,6 +298,9 @@ func (s *Scheduler) Register(sch Schedule) error {
if strings.Contains(sch.Key, ":") {
return fmt.Errorf("scheduler: register %s: key has a colon", sch.label())
}
if sch.Key != "" && sch.PeriodKey != nil {
return fmt.Errorf("scheduler: register %s: both key and period key", sch.label())
}
s.mu.Lock()
defer s.mu.Unlock()
if s.started {
@@ -562,14 +570,17 @@ func (s *Scheduler) retry(ctx context.Context, targets []target, now time.Time)
func (s *Scheduler) handle(ctx context.Context, t target, now time.Time) bool {
it, at, date := t.it, t.at, t.date
period := Period{Key: it.rule.PeriodKey(date), FireAt: at, Date: date}
if it.sch.Key != "" {
period.Key = it.sch.Key + ":" + period.Key
}
if it.rule.NextWeek {
period.Week = household.WeekStart(addDays(date, 7))
} else {
period.Week = household.WeekStart(date)
}
switch {
case it.sch.Key != "":
period.Key = it.sch.Key + ":" + period.Key
case it.sch.PeriodKey != nil:
period.Key = it.sch.PeriodKey(period)
}
log := s.logger.With("schedule", it.sch.Name, "period", period.Key, "fire_at", at.Format(time.RFC3339))
claimed, err := s.claim(ctx, it.sch.Name, period.Key, now)