Skip to content

Release 0.9.0-rc.1 - #514

Merged
fabiodalez-dev merged 633 commits into
mainfrom
release/0.9.0-rc.1
Nov 1, 2026
Merged

fabiodalez-dev merged 633 commits into
mainfrom
release/0.9.0-rc.1

Conversation

@fabiodalez-dev

Copy link
Copy Markdown
Owner

Release candidate 0.9.0-rc.1: the 0.9.0 stack (#502 → #504 → #505 → #506 → #507 → #508 → #509 → #510 → #511 → #512 → #513) plus the version bump, the CHANGELOG entry and the README lead.

The prerelease tag goes on the head of this PR once every required check is green; the PR is merged with a merge commit afterwards, so the tagged commit stays in main. #503 (CI runners, TinyMCE 8.10.0) carries the same three CI commits as #502 and is part of this tree.

Upgrade path

  • The migration ships as migrate_0.9.0-rc.1.sql: a prerelease sorts before its final, so migrate_0.9.0.sql would be skipped on the upgrade to the RC; this name runs on the RC and again on the later 0.9.0 upgrade, where it is a no-op.
  • tests/migration-0.9.0-rc.1.unit.php runs every section test; scripts/verify-schema.sh now also runs the test of a migrate_X.Y.Z-rc.N.sql at the stable X.Y.Z, and fails when it is missing.
  • mobile-api 1.9.0 requires 0.9.0-rc.1, so it can be activated on the RC.

Settings of an upgraded installation
The migration only inserts missing rows. Stocktake, suppliers, the visitor log, RDA overrides and fines start switched off; the other modules are on but change nothing until configured (the seeded Standard patron type inherits every global setting, the closures calendar is empty, no fine is charged, nobody is blocked, no new e-mail is sent). Historic prestiti.sanzione amounts become ledger debts only after fines and loss penalties are switched on.

Checks run on this head
Local Code Quality mirror on a fresh 0.9.0 database: PHPStan level 5 on the full tree, composer and npm audits, locale and route parity, frontend lint, migration and requires_app guards, schema gate with version.json at 0.9.0-rc.1, 325 of 328 standalone unit tests. The three that do not pass locally fail identically on the unchanged code from a worktree (two maintenance tests hit the main checkout's server; one suite needs to create databases as root) and run in CI.

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 659 files, which is 559 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

Usage-priced reviews support at most 300 files.

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 9a9e0ea and 19e7c60.

Files ignored due to path filters: 137
  • package-lock.json is excluded by !**/package-lock.json
  • public/assets/tinymce/README.md is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/bower.json is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/composer.json is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/icons/default/icons.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/icons/default/icons.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/license.md is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/models/dom/model.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/models/dom/model.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/notices.txt is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/package.json is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/accordion/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/accordion/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/advlist/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/advlist/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/anchor/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/anchor/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autolink/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autolink/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autoresize/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autoresize/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autosave/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/autosave/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/charmap/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/charmap/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/code/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/code/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/codesample/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/codesample/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/directionality/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/directionality/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/emoticons/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/emoticons/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/fullscreen/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/fullscreen/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/help/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/help/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/image/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/image/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/importcss/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/importcss/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/insertdatetime/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/insertdatetime/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/link/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/link/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/lists/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/lists/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/media/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/media/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/nonbreaking/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/nonbreaking/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/pagebreak/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/pagebreak/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/preview/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/preview/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/quickbars/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/quickbars/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/save/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/save/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/searchreplace/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/searchreplace/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/table/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/table/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/visualblocks/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/visualblocks/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/visualchars/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/visualchars/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/plugins/wordcount/plugin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/plugins/wordcount/plugin.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/skins/content/dark/content.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/content/dark/content.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/content/dark/content.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.inline.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.inline.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.inline.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.inline.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.inline.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/content.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/skin.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/skin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/skin.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/skin.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide-dark/skin.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.inline.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.inline.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.inline.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.inline.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.inline.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/content.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/skin.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/skin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/skin.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/skin.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/oxide/skin.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.inline.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.inline.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.inline.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.inline.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/content.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/skin.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/skin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/skin.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/skin.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5-dark/skin.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.inline.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.inline.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.inline.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.inline.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.inline.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/content.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/skin.css is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/skin.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/skin.min.css is excluded by !**/*.min.css, !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/skin.min.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/skins/ui/tinymce-5/skin.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/themes/silver/theme.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/themes/silver/theme.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
  • public/assets/tinymce/tinymce.d.ts is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/tinymce.js is excluded by !public/assets/tinymce/**
  • public/assets/tinymce/tinymce.min.js is excluded by !**/*.min.js, !public/assets/tinymce/**
Files selected for processing: 659
  • .github/workflows/ci-browser-security.yml
  • .github/workflows/ci-database-compatibility.yml
  • .github/workflows/ci-deep-regression.yml
  • .github/workflows/ci-e2e.yml
  • .github/workflows/ci-quality.yml
  • .github/workflows/ci-real-upgrade.yml
  • .github/workflows/ci-security-supply-chain.yml
  • .github/workflows/ci-upgrade-smoke.yml
  • .github/workflows/codeql.yml
  • .github/workflows/pullfrog.yml
  • .github/workflows/release.yml
  • .github/workflows/test-migrations.yml
  • .gitignore
  • .gitleaksignore
  • .rsync-filter
  • CHANGELOG.md
  • README.md
  • app/Controllers/Admin/LibraryCalendarController.php
  • app/Controllers/Admin/StatsController.php
  • app/Controllers/AttendanceController.php
  • app/Controllers/AutoriApiController.php
  • app/Controllers/CatalogueCardController.php
  • app/Controllers/CirculationSettingsController.php
  • app/Controllers/CollaneController.php
  • app/Controllers/CopyController.php
  • app/Controllers/CsvImportController.php
  • app/Controllers/DeweyApiController.php
  • app/Controllers/EditoriApiController.php
  • app/Controllers/FrontendController.php
  • app/Controllers/GeneriApiController.php
  • app/Controllers/ImportHistoryController.php
  • app/Controllers/InventoryController.php
  • app/Controllers/LibraryThingImportController.php
  • app/Controllers/LibriApiController.php
  • app/Controllers/LibriController.php
  • app/Controllers/LoanApprovalController.php
  • app/Controllers/MarcExportController.php
  • app/Controllers/MarcImportController.php
  • app/Controllers/PatronCardsController.php
  • app/Controllers/PatronLedgerController.php
  • app/Controllers/PrestitiApiController.php
  • app/Controllers/PrestitiController.php
  • app/Controllers/PublicApiController.php
  • app/Controllers/RegistrationController.php
  • app/Controllers/ReservationManager.php
  • app/Controllers/ReservationsAdminController.php
  • app/Controllers/ReservationsController.php
  • app/Controllers/SearchController.php
  • app/Controllers/SettingsController.php
  • app/Controllers/SuppliersController.php
  • app/Controllers/UserActionsController.php
  • app/Controllers/UserDashboardController.php
  • app/Controllers/UserImportController.php
  • app/Controllers/UsersController.php
  • app/Controllers/UtentiApiController.php
  • app/Middleware/FeatureGateMiddleware.php
  • app/Models/AttendanceRepository.php
  • app/Models/AuthorRepository.php
  • app/Models/BookRepository.php
  • app/Models/CopyRepository.php
  • app/Models/LoanRepository.php
  • app/Models/PublisherRepository.php
  • app/Models/SettingsRepository.php
  • app/Models/SupplierRepository.php
  • app/Routes/web.php
  • app/Services/BulkEnrichmentService.php
  • app/Services/CapacityService.php
  • app/Services/Circulation/LoanPolicy.php
  • app/Services/Circulation/PolicyResolver.php
  • app/Services/Circulation/UserPolicy.php
  • app/Services/CirculationPolicy.php
  • app/Services/FineCalculator.php
  • app/Services/FineParameters.php
  • app/Services/LoanRequestGate.php
  • app/Services/PatronLedger.php
  • app/Services/ReservationReassignmentService.php
  • app/Services/StocktakeService.php
  • app/Services/UnifiedCatalogService.php
  • app/Support/ActivityLog.php
  • app/Support/AuthorNormalizer.php
  • app/Support/CatalogueCard.php
  • app/Support/CataloguingExtras.php
  • app/Support/ConfigStore.php
  • app/Support/ContentSecurityPolicy.php
  • app/Support/ContributorSync.php
  • app/Support/DataIntegrity.php
  • app/Support/ExactSearch.php
  • app/Support/Features.php
  • app/Support/Holidays/ChineseLunarCalendar.php
  • app/Support/Holidays/CustomHolidays.php
  • app/Support/Holidays/HolidayCalculator.php
  • app/Support/Holidays/HolidayDataset.php
  • app/Support/Holidays/HolidayPresets.php
  • app/Support/Holidays/HolidayRules.php
  • app/Support/Holidays/WorldCalendars.php
  • app/Support/Holidays/data/AD.json
  • app/Support/Holidays/data/AE.json
  • app/Support/Holidays/data/AF.json
  • app/Support/Holidays/data/AG.json
  • app/Support/Holidays/data/AI.json
  • app/Support/Holidays/data/AL.json
  • app/Support/Holidays/data/AM.json
  • app/Support/Holidays/data/AO.json
  • app/Support/Holidays/data/AQ.json
  • app/Support/Holidays/data/AR.json
  • app/Support/Holidays/data/AS.json
  • app/Support/Holidays/data/AT.json
  • app/Support/Holidays/data/AU.json
  • app/Support/Holidays/data/AW.json
  • app/Support/Holidays/data/AX.json
  • app/Support/Holidays/data/AZ.json
  • app/Support/Holidays/data/BA.json
  • app/Support/Holidays/data/BB.json
  • app/Support/Holidays/data/BD.json
  • app/Support/Holidays/data/BE.json
  • app/Support/Holidays/data/BF.json
  • app/Support/Holidays/data/BG.json
  • app/Support/Holidays/data/BH.json
  • app/Support/Holidays/data/BI.json
  • app/Support/Holidays/data/BJ.json
  • app/Support/Holidays/data/BL.json
  • app/Support/Holidays/data/BM.json
  • app/Support/Holidays/data/BN.json
  • app/Support/Holidays/data/BO.json
  • app/Support/Holidays/data/BQ.json
  • app/Support/Holidays/data/BR.json
  • app/Support/Holidays/data/BS.json
  • app/Support/Holidays/data/BT.json
  • app/Support/Holidays/data/BV.json
  • app/Support/Holidays/data/BW.json
  • app/Support/Holidays/data/BY.json
  • app/Support/Holidays/data/BZ.json
  • app/Support/Holidays/data/CA.json
  • app/Support/Holidays/data/CC.json
  • app/Support/Holidays/data/CD.json
  • app/Support/Holidays/data/CF.json
  • app/Support/Holidays/data/CG.json
  • app/Support/Holidays/data/CH.json
  • app/Support/Holidays/data/CI.json
  • app/Support/Holidays/data/CK.json
  • app/Support/Holidays/data/CL.json
  • app/Support/Holidays/data/CM.json
  • app/Support/Holidays/data/CN.json
  • app/Support/Holidays/data/CO.json
  • app/Support/Holidays/data/CR.json
  • app/Support/Holidays/data/CU.json
  • app/Support/Holidays/data/CV.json
  • app/Support/Holidays/data/CW.json
  • app/Support/Holidays/data/CX.json
  • app/Support/Holidays/data/CY.json
  • app/Support/Holidays/data/CZ.json
  • app/Support/Holidays/data/DE.json
  • app/Support/Holidays/data/DJ.json
  • app/Support/Holidays/data/DK.json
  • app/Support/Holidays/data/DM.json
  • app/Support/Holidays/data/DO.json
  • app/Support/Holidays/data/DZ.json
  • app/Support/Holidays/data/EC.json
  • app/Support/Holidays/data/EE.json
  • app/Support/Holidays/data/EG.json
  • app/Support/Holidays/data/EH.json
  • app/Support/Holidays/data/ER.json
  • app/Support/Holidays/data/ES.json
  • app/Support/Holidays/data/ET.json
  • app/Support/Holidays/data/FI.json
  • app/Support/Holidays/data/FJ.json
  • app/Support/Holidays/data/FK.json
  • app/Support/Holidays/data/FM.json
  • app/Support/Holidays/data/FO.json
  • app/Support/Holidays/data/FR.json
  • app/Support/Holidays/data/GA.json
  • app/Support/Holidays/data/GB.json
  • app/Support/Holidays/data/GD.json
  • app/Support/Holidays/data/GE.json
  • app/Support/Holidays/data/GF.json
  • app/Support/Holidays/data/GG.json
  • app/Support/Holidays/data/GH.json
  • app/Support/Holidays/data/GI.json
  • app/Support/Holidays/data/GL.json
  • app/Support/Holidays/data/GM.json
  • app/Support/Holidays/data/GN.json
  • app/Support/Holidays/data/GP.json
  • app/Support/Holidays/data/GQ.json
  • app/Support/Holidays/data/GR.json
  • app/Support/Holidays/data/GS.json
  • app/Support/Holidays/data/GT.json
  • app/Support/Holidays/data/GU.json
  • app/Support/Holidays/data/GW.json
  • app/Support/Holidays/data/GY.json
  • app/Support/Holidays/data/HK.json
  • app/Support/Holidays/data/HM.json
  • app/Support/Holidays/data/HN.json
  • app/Support/Holidays/data/HR.json
  • app/Support/Holidays/data/HT.json
  • app/Support/Holidays/data/HU.json
  • app/Support/Holidays/data/ID.json
  • app/Support/Holidays/data/IE.json
  • app/Support/Holidays/data/IL.json
  • app/Support/Holidays/data/IM.json
  • app/Support/Holidays/data/IN.json
  • app/Support/Holidays/data/IO.json
  • app/Support/Holidays/data/IQ.json
  • app/Support/Holidays/data/IR.json
  • app/Support/Holidays/data/IS.json
  • app/Support/Holidays/data/IT.json
  • app/Support/Holidays/data/JE.json
  • app/Support/Holidays/data/JM.json
  • app/Support/Holidays/data/JO.json
  • app/Support/Holidays/data/JP.json
  • app/Support/Holidays/data/KE.json
  • app/Support/Holidays/data/KG.json
  • app/Support/Holidays/data/KH.json
  • app/Support/Holidays/data/KI.json
  • app/Support/Holidays/data/KM.json
  • app/Support/Holidays/data/KN.json
  • app/Support/Holidays/data/KP.json
  • app/Support/Holidays/data/KR.json
  • app/Support/Holidays/data/KW.json
  • app/Support/Holidays/data/KY.json
  • app/Support/Holidays/data/KZ.json
  • app/Support/Holidays/data/LA.json
  • app/Support/Holidays/data/LB.json
  • app/Support/Holidays/data/LC.json
  • app/Support/Holidays/data/LI.json
  • app/Support/Holidays/data/LICENSE-python-holidays
  • app/Support/Holidays/data/LK.json
  • app/Support/Holidays/data/LR.json
  • app/Support/Holidays/data/LS.json
  • app/Support/Holidays/data/LT.json
  • app/Support/Holidays/data/LU.json
  • app/Support/Holidays/data/LV.json
  • app/Support/Holidays/data/LY.json
  • app/Support/Holidays/data/MA.json
  • app/Support/Holidays/data/MC.json
  • app/Support/Holidays/data/MD.json
  • app/Support/Holidays/data/ME.json
  • app/Support/Holidays/data/MF.json
  • app/Support/Holidays/data/MG.json
  • app/Support/Holidays/data/MH.json
  • app/Support/Holidays/data/MK.json
  • app/Support/Holidays/data/ML.json
  • app/Support/Holidays/data/MM.json
  • app/Support/Holidays/data/MN.json
  • app/Support/Holidays/data/MO.json
  • app/Support/Holidays/data/MP.json
  • app/Support/Holidays/data/MQ.json
  • app/Support/Holidays/data/MR.json
  • app/Support/Holidays/data/MS.json
  • app/Support/Holidays/data/MT.json
  • app/Support/Holidays/data/MU.json
  • app/Support/Holidays/data/MV.json
  • app/Support/Holidays/data/MW.json
  • app/Support/Holidays/data/MX.json
  • app/Support/Holidays/data/MY.json
  • app/Support/Holidays/data/MZ.json
  • app/Support/Holidays/data/NA.json
  • app/Support/Holidays/data/NC.json
  • app/Support/Holidays/data/NE.json
  • app/Support/Holidays/data/NF.json
  • app/Support/Holidays/data/NG.json
  • app/Support/Holidays/data/NI.json
  • app/Support/Holidays/data/NL.json
  • app/Support/Holidays/data/NO.json
  • app/Support/Holidays/data/NP.json
  • app/Support/Holidays/data/NR.json
  • app/Support/Holidays/data/NU.json
  • app/Support/Holidays/data/NZ.json
  • app/Support/Holidays/data/OM.json
  • app/Support/Holidays/data/PA.json
  • app/Support/Holidays/data/PE.json
  • app/Support/Holidays/data/PF.json
  • app/Support/Holidays/data/PG.json
  • app/Support/Holidays/data/PH.json
  • app/Support/Holidays/data/PK.json
  • app/Support/Holidays/data/PL.json
  • app/Support/Holidays/data/PM.json
  • app/Support/Holidays/data/PN.json
  • app/Support/Holidays/data/PR.json
  • app/Support/Holidays/data/PS.json
  • app/Support/Holidays/data/PT.json
  • app/Support/Holidays/data/PW.json
  • app/Support/Holidays/data/PY.json
  • app/Support/Holidays/data/QA.json
  • app/Support/Holidays/data/RE.json
  • app/Support/Holidays/data/RO.json
  • app/Support/Holidays/data/RS.json
  • app/Support/Holidays/data/RU.json
  • app/Support/Holidays/data/RW.json
  • app/Support/Holidays/data/SA.json
  • app/Support/Holidays/data/SB.json
  • app/Support/Holidays/data/SC.json
  • app/Support/Holidays/data/SD.json
  • app/Support/Holidays/data/SE.json
  • app/Support/Holidays/data/SG.json
  • app/Support/Holidays/data/SH.json
  • app/Support/Holidays/data/SI.json
  • app/Support/Holidays/data/SJ.json
  • app/Support/Holidays/data/SK.json
  • app/Support/Holidays/data/SL.json
  • app/Support/Holidays/data/SM.json
  • app/Support/Holidays/data/SN.json
  • app/Support/Holidays/data/SO.json
  • app/Support/Holidays/data/SR.json
  • app/Support/Holidays/data/SS.json
  • app/Support/Holidays/data/ST.json
  • app/Support/Holidays/data/SV.json
  • app/Support/Holidays/data/SX.json
  • app/Support/Holidays/data/SY.json
  • app/Support/Holidays/data/SZ.json
  • app/Support/Holidays/data/TC.json
  • app/Support/Holidays/data/TD.json
  • app/Support/Holidays/data/TF.json
  • app/Support/Holidays/data/TG.json
  • app/Support/Holidays/data/TH.json
  • app/Support/Holidays/data/TJ.json
  • app/Support/Holidays/data/TK.json
  • app/Support/Holidays/data/TL.json
  • app/Support/Holidays/data/TM.json
  • app/Support/Holidays/data/TN.json
  • app/Support/Holidays/data/TO.json
  • app/Support/Holidays/data/TR.json
  • app/Support/Holidays/data/TT.json
  • app/Support/Holidays/data/TV.json
  • app/Support/Holidays/data/TW.json
  • app/Support/Holidays/data/TZ.json
  • app/Support/Holidays/data/UA.json
  • app/Support/Holidays/data/UG.json
  • app/Support/Holidays/data/UM.json
  • app/Support/Holidays/data/US.json
  • app/Support/Holidays/data/UY.json
  • app/Support/Holidays/data/UZ.json
  • app/Support/Holidays/data/VA.json
  • app/Support/Holidays/data/VC.json
  • app/Support/Holidays/data/VE.json
  • app/Support/Holidays/data/VG.json
  • app/Support/Holidays/data/VI.json
  • app/Support/Holidays/data/VN.json
  • app/Support/Holidays/data/VU.json
  • app/Support/Holidays/data/WF.json
  • app/Support/Holidays/data/WS.json
  • app/Support/Holidays/data/XK.json
  • app/Support/Holidays/data/YE.json
  • app/Support/Holidays/data/YT.json
  • app/Support/Holidays/data/ZA.json
  • app/Support/Holidays/data/ZM.json
  • app/Support/Holidays/data/ZW.json
  • app/Support/HttpClient.php
  • app/Support/ImportLogger.php
  • app/Support/LibraryCalendar.php
  • app/Support/LoanEligibility.php
  • app/Support/LoanPdfGenerator.php
  • app/Support/LoanWindow.php
  • app/Support/MaintenanceService.php
  • app/Support/Marc/BookMarcBuilder.php
  • app/Support/Marc/ContributorSorter.php
  • app/Support/Marc/Danmarc2LibriMapper.php
  • app/Support/Marc/Danmarc2Parser.php
  • app/Support/Marc/GeneratorStream.php
  • app/Support/Marc/Iso2709Reader.php
  • app/Support/Marc/Iso2709Writer.php
  • app/Support/Marc/Marc21LibriMapper.php
  • app/Support/Marc/Marc8Decoder.php
  • app/Support/Marc/MarcBookData.php
  • app/Support/Marc/MarcBookImporter.php
  • app/Support/Marc/MarcCoverFetcher.php
  • app/Support/Marc/MarcField.php
  • app/Support/Marc/MarcFormat.php
  • app/Support/Marc/MarcLanguage.php
  • app/Support/Marc/MarcLibriMapper.php
  • app/Support/Marc/MarcMediaType.php
  • app/Support/Marc/MarcParseException.php
  • app/Support/Marc/MarcReadError.php
  • app/Support/Marc/MarcRecord.php
  • app/Support/Marc/MarcXmlReader.php
  • app/Support/Marc/MarcXmlWriter.php
  • app/Support/Marc/RelatorRoles.php
  • app/Support/Marc/UnimarcLibriMapper.php
  • app/Support/Marc/UnimarcLibriParser.php
  • app/Support/NotificationService.php
  • app/Support/PatronCardPdf.php
  • app/Support/PatronCardSettings.php
  • app/Support/PatronPhoto.php
  • app/Support/PatronTypeAssignment.php
  • app/Support/PatronTypeImport.php
  • app/Support/PaymentReceiptPdf.php
  • app/Support/Permissions.php
  • app/Support/RdaTypes.php
  • app/Support/RolePresets.php
  • app/Support/SearchIndexBuilder.php
  • app/Support/SettingsMailTemplates.php
  • app/Support/StatisticsSections.php
  • app/Support/StocktakePdfGenerator.php
  • app/Support/Updater.php
  • app/Support/UserImport.php
  • app/Support/mail_templates/da_DK.php
  • app/Support/mail_templates/de_DE.php
  • app/Support/mail_templates/en_US.php
  • app/Support/mail_templates/fr_FR.php
  • app/Views/admin/calendar.php
  • app/Views/admin/csv_import.php
  • app/Views/admin/imports_history.php
  • app/Views/admin/marc_import.php
  • app/Views/admin/plugins.php
  • app/Views/admin/stats.php
  • app/Views/attendance/index.php
  • app/Views/autori/index.php
  • app/Views/dashboard/permissions.php
  • app/Views/editori/index.php
  • app/Views/fornitori/form.php
  • app/Views/fornitori/index.php
  • app/Views/frontend/book-detail.php
  • app/Views/frontend/catalog.php
  • app/Views/frontend/home-sections/hero.php
  • app/Views/frontend/layout.php
  • app/Views/frontend/partials/filters-sidebar.php
  • app/Views/inventario/index.php
  • app/Views/inventario/show.php
  • app/Views/layout.php
  • app/Views/libri/index.php
  • app/Views/libri/partials/book_form.php
  • app/Views/libri/scheda_libro.php
  • app/Views/partials/role-navigation.php
  • app/Views/partials/settings-sections.php
  • app/Views/partials/workspace-header.php
  • app/Views/prenotazioni/crea_prenotazione.php
  • app/Views/prenotazioni/index.php
  • app/Views/prenotazioni/modifica_prenotazione.php
  • app/Views/prestiti/crea_prestito.php
  • app/Views/prestiti/dettagli_prestito.php
  • app/Views/prestiti/index.php
  • app/Views/prestiti/restituito_prestito.php
  • app/Views/settings/cards-tab.php
  • app/Views/settings/circulation-tab.php
  • app/Views/settings/circulation-type-edit.php
  • app/Views/settings/index.php
  • app/Views/settings/loans-tab.php
  • app/Views/settings/modules-tab.php
  • app/Views/settings/partials/circulation-type-fields.php
  • app/Views/settings/partials/feature-switch.php
  • app/Views/user_dashboard/prenotazioni.php
  • app/Views/utenti/_movimenti.php
  • app/Views/utenti/crea_utente.php
  • app/Views/utenti/dettagli_utente.php
  • app/Views/utenti/import.php
  • app/Views/utenti/index.php
  • app/Views/utenti/modifica_utente.php
  • app/Views/utenti/tipologia-lettore.php
  • cron/automatic-notifications.php
  • cron/full-maintenance.php
  • docs/reviews/pr-512-settings-flexibility-2026-10-29.md
  • installer/classes/Installer.php
  • installer/database/data_da_DK.sql
  • installer/database/data_de_DE.sql
  • installer/database/data_en_US.sql
  • installer/database/data_fr_FR.sql
  • installer/database/data_it_IT.sql
  • installer/database/migrations/migrate_0.9.0-rc.1.sql
  • installer/database/schema.sql
  • installer/steps/step7.php
  • locale/da_DK.json
  • locale/de_DE.json
  • locale/en_US.json
  • locale/fr_FR.json
  • locale/it_IT.json
  • package.json
  • public/assets/catalog-pages.css
  • public/assets/main.css
  • public/assets/pinakes-2026.css
  • public/index.php
  • scripts/ci-audit-playwright-results.js
  • scripts/ci-verify-release-source.sh
  • scripts/copy-vendor-assets.js
  • scripts/generate-holiday-dataset.py
  • scripts/verify-schema.sh
  • storage/plugins/archives/ArchivesPlugin.php
  • storage/plugins/archives/views/index.php
  • storage/plugins/archives/views/public/index.php
  • storage/plugins/archives/views/search.php
  • storage/plugins/bibframe-linked-data/BibframeLinkedDataPlugin.php
  • storage/plugins/book-club/src/Repo.php
  • storage/plugins/emeroteca/EmerotecaPlugin.php
  • storage/plugins/emeroteca/src/Controllers/PublicController.php
  • storage/plugins/emeroteca/src/Services/ContributionService.php
  • storage/plugins/emeroteca/src/Services/PeriodicalPublisherService.php
  • storage/plugins/mobile-api/MobileApiPlugin.php
  • storage/plugins/mobile-api/plugin.json
  • storage/plugins/mobile-api/src/Controllers/ActionsController.php
  • storage/plugins/mobile-api/src/Controllers/CatalogController.php
  • storage/plugins/mobile-api/src/Controllers/CollectionsController.php
  • storage/plugins/mobile-api/src/Controllers/HealthController.php
  • storage/plugins/mobile-api/src/Controllers/OpenApiController.php
  • storage/plugins/mobile-api/src/Controllers/StaffArchivesController.php
  • storage/plugins/mobile-api/src/Controllers/StaffDesiderataController.php
  • storage/plugins/mobile-api/src/Controllers/StaffEntitiesController.php
  • storage/plugins/mobile-api/src/Controllers/StaffReservationsController.php
  • storage/plugins/mobile-api/src/Support/CirculationOutcome.php
  • storage/plugins/mobile-api/src/Support/StaffCirculationOpenApi.php
  • storage/plugins/mobile-api/src/Support/StaffLoanReader.php
  • storage/plugins/ncip-server/NcipServerPlugin.php
  • storage/plugins/oai-pmh-server/OaiPmhServerPlugin.php
  • storage/plugins/z39-server/Z39ServerPlugin.php
  • storage/plugins/z39-server/classes/CopyCataloging.php
  • storage/plugins/z39-server/classes/Danmarc2Parser.php
  • storage/plugins/z39-server/classes/LocalSruClient.php
  • storage/plugins/z39-server/classes/RelatorRoles.php
  • storage/plugins/z39-server/classes/SruClient.php
  • storage/plugins/z39-server/classes/UNIMARCXMLFormatter.php
  • storage/plugins/z39-server/classes/UnimarcLibriParser.php
  • storage/plugins/z39-server/views/copy-cataloging.php
  • storage/plugins/z39-server/views/reicat/book-fields.php
  • tests/archives-plugin.unit.php
  • tests/attendance-090.spec.js
  • tests/calendar-permission.unit.php
  • tests/catalogue-cards-090.spec.js
  • tests/cataloguing-extras-090.unit.php
  • tests/circulation-card.spec.js
  • tests/circulation-consultation.spec.js
  • tests/circulation-hardening-0780.unit.php
  • tests/circulation-interop.spec.js
  • tests/circulation-patron-types.spec.js
  • tests/circulation-policy-equivalence.unit.php
  • tests/circulation-policy-resolver.unit.php
  • tests/circulation-queue-material-rules.unit.php
  • tests/circulation-reservations.spec.js
  • tests/circulation-rules-matrix.spec.js
  • tests/circulation-settings-access.spec.js
  • tests/closures-calendar-admin.spec.js
  • tests/closures-calendar-circulation.spec.js
  • tests/closures-calendar-loans.spec.js
  • tests/contributor-plugin-compatibility-237.unit.php
  • tests/copy-cataloging-limits.unit.php
  • tests/custom-holidays.unit.php
  • tests/debt-block.spec.js
  • tests/emeroteca-412.unit.php
  • tests/exact-quoted-search-501.unit.php
  • tests/exact-search-apis-501.unit.php
  • tests/exact-search-archives-501.unit.php
  • tests/exact-search-articles-501.unit.php
  • tests/exact-search-backend-501.unit.php
  • tests/exact-search-core-501.unit.php
  • tests/exact-search-dedup-501.unit.php
  • tests/exact-search-fulltext-501.unit.php
  • tests/exact-search-mobile-collections-501.unit.php
  • tests/feature-toggle-catalogue-cards.spec.js
  • tests/feature-toggle-circulation-rules.spec.js
  • tests/feature-toggle-closures-calendar.spec.js
  • tests/feature-toggle-fines.spec.js
  • tests/feature-toggle-marc.spec.js
  • tests/feature-toggle-patron-cards.spec.js
  • tests/feature-toggle-rda-types.spec.js
  • tests/feature-toggle-stocktake.spec.js
  • tests/feature-toggle-suppliers.spec.js
  • tests/feature-toggle-user-import.spec.js
  • tests/feature-toggle-visitor-log.spec.js
  • tests/feature-toggles-followups.spec.js
  • tests/feature-toggles-registry.unit.php
  • tests/feature-toggles-routes.unit.php
  • tests/feature-toggles-services.unit.php
  • tests/feature-toggles-settings.spec.js
  • tests/fine-calculator.unit.php
  • tests/fines-closed-days.spec.js
  • tests/fines-ledger.spec.js
  • tests/fines-patron-types.spec.js
  • tests/fixtures/marc/malformed.mrc
  • tests/fixtures/marc/marc21-collection.xml
  • tests/fixtures/marc/marc21-marc8.mrc
  • tests/fixtures/marc/marc21-utf8.mrc
  • tests/fixtures/marc/oai-golden/minimal.marcxml.xml
  • tests/fixtures/marc/oai-golden/minimal.unimarc.mrc
  • tests/fixtures/marc/oai-golden/minimal.unimarc.xml
  • tests/fixtures/marc/oai-golden/monograph.marcxml.xml
  • tests/fixtures/marc/oai-golden/monograph.unimarc.mrc
  • tests/fixtures/marc/oai-golden/monograph.unimarc.xml
  • tests/fixtures/marc/oai-golden/serial.marcxml.xml
  • tests/fixtures/marc/oai-golden/serial.unimarc.mrc
  • tests/fixtures/marc/oai-golden/serial.unimarc.xml
  • tests/fixtures/marc/unimarc-utf8.mrc
  • tests/fixtures/upgrades/README.md
  • tests/fixtures/upgrades/schema-0.8.9.sql
  • tests/helpers/circulation-fixtures.js
  • tests/helpers/exact-search-501-seed.php
  • tests/helpers/exact-search-501.js
  • tests/helpers/exact-search-501.php
  • tests/helpers/feature-toggles.js
  • tests/helpers/marc-e2e.js
  • tests/helpers/marc-fixtures.php
  • tests/helpers/marc-inspect.php
  • tests/helpers/minor-features-090.js
  • tests/helpers/server-files.js
  • tests/holiday-calculator.unit.php
  • tests/holiday-presets-apply.unit.php
  • tests/holiday-presets-missing.unit.php
  • tests/holidays-preset.spec.js
  • tests/holidays-world.spec.js
  • tests/installer-trigger-import.unit.php
  • tests/inventory-stocktake.spec.js
  • tests/issue-237-regression.unit.php
  • tests/issue-501-admin-lists.spec.js
  • tests/issue-501-exact-quoted-search.spec.js
  • tests/issue-501-name-pages.spec.js
  • tests/issue-501-quoted-hint.spec.js
  • tests/issue-501-quoted-new-author.spec.js
  • tests/issue-501-search-fields.spec.js
  • tests/issue-501-search-hint.spec.js
  • tests/issues-301-306.unit.php
  • tests/ledger-permission.unit.php
  • tests/library-calendar-loans.unit.php
  • tests/library-calendar.unit.php
  • tests/loan-auto-approval-301-reservation-path.unit.php
  • tests/loan-coherence-audit.unit.php
  • tests/loan-renewal-window.unit.php
  • tests/loan-window-cap.unit.php
  • tests/loan-window-surfaces.unit.php
  • tests/marc-bulk-export.spec.js
  • tests/marc-bulk-import.spec.js
  • tests/marc-copy-cataloging.spec.js
  • tests/marc-import-robustness.unit.php
  • tests/marc-library.unit.php
  • tests/marc-oai-byte-identity.unit.php
  • tests/migration-0.8.6-rc.1-accounts.unit.php
  • tests/migration-0.9.0-circulation-policy.unit.php
  • tests/migration-0.9.0-closures-calendar.unit.php
  • tests/migration-0.9.0-custom-holidays.unit.php
  • tests/migration-0.9.0-feature-toggles.unit.php
  • tests/migration-0.9.0-fines-ledger.unit.php
  • tests/migration-0.9.0-holiday-presets.unit.php
  • tests/migration-0.9.0-marc.unit.php
  • tests/migration-0.9.0-minor-features.unit.php
  • tests/migration-0.9.0-patron-import.unit.php
  • tests/migration-0.9.0-rc.1.unit.php
  • tests/migration-0.9.0-stocktake.unit.php
  • tests/minor-features-090.unit.php
  • tests/mobile-api-circulation.spec.js
  • tests/mobile-api-circulation.unit.php
  • tests/mobile-api-idempotency.spec.js
  • tests/ncip-circulation-coherence.unit.php
  • tests/patron-cards-import.unit.php
  • tests/patron-cards.spec.js
  • tests/patron-ledger.unit.php
  • tests/patron-photo.spec.js
  • tests/plugin-audit-hardening-regressions.unit.php
  • tests/rda-types-090.spec.js
  • tests/release-0.8.7-changes.unit.php
  • tests/release-source-policy.test.sh
  • tests/sru-search.unit.php
  • tests/stack-090-integration.spec.js
  • tests/stack-090-review-fixes.spec.js
  • tests/stack-090-review-fixes.unit.php
  • tests/stack-090-settings-flexibility.unit.php
  • tests/stack-090-zero-config.spec.js
  • tests/statistics-090.spec.js
  • tests/stocktake-classification.unit.php
  • tests/stocktake-pdf.unit.php
  • tests/stocktake-permission.unit.php
  • tests/stocktake-snapshot.unit.php
  • tests/suppliers-090.spec.js
  • tests/unimarc-standards.unit.php
  • tests/user-import.spec.js
  • version.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues. There is one small regression in the contributor cache normaliser; see the inline comment.

Reviewed changes

The stacked feature PRs (#502 → #513) were already reviewed on their own PRs. This review covers only what landed after the last reviewed #512 head (029b19a7): 42 files, up to and including the release commit.

  • Release metadata: version.json is now 0.9.0-rc.1. The CHANGELOG heading is the exact ## [0.9.0-rc.1] that create-release.sh needs, and README has ## What's New in v0.9.0-rc.1. Every bundled requires_app is ≤ 0.9.0-rc.1; mobile-api is the only plugin pinned to the RC.
  • Migration renamed for the RC: migrate_0.9.0.sql → migrate_0.9.0-rc.1.sql with identical content. All section tests, seed comments and version_compare guards point at the new name. The dispatcher tests/migration-0.9.0-rc.1.unit.php now skips itself, since it matches its own migration-0.9.0-* glob. scripts/verify-schema.sh also runs the RC migration's test when version.json is the stable X.Y.Z, and fails if that test is missing.
  • Contributor cache lists: AuthorNormalizer::normalizeStored() now splits a ;/| list and normalises each name, so inverted names and per-name quotes come out right. LibraryThing import and BookRepository::updateOptionals() use it for the libri.* cache columns.
  • Vanished holiday ids: HolidayPresets::missingIds() lists the chosen ids that the rule table or dataset no longer knows. The calendar page shows them in a warning box, with locale strings in all five languages, a unit test and an E2E test.

ℹ️ The RC migration will not run again on the upgrade from the RC to 0.9.0

The PR body says migrate_0.9.0-rc.1.sql "runs on the RC and again on the later 0.9.0 upgrade". However, Updater::shouldRunMigration() needs the migration version to be greater than $fromVersion, and isMigrationExecuted() also skips it. So on an RC install that upgrades to 0.9.0, the file never runs again. It does still run once for libraries that go straight from 0.8.x to 0.9.0. This means any schema fix made after the RC has to ship in a new file, such as migrate_0.9.0.sql or migrate_0.9.0-rc.2.sql, not as an edit to this one.

Technical details
# RC migration is not re-run on RC → stable

## Affected sites
- app/Support/Updater.php:3827 — `shouldRunMigration()` uses `version_compare($migrationVersion, $fromVersion, '>')`; `'0.9.0-rc.1' > '0.9.0-rc.1'` is false.
- scripts/verify-schema.sh:55 — comment "That migration still runs on the upgrade to the stable release" is true only for upgrades from < 0.9.0-rc.1.

## Required outcome
- Release notes / PR body describe the actual behaviour; any change to the 0.9.0 schema after this RC ships in a new migration file.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread app/Support/AuthorNormalizer.php Resolved

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found. The contributor cache fix and the MARC dedup change both look correct.

Reviewed changes

This run covers what changed since the previous Pullfrog review at 4ffc58b8. The fixes were made on the stack branches and merged forward into this branch.

  • Entity-safe list split: AuthorNormalizer::normalizeStored() now looks for the list separator on the decoded value and splits with ContributorSync::splitNames(). As a result, O&#039;Brien, Flann stays one name, and the cache uses the same rule as the entity sync. Two new checks cover a single name with an entity and a list that contains one.
  • MARC title + author dedup: when a record has no ISBN, MarcBookImporter::findExisting() now resolves the first author with AuthorRepository::findByCanonicalName(). That is the same lookup that CsvImportController::getOrCreateAuthor() uses when it links the author. The query then matches la.autore_id together with the accent-exact title. Before, a Haffner record never matched a book filed under Häffner, so re-importing it created a duplicate. New DB checks cover four cases: the fold-to-existing match, a double import that leaves one book, the exact spelling winning once both authors are on file, and accent-distinct titles.

The earlier note on the migration still applies, and the PR body has not changed. An RC install that upgrades to 0.9.0 will not run migrate_0.9.0-rc.1.sql again, so any schema fix after the RC needs a new migration file.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

The UNIMARC builder always wrote bibliographic level m in label/07, so a periodical exported as a monograph and its ISSN was lost. A serial now gets level s and its ISSN in field 011, mirroring the MARC 21 leader/07 and 022 logic; monographs are unchanged.
The deleted-book duplicate case soft-deleted the book with a direct UPDATE, so it proved nothing about what the real delete path leaves behind. It now deletes through the admin bulk delete endpoint and asserts the soft delete cleared the identifiers before re-importing.
Instead of accepting any start date after today, the test walks the stored
library-wide closures (one-off and yearly) from tomorrow and asserts the
reservation starts on the first day none of them covers, so a pre-existing
closure can no longer hide a wrong date.
The default-port test only covered MarcCoverFetcher::effectivePort. LocalSruClient::isLocalUrl now has its own checks: the installation's /api/sru is recognised with the HTTPS port implicit or written out, on either the canonical URL or the target, while another port or plain http on 443 is not.
The whole suite was skipped when the bibframe-linked-data plugin was inactive, although only the BIBFRAME checks need it: now only those tests skip, and the form, storage, page and clear-override tests always run. The DVD case also checks the derived video media label, the post-clear BIBFRAME check asserts the derived audio media type, and a new pair of tests saves a content type override and verifies it in the database, the reloaded form, the book page and BIBFRAME.
expectCardSize read only the first /MediaBox, so a multi-card PDF with a wrongly sized later page still passed. It now collects every MediaBox, requires at least one and checks width and height of each against 125 x 75 mm.
The schema.sql check confirmed the presenze table and columns but not the delete rule of fk_presenze_utente. It now also requires ON DELETE SET NULL there, so a fresh install cannot drift from the migration and drop visits when a member is deleted.
The test now dispatches a real POST to /admin/calendar/rotate-link through
the registered routes and middleware, with a valid CSRF token, as a custom
role holding settings.manage and as staff. Both pass the middleware, are
refused by the route and leave the library feed secret unchanged. A failed
check now throws so the role and user fixtures are always removed.
Both modules are off on an upgraded install, so the 0.9.0 write checks
ran against modules that refuse to write. The test now switches them on
for those checks and also asserts the opposite: with the modules off a
save keeps the stored values and an import batch assigns no supplier.
The explicit section-to-test map stopped at the fines ledger, so the
three sections this branch adds to migrate_0.9.0-rc.1.sql failed the
runner as untested. Each now names its own behavioural test.
Re-recorded with --record after the UNIMARC export started marking a
serial with bibliographic level s (leader/07) and its ISSN in 011. The
serial goldens differ only in those two places, plus the record length
and directory that follow from them; every other golden is unchanged.
0162a39 stopped the longest return date at the last loaded availability day, but the book page loads 180 days and lets a reader start on almost any of them: a start four months ahead could no longer have its return date in the following month. The public availability route now loads occupancy data past the 180 start days by the longest loan plus the closed-day margin (the same horizon the closed days already use), and returns start_until, the last day a request may start on, which the start picker uses as its maximum. The clamp from 0162a39 stays as a safety net.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found. A reader who picks a late start date can now get the full loan window again.

Reviewed changes

This run covers the single non-merge commit since the previous Pullfrog review at 96881d09.

  • Availability past the last start day: getBookAvailabilityData() has a new $coverLoanWindow flag. When the flag is set, days now reaches as far as closed_dates already did: 180 start days, plus the longest loan, plus the 31-day closed-day margin. The method also always returns start_until, the last day a request may start on. Only the public /api/books/{id}/availability route sets the flag, so the mobile, staff and calendar callers are unchanged.
  • Start picker cap: book-detail.php now uses start_until as the start picker's maxDate, and falls back to the last loaded day when it is missing. The lastLoaded clamp in loanWindowFrom() stays as a safety net, and it no longer cuts a late start short. tests/loan-window-cap.unit.php checks that the plain call ends at start_until and that the covered call runs past it by at least the longest loan plus 31 days.
  • Side effects on the same route: earliest_available and unavailable_dates now cover the longer window. This only matters when all 180 start days are blocked, and then no start can be picked either way. In the admin loan form (crea_prestito.php), isAvailableNow still means "no blocked day in the loaded window", but the window is now longer. That form takes no maxDate from days.

The earlier note on the migration still applies: an RC install that upgrades to 0.9.0 will not run migrate_0.9.0-rc.1.sql again.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

importTriggers() counted a trigger only when the chunk between two $$ delimiters started with CREATE TRIGGER, but every chunk starts with comments and a DROP TRIGGER. The count stayed at 0, so every successful install ended on the "manual action required" page, blaming database permissions while all the triggers were in place.

The final page now also shows the database error behind a warning, since the fixed permissions text hid the real cause whatever it was.
@fabiodalez-dev

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Action not completed

Review skipped: 654 files exceed the limit of 100.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

CodeRabbit refuses to review a pull request with more than 100 files and now reports that as a skipped check run instead of a successful status. A release PR that carries a stacked series always crosses the limit, so the prerelease gate vetoed v0.9.0-rc.1 even though every PR in the series was reviewed on its own.

The gate now reads the CodeRabbit app's check run on the tagged commit and accepts the skip only when every run comes from the coderabbitai app, targets that exact commit, and carries the file-limit title. A rate-limit skip, a skip on another commit or a run posted by another app still vetoes, and the skip never excuses any other failing check.
The test dropped and recreated <DB_NAME>_migtrg with DROP DATABASE, so a database that already carried that name lost its data without warning.

It now follows the other sandbox suites: the name can be set with INSTALLER_TRIGGER_SANDBOX_DB and is refused when it is the installation's own database, the database is created only if missing, and a database that already holds tables without this test's marker table is refused. Between scenarios and at the end only the tables are emptied.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No blocking issues. One minor wording point on the installer's final page is inline.

Reviewed changes

This run covers the four non-merge commits since the previous Pullfrog review at 93c25855. Both new tests pass locally: tests/installer-trigger-import.unit.php gave 9/0 against a temporary MySQL 8.4, and tests/release-source-policy.test.sh gave 31/0.

  • Trigger count fixed: Installer::importTriggers() now matches CREATE TRIGGER at the start of any line of a $$ chunk, not only at the start of the chunk. Each chunk opens with comments, SET and DROP TRIGGER, so the count used to stay at 0 and every install ended with the "Nessun trigger valido" warning. A real failure is still reported: the multi-statement exec() surfaces the failing CREATE, and the healthy triggers stay in place.
  • Warnings shown on the final page: step7.php now lists each trigger warning, escaped with htmlspecialchars.
  • Sandbox test: the new DB test runs the real importer and the real triggers.sql in a <DB_NAME>_migtrg sandbox. It refuses a database that holds tables without its marker, and it never drops the sandbox. It covers a fresh import, a re-import, and a missing prestiti table.
  • Release gate: ci-verify-release-source.sh now accepts a required CodeRabbit check in the skipping bucket, but only when every CodeRabbit check run on $GITHUB_SHA comes from the coderabbitai app and is a skip titled Review skipped: N files exceed the limit of M. A rate-limit skip, a run from another app, a different SHA, or a failure in another check still vetoes. The fake gh covers each of these cases.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread installer/steps/step7.php Resolved
The final page opened the trigger warning with "the database user lacks the permissions to create triggers", and since the previous commit it shows the real database error right under it. When a trigger fails for another reason, such as a missing table, the two lines contradicted each other. The opening sentence now only says that some triggers could not be created, in all five locales, and the CHANGELOG entry says both lines are shown.
The final page opened the trigger warning with "the database user lacks the permissions to create triggers", and since the previous commit it shows the real database error right under it. When a trigger fails for another reason, such as a missing table, the two lines contradicted each other. The opening sentence now only says that some triggers could not be created, in all five locales.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found. The installer's final page no longer blames the database user's permissions for every trigger failure.

Reviewed changes

This run covers the two non-merge commits since the previous Pullfrog review at 23fa2dd9.

  • Neutral trigger warning: installer/steps/step7.php now opens the warning with "Some database triggers could not be created", followed by the escaped database messages. The new string is translated in all five locales, and scripts/ci-check-locales.py passes. The old permissions string remains in the locale files but nothing uses it.
  • CHANGELOG: the Fixes entry now says that the page shows both the general sentence and the database's own message.

The earlier note on the migration still applies: an RC install that upgrades to 0.9.0 will not run migrate_0.9.0-rc.1.sql again.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

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