Skip to content

Releases: mosamlife/wpmgr

v0.42.2

12 Jun 03:44
48efbbd

Choose a tag to compare

[0.42.2] - 2026-06-12

Fixed

  • Object cache: dashboard status froze once the cache went live (stats reports rejected). The agent reports cache operations per second as a JSON number with decimals; the control plane typed the field as an integer and rejected the entire stats report, so the dashboard kept showing the last state from before the cache was enabled. Idle sites passed (whole numbers encode without decimals), which is how it escaped testing. The control plane now accepts the decimal value, and the agent reports a whole number for compatibility with older control planes.
  • Object cache: a malformed status block can no longer reject the whole stats report. The block is now decoded separately and skipped with a logged warning, so page cache stats always land even if the object cache block is unparseable. This applies the same tolerant ingest approach used in 0.35.3.

Control plane and agent 0.42.2; the drop-in stays at 2.1.1 (no site-side cache changes). Sites already running agent 0.42.1 are fixed by the control plane update alone.

v0.42.1

12 Jun 02:33
e00e365

Choose a tag to compare

Critical hotfix for the 0.42.0 object cache

Important

If you enabled the object cache on agent 0.42.0, update to this version before re-enabling it. If a site was already affected (fatal errors on every request after enabling): delete wp-content/object-cache.php, restart PHP or the container (required to release leaked file descriptors), update the agent, then re-enable.

[0.42.1] - 2026-06-12

Fixed

  • Object cache: a boot recursion in drop-in 2.1.0 could exhaust the PHP worker's file descriptors and take the site down. The boot-time failback safety check ran before the cache global was assigned; it called into the WordPress options API, which re-entered the boot path and opened one persistent Redis connection per recursion level until the worker hit its descriptor limit. Affected sites returned a fatal on every request and kept broken workers until the web server was restarted. The check now runs only after the cache global is assigned, and boot is guarded against re-entry, with a safe in-memory fallback serving any cache call that arrives while boot is still running.
  • Sockets are now closed explicitly on failed or abandoned connection attempts, including when boot falls back to the in-memory cache.
  • Unavailable serializer or compression codecs no longer abort the connection. The engine falls back to the PHP serializer or no compression, reports the effective codec to the dashboard, and the integrity check compares effective values so stored data is never read with the wrong codec.
  • AUTH and SELECT results are verified, so a half-established connection can no longer be reported as connected.

Added

  • A per-request connection attempt budget (12) that converts any future connection loop into a single degraded request instead of an outage.
  • A persisted reconnect cool-down (15 seconds doubling to 5 minutes) so a down Redis is not re-dialed on every request; the dashboard shows the cool-down state, and a clock step backward fails open rather than suppressing the cache.
  • Connection retry bounds enforced at both the agent and the control plane (retry count 0 to 10, retry interval 1 to 5000 ms).
  • New regression nets: an artifact-level boot test that fails on any recursive boot, plus end-to-end stages for descriptor counting and codec fallback.

Control plane and dashboard

  • Object cache config saves validate retry bounds before persisting.
  • Readable labels for the new degradation causes (reconnect cool-down, connection attempt limit) and for previously raw cause strings.

Agent 0.42.1 with drop-in 2.1.1; existing installs refresh automatically after the agent updates. No new migrations.

v0.42.0

12 Jun 00:29
8436d2c

Choose a tag to compare

Caution

Do not enable the object cache on this version. Agent 0.42.0's drop-in (2.1.0) contains a boot recursion that exhausts the PHP worker's file descriptors on the first request after the object cache is enabled, fataling the site on every request. Update to v0.42.1 before enabling the object cache. If a site is already affected: delete wp-content/object-cache.php, restart PHP or the container (required to release leaked descriptors; deleting the file alone is not enough), update the agent to 0.42.1, then re-enable. All other 0.42.0 features are unaffected.

The object cache hardening arc (0.41.4 to 0.42.0)

This release consolidates the complete arc since v0.41.3 into one public tag. Versions 0.41.4 and 0.41.5 were never tagged publicly (0.41.4 contained a fatal fixed within the hour); the agent update channel received each step.

