# UpdateWorkSchedule

## Permission Scope

workSchedule

## Overview

updateWorkSchedule records a planned-minutes change as a new effective-dated generation. It closes the current generation rather than overwriting history.

## Business Rules

- The Assignment must exist and its generation must cover the successor's `effectiveStart`
- The current open generation is closed on the day before the successor starts
- The successor shares `versionOf` with the current generation and has `effectiveEnd = null`
- The successor must start after the current generation starts
- `scheduledDailyMinutes` and `scheduledWeeklyMinutes` must be non-negative
- Existing custom fields are carried forward and explicit input values take precedence

## Process Flow

```mermaid
flowchart TD
    A[Receive Assignment, effectiveStart, planned minutes] --> B{Open generation exists?}
    B -- No --> BX[Return WORK_SCHEDULE_NOT_FOUND]
    B -- Yes --> C{New start is later?}
    C -- No --> CX[Return INVALID_EFFECTIVE_DATE]
    C -- Yes --> D{Minutes non-negative?}
    D -- No --> DX[Return NEGATIVE_MINUTES]
    D -- Yes --> E[Close current generation]
    E --> F[Insert successor generation]
```

## External Dependencies

None — `assignmentId` references this module's own Assignment, read directly for the effective-date check.

## Error Scenarios

- **ASSIGNMENT_NOT_EFFECTIVE**: the referenced Assignment does not exist or is not effective on the relevant date
- **WORK_SCHEDULE_NOT_FOUND**: no current WorkSchedule generation exists for the given assignment
- **INVALID_EFFECTIVE_DATE**: the effective date is not after the current generation's effectiveStart
- **NEGATIVE_MINUTES**: scheduledDailyMinutes or scheduledWeeklyMinutes is negative

## Test Cases

- throws ASSIGNMENT_NOT_EFFECTIVE when the Assignment does not cover the effective date
- closes the prior generation and inserts the revised planned-time baseline
- carries existing custom fields forward onto the successor generation
- throws INVALID_EFFECTIVE_DATE when the new generation does not start later
- throws WORK_SCHEDULE_NOT_FOUND when no open generation exists
