# Organizational Assignment

## Overview

Organizational Assignment places a `WorkerEmployment` into a `Position` and maintains that placement as an **effective-dated** series (ADR-013). A transfer is a new Assignment generation, not an overwrite; concurrent posts are multiple simultaneously-open Assignments with exactly one flagged primary. This is the layer downstream modules use to answer **"whose"** — a time punch, a scheduled shift, and a leave request all reference the Assignment effective on their date, which is how support work and multi-post staffing become representable (issues #14, #16).

## Business Purpose

- Represent transfers, promotions, and concurrent postings as versioned assignment history rather than destructive updates
- Provide the "whose / which department / which site" resolution that time-tracking, scheduling, and leave-management depend on
- Enable point-in-time org-chart reconstruction together with Position and AppointmentHistory
- Lay the seam for future manager-chain approval routing (via Position hierarchy) without implementing it now (ADR-016)

## Process Flow

```mermaid
flowchart TD
    A[Assign employment to a Position] --> B{Position effective on assignment date?}
    B -- No --> X[Reject: POSITION_NOT_EFFECTIVE]
    B -- Yes --> C{Assignment range within employment range?}
    C -- No --> Y[Reject: OUTSIDE_EMPLOYMENT_RANGE]
    C -- Yes --> D[Create primary Assignment generation]
    D --> E{Transfer to a new Position?}
    E -- Yes on date T --> F[Close current: effectiveEnd = T - 1]
    F --> G[Insert new generation: effectiveStart = T]
    E -- Concurrent post --> H[Open additional non-primary Assignment]
```

## Scenario Patterns

- **Initial assignment**: a newly employed Worker is assigned to a Position as their primary post
- **Transfer**: moving to a new Position closes the prior generation and opens a new one; prior placement stays queryable
- **Concurrent posting**: a Worker holds two open Assignments; exactly one is primary, the other(s) non-primary
- **Support / multi-site**: a time punch or shift references an Assignment other than the primary to attribute work to the right post (minimal one-dimensional allocation, ADR-018)
- **Post abolished**: when a Position is abolished, the Assignment generation is closed; the employment may be reassigned
- **Guardrails**: assignment cannot start before employment begins or after termination; cannot target a not-yet-effective or abolished Position

## Test Cases

- assigning an active employment to an effective Position creates one open primary Assignment
- a transfer closes the prior generation and inserts a new one with no range overlap
- opening a concurrent assignment yields exactly one primary among the open assignments
- assigning outside the employment's effective range is rejected
- assigning to a Position not effective on the assignment date is rejected
- querying `asOf` a past date returns the Assignment effective then

## Reference Links

- Data-model design research (Assignment tier, "whose" resolution): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/7
- sdx comparison (Contract-unit work attribution, org-linked routing as reference): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/14