[0.42.0] - 2026-06-12

Fixed

  • Object cache: full behavioral parity audit against the category-leading implementation, with every accepted fix shipping alongside the test that proves it. Headline corrections: the in-request cache layer is now keyed identically to Redis, eliminating a multisite scenario where switching blogs could serve one site's cached values as another's; counter operations on missing keys now return false exactly as WordPress core does instead of fabricating values; serializer and compression settings the server cannot honor now fail loudly into safe mode with a named cause instead of silently mixing storage formats; the post-outage cache flush is rebuilt around a persisted outage marker and a Redis lock so exactly one request flushes after a genuine recovery and never during normal traffic; and install-mode detection no longer suppresses cache writes during WordPress upgrades.
  • Sixteen further contract corrections covering delete-on-missing return values, force-refresh reads on memory-only groups, write-through ordering, key validation, batched-read result ordering, back-compat property access, version-aware flush flags, multisite transient cleanup, and a guard against a performance plugin disabling our drop-in.

Added

  • Configuration drift detection. The agent now reports the fingerprint of the configuration file it is actually reading, and the dashboard flags when it diverges from the saved settings, ending the class of silent mismatch between what the control plane believes and what the site runs. Failed configuration pushes to the site now surface as a visible warning instead of being discarded.
  • Codec capability gate. Saving a configuration that requests a serializer or compression codec the site's own connection test reported as unavailable is now rejected up front with a clear message.
  • Named diagnosis for unreadable credentials files and honest cache-flush results in command-line contexts, plus complete teardown on deactivation and uninstall.
  • Four new integration-harness stages: multisite isolation, install-mode writes, file-ownership drift from command-line sessions, and outage-recovery flushing exactly once.

Migration m69 applies automatically on API boot. Agent 0.42.0 with drop-in 2.1.0; existing installs refresh automatically after the agent updates. Security reviewed (verdict ship, no findings).

[0.41.6] - 2026-06-11

Fixed

  • Object cache: the cache no longer flushes itself on every request. The recovery mechanism that clears potentially stale keys after a Redis outage misread its per-request state and treated the first successful operation of every page load as an outage recovery, wiping the entire site keyspace each request. With the cache enabled this made wp-admin dramatically slower than no cache at all: every read missed, every option re-queried the database, and all transients died per request. The flush now fires only after a genuinely recorded outage-to-recovery transition, with regression tests asserting no flush ever happens without a prior failure.
  • Object cache: non-activation diagnosis is accurate and names the culprit. The previous cause detection used a leftover substring check that misread the current drop-in and made four causes unreachable. The rewritten diagnosis distinguishes a replaced cache object (reporting the replacing class and file), an incomplete boot, a stale opcode cache, a suppression filter, an early definer (reporting its file), and missing, outdated, or foreign drop-ins, in the correct precedence order.

Added

  • A real-WordPress integration harness (docker compose: WordPress, MariaDB, Redis) that installs the built agent zip and asserts what unit tests structurally cannot: the engine actually serving as the active cache, keys surviving across requests (the direct regression net for the per-request flush bug), loose-typed plugin call shapes against the installed drop-in, heartbeat correctness in web and cron contexts, and a negative test for early cache definition. Runs nightly and on demand; not part of the default CI gate.

Agent-only release. Drop-in 2.0.2; existing installs refresh automatically after the agent updates.


What's Changed

  • feat: object cache 0.42.0 — full reference-parity contract + drift detection (+ 0.41.4-0.41.6 fix arc) by @mosamlife in #39

Full Changelog: v0.41.3...v0.42.0

v0.41.3

11 Jun 14:46
32b3d9a

Choose a tag to compare

[0.41.3] - 2026-06-11

Changed

  • Object cache: the status heartbeat now reads the live engine, not a persisted option. The dashboard pill previously depended on a fragile chain (an analytics-gated shutdown write into a WordPress option, read back by a later request) where several links could silently fail and present as "Disabled". The reporting request has the drop-in active too, so the heartbeat now asks the running cache object for its state directly; the persisted option only carries the analytics counters. The heartbeat also reports the engine's own version on the wire, so "which code is actually executing on this site" is always visible.

