feat(schedule_type): minute-precision windows + variable maintenance length #21

Merged
hzhang merged 1 commits from feat/schedule-type-minutes into main 2026-05-22 19:19:21 +00:00
Contributor

Lifts the two hard restrictions added in PR #18:

  • window bounds: int hour (0-23) → int minutes-since-UTC-midnight (0-1439). 半点 boundaries now exact
  • maintenance window: was exactly 1 hour → now any duration in [1, 180] minutes ((maint_to - maint_from) mod 1440)

Schema migration

_migrate_schema() detects legacy 'hours' rows (MAX of the 6 window columns ≤ 23) and multiplies each column by 60 to convert. Idempotent — guard never fires twice.

Touched surfaces (high-level)

  • models/schemas: bounds + validators; new compute_maintenance_duration() helper + derived maintenance_duration_minutes in response
  • special-slot schemas: minute_in_window max 59→179, estimated_duration max 60→180
  • special-slot router: _validate_fits_window takes the parent's maintenance duration
  • calendar router: maintenance-window guard arg names hour→min; error message formats HH:MM
  • materialiser: scheduled_at derives from (maint_from_min + tpl.minute_in_window) with hour/minute split

🤖 Generated with Claude Code

Lifts the two hard restrictions added in PR #18: - **window bounds**: `int hour` (0-23) → `int minutes-since-UTC-midnight` (0-1439). 半点 boundaries now exact - **maintenance window**: was exactly 1 hour → now any duration in `[1, 180]` minutes ((maint_to - maint_from) mod 1440) ## Schema migration `_migrate_schema()` detects legacy 'hours' rows (MAX of the 6 window columns ≤ 23) and multiplies each column by 60 to convert. Idempotent — guard never fires twice. ## Touched surfaces (high-level) - models/schemas: bounds + validators; new `compute_maintenance_duration()` helper + derived `maintenance_duration_minutes` in response - special-slot schemas: `minute_in_window` max 59→179, `estimated_duration` max 60→180 - special-slot router: `_validate_fits_window` takes the parent's maintenance duration - calendar router: maintenance-window guard arg names hour→min; error message formats HH:MM - materialiser: `scheduled_at` derives from `(maint_from_min + tpl.minute_in_window)` with hour/minute split 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hzhang added 1 commit 2026-05-22 19:19:16 +00:00
Lifts the two hard restrictions in PR #18:
  * window bounds were `int hour` (0-23) → now `int minutes-since-UTC-midnight` (0-1439)
  * maintenance window was exactly 1 hour → now any duration in [1, 180] minutes
    ((maint_to - maint_from) mod 1440)

## Schema migration (additive)

`_migrate_schema()` detects legacy "hours" rows (any row where MAX of the
6 window columns is ≤ 23) and multiplies each column by 60 to convert
to minutes. Idempotent — post-conversion values are well above 23 so
the guard never fires twice.

## Touched surfaces

- `models/schedule_type.py` — column comments updated; new
  `compute_maintenance_duration()` helper (returns 1-1440 min, treats
  from==to as 1440 which is then rejected by validator)
- `schemas/schedule_type.py` — `*_from`/`*_to` upper bound 23 → 1440;
  `_validate_maintenance_window` accepts 1-180min duration; response
  includes derived `maintenance_duration_minutes`
- `schemas/schedule_type_special_slot.py` — `minute_in_window` max
  59→179; `estimated_duration` max 60→180
- `routers/schedule_type.py` — PATCH re-validates merged maintenance
  pair (partial updates can put the row into an invalid combo the
  pydantic single-field validator can't catch); `_attach_derived`
  populates the new response field
- `routers/schedule_type_special_slot.py` — `_validate_fits_window`
  now takes the parent's maintenance duration instead of hard-coded 60
- `routers/calendar.py` — `_scheduled_inside_window` arg renamed
  hour→min; the maintenance-window guard error message formats
  HH:MM not HH:00
- `services/special_slot_materialiser.py` — materialised
  `scheduled_at` derived from `(maint_from_min + tpl.minute_in_window)`
  with hour/minute split

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hzhang merged commit 6fd37ab46d into main 2026-05-22 19:19:21 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: zhi/HarborForge.Backend#21