Skip to content

feat(timetable): score a timetable week on clashes, wishes, gaps and room use - #793

Merged
rubenvdlinde merged 3 commits into
developmentfrom
feat/timetable-generator-scorer
Sep 30, 2026
Merged

rubenvdlinde merged 3 commits into
developmentfrom
feat/timetable-generator-scorer

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Timetable generator, section 4: a scorer that measures a week

Base: development (19711e0). Sits on #791 (section 2, the solver input); merge #791 first, or merge this PR with a merge commit to land both.

Change: timetabling-generator (DECISIONS rows 17 and 21), section 4 of 9 (task 4.1). The change stays open; no row moves yet. Section 3 (the wish editor page) follows in its own PR.

What changes

  • lib/Timetabling/TimetableScorer.php: score(SolverInput, placements) returns metrics, brokenWishes and clashes for a week (design decision 5): lessons placed and unplaced, clashes (teacher, group or room booked twice, or a lesson that does not fit the day), hard wishes broken, soft wishes broken and their weighted sum, teacher gaps (total and worst), the worst lessons per day for a group, and room use per room type. cost(metrics) is the one number the solver will minimise: clashes, then hard wishes, then unplaced lessons, then soft wishes, then gaps.
  • lib/Timetabling/WeekGrid.php: period keys, the periods a multi-period lesson takes, days and gaps.
  • lib/Timetabling/WishChecker.php: the five wish kinds (unavailable, avoid, maxPerDay, noGaps, sameRoom) on a teacher, group, room or activity.

No screen, no schema, no string change.

Tests

TimetableScorerTest (10): a clean week and its measures; clashes counted; an unplaced lesson; each wish kind broken once and kept once (unavailable hard, avoid soft with weight, maxPerDay, noGaps, sameRoom, a wish on a room); the metrics and broken wishes of a finished scenario pass OpenRegister's validator against the real timetableScenario fragment.

Red first, against the section 2 head: all 10 failed (class missing). Log in the lane files.

Verification

At head 621476e (development 19711e0 + #791 + this section): composer check:strict 0 (lint, phpcs, phpmd, psalm, phpstan, PHPUnit 510 tests, 7 skipped). CI-shaped Hydra gates (hydra-gates@main, full coverage, this body): ALL 81 applicable gates passed. No frontend, l10n or schema change, so the npm checks were not rerun.

Live check

No endpoint yet: the scorer is called by the solver (section 5) and the import (section 6). vendor/bin/phpunit -c phpunit-unit.xml tests/unit/Timetabling/TimetableScorerTest.php is the check.

Inherited: the non-required Newman, PHPUnit (pgsql) and Quality Report jobs have been red on every PR since #758.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/planninq @ 6c8e334

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 02:37 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant