feat(timetable): generate a timetable scenario that keeps every hard wish - #795
Merged
Merged
Conversation
…er day and room use
…oft, on the week grid
…wish, in time-boxed background steps
Contributor
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 107/107 | |||
| npm | ✅ | ✅ 646/646 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it on any branch from the Actions tab, or locally with npx playwright test. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-30 05:34 UTC
Download the full PDF report from the workflow artifacts.
This was referenced Sep 30, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Timetable generator, section 5: generate a scenario that keeps every hard wish
Base: development (19711e0). Sits on #794 (section 3, wishes), which sits on #793 (section 4, scorer) and #791 (section 2, input). Merge in that order, or merge this PR with a merge commit to land all four.
Change:
timetabling-generator(DECISIONS rows 17 and 21), section 5 of 9 (tasks 5.1, 5.2, 5.3). The change stays open. Row moved to built:tt-hard-soft-wishes.What the user can now do
An admin opens Timetable, Scenarios, opens a scenario and presses Generate. The run goes to the background in 60-second steps up to the time budget (
timetable_generator_budget_minutes); the scenario page shows the status and the share of the budget used, then how many lessons got a place, the lessons without a place with the hard wish that blocked each one, and the soft wishes the timetable breaks. A generated scenario never breaks a hard wish: a lesson that cannot be placed without breaking one stays off the grid and names that wish.How
lib/Timetabling/TimetableSolver.phpinterface, bound toLocalSearchSolverinApplication::register(where a CP-SAT sidecar can be bound per instance later).LocalSearchSolverplaces lessons greedily, most constrained first, then improves with simulated annealing onTimetableScorer(section 4), seeded bySeededRandom, with a move bound per step so the same seed gives the same result, and ends with a repair pass that takes a lesson breaking a hard wish off the grid.SearchState,PlacementOptions,SolverResulthold the working state.POST /api/timetable/scenarios/{id}/generate(admin,AuthorizedAdminSettingplus an admin check: 403 otherwise, 400 for a scenario that has no input) queueslib/BackgroundJob/GenerateTimetableScenario.php; each step continues from the best placements of the step before (TimetableGenerationService), re-queues while it improves and time is left, and storesfailedwith the reason on an exception.TimetableScenarioStorereads and writes the scenario inside OpenRegister.TimetableScenarios(declarative index,/timetable/scenarios) andTimetableScenarioDetail(declarative detail) whosesectionsslot issrc/components/TimetableScenarioSections.vue. No new custom page, so the gate-69 ratchet holds. Helpers insrc/utils/timetableScenarios.js. 22 new strings in all 36 locales.Tests
tests/unit/Timetabling/LocalSearchSolverTest.php(7): a feasible week places everything and keeps the hard wish; an impossible hard wish leaves one lesson unplaced naming the wish; a hard limit is never broken; a soft wish is kept when it costs nothing; same seed same result; 600 lessons inside 60 seconds, with the stored result validated against the realtimetableScenariofragment.tests/unit/Service/TimetableGenerationServiceTest.php(6): re-queues while improving, stops at the budget, storesfailedwith the reason on an exception.tests/unit/Controller/TimetableScenarioControllerTest.php(3): a non-admin is refused.tests/vitest/timetableScenarios.spec.js(5);tests/e2e/timetable-generator.spec.ts: "generate a scenario that respects a hard wish" (nightly Playwright; not runnable from the lane clone).Red first: all 16 PHPUnit cases failed with the classes missing (lane log
lane16/red-s5.log).Verification
At head 9f23200 (development 19711e0 + #791 + #793 + #794 + this section):
composer check:strict1 (phpcs, phpmd static access) then 0 (PHPUnit 526, 7 skipped); npm lint, stylelint, check:l10n, check:l10n-js, check:schema-l10n, check:manifest, vitest (42 files, 413 tests) and build all 0. CI-shaped Hydra gates (hydra-gates@main, full coverage, this body): gate-16 spec-coverage 1 (the job's run method) then 0: ALL 82 applicable gates passed.Live check
POST /apps/planninq/api/timetable/scenarios/<id>/generateanswers 403.Inherited: the non-required Newman, PHPUnit (pgsql) and Quality Report jobs have been red on every PR since #758.
🤖 Generated with Claude Code