schedule

package
v0.11.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: BSD-2-Clause Imports: 2 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

AllRecurrenceKinds is the canonical, closed set of RecurrenceKind values in stable declaration order. Consumers that need to iterate over every kind (e.g. pre-initializing Prometheus counter label combinations) range over this slice — never hand-roll a duplicate slice.

Functions

This section is empty.

Types

type Date

type Date struct {
	Year  int
	Month time.Month
	Day   int
}

Date is a civil date (year, month, day) with no time, location, or zone ambiguity in its public surface. It is the only input shape accepted by publisher.Publish and the TasksForDate filter.

func NewDate

func NewDate(year int, month time.Month, day int) Date

NewDate constructs a Date from year/month/day.

func (Date) IsZero

func (d Date) IsZero() bool

IsZero reports whether the Date is the zero value (Year == 0 && Month == 0 && Day == 0).

func (Date) Time

func (d Date) Time() time.Time

Time converts the civil Date to its midnight-UTC carrier time.Time. Pure conversion — no system clock access, no DST math. Provided so consumers can run stdlib time arithmetic (ISOWeek, AddDate, Format) against the carrier without re-implementing the conversion or forcing a duplicate helper in their own package.

type Frontmatter

type Frontmatter = map[string]interface{}

Frontmatter is operator-defined YAML frontmatter stamped onto the generated vault file. Structurally identical to `bborbe/agent/lib`'s `TaskFrontmatter` (`map[string]interface{}`) but declared locally so the pure-data layer here doesn't pull in the agent module just to name a map type. The publisher converts to/from `lib.TaskFrontmatter` at its package boundary.

type RecurrenceKind

type RecurrenceKind string

RecurrenceKind classifies how often an entry repeats. Closed set.

const (
	RecurrenceDaily     RecurrenceKind = "daily"
	RecurrenceWeekly    RecurrenceKind = "weekly"
	RecurrenceWeekday   RecurrenceKind = "weekday"
	RecurrenceMonthly   RecurrenceKind = "monthly"
	RecurrenceQuarterly RecurrenceKind = "quarterly"
	RecurrenceYearly    RecurrenceKind = "yearly"
	// RecurrenceOnDate fires on one fixed calendar date (Month + Day) every
	// year — e.g. 03-15 for a birthday. Point-shaped match-fire, mirroring
	// how RecurrenceWeekday matches a day-of-week. Its publisher period token
	// is the fire date's 4-digit year ("YYYY"), so replays within a year are
	// idempotent (UUID5 dedup collapses them to one task file).
	RecurrenceOnDate RecurrenceKind = "ondate"
)

type TaskDefinition

