Skip to content

Load safeguards before the floor gate - #68

Merged
ahegyes merged 7 commits into
trunkfrom
feat/safeguards-before-floor-gate
Oct 31, 2026
Merged

ahegyes merged 7 commits into
trunkfrom
feat/safeguards-before-floor-gate

Conversation

@ahegyes

@ahegyes ahegyes commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Summary

A plugin's safeguards now load before its floor gate, so a site below the plugin's PHP or WordPress floor keeps the restrictions they enforce, as a failed boot and a missing dependency already did. consumer-a, the reference anatomy, loads includes/safeguards.php first, and the conventions state what that asks of a safeguard: it parses on PHP 7.4 and calls only WordPress APIs present at the oldest WordPress the bootstrap package runs on, or guards them.

Affected packages

  • wp-framework-bootstrap
  • wp-framework-shared
  • wp-framework-core
  • wp-framework-settings
  • wp-framework-woocommerce

No package code changes; the change is consumer-a's entry, AGENTS.md and the test lanes.

Checklist

  • Tests added or updated (Unit and/or Integration as appropriate)
  • composer quality-check passes locally (PHPCS, PHPStan and the tests)
  • Public API changes are documented in the affected package's README.md
  • Breaking changes are explicitly justified below

What changes

  • consumer-a's entry requires includes/safeguards.php before the bootstrap check, which takes consumer-b's and the personas' shape: a missing load.php shows the build notice and returns, otherwise load.php, Updater::register() and Requirements::check_floors() run.
  • AGENTS.md: convention 5 states where the entry loads a safeguard and the PHP 7.4 and oldest-WordPress rule that follows; limitation 6 no longer lists below-floor runtimes, and limitation 5 drops its safeguard clause; the file map and commands describe the lanes below.
  • Tests: the PHP 8.5 below-floor row expects the safeguard attached and an explicit false refused; a new Php74 row runs consumer-a on PHP 7.4 with WordPress 6.3 and expects the export capability mapped to do_not_allow, the updater hooked and core's requirements message; the missing-build-file rows hook a false relaxation, so a safeguard relaxing without a booted plugin fails them. The Php74 lane builds consumer-a.
  • PHPStan: phpstan.bootstrap.neon analyzes consumer-a's safeguard at PHP 7.4 and WordPress 5.2, beside the bootstrap package.
  • Packages: the Composer lock moves wordpress-configs to its trunk and refreshes the security advisories.

Not verified locally

  • The integration-php74 job building consumer-a, and the older WordPress branches of the Integration matrix, run only in CI.

Refresh the Composer lock: wordpress-configs moves to its trunk at
8d53efd, which finds a plugin's main file by its header, and
roave/security-advisories to its latest advisories; the framework's
path packages take trunk's references. The npm lock stays as it is,
because npm's seven-day release-age cooldown on this host resolved
older @php-wasm and @WordPress packages than the lock already holds.
No code change was needed.

Assisted-by: Claude Code:claude-opus-5-5
consumer-a's entry loads its safeguard after the floor gate, so on a
runtime below the plugin's PHP or WordPress floor the export lock never
loads, while a failed boot or a dependency below its floor keeps it. A
restriction the merchant set should hold whenever the plugin cannot
run, so the safeguard loads before the gate.

The PHP 8.5 row that raises Requires PHP now expects the safeguard
attached and an explicit false relaxation to change nothing. A new
Php74 row runs consumer-a on PHP 7.4 with WordPress 6.3 and expects
the export capability to map to do_not_allow, the updater to stay
hooked and core's requirements message to show; the Php74 lane builds
consumer-a for it. Both fail until the entry moves the safeguard.

Assisted-by: Claude Code:claude-opus-5-5
The PHP 7.4 harness reads consumer-a's export capability by its literal
name, which WPCS reports as unknown because only the safeguard's
map_meta_cap callback knows it. The line now waives that sniff with
its reason, so the tests profile passes.

Assisted-by: Claude Code:claude-opus-5-5
consumer-a loaded includes/safeguards.php after Requirements::check_floors(),
so a site below the plugin's PHP or WordPress floor showed what the
export lock forbids, while a missing vendor-prefixed/ skipped the gate
and loaded the safeguard anyway: two ways the build cannot run, with
opposite outcomes. A restriction should hold whenever the plugin
cannot boot, so the entry now loads the safeguard first, and the
bootstrap check takes the same shape as consumer-b's and the personas'.

A safeguard therefore runs on any runtime that parses the plugin.
Convention 5 states the rule that follows: it parses on PHP 7.4 and
calls only WordPress APIs present at the oldest WordPress the bootstrap
package runs on, or guards them. phpstan.bootstrap.neon analyzes
consumer-a's safeguard at that PHP and WordPress, which reports a PHP 8
function, a native mixed type or a WordPress 5.9 function there.
Limitation 6 no longer lists below-floor runtimes, and limitation 5
drops the safeguard clause it no longer needs.

X ruling 89.

Assisted-by: Claude Code:claude-opus-5-5
The README's command table said the PHP 7.4 lane builds only the
bootstrap persona, and its testing strategy listed only the persona's
rows there, while the lane now also builds consumer-a and checks that
its safeguard holds below its floors. Both now say so.

Assisted-by: Claude Code:claude-opus-5-5
The missing-build-file rows and the PHP 7.4 row hooked no relaxation,
so the export capability mapped to do_not_allow from the safeguard's
default branch and would still have done so had the safeguard honored
an explicit false before boot. Each now hooks one, so a safeguard that
relaxes without a booted plugin fails all six rows.

Assisted-by: Claude Code:claude-opus-5-5
Convention 5 bounded a safeguard's WordPress APIs by the oldest
WordPress the bootstrap package runs on, a version no manifest key
holds, while the bootstrap manifest's extra.requires-wp names a newer
one for its updater. It now names phpstan.bootstrap.neon, whose
WPCompat.requiresAtLeast sets it.

Assisted-by: Claude Code:claude-opus-5-5
@ahegyes ahegyes changed the title Feat/safeguards before floor gate Load safeguards before the floor gate Oct 31, 2026
@ahegyes
ahegyes merged commit 02ce0e8 into trunk Oct 31, 2026
24 checks passed
@ahegyes
ahegyes deleted the feat/safeguards-before-floor-gate branch October 31, 2026 20:42
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