rayhpeng 9d0b09558e feat(schedule): add the schedule domain model
First step of the scheduled-task context's hexagonal migration: the
inner-ring model, with zero infrastructure dependencies.

- ScheduleSpec / SchedulePolicy value objects
- ScheduledTask aggregate root
- ScheduledRun aggregate
- 9 domain errors, 5 enums

Rules are migrated verbatim from their current homes, each method's
docstring citing the source line: timezone/cron/next-run calculation
from deerflow/scheduler/schedules.py, context-mode and re-arm rules from
routers/scheduled_tasks.py, and the four status-derivation rules from
app/scheduler/service.py.

Two things previously held by convention are now enforced by
construction. Validation and normalization live in __post_init__, so
building a ScheduleSpec field-by-field cannot bypass them. The skipped
tombstone is a separate factory, so it can never be written as the
transient queued row that would collide with uq_scheduled_task_run_active.

The domain does not serialize itself: mapping the stored schedule_spec
JSON in and out stays with the adapter layer, keeping Mapping[str, Any]
out of every domain signature.

Production code still runs through app/scheduler/service.py -- this
commit adds no call sites and changes no behavior.
2026-07-28 11:16:16 +08:00

59 lines
1.4 KiB
Python

"""Schedule bounded context: standing instructions to run a prompt on time.
Public API of the context. Import domain objects from here; ports will live in
`deerflow.domain.schedule.ports` -- they are contracts consumed by adapters and
tests, not everyday call-site symbols.
`ScheduleService` is not exported yet: this commit lands the model only.
"""
from deerflow.domain.schedule.model import (
ACTIVE_RUN_STATUSES,
CRON_FIELD_COUNT,
TERMINAL_RUN_STATUSES,
TERMINAL_TASK_STATUSES,
ActiveRunConflictError,
ContextMode,
InvalidContextModeError,
InvalidScheduleError,
LaunchFailedError,
RunStatus,
ScheduledRun,
ScheduledTask,
ScheduleError,
SchedulePolicy,
ScheduleSpec,
ScheduleType,
TaskNotFoundError,
TaskNotMutableError,
TaskStatus,
ThreadBusyError,
ThreadNotFoundError,
TriggerKind,
)
__all__ = [
"ACTIVE_RUN_STATUSES",
"CRON_FIELD_COUNT",
"TERMINAL_RUN_STATUSES",
"TERMINAL_TASK_STATUSES",
"ActiveRunConflictError",
"ContextMode",
"InvalidContextModeError",
"InvalidScheduleError",
"LaunchFailedError",
"RunStatus",
"ScheduleError",
"SchedulePolicy",
"ScheduleSpec",
"ScheduleType",
"ScheduledRun",
"ScheduledTask",
"TaskNotFoundError",
"TaskNotMutableError",
"TaskStatus",
"ThreadBusyError",
"ThreadNotFoundError",
"TriggerKind",
]