Fix the init-time fatal: require Booking_Adapter, and guard the whole manifest - #4
Merged
Merged
Conversation
… manifest
includes/integrations/class-booking-adapter.php shipped in 2.0.0 but was never
added to the manual require list in Plugin::load_dependencies(), and the plugin
has no autoloader. It was the only file under includes/ absent from that list
(71 listed, 73 on disk; the other is class-plugin.php, which the bootstrap
requires directly).
Waiver_Booking_Bridge::register() calls Booking_Adapter::hook() as its first
statement, and is registered on init priority 4 whenever the Waiver Manager
integration is enabled — whose default is 'yes'. So the chain fires on a stock
install with no configuration:
init(4) -> Waiver_Booking_Bridge::register()
-> Booking_Adapter::hook('waiver_satisfied')
-> Error: Class "...\Integrations\Booking_Adapter" not found
Booking_Engine, POS_Bridge and Staff_Dashboard reach the same class. The
published public_release_v_2.0.0 tag carries this.
The one-line fix is the require. The rest of this commit is about why CI never
saw it: php -l proves each file parses, and it does parse perfectly on its own,
and the unit suite never boots the plugin, so nothing ever walked the list.
DependencyManifestTest closes that gap by asserting the property that was
violated rather than the single instance — every file under includes/ appears
in the manifest, every listed path exists, no duplicates, and Booking_Adapter
precedes each of its four consumers. A file added under includes/ and forgotten
now fails on the pull request that adds it.
Verified:
- Guard fails on the unfixed tree with the right message (2 failures), passes
with the fix.
- The original reproduction — load only what load_dependencies() lists, then
invoke the init path — goes from "Class not found" to completing with no
error. class_exists() is now true; the require list holds 72 of 73.
- Full unit suite 51 tests / 847 assertions / 0 failures, up from 47 / 831.
- php -l clean on 8.4, node --check clean.
No version bump: 2.0.1 is its own release PR (P0-1, P0-2). No schema change, so
MEMBERISTIC_DB_VERSION is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LgGmwdEzTdVas4VTDzJQ5m
Shubochandrosarker
marked this pull request as ready for review
August 8, 2026 22:36
This was referenced Aug 8, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The published
public_release_v_2.0.0tag fatals oninitfor every install. Before: activating the plugin on a stock WordPress with no configuration throwsError: Class "WordPressistic\Memberistic\Integrations\Booking_Adapter" not found. After:initcompletes.includes/integrations/class-booking-adapter.phpshipped in 2.0.0 but was never added to the manual require list inPlugin::load_dependencies(), and the plugin has no autoloader. It was the only file underincludes/absent from that list — 71 listed, 73 on disk, the other beingclass-plugin.php, which the bootstrap requires directly.Waiver_Booking_Bridge::register()callsBooking_Adapter::hook()as its first statement, and is registered oninitpriority 4 whenever the Waiver Manager integration is enabled — whosedefaultis'yes'. So the chain fires unconditionally:Booking_Engine,POS_BridgeandStaff_Dashboardreach the same class.Delivers backlog item P0-11.
Type
Rules touched
No invariant is affected. The fix restores intended behaviour; it grants nothing, enables nothing, and makes no request.
Multi-edit checklist
require_oncelist inPlugin::load_dependencies()— nothing autoloadsThat is this PR's entire subject. This repository's own PR template lists it first, which is a fair indication of how easy it is to miss.
MEMBERISTIC_DB_VERSIONis untouched2.0.1is its own release PR (P0-1, P0-2)Documentation
CHANGELOG.md— new Unreleased section with the Fixed and Added entriesThe one-line fix is not the interesting part
The require is one line. The rest of this PR is about why CI was green for the entire life of the 2.0.0 release:
php -lproves every file parses — and every file does parse, perfectly, on its own. A missingrequire_onceis not a syntax error.tests/unit/DependencyManifestTest.phpcloses that gap by asserting the property that was violated, not the single instance:test_every_file_under_includes_is_in_the_require_listclass-plugin.phpexcepted — the bootstrap requires it directly)test_every_path_in_the_require_list_existsrequire_onceon a missing path is also fataltest_the_require_list_has_no_duplicatestest_booking_adapter_precedes_its_consumersA file added under
includes/and forgotten now fails on the pull request that adds it.Source inspection rather than execution, deliberately — the same approach
FreshInstallDefaultsTestandPmproRemovalTestalready take. Requiring the real files needs a live WordPress and this suite has none; the question here is what the manifest says, which is exactly what the fatal depended on.What I ran
The guard fails on the unfixed tree — a guard that never fails is not a guard. Reverting only the require, keeping the test:
The original reproduction, before → after. Load only the files
load_dependencies()lists, then invoke theinitpath:Full suite:
What I did NOT test
load_dependencies()names and calls whatinitpriority 4 calls — but it is not WordPress. The class-resolution failure it demonstrates does not depend on WordPress being present, and the fix is verified the same way.initno longer fatals. WhetherWaiver_Booking_Bridgethen behaves correctly with a booking engine mapped is untested here and needs P0-0.Licensing::build_info()slug,uninstall.phpglobals,readme.txtlimits). Deliberately out of scope — each gets its own PR.Note on the backlog
P0-11 is defined in
docs/strategy/09-execution-backlog.md, which arrives in #3. This branch is based onmain, not on #3, so the fix can merge on its own without waiting for a documentation PR — the fatal is live in the published release, and coupling it to a docs merge would be the wrong trade. The P0-11 acceptance boxes should be ticked when both have landed.Risk and rollback
require_onceof a file that already ships, placed before its consumers.Booking_Adapteris a static resolver whosehook()/table()return values pass throughapply_filtersand default to empty when nothing is mapped, so loading it changes no behaviour on a site with no booking engine — it stops the class-resolution failure and nothing else. Sites currently fatalling oninitwill start working.Generated by Claude Code