# Changelog

All notable changes to this project are documented here. Newest entries on top.

## [2026.10.31-258] - 2026-10-31 - 02:58

### Added

- The web solver is published on GitLab Pages at <https://rostering-solver.niftylittletools.dev/>: a `.gitlab-ci.yml` runs its 11 tests (the Python cross-check uses recorded figures), builds `solver_web/` and publishes it; `site` set; the README's Live line.

## [2026.10.30-1916] - 2026-10-30 - 19:16

### Changed

- Repository link: GitLab group `web-static` is now `browser-tools`.

## [2026.10.30-1844] - 2026-10-30 - 18:44

### Changed

- Repository link follows the project to `web-static/rostering-solver`.

## [2026.10.29-1959] - 2026-10-29 - 19:59

### Documentation

- README rewritten to the workspace structure (`_templates/README.md`): the key line, Features, Installation, Usage (with the Python solver's `--log`), Parameters/Flags, How it works (the model) and Development.
- The Python solver's `uv run pytest` is no longer listed: `solver_python/tests/` holds no tests yet.

### Fixed

- `uv.lock` had recorded an older version of the project itself, which `uv sync --locked` refuses; relocked (one line, no dependency changed). `check_conformance.py` now checks it.

## [2026.10.28-28] - 2026-10-28 - 00:28

### Added

- **`solver_web` rebuilt as a real tool** (owner decision, 2026-10-27: build, not retire). It is an Astro page in the Cyanotype house style that solves the Python solver's model exactly in the browser, with HiGHS (`highs` 1.15.4, MIT) compiled to WebAssembly. The rules: each shift covered by exactly the people it needs every day; one shift a day per person, only where they are available and never on leave; hours within each person's maximum. The objective: the busiest person works as few shifts as any valid roster allows.
- Editing in the page: shifts (name, times, hours, how many needed), one or two weeks, staff with maximum hours, and an availability grid per person with a leave row. Results: a roster table, hours per person, and, when there is no roster, why: the shifts nobody can work on a given day, or conflicting hour limits.
- Files: the example (the Python sample CSV), import of the Python solver's staff CSV, save and open the setup as JSON, roster export as CSV.
- Tests (`pnpm test`, 11, with the real HiGHS): **the Python cross-check**. The sample CSV, solved by the Python solver (OR-Tools) and by this page, gives the same optimum: all 56 slots covered, the busiest person on 2 shifts. An independent validator checks every rule on the result. Each rule is tested in both directions: a fairness split, a slot nobody can work, hour limits that cannot be met next to ones that can, and no double shifts. The CSV tests cover quoting and missing columns.
- `mise.toml` at the repository root (Node 24, pnpm 12.15.0), and a hashed `packageManager` in `solver_web`.

### Removed

- The single-file prototype (`solver_web/index.html` and its vanilla privacy files). It loaded `constraint-solver` from unpkg.com, a third-party request, and solved one fixed week for two built-in people with no leave or hour limits.

### Changed

- README rewritten around the shared model, the web tool's features, and its privacy (no third party now; `'wasm-unsafe-eval'` for the solver). `solver_python/uv.lock` records the project's own current version.

## [2026.10.27-2249] - 2026-10-27 - 22:49

### Fixed

- The privacy notice's stylesheet copied again from `_notice/`: it is drawn on `--paper` when a tool defines it, falling back to `--surface` and then white as before.

## [2026.10.27-0911] - 2026-10-27 - 09:11

### Fixed

- `solver_web/`: the privacy notice sits above every overlay and closing it returns focus to what opened it.

## [2026.10.26-1926] - 2026-10-26 - 19:26

### Added

- `solver_web/`: **Privacy & security notice** (`_notice/`, English only): it stores nothing of yours; unpkg is named as the one third party. A footer with the repository, changelog, attribution and **Privacy settings**; Content-Security-Policy and referrer-policy `<meta>` tags.

### Verified

- `verify.mjs` in Edge: the notice passes every check.

### Known issue

- **The web prototype does not run**: it loads `constraint-solver` unpinned from unpkg, which now serves version 4.0.0 as an ES module, so the classic `<script>` fails and `Solver is not defined`. Older than today; the prototype's conversion should pin or bundle the solver.

## [2026.10.26-1842] - 2026-10-26 - 18:42

### Changed

- `solver_python/` migrated from Poetry to **uv**: PEP 621 `[project]`, `uv_build` backend (flat layout), `requires-python = ">=3.12"`, `.python-version` 3.12, `uv.lock`; `poetry.lock` removed. Authorship set to Arziel.
- OR-Tools moved to 9.15.6755. `README.md` rewritten: it was still GitLab's project template; it now says what the tool is, both versions, how to run them, and their privacy notes.

### Fixed

- `solver_python`: the solver crashed after solving on OR-Tools 9.15 (`TypeError: 'CpSolverStatus' object is not callable` inside the deprecated `StatusName()`). `print_solution` now takes the status `Solve()` returns and names it with `status_name(status)`. Verified: the bundled two-week sample solves in 0.15 s and prints the roster, with no deprecation warnings.

### Added

- `solver_python/README.md` (it was empty): what it does, install, usage, the CSV columns, privacy.
- `## Privacy & security` in both READMEs: the Python solver keeps everything local and a real staff CSV is personal data; the web prototype loads `constraint-solver` from unpkg and sends no roster data.

### Security

- `pip-audit` over the new lockfile: no known vulnerabilities.

## [2026.10.26-1813] - 2026-10-26 - 18:13

### Changed

- `.gitattributes` normalising line endings to LF (`* text=auto eol=lf`) and marking binaries.

## [2026.6.29-2006] - 2026-06-29 - 20:06

### Added

- **Navbar logo:** the tool's `logo.svg` now appears as the brand mark in the
  header/navbar, matching the in-app favicon and the catalogue listing.

## [2026.6.29-0412] - 2026-06-29 - 04:12

### Added

- **Logo / favicon:** added a tool-specific `logo.svg` (Lightline house recipe —
  accent-coloured Font Awesome `calendar-check` glyph on a dark rounded tile) and wired it
  as the favicon. solver_web; was none. The single SVG doubles as the reusable tool logo.
