diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md index ab149ca..132bee4 100644 --- a/.claude/agents/code-reviewer.md +++ b/.claude/agents/code-reviewer.md @@ -32,13 +32,14 @@ Review against the checklist below, in this order of severity. ## 2. Version pins (blocking) -- `composer.json` must keep `"php": "~8.4.0"` and `"lisachenko/z-engine": "dev-master"`, - with root `"minimum-stability": "dev"` and `"prefer-stable": true`. -- Any diff that widens the PHP constraint (`^8.4`, `>=8.4`), drops the z-engine dev - requirement, or bypasses `Core::init()`'s version guard is rejected outright. Offsets into - engine structures are minor-version specific; loosening the pin trades a clear error for - memory corruption. -- CI must run on PHP 8.4 with `ffi.enable=1` and `opcache.jit=off`. +- `composer.json` must keep `"php": "^8.4"` and `"lisachenko/z-engine": "~8.4.2 || ~8.5.0"` + — one stable z-engine line per supported PHP minor, resolved by Composer against the + running PHP. +- Any diff that widens either constraint beyond the minors z-engine has definitions for + (`>=8.4`, a `^8.4` z-engine constraint that would span future lines), or bypasses + `Core::init()`'s version guard, is rejected outright. Offsets into engine structures are + minor-version specific; loosening the pin trades a clear error for memory corruption. +- CI must run on PHP 8.4 and 8.5 with `ffi.enable=1` and `opcache.jit=off`. ## 3. PHPStan generics honesty (blocking) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3be3e9..925e269 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,9 +9,9 @@ on: permissions: contents: read -# z-engine tracks one PHP minor per release line; the "8.4.x-dev || 8.5.x-dev" -# constraint lets Composer resolve the line matching each runner's PHP, so the -# suite runs on PHP 8.4 and 8.5 in parallel. +# z-engine tracks one PHP minor per release line; the "~8.4.2 || ~8.5.0" constraint +# lets Composer resolve the stable line matching each runner's PHP, so the suite +# runs on PHP 8.4 and 8.5 in parallel. jobs: tests: name: Tests (PHP ${{ matrix.php }}) diff --git a/CLAUDE.md b/CLAUDE.md index 9944bc8..d1a9fcf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,9 +15,10 @@ structures (`zend_class_entry`, `zval`, `zend_object_handlers`) by byte offset, those offsets change on every PHP minor release. Running against the wrong minor does not throw a nice exception; it reads and writes the wrong memory. -That is why z-engine is required as **`8.4.x-dev || 8.5.x-dev`**: Composer resolves -the line matching the running PHP (the `8.4` branch on PHP 8.4, `master` — aliased -`8.5.x-dev` — on PHP 8.5). `ZEngine\Core::init()` (called from `bootstrap.php`) +That is why z-engine is required as **`~8.4.2 || ~8.5.0`**: Composer resolves the +release line matching the running PHP (`8.4.x` on PHP 8.4, `8.5.x` on PHP 8.5 — each +tag declares its own `~8.4.0`/`~8.5.0` platform requirement, so only one line can +ever satisfy a given runtime). `ZEngine\Core::init()` (called from `bootstrap.php`) enforces the exact match and aborts with a clear message. **Never "fix" an initialization failure by loosening the constraints past the minors z-engine has definitions for, skipping `Core::init()`, or defeating the guard.** If the @@ -36,13 +37,15 @@ process it spawns: - `ffi.enable=1` — FFI cannot be turned on at runtime. - `opcache.jit=off` — the JIT rewrites the very executor internals z-engine hooks. -- `error_reporting=E_ALL & ~E_DEPRECATED` — z-engine `dev-master` still declares - implicitly nullable parameters (e.g. `ZEngine\Type\OpLine::__construct()`), which - PHP 8.4 reports as a deprecation. PHPUnit's `.phpt` runner forces - `display_errors=1`, so without this the dependency's deprecation is prepended to - the captured output of **every** test and each `--EXPECT--` block fails on noise - that has nothing to do with this library. Drop the suppression once z-engine - declares those parameters `?Type`. +- `error_reporting=E_ALL & ~E_DEPRECATED` — a guard against dependency deprecations + leaking into captured output. PHPUnit's `.phpt` runner forces `display_errors=1`, + so a deprecation raised by a dependency is prepended to the captured output of + **every** test and each `--EXPECT--` block fails on noise that has nothing to do + with this library. The specific offender that motivated it — z-engine declaring + implicitly nullable parameters (e.g. `ZEngine\Type\OpLine::__construct()`) — is + fixed as of the stable releases (`~8.4.2 || ~8.5.0`), and the suite passes with + `error_reporting=E_ALL` forced on both minors, so the line is now belt-and-braces + rather than a requirement. CI supplies the FFI and JIT pair as `ini-values` on the PHP setup step, and **every `.phpt` file carries its own `--INI--` section** — all three lines — so the child @@ -190,13 +193,14 @@ proposing a change rather than hand-formatting. ## Dependency policy -- `lisachenko/z-engine` is required as **`8.4.x-dev || 8.5.x-dev`** — one dev line - per supported PHP minor, resolved by Composer to match the running PHP. Those are - development branches, so the root `composer.json` also carries - `"minimum-stability": "dev"` with `"prefer-stable": true` — Composer resolves - development stability only at the root level, so consumers need the same pair. +- `lisachenko/z-engine` is required as **`~8.4.2 || ~8.5.0`** — one **stable** release + line per supported PHP minor, resolved by Composer to match the running PHP. The + tilde is deliberate: it admits patch releases within a line (`8.4.3`, `8.5.1`) but + never the next minor line, which would be built for a PHP this package does not + claim to support. +- The root `composer.json` no longer carries `"minimum-stability": "dev"` / + `"prefer-stable": true` — nothing in `require` is a development branch any more, + and consumers no longer need those flags to install this package's dependencies. - PHP stays at `^8.4`, in lockstep with the set of z-engine lines this package tracks: a new PHP minor is added here only together with the z-engine line built for it, and never one without the other. -- When z-engine ships stable releases for the supported minors, the constraint and - the root stability flags should be tightened in a single change. diff --git a/README.md b/README.md index 359638f..0363b5a 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The maths is plain PHP. The magic is only in getting the engine to call it. - **PHP `^8.4`** — 8.4 and 8.5 are supported in parallel. Z-Engine reads engine structures by byte offset and those offsets change on every PHP minor release, so each minor rides its own Z-Engine line; `Core::init()` refuses to boot on a mismatch rather than corrupting memory. - **`ext-ffi` enabled**, with `ffi.enable=1` for CLI usage. - **x64, non-thread-safe (NTS)** build — the same platform limitations as [Z-Engine](https://github.com/lisachenko/z-engine#requirements--support-matrix). -- The **matching Z-Engine minor branch**. Composer resolves it for you from the `8.4.x-dev || 8.5.x-dev` constraint; mixing a Z-Engine built for another minor is not a configuration choice, it is undefined behaviour. +- The **matching Z-Engine minor release line**. Composer resolves it for you from the `~8.4.2 || ~8.5.0` constraint; mixing a Z-Engine built for another minor is not a configuration choice, it is undefined behaviour. ## Installation @@ -66,16 +66,9 @@ The maths is plain PHP. The magic is only in getting the engine to call it. composer require lisachenko/native-php-matrix:dev-master ``` -This package requires Z-Engine as `8.4.x-dev || 8.5.x-dev` — z-engine minors track PHP minors and are not interchangeable, so Composer resolves the line matching your PHP automatically (the `8.4` branch on PHP 8.4, `master` on PHP 8.5). Those are development branches, and the package itself is consumed from `dev-master`; Composer only resolves development stability at the **root** level, so your `composer.json` needs: +This package requires Z-Engine as `~8.4.2 || ~8.5.0` — z-engine minors track PHP minors and are not interchangeable, so Composer resolves the release line matching your PHP automatically (`8.4.x` on PHP 8.4, `8.5.x` on PHP 8.5). Both are **stable tags**, so no `minimum-stability` tweak is needed for them. -```json -{ - "minimum-stability": "dev", - "prefer-stable": true -} -``` - -Once a native-php-matrix release covering the current code is tagged, this collapses to a plain `composer require lisachenko/native-php-matrix`. +native-php-matrix itself is not tagged yet, which is why the command above asks for `dev-master`; that one dev constraint is explicit, so Composer accepts it without a root stability change. Once a native-php-matrix release is tagged, this collapses to a plain `composer require lisachenko/native-php-matrix`. No initialization call is needed: `bootstrap.php` ships in the package's `files` autoload and sets everything up behind `require vendor/autoload.php`. diff --git a/composer.json b/composer.json index a0033e9..3cbae7f 100644 --- a/composer.json +++ b/composer.json @@ -13,10 +13,8 @@ "require": { "php": "^8.4", "ext-ffi": "*", - "lisachenko/z-engine": "8.4.x-dev || 8.5.x-dev" + "lisachenko/z-engine": "~8.4.2 || ~8.5.0" }, - "minimum-stability": "dev", - "prefer-stable": true, "require-dev": { "friendsofphp/php-cs-fixer": "^3.75", "phpstan/phpstan": "^2.1",