type TaskDefinition struct {
	// Slug is a stable, kebab-case identifier unique across the inventory.
	// Once committed, a slug rename is a breaking change to the future Kafka
	// stream and requires a separate spec.
	Slug string

	// TitleTemplate is the title shown to the user. Supports only the
	// placeholders listed in publisher.SupportedPlaceholders (declared
	// in pkg/publisher/placeholders.go).
	TitleTemplate string

	// BodyTemplate is raw markdown. Supports the same placeholder set.
	BodyTemplate string

	// Recurrence classifies the cadence (daily/weekly/monthly/quarterly/yearly).
	Recurrence RecurrenceKind

	// Weekdays is the canonical set of weekdays a RecurrenceWeekday entry
	// fires on. Non-empty for RecurrenceWeekday (one or more days); nil/empty
	// and ignored for every other kind. Produced by the store adapter, which
	// normalizes the CR's string-or-list weekday value (long or short form)
	// to canonical time.Weekday values. The matcher (TasksForDate) fires the
	// entry on any day whose weekday is in this set; the publisher's period
	// token encodes the FIRING day's weekday (guaranteed in this set on a
	// firing day), so a list {Monday,Wednesday,Friday} yields three distinct
	// task files per ISO week, one per matching day.
	Weekdays []time.Weekday

	// Month is the calendar month a RecurrenceOnDate entry fires in
	// (time.January..time.December). Consulted only when
	// Recurrence == RecurrenceOnDate; is the zero value (time.Month(0)) and
	// ignored for every other kind. Produced by the store adapter from the
	// CR's spec.schedule.month field. Paired with Day: the matcher
	// (TasksForDate) fires the entry only when both this Month and Day equal
	// the civil date's month and day.
	Month time.Month

	// Day is the day-of-month a RecurrenceOnDate entry fires on (1-31).
	// Consulted only when Recurrence == RecurrenceOnDate; is the zero value (0)
	// and ignored for every other kind. Produced by the store adapter from
	// the CR's spec.schedule.day field. An OnDate of Month=February, Day=29
	// fires only in leap years (documented behavior, not an error).
	Day int

	// Frontmatter is operator-defined YAML frontmatter stamped onto the
	// generated vault file. Sourced from the `spec.template.frontmatter`
	// field on the Schedule CR (free-form map[string]interface{}). The
	// publisher seeds two defaults (`status: in_progress`,
	// `page_type: task`) and lets operator keys override them on
	// collision. `created_by: recurring-task-creator` is force-set as
	// provenance and cannot be overridden by configuration.
	Frontmatter Frontmatter

	// PeriodOffset shifts the period-anchored token by N periods. Default 0
	// (current period). Only meaningful for RecurrenceMonthly /
	// RecurrenceQuarterly / RecurrenceYearly — the CRD's CEL rule rejects
	// non-zero values for the date-anchored kinds (Daily / Weekly / Weekday).
	// Negative offsets name a prior period; the publisher's buildPeriodToken
	// applies the shift to the fire date before formatting the token.
	PeriodOffset int

	// AutoAbortPrior is the opt-in flag resolved from the CR's
	// spec.autoAbortPrior pointer by the store adapter (nil → false). A plain
	// bool, consistent with PeriodOffset's plain-int style — the schedule
	// layer stays pure data. The publisher mirrors this value onto every
	// materialized task's frontmatter as the `auto_abort_prior` key; the
	// downstream task-controller reads that key as its auto-abort eligibility
	// gate. Default false means a Schedule never opts into auto-abort unless
	// the operator explicitly sets spec.autoAbortPrior: true.
	AutoAbortPrior bool

	// Vault is the Obsidian vault slug the publisher stamps as TargetVault on
	// each CreateCommand — the controller's vaultName must equal this string
	// else the create is silently skipped as a vault mismatch. Sourced from
	// the CR's spec.vault by the store adapter; empty means "fall back to the
	// controller's legacy default (openclaw)" — wire-compatible with
	// pre-vault-aware producers.
	Vault string
}

TaskDefinition is one entry in the recurring-task inventory.

func TasksForDate

func TasksForDate(defs []TaskDefinition, date Date) []TaskDefinition

TasksForDate returns the subset of defs that fires on the given civil date. The caller supplies the definition slice; this function no longer reads a package-level inventory. The filter rule is:

  • RecurrenceDaily, RecurrenceWeekly, RecurrenceMonthly, RecurrenceQuarterly, RecurrenceYearly: always-fire (the entry fires on every day; this is the spec 006 always-fire semantic, preserved by spec 009).
  • RecurrenceWeekday: fires only when date.Time().Weekday() is a member of the entry's Weekdays set. An empty Weekdays set never fires (the CRD CEL rule rejects empty lists at apply time).
  • RecurrenceOnDate: fires only when both the entry's Month and the entry's Day equal the civil date's month and day. A zero Month or Day never fires (the CRD CEL rule rejects zero values at apply time).
  • Unknown kinds: skipped with a Warning log message — never fired.

The result is NOT sorted; the caller may sort on Slug if a stable order is required (the HTTP trigger handler does so for the response body).

Pure function: no I/O, no clock, no env. The Europe/Berlin civil-date conversion (and the ISO-week boundary math that goes with it) is the caller's responsibility — this function takes a civil Date, not a time.Time with a location.

An empty defs slice yields an empty slice. A defs slice that contains only RecurrenceWeekday entries whose Weekdays set does not include the given date's weekday also yields an empty slice.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL