# S9 — Schedule dance groups across show dayparts with OR-Tools Status: IMPLEMENTED Agreed after the grill-me review; shared understanding confirmed. ## User story As a dance-school maintainer, I want to assign my school's dance groups to a show's dated dayparts, using configurable appearance counts per group type, so that appearances are spread evenly across the show. ## Show configuration - A show can have one to six dayparts across multiple dates. Each daypart has a date and a type: MORNING, AFTERNOON or EVENING. A date/type combination must be unique within a show. For example, Friday afternoon, Saturday afternoon and Saturday evening are three distinct dayparts. - An unscheduled show may have no dayparts while being configured. - Daypart dates are the source of truth. Remove the separate editable show date. Display the range from the earliest to the latest daypart date, or "No dates configured" when there are none. - Each show stores an editable appearance count for every dance-group type, including types with no current groups. Remove the backend `DanceGroupType.dayPartsRequired` property. - Initialize counts when creating the show using the following defaults, where N is the configured number of dayparts: | Type | Default appearances | | --- | --- | | PRE_SCHOOLER | 1 | | SHOW_CASE | N | | PRE_EDUCATION | N | | All remaining types | min(2, N) | - PRE_SCHOOLER's count is editable; one is a default, not a fixed exception. - Both frontend and backend enforce integer counts greater than zero and no greater than N for a configured show. With one daypart, all fields display one and are disabled in the frontend. - A show without dayparts remains unscheduled; usable counts must be initialized when its initial daypart configuration becomes available. - Subsequent daypart edits preserve the saved counts rather than reapplying defaults. Block saving if a count exceeds the new number of dayparts until the user corrects it. Adding a daypart does not automatically increase counts. ## Scheduling rules and objective - Use Google OR-Tools in the backend. - Include every current dance group belonging to the show's school. - Each group must appear in exactly the number of distinct dayparts configured for its type. A group cannot appear twice within one daypart. - Among assignments satisfying those requirements, minimize the difference between the largest and smallest number of group appearances per daypart. Count every configured daypart, including an empty one. - Assign groups to dayparts only. Do not calculate performance order or timing. - Require at least one school group and one configured daypart. Disable the scheduling action with an explanation when either is missing, and enforce the same requirements in the backend. ## Scheduling action and result handling - Provide an explicit "Schedule groups" action clearly indicating that it replaces the current assignments. A separate preview/accept workflow is outside this specification. - Run scheduling synchronously, with a solver time limit of 30 minutes. For S9, the frontend may remain blocked until the request returns; configure the request path to accommodate the agreed duration. - If a valid result is found, save it as a complete replacement of the existing assignments. This includes a valid result whose optimality has not been proven when the time limit is reached. - Distinguish "optimal balance" from "valid result; optimal balance not proven" in the result presented to the user. - If validation fails, the problem is infeasible, the solver fails, or the limit is reached without a valid result, explain the outcome and preserve existing assignments. Never silently reduce required appearances. - Disable the scheduling action while a run is pending. The backend must reject another concurrent run for the same show. - Before saving, verify that scheduling inputs have not changed during the run. If they changed, reject the stale result, preserve existing assignments and explain that the user must run scheduling again. ## Changes affecting existing schedules - Before accepting a potentially invalidating edit, warn that an existing show schedule may become invalid, name the affected shows and allow cancellation. - Cover adding/deleting school groups, changing a group's type, changing show dayparts and changing appearance counts when affected shows have assignments. Name-only edits do not require this warning. - After accepting the edit, do not automatically reschedule. Identify schedules whose assignments no longer meet the appearance requirements and offer the explicit scheduling action again. - Newly added groups use their type's saved count on the next scheduling run. ## JSON import/export - Preserve dated dayparts, group assignments and every per-type appearance setting through JSON export/import. - Update the format version and validation for the new structure, including allowing the same daypart type on different dates. - No legacy export compatibility or migration is required: the application is still greenfield and no exports have been made. ## Optional repeatability Identical inputs producing identical assignments is a nice-to-have for testability, not a mandatory scheduling requirement. Spend at most three minutes investigating how to achieve it. Implement it only if it requires at most ten additional code statements; otherwise omit it. Changed inputs may produce different assignments regardless. ## Out of scope and follow-up specifications - Group exclusions: S10_allow-group-exclusion-for-show. - Season context: S11_add-season-context-go-groups-and-shows. - Asynchronous scheduling feedback: S12_support-async-feedback-for-scheduling. - Scheduling on another PC: S13_create-runner-to-allow-scheduling-on-different-pc. - Availability restrictions, pinned assignments, capacity limits, shared-dancer constraints, duration/audience balancing and performance ordering. S10–S13 are intentionally empty placeholders and are to be refined separately. ## Acceptance criteria - [x] Configure up to six dated dayparts, reject duplicate date/type combinations and derive the displayed show date range from them. - [x] Persist editable per-type counts with the agreed defaults, remove the backend type-level property and validate counts in frontend and backend. - [x] With one daypart, every count is one and frontend fields are disabled. - [x] Daypart edits preserve configured counts and require correction of counts that exceed the new number of dayparts. - [x] OR-Tools assigns every school group to exactly its type's required number of distinct dayparts and minimizes the busiest/quietest appearance gap. - [x] Scheduling requires groups and dayparts and replaces assignments only after a successful, current result. - [x] The synchronous request supports a 30-minute solver limit, accepts valid unproven results and communicates whether optimality was proven. - [x] Failed, infeasible, stale and no-result runs preserve existing assignments and explain why no replacement was saved. - [x] Duplicate concurrent runs for a show are prevented in frontend and backend. - [x] Potentially invalidating edits warn beforehand, identify affected shows, permit cancellation and expose invalid schedules afterward without automatically rescheduling. - [x] New-format JSON round-trips dates, assignments and all type settings; legacy import support is not required. - [x] Any repeatability work respects both the three-minute investigation limit and the ten-additional-statement implementation limit. ## Implementation handoff This specification records the agreed behavior implemented on the current branch. The current application uses in-memory storage with JSON import/export for transfer. S9 adds the scheduling model, frontend controls, backend operation and JSON changes within that existing persistence approach. ## Implementation validation - Backend: 29 tests, including real OR-Tools balancing, input validation, JSON round-trips, concurrent scheduling, stale input rejection and failure preservation. - Frontend: 20 tests covering count validation, disabled single-daypart fields, edit cancellation, API timeout contract, production build and lint checks. - Playwright: real REST workflow for dated dayparts, scheduling and cancellation. - Repeatability uses one solver-parameter statement (single worker, fixed seed); no extended investigation was needed.