Fixed

  • Object cache: agent updates can no longer leave stale engine bytecode running. On hosts with aggressive opcode caching, replacing the plugin files did not guarantee the new engine code executed. The agent now invalidates the engine and its supporting files on every version change at boot, and the drop-in installer invalidates them on every install.
  • Object cache: the drop-in self-heal actually fires. The installed-stub version check read only the first 512 bytes of the file while the version header sat past byte 1100, so outdated stubs were always misread as current. The header now sits at the top of the file and the check reads further regardless.
  • Object cache: array mode always records a named reason (such as a missing config or unloadable classes), the state snapshot persists regardless of the analytics toggle, and a connection-retry path no longer calls a WordPress function that may not exist at drop-in load time. A single invalid number can no longer silently drop an entire stats report.

Agent-only release.


What's Changed

  • fix: live-introspection object-cache heartbeat + opcache discipline (0.41.3) by @mosamlife in #38

Full Changelog: v0.41.2...v0.41.3

v0.41.2

11 Jun 13:57
a64ef70

Choose a tag to compare

[0.41.2] - 2026-06-11

Fixed

  • Object cache: the engine's supporting classes now load at drop-in time. The 0.41.1 drop-in located the engine correctly, but the engine file then loaded its config and connection classes through a plugin constant that does not exist that early in the WordPress boot, so it silently fell back to the in-memory array cache on every request and kept reporting itself idle. The engine now resolves its sibling class files from its own directory, which is always available. Agent-only fix.
  • Object cache: the stamped engine path in the drop-in is honored. The installer's placeholder replacement also rewrote the guard that detects an un-stamped stub, turning the stamped path into dead code; standard installs survived only via the content-directory fallback. The guard token is now built so stamping cannot touch it, and the drop-in version bump makes existing installs self-heal on the next agent heartbeat.

Requires agent 0.41.2. No control plane or dashboard changes.


What's Changed

  • fix: object cache engine actually connects (0.41.2) by @mosamlife in #37

Full Changelog: v0.41.1...v0.41.2

v0.41.1

11 Jun 13:45
8bb908f

Choose a tag to compare

Note: the agent in this release still had two early-boot bugs that kept the engine in array mode on real sites; use agent 0.41.2 (next release) which supersedes it. The API and dashboard fixes in this release are complete.

[0.41.1] - 2026-06-11

