# Shift Schedule And Support Assignment

## Overview

Shift Schedule And Support Assignment places workforce `Assignment`s onto shifts (`ShiftPlacement`) and derives predicted-vs-actual variance. Placements are kept rather than deleted, so a confirmed shift schedule can be read back as "who was planned here, and when did that change". Beyond straightforward fixed shift schedules, it covers filling **open shifts**, 応援 (support work by someone from another post), and **multi-site** placement where a worker is placed at a Site other than their home post. After the fact, it compares the PLANNED shift span against time-tracking actuals (`ReportedTimeBlock` / `CalculatedTimeBlock`) to surface 遅刻 / 早退 / 未出勤 / 超過 (issues #11, #14, ADR-017).

## Business Purpose

- Record who staffs each slot — the single authoritative staffing record, since a Shift names nobody
- Enable 応援 (support) and multi-site fills where the staffing Assignment differs from the home post
- Fill open (unassigned) demand slots with a concrete Assignment
- Provide predicted-vs-actual variance by reading time-tracking actuals against the PLANNED shift
- Keep the one-dimensional labor-attribution seam (Assignment-level) that future multi-dimensional allocation builds on (ADR-018)

## Process Flow

```mermaid
flowchart TD
    A[Slot in a shiftSchedule] --> B{Placement type?}
    B -- Ordinary --> C[Place an Assignment]
    B -- Open-shift fill --> D[Place any eligible Assignment]
    B -- 応援 or multi-site --> E[Place an Assignment from another post or site]
    C --> F[ShiftPlacement created]
    D --> F
    E --> F
    F --> S{Plan changes before the date?}
    S -- Substitution --> T[swapShiftPlacement: old SUPERSEDED, new ACTIVE]
    S -- Unstaffed --> U[releaseShiftPlacement: CANCELLED, slot open again]
    S -- No --> G[Shift date reached and work performed]
    T --> G
    U --> G
    G --> H[Read time-tracking actuals for the Assignment]
    H --> I[Compare PLANNED span vs CalculatedTimeBlock]
    I --> J[Derive variance 遅刻 早退 未出勤 超過]
```

## Scenario Patterns

- **Direct placement**: an Assignment is placed onto a slot
- **Open-shift fill**: an eligible Assignment is placed onto a previously unassigned shift
- **応援 (support)**: an Assignment whose home Position / Site differs from the shift's Site is placed as coverage
- **Multi-site placement**: a worker is placed at a Site other than their home post
- **Team shift**: one shift carries multiple ShiftPlacements
- **Substitution (交代)**: `swapShiftPlacement` retires the outgoing placement as SUPERSEDED and places the replacement in one step; variance then reads the replacement, and the outgoing row remains the audit trail
- **Variance detection**: the planned span vs actuals yields 遅刻 / 早退 / 未出勤 / 超過, computed over ACTIVE placements only
- **Withdrawn shift guard**: a shift with `cancelledAt` set accepts no placements
- **Pay From Schedule (future room)**: paying by plan when no punch exists is left as a future rule option (ADR-017)

## Test Cases

- placing an Assignment onto a shift creates an ACTIVE ShiftPlacement
- filling an open shift (a slot with no ACTIVE placement) marks it staffed
- placing onto a withdrawn shift is rejected
- a substitution supersedes the outgoing placement rather than deleting it
- a support placement references an Assignment whose home Site differs from the shift's Site
- variance compares the PLANNED span against the time-tracking CalculatedTimeBlock for the placed Assignment
- the placed Assignment must be effective on the shift's date

## Reference Links

- 応援 (support) and shift schedule methods (キンタイミライ): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/11
- Contract-unit placement / work-attribution reference (sdx comparison): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/14
- ROI threshold for optimization scope: https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/6
