Enhance school day structure and decision-making for lunch breaks
ci / server (push) Failing after 3m43s
ci / client (push) Successful in 15s

- Updated `ai.md` to clarify the mechanics of hunger restoration and the importance of lunch breaks in the school schedule.
- Revised `schedule.md` to detail the new lunch break structure, allowing for separate sittings for different grade levels.
- Enhanced `Decision.cs` and `DecisionPlanner.cs` to incorporate logic for lunch breaks, ensuring that students only leave lessons during their designated lunch windows.
- Updated `DayFrameDef` and related classes to support multiple lunch breaks and validate their configurations.
- Adjusted tests to validate the new decision-making logic regarding lunch breaks and hunger management, ensuring robust functionality.
- Improved localization strings to reflect changes in the school day structure and lunch functionalities.
This commit is contained in:
Leonid Pershin
2026-08-19 23:17:16 +03:00
parent a441ed9763
commit 5eabc90d53
33 changed files with 831 additions and 404 deletions
@@ -179,25 +179,10 @@ public class StaffingApiTests(AppHostFixture fixture)
Assert.True(assigned.Payroll > hired.Payroll);
Assert.Equal(2, assigned.Staff.Single().Subjects.Count);
using var over = await client.PostAsJsonAsync(
$"/api/schools/{school.Id}/staff/{Uri.EscapeDataString(teacher.Id)}/subjects",
new { subject = "Literature" },
TestContext.Current.CancellationToken);
// Cheap asks may still fit; only the numbers matter when the cap actually bites.
if (over.StatusCode == HttpStatusCode.Conflict)
{
var problem = await over.Content.ReadFromJsonAsync<ProblemResponse>(TestContext.Current.CancellationToken);
Assert.Equal("payroll-exceeded", problem?.Code);
Assert.True(problem?.Attempted > problem?.Allocated);
Assert.Equal(assigned.Payroll, problem?.Payroll);
}
else
{
over.EnsureSuccessStatusCode();
assigned = await over.Content.ReadFromJsonAsync<StaffingResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(assigned);
}
// A third subject used to be tried here with an if/else around the cap, which meant the
// test passed whichever way it went. The refusal has its own test now
// (AssigningPastTheCap_IsRejectedWithTheNumbers); this one is about assign, unassign and
// what survives a restart.
var payrollWithSubjects = assigned.Payroll;
using var unassign = await client.DeleteAsync(
$"/api/schools/{school.Id}/staff/{Uri.EscapeDataString(teacher.Id)}/subjects/RussianLanguage",