Fixed

  • Object cache: the engine now actually starts on real sites. The object-cache.php drop-in installed by 0.41.0 located the engine through constants that WordPress does not define yet at the moment drop-ins load, so the engine silently never booted: the status pill stayed "Disabled", analytics stayed empty, and Redis never received a key even though Enable reported success. The installer now stamps the resolved engine path directly into the drop-in at install time, with a content-directory fallback, and the agent automatically refreshes an outdated drop-in on its next heartbeat, so existing installs self-heal after updating the agent. No manual disable and re-enable needed.
  • Object cache: flush no longer fails with a 422. Five Redis SCAN call sites (the flush and disable commands, the connection test's capability probe, and two engine flush paths) called SCAN with the wrong client API shape, which threw on every invocation. The connection test also misreported this as an ACL denial. All five now use the correct phpredis iterator pattern, pinned by a signature-enforcing test double.
  • Object cache: the saved connection test result now survives reloads. The config response never included the stored test result, and saving any unrelated setting wiped it. The Server capabilities card now renders from the stored result, which is preserved across saves and intentionally discarded only when connection fields change.
  • Object cache: analytics can now populate. The agent heartbeat previously never included hit and miss counts, so the charts could never receive data. The engine now accumulates per-request counters and the heartbeat reports them as consume-and-reset deltas alongside average latency and operations per second.
  • Object cache: honest status reporting end to end. The dashboard pill now distinguishes "configured but not serving" (a real reported state) from never configured; an unrecognised state from an agent no longer blanks the stored state; agent command failures now surface as error toasts instead of success; and command failures carry the exception class name (never the message, which could contain connection details) for diagnosability. Swallowed ingest and command errors are now logged with bounded, length-capped detail strings.

Requires agent 0.41.1 for the on-site fixes; the dashboard fixes apply on the API and web update alone. Security reviewed (verdict ship; the two log-hygiene notes were fixed before release).


What's Changed

  • fix: object cache v0.41.1 — engine boots on real sites, flush fixed, honest reporting by @mosamlife in #36

Full Changelog: v0.41.0...v0.41.1

v0.41.0

11 Jun 12:28
c0d7ea1

Choose a tag to compare

Redis Object Cache (v1)

WPMgr 0.41.0 ships a full per-site Redis object cache: the persistent-cache layer that accelerates everything the page cache cannot serve (logged-in users, admin, carts and checkout, REST responses, repeated database queries).

Highlights

  • Per-site connection config from the dashboard — TCP host/port, unix socket, database number, ACL username/password, TLS, and a key prefix that scopes all keys on a shared Redis instance.
  • Test-before-enable handshake — the agent dials the candidate config without persisting it, probes phpredis version and extension capabilities (igbinary, lzf/lz4/zstd, TLS), reads the eviction policy with guidance, and returns a structured result. Enable is blocked until a test passes for the current config.
  • Credential security by design — the password is age-encrypted (X25519) at rest in the control plane, delivered over the signed command channel, and stored only in a 0600 private PHP file on the site. It never appears in API responses, logs, SSE payloads, test results, heartbeats, or backups (the config file is excluded from file archives by name, with a regression test).
  • Two-level safe degradation — a boot failure swaps in a pure in-memory array cache so the site never goes down; mid-request Redis errors become misses with one reconnect attempt, then degrade for the rest of the request.
  • Live status + analytics — connected/degraded/down pill streaming over SSE, plus 7-day charts for hit ratio, used memory, command latency, and ops/sec with a 90-day daily downsample.
  • Shared-Redis safety — flush operations scope to the site's own prefixed keys only; persistent connections use an explicit identity to prevent pooled-socket database confusion.
  • Full WP cache API — add/get/set/replace/delete, multi-key variants, flush_group, flush_runtime, wp_cache_supports, and switch_to_blog for multisite.

v1 topology is single instance or unix socket (with TLS); Sentinel and Cluster are reserved in the config schema for a later release.

Also in this release

  • Test-suite integrity fix — the agent phpunit suite had been silently truncating in CI (a drop-in ABSPATH guard killed the process with exit 0 mid-suite); the full 1414-test suite now runs in CI, and the repair surfaced and fixed a hidden bug where the page-cache URL purge reported 0 removed files.
  • Object-cache stats ingest hardening: attacker-controlled gauge fields are clamped to their column ranges so forged values cannot drop a site's own stats rows.

Migration m68 applies automatically on API boot. Requires agent 0.41.0.


What's Changed

  • feat: Redis object cache v1 — clean-room phpredis engine + live status + analytics (v0.41.0) by @mosamlife in #35

Full Changelog: v0.40.0...v0.41.0

v0.40.0

11 Jun 08:15
c84bc20

Choose a tag to compare

Added

  • The client portal overview is now a real dashboard. Instead of a thin header and a plain sites list, portal users land on a live summary of everything their agency does for them: a status banner ("All sites operating normally" or "N sites need attention"), five headline numbers with animated counters (sites monitored, average uptime, backups, updates applied, site speed rating), a month-at-a-glance section with the fleet uptime trend and a Core Web Vitals distribution band, a callout for the latest white-label report with HTML and PDF downloads, richer site cards (brand-colored avatar, 30-day uptime sparkline, speed rating chip, TLS expiry, last backup, per-period backup and update counts), and a day-grouped "Recent work" timeline showing each update and backup the agency performed. A period switcher covers the last 7, 30, or 90 days. The data comes from one new read-only summary endpoint that reuses the report aggregator; everything is strictly scoped to the client's own sites, and agency-internal details (email logs, error logs, raw metrics) are never exposed. Security reviewed (verdict ship, no findings to fix).

Fixed

  • Client portal invitations never sent the email. The invitation email template existed and the send was wired, but the template was missing from the mailer's subject registry, so every send failed silently while the screen claimed the invitation was emailed. Invitations now send when instance email is configured, and the confirmation is honest either way: "Invitation emailed to {address}" only when it actually went out, otherwise a clear prompt to share the copyable invite link. A new completeness test prevents any future template from shipping without its subject registration.

What's Changed

  • v0.40.0: client portal dashboard v2 + invitation email fix by @mosamlife in #34

Full Changelog: v0.39.1...v0.40.0

v0.39.1

11 Jun 06:38
7003844

Choose a tag to compare

Fixed

  • The WooCommerce cart-aware caching toggle could never be enabled, on any site or theme. The agent's theme support detection ran only inside scheduled background jobs and remote command handlers, two contexts where WooCommerce never loads its storefront scripts, so every check reported "unsupported" and re-stamped that result on every heartbeat. Detection now runs during real storefront page renders: any positive detection enables the toggle immediately, a negative verdict requires three different pages to agree (cart fragments often load only on cart pages), the check repeats after theme or plugin changes, and until a real check has happened the dashboard now says "Checking your theme" instead of pretending the theme is unsupported. Existing stored verdicts were reset since none were trustworthy. Requires agent 0.39.1; migration m67.
  • Enabling the CDN failed with "cdn_url is required" before you could type a URL. The CDN switch saved immediately on flip, but the URL field only appears after the switch is on, so the save was always rejected and the switch snapped back, hiding the field again. Flipping the switch on now reveals and focuses the URL field without saving; the setting saves in one step once a valid URL is entered, and validation problems show inline on the field instead of a generic error message.

What's Changed

  • v0.39.1: WooCommerce cart-cache detection + CDN enable flow by @mosamlife in #33

Full Changelog: v0.39.0...v0.39.1

v0.39.0

11 Jun 05:00
affe6e1

Choose a tag to compare

Added

  • Read-only client portal: give each client their own branded login and dashboard. From a client's detail page, open the new "Portal access" tab to invite client users by email. Existing users are added immediately; new email addresses receive a tokenized invite link with a 7-day expiry. The invite accept link is always shown as a copyable fallback so the flow works even when instance email is not configured. Revoke any member instantly, revoke or regenerate a pending invite, and all of this is also available to the agency when the invite is regenerated (the link rotates and the old one stops working). Clients sign in on the same login page and land automatically at /portal after authentication, with no agency screens visible and no way to navigate to them. The portal shell shows the client's logo, brand color applied as a scoped accent, and an agency attribution footer ("Managed by {agency}"). Two-item navigation: Sites and Reports. No sidebar, no org switcher, no write controls anywhere in the portal tree. The sites overview lists each client site with its last backup date, 30-day uptime percentage, and TLS expiry. Site status wording is softened for client audiences: "Monitoring active" instead of connected, and "Needs attention" instead of degraded or disconnected. Each site links to a detail page with four read-only cards: uptime summary and incident history (24-hour, 7-day, 30-day, and 90-day ranges), backup inventory (completed backups only, no restore or download controls, no destination or blob keys), applied updates log, and Core Web Vitals p75 field data with per-metric ratings. The Reports page lists all completed white-label reports for the client and provides HTML and PDF download links. Portal users hold a new client role ranked below viewer with zero permissions. They can see only their own client's sites and reports, cannot access any agency endpoint or event stream, and lose access the moment they are removed, when the client is archived, or when the client is deleted. Migration m66. Security reviewed in two rounds including live row-level-security isolation tests.

Fixed

  • Deleting a client that still had sites assigned failed with a database error since 0.37.0. The composite foreign key on the clients-to-sites relationship nulled the wrong columns on delete, causing a constraint violation instead of cleanly unassigning the sites. Sites are now correctly unassigned when a client is deleted, matching the documented behavior.

What's Changed

  • v0.39.0: read-only client portal (Clients Phase 3) by @mosamlife in #32

Full Changelog: v0.38.1...v0.39.0