# Spec 049 — Configurable Break Policy System

**Status:** Ready for implementation
**Owner:** Scheduling / Timesheet team
**Created:** 2026-05-12
**Last reviewed:** 2026-05-12

## Documents

| Document | Path |
|---|---|
| Product Requirements | [product-requirements.md](./product-requirements.md) |
| Solution Design | [solution-design.md](./solution-design.md) |
| Implementation Plan | [implementation-plan.md](./implementation-plan.md) |

## One-line summary

Replace BuyerKiosk's hardcoded break classification with a per-store, rules-driven break policy engine. Ships with seven presets (FLSA-default + 6 state presets: CA, NY, OR, WA, CO, IL). Phased, feature-flagged rollout pilot-first. Eliminates employee-side break-type classification. Surfaces compliance violations (missed / late / short meals + premium pay).

## Phase structure

| PRD phase | PLAN phase | Title | Behavior change |
|---|---|---|---|
| Phase 1 | **T1** | Foundation — schemas, presets, evaluator, backfill | None |
| Phase 2 | **T2** | Read-path preview | None |
| Phase 3 | **T3** | Write-path cutover + Settings UI | Payroll-affecting; pilot-first |
| Phase 4 | **T4** | Employee UX cleanup | Cosmetic (employee pickers removed) |
| Phase 5 | **T5** | Compliance Dashboard + yearly refresh | Additive reporting |
| — | **T6** | Integration & E2E gate (cross-phase) | Quality gate |

Estimated effort: **~2.5-3 weeks** focused single-developer work + pilot buffer.

## Locked decisions

Captured as ADRs in the SDD, confirmed with the user via `AskUserQuestion`:

- **ADR-1** Pure-function rules engine (no I/O).
- **ADR-2** Adoption clones preset rules — preset changes never silently mutate adopted policies.
- **ADR-3** Per-store feature flag `stores.breakPolicyEnabled`, off by default.
- **ADR-4** Premium pay is flag-only in v1 (no auto-add to payroll totals).
- **ADR-5** WIW-integrated stores excluded from v1.
- **ADR-6** No city presets in v1 (data model supports v2).
- **ADR-7** Compliance flags only what active policy declares `isRequired = true`.
- **ADR-8** Yearly preset refresh = opt-in per store via "Update available" banner.

## Review history

### 2026-05-12 — Implementation Plan review (self-review)

- **Reviewer:** Self (Codex MCP was unavailable — three consecutive invocations returned empty output). A structured 10-dimension critique was performed independently against the same checklist Codex would have used.
- **Findings:** 4 blockers, 7 important, 4 enhancements. All accepted and patched into the plan.
- **Key changes applied:**
  - Rule snapshot in `breakComplianceLog.details` moved from Phase 5 retrofit to Phase 3 day-one wiring (T3.2.2a).
  - CSV export injection / RFC 4180 escaping / UTF-8 BOM made explicit (T5.2.3a-b).
  - WIW exclusion is now a concrete runtime check, not just an ADR (T3.2.1a-b).
  - Evaluator implementation decomposed into 7 sub-tasks (T1.5.3a-g).
  - Defensive read on flag column for partial-deploy safety (T1.5.2).
  - Evaluator instantiation pattern + per-request policy cache specified (T1.5.4-5).
  - Diff-replay harness now a Phase-1 deliverable (T1.7c) so Phase 3 has it ready.
  - Dev-fixture pattern for flag flipping (no ad-hoc UPDATE in PR descriptions) (T2.5.3a).
  - PRD ↔ PLAN phase-naming mapping table added.
- **Recommendation:** Re-run the review with Codex when MCP is back online — self-review is biased toward what was originally written, and an independent reviewer may catch additional issues.
- **Final phase count:** 6 (T1-T6). No structural changes.
- **Estimated complexity:** Unchanged at 2.5-3 weeks.
- **Decision:** ✅ Ready for implementation.

## Readiness checklist

- [x] All blockers resolved (4 blockers from review applied).
- [x] Plan covers all SDD components (schemas × 2 DBs, 7 presets, evaluator + DTOs, 2 controllers, 2 admin pages, employee surfaces, backfill, feature flag, compliance log, all 8 ADRs).
- [x] Tasks are actionable (evaluator broken into 7 sub-steps, no orphan "implement X" bullets).
- [x] Test tasks present in each phase (TDD-first per phase; ≥95 % evaluator coverage target).
- [x] Dependencies correctly mapped (T1 → T2 → T3 → T4 / T5 (parallel) → T6).
- [x] README captures review notes.

## Implementation kickoff — Phase 1 (T1) summary

**Goal:** All persistence and logic in place. Zero behavior change to any store.

**Files to create:**
- 11 migration JSON files under `userfrosting/migrations/input/break-policies/`:
  - 3 schema migrations (shared DB, store DB, feature flag column)
  - 7 preset data migrations (FLSA-default + 6 states)
  - 1 backfill migration (every store → FLSA-default policy, flag stays off)
- 5 model classes under `userfrosting/src/BuyerKiosk/Scheduling/Models/`
- 3 repository classes under `userfrosting/src/BuyerKiosk/Scheduling/Repositories/`
- DTO classes + `BreakPolicyEvaluator` + `BreakPolicyFeatureFlag` under `userfrosting/src/BuyerKiosk/Scheduling/Services/BreakPolicy/`
- 8 test classes under `tests/Unit/Scheduling/Services/BreakPolicy/`
- 1 conductor CLI command for diff-replay harness

**Tests to write first (TDD):**
1. `BreakPolicyEvaluatorTest` — happy paths + edge cases + open-punch non-throwing.
2. `PresetCa2025Test`, `PresetFlsaDefaultTest`, `PresetNy2025Test`, ... — fixture matrix per preset.
3. `BreakPolicyRepositoryTest` — adopt-preset transaction + cache invalidation + re-adoption idempotency.
4. `BreakComplianceRepositoryTest` — UPSERT idempotency.

**Command to start:**

```
/start:implement 049
```

**Validation gates for Phase 1 completion:**
- All migrations idempotent (re-run produces zero new operations).
- `./test.sh --testsuite unit` green.
- `./vendor/bin/phpstan analyse src/BuyerKiosk/Scheduling/Services/BreakPolicy/ src/BuyerKiosk/Scheduling/Models/` clean.
- Evaluator coverage ≥ 95 %.
- Every store has a backfilled `storeBreakPolicy` row pointing at `FLSA-default`.
- `stores.breakPolicyEnabled = 0` for every store (no behavior change yet).
- Diff-replay CLI works against pc00 historical data and prints zero delta vs current hot-fix totals.
