Release news · 20 September 2026
PHP Ledger 1.1.3: the in-app updater completes
1.1.3 fixes issue #90, which stopped the in-app updater at its migrate phase. An installation on 1.1.1 or 1.1.2 with the publisher key pinned now installs 1.1.3 from /maintenance.php; a 1.1.0 installation uses the manual procedure (issue #91).
This is a patch release. It carries one fix, no migration, no schema change and no change to any accounting behaviour or the rules that guard posted data.
What stopped the updater?
Before starting to replace files, the updater saves a copy of its own helpers—including database_platform_functions.php—as a private recovery runtime and works from that copy so that recovery keeps working while the application is being replaced. The migrate phase then loaded the new release's install_functions.php, which loaded the application's copy of the same helper file, and PHP stopped with Cannot redeclare pl_database_platform(). The updater's fail-safe worked as designed: it detected the failure, entered automatic recovery and restored the previous release completely, bringing back files, database and sign-in page. But no real update could finish, even though issue #90 was not reported until after the proof was already complete.
The fix
install_functions.php and the recovery runtime now keep whichever copy of the platform helpers is already loaded instead of declaring them twice. The fix lives in the new release's files, so it applies to updates into 1.1.3 as well: the copied runtime of the installed 1.1.0, 1.1.1 or 1.1.2 is unchanged and needs no change. A new test case, tests/update-migrate-test.php, installs a schema with one migration pending, copies the recovery runtime and drives a signed update through the real /maintenance.php loader with no callbacks injected, verifying the phase sequence backup > apply > migrate > verify > runtime > complete. CI runs it on MySQL 8.4 and every MariaDB in the matrix.
One rule for maintainers
At the top of database_platform_functions.php: during an update the installed release's copy of that file serves the next release's migrations, so the file must stay backward compatible across one release step. A release must not make install_functions.php or a migration depend on a helper that this file first adds or changes in the same release.
Upgrading
From 1.1.2 this replaces files only, with no migration and no receipt change. From 1.1.1 it also applies migration 034. Both install from /maintenance.php with the pinned publisher key, and both paths were driven end to end before publication. From 1.1.0 use the manual procedure instead: replace the files and run php www/phpledger/install/migrate.php once, which also applies migration 034. An in-app update from 1.1.0 stops in its migrate step and restores itself, losing nothing, because the installed release’s database helpers predate a function the new migrations call (issue #91).
The maintenance loader public/maintenance.php is byte-identical to 1.1.0, 1.1.1 and 1.1.2, which is what allows the in-app path to work across those releases.
What is the assurance status?
These releases ship with automated test suites, fault-injection update/recovery tests, exact-artifact install/upgrade/recovery checks and developer-operated browser checks. Independent accounting review, independent security review, supervised pilots including a real month-end close, and installation observation by an unfamiliar operator remain outstanding, as recorded for 1.0.0. The first supervised pilot, on the maintainer's own books, starts on 1 October 2026.
Patch releases ship without a media kit. The public demo still runs 1.1.0.
