How it decides.
The scheduler is a constraint solver, not a language model. Everything below is what it is given, what it may not break, and what it weighs when more than one roster would work. Written for anyone who wants to check our work.
CP-SAT
Solver
Google OR-Tools, pinned at 9.8.3296. A constraint solver, not a language model.
22
Rules it cannot break
Published in full below, with 8 more it weighs rather than forbids.
6
Jurisdictions
Break, rest, young-worker and leave rules, per country and per site.
1–5s
Typical solve
Around 50 staff and 70 shifts. Longer problems get a longer budget.
04 — The register
The rules, in full.
22 it cannot break. 8 it weighs. Grouped by how each one is enforced.
- Engine
- OR-Tools CP-SAT
- Version
- 9.8.3296
Open any rule for the detail and where it lives in the source.
Role Conflict
Rostered to a role they do not hold.
Warning
Inside the minimum rest gap after the night before.
Backdated
Placed on a date that has already passed.
Unavailable
Outside the days this person can work.
Four of them, as the grid draws them. The rest of the register is below.
Who is even a candidate
12Applied before the search. Each returns the reason you saw above.
Only active staff enter the search
Employment status
Only ACTIVE staff enter the search at all.
scheduler.py:224
Trainees only fill shadow slots, and vice versa
Training segregation
Both directions are enforced, so a trainee cannot quietly become the coverage.
scheduler.py:231-235
Must hold the role the slot asks for
Role held
The person must hold the role the slot asks for.
scheduler.py:238-243
Must be assigned to that site
Location assignment
The person must be assigned to that site.
scheduler.py:241-244
Every certification the role needs, current
Role-required certifications
A lapsed certificate removes the person from the slot, not from a warning list.
scheduler.py:246-250
Inside their start and end dates
Employment date window
Both are checked per shift date, not once per roster.
scheduler.py:256-264
Week-on/week-off cycles, from an anchor date
Multi-week roster pattern
Longer cycles too, computed from a cycle length and an anchor date, so an off-week person is never offered.
scheduler.py:266-275
A specific date beats the usual pattern
Date-specific override
UNAVAILABLE blocks the day or just the overlapping hours. AVAILABLE replaces the recurring window for that date rather than adding to it.
scheduler.py:279-317
Shift sits entirely inside a declared window
Recurring availability
Partly-inside is not eligible.
scheduler.py:319-334
Full days, and half days by morning or afternoon
Approved leave
Half-day leave blocks only the matching half — AM blocks starts before noon, PM blocks starts from noon.
scheduler.py:336-351
Minimum and maximum length, overridable per site
Shift length by employment type
A per-location override outranks the org default, so a three-hour engagement minimum at one site does not have to become the rule everywhere.
scheduler.py:353-362
Curfews and shift caps, per age band, per country
Young-worker rules
Curfew start, curfew end and maximum shift length. Bands are configurable per organisation and default from the country preset.
scheduler.py:364-394 · lib/minor-work-rules.ts
What the model will not allow
10A roster breaking one of these is not scored badly. It cannot be represented.
Minimum, ideal and maximum headcount per slot
Staffing ceiling
The maximum is a hard ceiling the model cannot exceed. Slots between ideal and maximum are allowed but scored against.
scheduler.py:626-656 (CONSTRAINT 1)
No mentor on the floor, no shadow shift
Mentor pairing
A trainee in a shadow slot requires a non-trainee working an overlapping shift at the same site and role.
scheduler.py:668 (CONSTRAINT 1a)
A slot can require several certified people
Certification coverage
Not merely one.
scheduler.py:751 (CONSTRAINT 1b)
A first-aider on the floor every operating hour
Certification time-coverage
Enforced by hour, not by day. Not simply someone certified rostered somewhere that day.
scheduler.py:781 (CONSTRAINT 1c)
One person cannot be in two places
No overlapping shifts
No two shifts that overlap in time on the same date.
scheduler.py:846 (CONSTRAINT 2)
Always hard, never a warning
Maximum hours per day
Not a preference, not a flag after the fact.
scheduler.py:895 (CONSTRAINT 3)
Week, fortnight or month — whichever you run
Maximum hours per pay period
Scaled to the organisation’s pay period rather than assumed weekly. A fortnightly cap is enforced fortnightly.
scheduler.py:943 (CONSTRAINT 4)
No close followed by an open
Minimum rest between shifts
Reads shifts outside the range being filled, so the gap is still enforced across the boundary into the week you already published.
scheduler.py:1008 (CONSTRAINT 5)
Counts days already worked before this roster
Maximum consecutive days
Boundary-aware, so a run does not reset when a new roster starts.
scheduler.py:1079 (CONSTRAINT 6)
Two days off means two together
Minimum consecutive days off
A rolling-window check, so two separate single days do not satisfy a requirement for two consecutive.
scheduler.py:1139 (CONSTRAINT 6b)
What the model weighs
8Genuine trade-offs. A higher tier can never be outbid by a lower one.
The core goal, and nothing outbids itMEDIUM
Fill every slot
The tier every other consideration sits beneath.
scheduler.py:1714
Allowed to the maximum, scored past idealMEDIUM
Overstaffing above ideal
Every slot past ideal costs the solver something.
scheduler.py:1753
Heavy reward for giving everyone a shiftMEDIUM
Nobody sent home with nothing
In hospitality a casual rostered zero hours is a retention problem before it is a scheduling one.
scheduler.py:1794
Shortfall against a contracted commitmentMEDIUM
Minimum hours per period
For staff whose agreement is expressed in hours.
scheduler.py:1355 (CONSTRAINT 7)
For agreements written in days, not hoursMEDIUM
Minimum days per week
Tracked separately from the hours commitment.
scheduler.py:1206 (CONSTRAINT 8)
Grouped days beat a fragmented weekMEDIUM
Consecutive working days
Prefers a run over single shifts scattered with gaps between them.
scheduler.py:1311 (CONSTRAINT 9)
Under-hours penalised three times as hard as overSOFT
Asymmetric fairness
Short-changing someone is treated as the worse error, and that is a constant in the source rather than a claim in a brochure.
scheduler.py:1734-1735 · W_UNDER_TARGET = -3, W_OVER_TARGET = -1
Multi-site staff stay where they usually workSOFT
Home-site preference
Where the rest of the roster allows it.
scheduler.py:1750-1830
Scope
Where Rosie stops.
Inside
Rostering, time and the rules between them.
- Rosters and auto-fill
- Clock-ins and timesheets
- Leave and swaps
- Compliance rules
Outside, and the seam
Payroll
Rosie hands over hours and rates. It does not calculate tax or pay anyone.
Award advice
It applies the rules you configure. That is not the same as advice.
Point of sale
It does not read your sales, so it will not forecast labour against revenue.
Agentic AI
A constraint solver. It has no opinion about your team.
Jurisdictions
Six countries, and the gaps left visible.
| Rule | NZ | AU | UK | IE | US | CA |
|---|---|---|---|---|---|---|
| Rest and meal breaks | 10m at 2h
30m at 4h
10m at 6h | 10m at 4h
30m at 5h
10m at 7.5h | 20m at 6h | 15m at 4.5h
30m at 6h | No requirement | 30m at 5h |
| Minimum rest between shifts | 10h | 12h | 11h | 11h | No requirement | 11h |
| Maximum consecutive days | 6 | 6 | 6 | 6 | 7 | 6 |
| Young-worker bands1 | 2 bands, from 21:00 | 2 bands, from 21:00 | 3 bands, from 19:00 | 2 bands, from 20:00 | 2 bands, from 00:00 | 2 bands, from 21:00 |
| Annual leave (days, full-time) | 20 | 20 | 28 | 20 | No requirement | 10 |
| Sick leave (days per year)2 | 10 | 10 | No requirement | 5 | No requirement | 10 |
| Right to disconnect | No requirement | In force | No requirement | In force | No requirement | No requirement |
| Predictive scheduling | No requirement | No requirement | No requirement | No requirement | By jurisdiction | No requirement |
- 1New Zealand does set a youth night limit — Health and Safety at Work (General Risk and Workplace Management) Regulations 2016 reg 48 bars under-16s from work between 22:00 and 06:00 — and Rosie defaults one hour stricter than that. Australia has no federal youth curfew at all: child employment is state and territory law, and neither MA000004 nor MA000009 contains one. All of these are editable per organisation.
- 2The UK runs Statutory Sick Pay rather than a day entitlement.
Rates and rules
Dated, versioned, and replaceable.
United States · loadings
Full-time
- 1x
- Saturday
- 1x
- Sunday
- 1x
- Night
- 1x
- Public holiday
- after 40h · 1.5x
- Overtime
Full-time defaults. Part-time and casual are configured per employment type. Rule changes are dated rather than overwritten — fair Workweek laws in NYC, SF, Seattle, Chicago, Philadelphia, Oregon, LA, Berkeley, Emeryville.
Predictive scheduling
Advance-notice rules are modelled per jurisdiction, because they are city and state law rather than federal.
- New York City
- Chicago
- Philadelphia
- Seattle
- San Francisco
- Los Angeles
- Berkeley
- Emeryville
- Oregon
Changelog
Every rule change, in full.
Appended whenever a preset changes. Dates are when the change took effect, not when it was authored.
- AU Modern Award library v1 addedAU
Top-5 AU Modern Awards now available as installable presets: HIGA (Hospitality), GRIA (Retail), SCHADS, RIA (Restaurant), Aged Care MA000018. Apply via Settings → Compliance → Awards. Rates are best-known midpoints for the 2026-07-01 effective date — verify against the Fair Work pay tool before relying on for payroll.
- Extended leave typesAll countries
Added PARENTAL, BEREAVEMENT, JURY_DUTY, FAMILY_VIOLENCE, STUDY, IN_LIEU to the LeaveType enum. Statutory entitlements per country surfaced via `getStatutoryEntitlement(country, type)`.
- US Predictive Scheduling / Fair Workweek presetsUS
10 city presets added (NYC fast-food / NYC retail, Chicago, Philadelphia, Seattle, San Francisco, Oregon statewide, LA, Berkeley, Emeryville). Apply per-Location via Settings → Compliance → [Location] → Predictive. Compares Shift.publishedAt vs the configured advance-notice window.
- AU Right to Disconnect supportAU · IE
Per-Location quiet hours config; `sendPushToStaff()` now filters out recipients whose home location is in quiet hours. Default RTD config off — opt-in per Location. AU large-business law in force from 26 Aug 2024, small-business from 26 Aug 2025.
- Per-location compliance engineAll countries
New `LocationComplianceProfile` model + `lib/compliance-context.ts` resolver: every jurisdictional rule (breaks, minors, penalty rates, RTD, predictive scheduling, geofence, award) now resolves per-location with org-default fallback. Multi-jurisdiction orgs (e.g. Sydney + Auckland + London) supported end-to-end.
- AU Right to Disconnect extended to small businessAU
Right to refuse out-of-hours contact extended to employees of small business employers (under 15 employees). Awards updated to include RTD term. (Reference event — Rosie support shipped 2026-04-19.)
- AU Right to Disconnect commenced (large business)AU
Closing Loopholes Act provisions came into force for non-small-business employers. Employees can refuse to monitor / read / respond to contact outside their working hours, unless that refusal is unreasonable. (Reference event — Rosie support shipped 2026-04-19.)