# ListPunchesByAssignment

## Overview

Lists an Assignment's `TimeClockEvent`s over a date range, in occurrence order, paginated. This is the raw punch trail view for a worker — for example when investigating a discrepancy or reviewing the full audit history behind a period.

## Business Rules

- Filters by `assignmentId` and an inclusive `occurredAt` date range
- Events are ordered by `occurredAt` (occurrence order), not by insertion or workday
- Includes voided events; the raw rows are returned unchanged and nothing is excluded because it was later voided (void state lives in TimeClockEventVoid)
- Results are paginated

## Process Flow

```mermaid
flowchart TD
    A[Caller supplies assignmentId + date range + pagination params] --> B{Valid assignmentId and range?}
    B -- No --> C[Return INVALID_QUERY_PARAMS]
    B -- Yes --> D[Look up TimeClockEvents for assignmentId within occurredAt range]
    D --> E[Sort by occurredAt, occurrence order]
    E --> F[Return paginated page of events]
```

## External Dependencies

- [time-tracking::TimeClockEvent](../model/TimeClockEvent.md) model — entity being queried

## Error Scenarios

- **INVALID_QUERY_PARAMS**: a required query parameter is missing or malformed
- **INVALID_PAGINATION_CURSOR**: supplied pagination cursor is not valid for this query

## Test Cases

- returns events for the Assignment within the date range, ordered by occurredAt
- includes voided events: the raw rows are returned unchanged (void state is external)
- returns an empty page when no events exist in the range
- events from multiple sources (e.g. IC_CARD clock-in, MOBILE clock-out) on the same day are both returned
- returns INVALID_QUERY_PARAMS when the date range start is after the end
