Repository navigation
Releases: ahzs645/zoer-connect
Release list
Zoer Connect 0.5.3
Zoer Connect 0.5.3
Clients that see capabilities.compactImportResponses may request
?view=compact on native import creation, status, steps and controls. Responses
retain exact source/destination binding, durable phase, progress counts, safe
errors, recovery refusal and bounded replacement samples without repeating
every artifact and upload offset. The ordinary detailed API and authoritative
?view=upload cursor remain unchanged. Compact identities are limited to 2,048
bytes; longer identities keep their exact value through the detailed API.
The compact view reduces transport bytes and per-artifact filesystem checks.
It does not change complete journal persistence, staged verification, backups,
request fencing, rollback preconditions or publication scheduling. Full journal
decoding and write costs still apply.
Export source now reports originalUrls with the source siteurl when it
differs from home, so imports into a destination replace URLs of WordPress
installed in a subdirectory, not only the home URL. Imports from a source with a
different table prefix no longer stage the source's {prefix}user_roles option
as an orphan; the destination's roles row is preserved as before.
Release status: owner-approved without integration qualification
Unlike 0.5.1 and 0.5.2, this release was published at the owner's direction on
2026-10-09 without a fresh live hosting or updater qualification. The
qualified receipt for 0.5.3 records that approval and pins the exact source
files and the ZIP built by this repository's CI; it is not evidence of a
live-site update test. Automatic updates remain off unless a site's
administrator enables them.
What was verified:
- Temporary-file tests cover 100,000-artifact response bounds, escaped excerpts,
exact identities, detailed legacy responses, native capability/query
selection, idempotent completed finish, pause/resume, successful rollback and
later-edit refusal. New tests coveroriginalUrlsreporting
(tests/export-source.php) and the dropped source-prefix roles row
(tests/prefix-roles.php). - The compact-response changes passed the full
make testsuite as
unprivilegedwww-dataon Linux PHP 8.3.35 in the official WordPress image. - For the final source, every test except the Linux-only request-protection
tests passed on macOS PHP 8.5; the full suite runs on Linux PHP 8.1, 8.2 and
8.3 in CI before the package is built. Release-guard, update-manifest,
reproducible ZIP/layout and version-consistency checks passed. - No live WordPress site was updated to this build before publication.
Zoer Connect 0.5.2
Zoer Connect 0.5.2
WordPress update discovery and ZIP downloads now use the public
ahzs645/zoer-connect repository's GitHub Releases directly. Stable releases
include an update.json asset containing the exact qualified version and ZIP
SHA-256. The updater reads releases/latest/download/update.json, then verifies
the ZIP against the immutable versioned releases/download/vVERSION/update.json.
GitHub's asset redirects are supported; metadata remains bounded to 4 KiB.
Malformed versions, missing metadata, version mismatches and altered ZIPs fail
closed. Automatic updates remain off unless the administrator enables them.
0.5.2 is also the final migration bridge published to zoer-connect-releases.
Sites running older connectors discover and install it through their existing
WordPress update workflow, retaining keys, permissions, private storage and
transfer journals. Once installed, subsequent update checks use zoer-connect.
The old feed remains publicly available at 0.5.2 for sites that upgrade later;
future release jobs do not need its deploy key or publish there. Cached legacy
download URLs still receive checksum verification in the new updater.
Transfer/export/import behavior is unchanged from qualified 0.5.1. This release
qualifies the updater migration, not new transfers or hosting compatibility.
Qualification
On 2026-10-07, the full PHP suite passed on Linux PHP 8.3.35 as an
unprivileged user in the official WordPress image. Updater boundary tests cover
stable version gating, malformed/oversized/error metadata, immutable versioned
checksum lookup, missing/mismatched metadata, altered ZIP removal, cached legacy
URLs and unchanged administrator-controlled automatic-update behavior. All six
release-qualification tests, four update-manifest tests and deterministic ZIP
layout/build checks passed. The macOS PHP 8.5 suite reaches the existing
Linux-only request-protection refusal; Linux is the supported test environment.
A fresh, owned ephemeral WordPress 7.1.2 / PHP 8.3.35 / MariaDB 11.4 installation
ran WordPress's native bulk plugin upgrader from the exact published 0.5.1 ZIP
to the exact staged 0.5.2 package. Only Connect's release HTTP requests were
intercepted with staged bytes for this pre-publication check. In a new PHP
process, the upgraded active plugin discovered and checksum-verified the package
from the source-repository URLs and refused to offer its current version again.
The same scoped connection record (Push off, Pull on), hash/owner, private
storage path and completed private journal were retained. The test's containers,
network and temporary fixture files were removed. This is a native WordPress
integration test with staged transport, not a claim of a production-site update.
tests/integration/github-update-wordpress.py --published repeats the transition
and new-source checks over public HTTPS after publication. Stable publication
also requires the PHP 8.1–8.3 and package GitHub CI gate. The exact source and ZIP
are recorded in 0.5.2.json.
Public release verification — 2026-10-07
Release CI
passed PHP 8.1, 8.2 and 8.3 and published the three stable release assets plus
the final legacy bridge. The canonical latest/versioned metadata, legacy
latest/versioned manifests and both ZIP locations match the qualified SHA-256
e34a4392390e07368807c7d67e74cf43dfbc0824086699b0b42a328f8f485cb6.
The --published native WordPress test passed using real public HTTPS, with no
HTTP interception: the published 0.5.1 connector discovered and installed the
bridge through the old feed; the new active 0.5.2 connector discovered and
checksum-verified the source-repository GitHub Release ZIP without requesting
the old feed. Connector record, permissions and completed private journal were
retained. All owned test containers and their network were removed.
WordPress Manager pins the exact v0.5.2 source commit. Its submodule checkout
fix and CI
passed typecheck, all 212 tests, build, validation and packaging. This changes
the connector pin and CI, not WordPress Manager's published package version.
Zoer Connect 0.5.1
Zoer Connect 0.5.1
Block exports now preserve empty files. Previously, a zero-byte file could stop
a hosted Pull with Snapshot block seal incomplete. because the empty snapshot
and digest sidecar had never been created. The fix creates both durable files
before advertising the authenticated zero-block checksum and resumes existing
export checkpoints without changing the connection key or file selection.
Small files up to 256 KiB are prepared together within 250 traversal entries,
4 MiB of file bytes and the existing four-second traversal budget. Larger files
retain their bounded copy and source-verification checkpoints. Batches keep the
same per-file block seals, source identity checks and private journal. If a
response is lost, the uncommitted snapshots are truncated and replayed from the
saved queue without skipped or duplicated files.
Source file exporters now match Zoer's portable hidden-file boundary. Unsupported
development caches, generator folders and potentially sensitive dotfiles such as
.npmrc are omitted; permitted packaged metadata, .github files and content
.htaccess files remain supported. This prevents vendor development files from
blocking an otherwise complete local copy without widening the importer.
Download batches stop before a checksum block that would exceed their remaining
byte budget. Mixing small files with block-sized files no longer produces a
partial block and a false Snapshot block changed. error; the next request
resumes on the original block boundary.
The regression test covers a reopened export checkpoint, a zero-byte manifest
entry, downloading the following file, checksums, identical retries, small-file
batch replay, and byte-budget checkpoint resumption. The full
PHP suite passed in the existing Linux PHP 8.1 test image as an unprivileged user;
the package layout and deterministic-build checks passed locally. GitHub CI
passed the full PHP 8.1–8.3 matrix and package checks (run 37143225066).
WP Migrate's supplied source was consulted for comparison: its full-site exporter
adds files, including empty files, to ZIP batches; its large-file chunker uses
bounded stream copies. This patch is an independent fix to Zoer's block snapshot
protocol and preserves its source verification and private staging.
Real Hostinger Pull and local-copy qualification — 2026-10-03
The final deterministic package was installed on the authorized UNBC Intramurals
Hostinger source, https://intramurals.unbctimberwolves.com, with Pull enabled
and Push disabled. Its existing connection key was retained. The source remained
available throughout read-only export; no source pause or content replacement
was requested.
The Zoer interface completed verified Pull 8be5c522f74743d68cbbb0419a60d514
and local-copy job f4d1095ad7ee761240fbc3e492aa3c04, including database,
11,228 portable files and 112,420,022 file bytes. The local DDEV site is
https://unbc-intramurals-local-f4d1095a.wp.k8s.overtheedgepaper.ca.
The source and copy both report WordPress 7.1.2. All copied files passed the
existing authenticated block checks and destination validation. Unsupported
hidden vendor caches/development files were omitted by the portable boundary;
WordPress core, credentials, MU plugins and connector code were not imported.
Browser checks confirmed the local homepage, local media, leagues, standings,
schedule and About page. Soccer's two tables and all 11 rows match the source
baseline exactly after whitespace normalization. Local WordPress admin opened
through Zoer's DDEV login. The copy retains its one local administrator; source
accounts are not imported. It has 30 published pages, 15 attachments, 25 team
records, 179 player records and 31 join-request records.
LeagueFlow 1.0.1 was enabled only locally through Zoer's reviewed plan, with the
existing automatic backup and before/after Site Health checks. Other imported
plugins remain inactive, including Clerk synchronization. Runtime checks confirm
mail interception, DISABLE_WP_CRON and the outbound HTTP local_copy guard.
These intentional development restrictions do not qualify production login,
email, background tasks or integrations. This release qualifies the changed
export/download path; it does not claim a fresh production Push or large-file
hosting stress test beyond the existing 0.5.0 evidence and automated suites.
Earlier failed export attempts remain in Zoer history. Regression tests cover
their empty-file seal, unsupported hidden metadata and mixed-file block-budget
failures, along with request replay and bounded preparation. The final installed
and qualified ZIP SHA-256 is
9138881158fb9514d5d7776cdc9a7c4c0909d1658f105515bc230e34814e91ea.
Zoer Connect 0.5.0
Zoer Connect 0.5.0 — stable
Qualified October 3, 2026 using the real Zoer cluster, task-owned DDEV sites and the authorized temporary Hostinger daycare review site. The exact source and deterministic ZIP are sealed in releases/0.5.0.json. Detailed qualification includes sanitized checksum proofs. No production content was replaced.
Changes
- Configurable incoming storage quota (16 GiB default; 1 MiB–64 GiB) with repeated free-space checks and a 64 MiB reserve. Hosted administrators configure it in Tools → Zoer Connect;
ZOER_CONNECT_TRANSFER_QUOTA_BYTESoverrides it. The matching Zoer backend and DDEV bridge useZOER_WORDPRESS_TRANSFER_QUOTA_BYTES. - New
largeTransfer/blockDigestExportnegotiation: bounded immutable source copy and verification, checksummed 256 KiB blocks, block-root manifests and downloads up to 4 MiB per request. Updated Zoer verifies the block root and computes normal whole-file SHA-256 for downloads/imports. Individual artifacts are limited to 4 GiB. Batch upload offsets now support that same ceiling. - Bounded file publication, original backup and rollback process up to 32 blocks per phase/request. Legacy journals retain their existing recovery behavior. Existing destination quota settings survive database imports.
- Optional resumable hosted database export with typed keyset table/row checkpoints, bounded SQL parts and part checksums. It requires native Push and Pull, current request protection, InnoDB primary keys and explicit acknowledgement that earlier requests/background/external writers stopped. WordPress pauses until the database seals or the export is cancelled. Query reads use supported MySQL/MariaDB execution budgets; idle expiry releases the pause and prevents resuming an expired snapshot.
- WordPress Manager 0.5.6 offers the source-pause control for Pull, Backup and Export, with acknowledgement and table/row/part progress. The matching Zoer backend validates these choices and resumes downloads. Local consistent-snapshot exports keep their existing background worker, with configurable quota and ongoing disk checks instead of a fixed 2 GiB total.
Qualification
Actual Zoer exported/downloaded a 2,203,978,458-byte set and pushed a 2,202,009,600-byte file over a 2,199,912,448-byte original. Review preserved the original; publish and rollback matched the full incoming/original SHA-256; finish and cleanup passed. Native source preparation and downloads at offsets above 2 GiB also passed.
A native source-pause SQL export survived an executing PHP-FPM worker's death and resumed to 344,869,407 bytes / 82 parts / 7,000 unsigned-64-bit-key rows, each exactly once. Part/root checksums passed and the source resumed. Hostinger passed a real 40 MiB Push/finish/rollback/cleanup, a verified maintenance-mode database Backup through Zoer's interface, quota persistence and missing/wrong-key 401 checks through canonical and rest_route URLs. Desktop/mobile acknowledgement gating and action reset passed. Native legacy no-options export and /chunks publication/recovery remained compatible.
Full PHP 8.1/8.2/8.3/8.4 suites, deterministic ZIP and release guards passed. Backend (42 tests), bridge (18 tests) and Manager (81 tests) passed their targeted verification/typechecks. Low disk space, corrupt blocks/parts, missing committed bytes, replay tails, cursor/schema rejection, cancellation and expiry have regression coverage.
Upgrade and remaining bounds
API version remains 2. Clients that omit the new negotiation retain legacy semantics and bounds. This release changes sealed fence code: repeat native request-protection setup before starting new imports or source-pause exports. Do not upgrade during an active transfer; existing authenticated recovery remains available. Keep private journals on persisted storage outside the public root.
Default read-only hosted snapshots remain 256 MiB / up to 40 seconds in one transaction. Source-pause exports cannot promise consistency against external SQL writers that were not stopped, and SQL interruption is cooperative rather than a hard HTTP deadline. Parts target 4 MiB/about three seconds, individual SQL statements are limited to 16 MiB, and pauses expire after one idle hour / 24 hours maximum. Quotas are per transfer; simultaneous transfers and retained originals need additional free space. The separate selective-comparison and Updraft upload workflows retain their documented bounds. No unlimited migration or universal host compatibility is claimed.
Zoer Connect 0.4.0
Zoer Connect 0.4.0 — stable
Qualified October 2–3, 2026 against the real OTE Zoer instance, dedicated disposable DDEV sites and the authorized temporary Hostinger daycare review site. Exact runtime and package checksums are recorded in releases/0.4.0.json. Detailed evidence is in the Zoer repository at docs/qualification/zoer-connect-040/ (also retained locally under output/ui-audit/2026-10-02-zoer-connect-040/). Production site content was not replaced.
0.4.0 is API version 2: WP Migrate-style transfer options and batched Push uploads. Every addition is optional; a client that sends none of them gets 0.3.14 behaviour. WriteFence.php, RequestDrain.php and the MU bootstrap are unchanged, so updating does not invalidate existing import readiness. The matching Zoer backend and independently released WordPress Manager sends an option only when this plugin advertises its capability. The README section "API version 2 (0.4.0)" is the protocol reference.
Changes
Status and diagnostics
/statusreportsapiVersion: 2,version: "0.4.0", 17 feature capability flags,batchUpload,batchDeflate,batchTransportsandbatchLimits.GET /diagnosticsfor Push or Pull keys: read-only WordPress, PHP and database facts (tables with engine, rows, bytes, primary/foreign keys, triggers), post types, themes, plugins, MU plugins and drop-ins, the pending plugin update, and warnings (firewall_plugin,page_cache_plugin,object_cache_dropin,mixed_case_tables,non_innodb,foreign_keys,triggers,blog_private,no_https).
Pull
databasefilter object: table suffix subset, post type inclusion list, exclude revisions, exclude spam comments, transients excluded by default. Dependent postmeta, comments, commentmeta and term relationships follow excluded parents inside the same consistent snapshot.database: truekeeps the 0.3.14 query byte for byte; with a filter object the transient patterns escape LIKE wildcards.- Profile modes:
themesMode/pluginsMode(all,active,selected,except) with item slugs, andmediaSince(UTC date). Exportsourcereportsabspathand exportedtables. - Fix: case-folded MariaDB tables use the logical WordPress prefix consistently in export, schema validation and replace snapshots while foreign prefixes remain protected.
- Fix: snapshots no longer fail with "Schema changed during export." when a concurrent insert (a transient written by a page view, a cron lock) advances a table's
AUTO_INCREMENT; MySQL 8 and MariaDB report the live counter even inside the consistent snapshot. Reproduced in 10 of 20 runs under insert load on MySQL 8.0, 0 of 20 with the fix.
Import (Push)
- Optional
sourcePathandoptions:replacements(automatic,variants,paths, up to 50customliteral or regex rows),replaceGuids,keepActivePlugins,keepActiveTheme,authorMapping(administratorormatch),createTables,partialDatabase,fence(earlyoractivation),reviewandpurgeCaches. - Without
options, the 0.3.14 sequential replacement rules apply byte for byte. With options, generated rules run as one longest-match pass, and original URLs under the source home map to the destination siteurl. - Replacement engine: the value limit is 16 MiB (was 1 MiB) and applies only to values a rule can match; case-insensitive literals; per-table counts and up to 20 before/after samples.
- New phases
mapping_authors,review_requiredand (replace kind)snapshotting; with the activation fence, tables are staged while the site stays live and the site pauses only from the fenced check inreserving. A live change detected before or under the fence cancels the import with a safe error and never leaves the site paused. Live cron and maintenance options are copied into the stage under the fence just before the swap. - Actions:
/pause,/resume,/approve,/cleanup, andGET /imports(newest 50). kind: "replace": find-and-replace on the destination's own database. It fingerprints the selected tables, then snapshots only those tables (keeping other tools' options such aswpmdb*settings, which Pull still omits), and continues through review and the activation fence.createTables: strict single-statementCREATE TABLEvalidation (InnoDB, primary key, no foreign keys, partitions, data directories, comments, backslashes, generated columns or other statements); created tables roll back by rename and are dropped on cleanup. Table creation and replace jobs refuse tables of another WordPress installation whose prefix extends this site's.- Safe errors:
{code: "zoer_import_failed", message, phase}with plugin-authored text only, paths redacted, at most 300 characters; persisted as the import'serror. purgeCaches: on the next normalwp_loadedafter finish or rollback, calls LiteSpeed, WP Rocket, W3 Total Cache, WP Super Cache, Breeze, WP Fastest Cache, Cache Enabler, SG Optimizer and Autoptimize purge hooks andwp_cache_flush().- Fix: rolling back a file publication also removes the directories that publication created (when empty), so rolling back a new theme or plugin no longer leaves an empty folder that WordPress lists as a broken theme.
Batched upload
POST /imports/{id}/batch: ordered spans of 256 KiB blocks, each checked against its manifest SHA-256 before it is written. Transports:ZBT1framedapplication/octet-stream(optionally one zlib stream per span, inflation bounded to the declared size), a multipart file partbatch, or JSON with base64 spans. Idempotent skip, torn-tail repair,gap/bounds/unverifiable/decoderejections, about 2 s of work per request, and 413zoer_import_body_limitwith the current limits.- Limits:
maxBatchBytes= min(post_max_size− 64 KiB, 8 MiB) (multipart also withinupload_max_filesize; filterzoer_connect_max_batch_bytes), 1,024 spans, 2 MiB JSON. - Fixed-width
artifacts.idx/blocks.idxand an atomicupload.jsoncursor, written at create and built lazily for older journals;GET /imports/{id}?view=uploadreturns the cursor without the import lock. /chunksresponses and messages are unchanged and share the block writer, so a job can switch transports mid-upload.
Administration
- Tools → Zoer Connect → Transfers: recent imports with Clean up backups for finished imports, including journals created before a key rotation. Export profiles are editable with the theme/plugin modes and media date.
Earlier local evidence
All runs on 2026-09-29, local machine, plugin from the working tree.
- Unit suites:
make testpasses under PHP 8.1 and PHP 8.3 (Docker PHP containers). CI additionally runs PHP 8.2. - Docker end-to-end (
tests/e2e-docker/run.sh): WordPress 7.1.2, PHP 8.3.35 (Apache), HTTPS through Caddytls internal. 225 checks, 0 failed, on MariaDB 11.4.13 and on MySQL 8.0.46 (runs after theAUTO_INCREMENTfix). Coverage: status and diagnostics, filtered paged Pull, Push with every import option, review/approve, late fence, rollback refusal and success, cleanup, a legacy client,kind: "replace", late-fence abort, pause/resume, list, safe errors and batched upload (scenarios 1–9 intests/e2e-docker/README.md). A separate loop of 60 replace imports with deliberate front-page andwp-cron.phptraffic showed no lost or invented option writes; the earlier intermittent failures were WordPress's ownwp_update_comment_type_batchcron job, which the fixture now makes deterministic withDISABLE_WP_CRON. - Batched push (scenario 9): the same export of 243 artifacts (about 8.7 MB) needs 243
/chunksrequests and 6/batchrequests (octet-stream 2, octet-stream + deflate 1, JSON 1, JSON + deflate 1, multipart 1, plus 1 idempotent retry), and publishes exactly what the/chunkspush published. - Zoer backend interop (
backend/scripts/zoer-connect-batch-interop.tsin the Zoer repository, the production uploader and connector sender against this fixture; 243 artifacts, 8,745,132 bytes):- baseline: 4
/batchrequests, octet-stream with deflate (8,214,709 bytes on the wire), adaptive growth to the advertised 8,323,072-byte limit; - body-limit learning: after
post_max_sizewas lowered to 1M mid-upload, the plugin answered four 413zoer_import_body_limitresponses, the client learned a 927,314-byte ceiling without backoff or a transport change, and finished in 10 accepted requests; - transport fallback: one 415 for octet-stream, then 6 multipart requests; 415 for octet-stream and multipart, then 7 JSON requests.
Every run completed review, approval, finish, verified the published data, rolled back and cleaned up.
- baseline: 4
Live integration qualification
- Final runtime: 225 native shared-host HTTPS checks, 0 failed; advanced verified-workers run: 118 checks, 0 failed. Request protection source remains sealed and unchanged. Administrator HTTP setup enrolled existing workers naturally without restarting the PHP pool.
- Real Zoer interface: Pull, Backup, Export and SQL/archive downloads; remote-to-Hostinger Push and local DDEV export/compare/select/Push; Find & Replace review/apply/finish/rollback, visible failures and same-job Retry, cancellation, saved profiles, local copy creation and refresh. Desktop 1280 px and mobile 390 px passed. Full copy refresh restored the snapshot title, retained local administrators and disabled cron.
- Hostinger PHP 8.3.33/LiteSpeed: actual reduction of request body limits mid-upload learned a 435,814-byte ceiling; all 1,966,080 raw bytes reached review. Host rules rejecting binary, then binary and multipart, exercised multipart and JSON fallback. Original PHP request limits were restored. Test changes were cancelled or rolled back and cleaned.
- LiteSpeed and CDN: canonical status had been cached despite
no-store. Connector-only public/privateCacheDisablerules, equivalent `r...
Zoer Connect 0.4.0-rc.1 (unqualified prerelease)
Zoer Connect 0.4.0 — UNQUALIFIED prerelease
Prerelease notes, last updated 2026-10-02. The v0.4.0-rc.1 prerelease is for disposable-site testing only and does not update the public WordPress feed. There is no qualification receipt (releases/0.4.0.json), so scripts/check-release.py fails and the CI package job stays red on every branch push; that is expected. Do not tag v0.4.0, publish it to the public update feed (ahzs645/zoer-connect-releases) or install it on a production site until the checklist below is complete and recorded. Local ZIPs from make build are for disposable test sites only.
0.4.0 is API version 2: WP Migrate-style transfer options and batched Push uploads. Every addition is optional; a client that sends none of them gets 0.3.14 behaviour. WriteFence.php, RequestDrain.php and the MU bootstrap are unchanged, so updating does not invalidate existing import readiness. The matching Zoer backend (WordPress Manager on the feature/zoer-connect-parity branch) sends an option only when this plugin advertises its capability. The README section "API version 2 (0.4.0)" is the protocol reference.
Changes
Status and diagnostics
/statusreportsapiVersion: 2,version: "0.4.0", 17 feature capability flags,batchUpload,batchDeflate,batchTransportsandbatchLimits.GET /diagnosticsfor Push or Pull keys: read-only WordPress, PHP and database facts (tables with engine, rows, bytes, primary/foreign keys, triggers), post types, themes, plugins, MU plugins and drop-ins, the pending plugin update, and warnings (firewall_plugin,page_cache_plugin,object_cache_dropin,mixed_case_tables,non_innodb,foreign_keys,triggers,blog_private,no_https).
Pull
databasefilter object: table suffix subset, post type inclusion list, exclude revisions, exclude spam comments, transients excluded by default. Dependent postmeta, comments, commentmeta and term relationships follow excluded parents inside the same consistent snapshot.database: truekeeps the 0.3.14 query byte for byte; with a filter object the transient patterns escape LIKE wildcards.- Profile modes:
themesMode/pluginsMode(all,active,selected,except) with item slugs, andmediaSince(UTC date). Exportsourcereportsabspathand exportedtables. - Fix: snapshots no longer fail with "Schema changed during export." when a concurrent insert (a transient written by a page view, a cron lock) advances a table's
AUTO_INCREMENT; MySQL 8 and MariaDB report the live counter even inside the consistent snapshot. Reproduced in 10 of 20 runs under insert load on MySQL 8.0, 0 of 20 with the fix.
Import (Push)
- Optional
sourcePathandoptions:replacements(automatic,variants,paths, up to 50customliteral or regex rows),replaceGuids,keepActivePlugins,keepActiveTheme,authorMapping(administratorormatch),createTables,partialDatabase,fence(earlyoractivation),reviewandpurgeCaches. - Without
options, the 0.3.14 sequential replacement rules apply byte for byte. With options, generated rules run as one longest-match pass, and original URLs under the source home map to the destination siteurl. - Replacement engine: the value limit is 16 MiB (was 1 MiB) and applies only to values a rule can match; case-insensitive literals; per-table counts and up to 20 before/after samples.
- New phases
mapping_authors,review_requiredand (replace kind)snapshotting; with the activation fence, tables are staged while the site stays live and the site pauses only from the fenced check inreserving. A live change detected before or under the fence cancels the import with a safe error and never leaves the site paused. Live cron and maintenance options are copied into the stage under the fence just before the swap. - Actions:
/pause,/resume,/approve,/cleanup, andGET /imports(newest 50). kind: "replace": find-and-replace on the destination's own database. It fingerprints the selected tables, then snapshots only those tables (keeping other tools' options such aswpmdb*settings, which Pull still omits), and continues through review and the activation fence.createTables: strict single-statementCREATE TABLEvalidation (InnoDB, primary key, no foreign keys, partitions, data directories, comments, backslashes, generated columns or other statements); created tables roll back by rename and are dropped on cleanup. Table creation and replace jobs refuse tables of another WordPress installation whose prefix extends this site's.- Safe errors:
{code: "zoer_import_failed", message, phase}with plugin-authored text only, paths redacted, at most 300 characters; persisted as the import'serror. purgeCaches: on the next normalwp_loadedafter finish or rollback, calls LiteSpeed, WP Rocket, W3 Total Cache, WP Super Cache, Breeze, WP Fastest Cache, Cache Enabler, SG Optimizer and Autoptimize purge hooks andwp_cache_flush().- Fix: rolling back a file publication also removes the directories that publication created (when empty), so rolling back a new theme or plugin no longer leaves an empty folder that WordPress lists as a broken theme.
Batched upload
POST /imports/{id}/batch: ordered spans of 256 KiB blocks, each checked against its manifest SHA-256 before it is written. Transports:ZBT1framedapplication/octet-stream(optionally one zlib stream per span, inflation bounded to the declared size), a multipart file partbatch, or JSON with base64 spans. Idempotent skip, torn-tail repair,gap/bounds/unverifiable/decoderejections, about 2 s of work per request, and 413zoer_import_body_limitwith the current limits.- Limits:
maxBatchBytes= min(post_max_size− 64 KiB, 8 MiB) (multipart also withinupload_max_filesize; filterzoer_connect_max_batch_bytes), 1,024 spans, 2 MiB JSON. - Fixed-width
artifacts.idx/blocks.idxand an atomicupload.jsoncursor, written at create and built lazily for older journals;GET /imports/{id}?view=uploadreturns the cursor without the import lock. /chunksresponses and messages are unchanged and share the block writer, so a job can switch transports mid-upload.
Administration
- Tools → Zoer Connect → Transfers: recent imports with Clean up backups for finished imports, including journals created before a key rotation. Export profiles are editable with the theme/plugin modes and media date.
Local evidence (not a qualification receipt)
All runs on 2026-09-29, local machine, plugin from the working tree.
- Unit suites:
make testpasses under PHP 8.1 and PHP 8.3 (Docker PHP containers). CI additionally runs PHP 8.2. - Docker end-to-end (
tests/e2e-docker/run.sh): WordPress 7.1.2, PHP 8.3.35 (Apache), HTTPS through Caddytls internal. 225 checks, 0 failed, on MariaDB 11.4.13 and on MySQL 8.0.46 (runs after theAUTO_INCREMENTfix). Coverage: status and diagnostics, filtered paged Pull, Push with every import option, review/approve, late fence, rollback refusal and success, cleanup, a legacy client,kind: "replace", late-fence abort, pause/resume, list, safe errors and batched upload (scenarios 1–9 intests/e2e-docker/README.md). A separate loop of 60 replace imports with deliberate front-page andwp-cron.phptraffic showed no lost or invented option writes; the earlier intermittent failures were WordPress's ownwp_update_comment_type_batchcron job, which the fixture now makes deterministic withDISABLE_WP_CRON. - Batched push (scenario 9): the same export of 243 artifacts (about 8.7 MB) needs 243
/chunksrequests and 6/batchrequests (octet-stream 2, octet-stream + deflate 1, JSON 1, JSON + deflate 1, multipart 1, plus 1 idempotent retry), and publishes exactly what the/chunkspush published. - Zoer backend interop (
backend/scripts/zoer-connect-batch-interop.tsin the Zoer repository, the production uploader and connector sender against this fixture; 243 artifacts, 8,745,132 bytes):- baseline: 4
/batchrequests, octet-stream with deflate (8,214,709 bytes on the wire), adaptive growth to the advertised 8,323,072-byte limit; - body-limit learning: after
post_max_sizewas lowered to 1M mid-upload, the plugin answered four 413zoer_import_body_limitresponses, the client learned a 927,314-byte ceiling without backoff or a transport change, and finished in 10 accepted requests; - transport fallback: one 415 for octet-stream, then 6 multipart requests; 415 for octet-stream and multipart, then 7 JSON requests.
Every run completed review, approval, finish, verified the published data, rolled back and cleaned up.
- baseline: 4
None of this covers certificate trust, public proxies or CDNs, real hosting limits, large transfers, process kills or the Zoer interface.
Qualification required before a receipt or tag
- Real Zoer UI against disposable DDEV (or disposable cluster) WordPress sites only, never SparkLab or another production site: Pull, Backup, Export and downloads; Push from a local DDEV export and from a verified Pull of another site (remote → remote); Find & Replace with review; pause/resume, approve, finish, rollback and cleanup; local copy refresh; desktop and 390 px widths.
- Public proxy and TLS: real certificates and hostname verification through Zoer's pinned HTTPS requester, a real reverse proxy (Traefik/nginx, Cloudflare where used) and connector-route passthrough.
- Page caches and CDN: connector routes excluded from caching;
purgeCachesagainst installed LiteSpeed, WP Rocket or Breeze; confirm what a host or CDN cache still serves. - Real shared hosting limits:
post_max_size,upload_max_filesize,max_execution_time,open_basedir, disabled functions (including zlibinflate_*), PHP-FPM pools, and web application firewalls (ModSecurity or host rules) that refuseapplication/octet-streamor multipart bodies. Confirm 413 learning and t...
Zoer Connect 0.3.14
Zoer Connect 0.3.14 qualification
- New connection keys enable Push and prepare shared-hosting migration in the same authenticated administrator POST. Pull remains opt-in. Site publication still requires the existing per-transfer replacement confirmation in Zoer.
- Key reset preserves existing permission choices. Revoked permissions stay disabled when generating a replacement key. Page views and plugin updates do not enable disabled access or rewrite existing setup.
- Automatic preparation validates private storage and hosting compatibility, installs the existing MU protection, and records a destination-bound version 4 readiness receipt. It does not claim that a content replacement was accepted or that PHP workers were isolated. Version 2 verified-worker and version 3 shared-hosting receipts remain supported.
- Existing advanced, stale or incomplete setup remains intact. Active recovery blocks setup changes. Preparation failures leave the connection key available and explain the required administrator action.
make testpassed under unprivileged Linux PHP 8.1, 8.2 and 8.3 containers, including new connection-form/default-setup coverage and the existing publication, rollback, request-drain and updater suites. The local macOS run passed the new checks but cannot complete Linux worker verification; the Linux runs provide that coverage.- Expect browser checks against the actual form renderers in a local WordPress boundary fixture passed: first key generation, Push on/Pull off, shared readiness, saving disabled Push and enabled Pull, reset preservation, revocation/regeneration, hiding the secret on GET, and repeated reset at phone width. No script errors were captured. This is form coverage, not a live WordPress browser or Zoer publishing workflow test.
- A new disposable WordPress 7.1.2 / MariaDB 11.4 installation passed
tests/integration/connection-defaults.php: real WordPress option persistence, form processing, automatic readiness, REST status dispatch reporting a publish-ready destination, permission/reset/revocation behavior, and stale-destination refusal. No production site was contacted or changed. make test-packagepassed deterministic ZIP and layout checks. The resulting ZIP was installed into the disposable WordPress instance; key settings and private readiness remained byte-equivalent across installation, and the installed plugin reported 0.3.14.- The package checksum and exact runtime file hashes are recorded in
0.3.14.json. Existing live sites need the plugin update; updating does not automatically change their saved permissions or publish site content.
Zoer Connect 0.3.13
Zoer Connect 0.3.13 qualification
- Change: preserve the destination
blog_publicsearch-visibility option during database replacement. - Change: queue a one-time soft permalink-rule refresh after a completed database or plugin/theme Push or rollback. It runs on the next normal WordPress request after the request fence is released and does not rewrite
.htaccess. The generated rule option and the pending marker remain outside rollback content fingerprints; authored permalink and search settings remain protected. make testpassed in PHP 8.1, 8.2 and 8.3 with ZIP support as an unprivileged user, including destination-option preservation, retry, rollback and updater checks.python3 tests/build_test.pypassed deterministic ZIP and layout checks.- Installed the candidate ZIP in a disposable WordPress 7.1.2 / MariaDB 11.4 installation.
wp eval-file tests/integration/rewrite-visibility.phpverified destination search visibility survives a source value of zero, the queued permalink refresh completes, a later authored visibility edit blocks rollback, and rollback restores the original options table. The disposable installation was not the PGAIR site. - The release ZIP SHA-256 is recorded in
0.3.13.jsonand in the public release manifest. No connection keys or private source files are packaged. - Published to
ahzs645/zoer-connect-releases; the existing PGAIR 0.3.12 installation discovered 0.3.13 in the WordPress dashboard and updated successfully. Zoer then verified the connected plugin as 0.3.13. Push/Pull permissions remained enabled, the destination indexing preference remained enabled, and the homepage and Wood Smoke course returned HTTP 200. No production content Push was run for this qualification.
Zoer Connect 0.3.11
Zoer Connect 0.3.11 qualification
This release normalizes MySQL/MariaDB integer display widths during source and destination schema comparison. The integer type, nullability, defaults, keys, engine and other schema details remain checked. It also adds WordPress dashboard update discovery from a public, versioned GitHub release feed and verifies each downloaded ZIP against the release manifest SHA-256 before installation. The source repository remains private; the public repository contains qualified distribution ZIPs only.
The schema change was exercised during the 2026-09-23 PGAIR local-to-Hostinger Push. The original plugin rejected wp_terms.term_group because the source used bigint(10) and the destination used bigint(20). After the equivalent normalization was applied to the destination plugin, the saved import resumed, verified its tables, applied 1,494 selected artifacts including the database, completed, and reopened the site. The live homepage, four inner pages, representative images and the connector connection were checked afterward. That production result qualifies this schema difference; it does not imply that every other SQL schema mismatch is safe.
The PHP suite includes a focused regression test for display-width equivalence and rejection of a changed integer type. Update tests cover a newer qualified version, invalid metadata, plugin isolation, valid ZIP checksum and changed ZIP rejection. The package layout and deterministic build are checked separately. GitHub Actions runs the PHP suite on PHP 8.1, 8.2 and 8.3 before publishing. WordPress dashboard update discovery and installation on the live site are checked after the release is built; 0.3.11 itself is installed once using the release ZIP because older versions have no update-discovery code. Automatic updates remain disabled unless an administrator enables them.
Zoer Connect 0.3.10
Zoer Connect 0.3.10 qualification
Reference inspected: user-supplied WP Migrate Pro 2.7.11, class/Common/Migration/Flush.php (object cache flush and rewrite regeneration), chunked transfer paths already described in the operating guide. No blanket early-cache-drop-in rejection was found in the inspected source. Implementation is independent; no third-party code copied.
Shared-hosting setup now explicitly permits regular advanced-cache.php/object-cache.php files; its exact generated MU bootstrap binds that mode into the private readiness identity. Strict worker mode still rejects both. db.php, sunrise.php, maintenance.php, symlinks and nonstandard content paths remain rejected. Known original MU bootstraps may switch mode atomically through authorized setup only while no import is active. Unknown bootstrap contents are never overwritten.
Recovery reads the key and destination URL from the database, and current owner capabilities from usermeta, rather than persistent option caches. Before reopening imports that affect DB/themes/plugins, the importer flushes the WordPress object cache inside the exclusive fence. Failure retains protection; replay retries invalidation. Page/CDN cache purges remain a separate host/plugin operation. No rewrite regeneration for the HTML-only transfer.
Validation: all existing Makefile PHP tests passed under an isolated network-disabled DDEV image as uid 1000. A root-run storage-test failure was environmental (root can write chmod-protected directories); rerunning as an unprivileged user passed. New shared-cache bootstrap/auth tests passed. New cache-flush failure and finish retry assertions passed in transfer-import.php. PHP syntax checks and deterministic ZIP layout checks passed.
Real disposable zoer-connect-transfer-peer only: installed candidate runtime, explicitly enabled shared mode, added two inert cache drop-in fixtures, and transferred a 528000-byte HTML file over native HTTPS import routes with duplicate chunk retries. Verified on-disk/upstream HTTP SHA, interrupted rollback, a second completed import, finish and post-finish rollback. Admin AJAX upstream returned 503 during the fence; anonymous import recovery was refused. The managed DDEV vanity proxy cannot resolve ordinary pages during the pause and reports 502; native upstream verification was used. wp-cron.php may close its HTTP response before WordPress bootstrap, so its HTTP status is not proof of fence behavior. Fresh-process cron bootstrap refusal is covered by unit tests.
Peer original plugin, MU bootstrap, readiness receipt, key and cache fixtures were restored. Peer home/siteurl, complete user rows and post rows compared equal before/after. Both cache fixtures are inert; this is not Redis persistence or all third-party page-cache-provider qualification. Existing DB publication tests remain regression coverage, not a newly completed large DB migration under Redis.
0.3.9 installed successfully on Aram, but the live host disables PHP link(), discovered during explicit setup. 0.3.10 serializes bootstrap installation with the private control lock and uses a fully flushed atomic rename fallback when link() is unavailable. Shared and strict fence tests and admin setup tests passed with PHP disable_functions=link. Existing artifact-reuse clients fall back to fresh upload offsets; capability reporting disables reuse when link() is unavailable. File-import, finish retry and cache-auth regression tests passed after this change. Deterministic packaging passed. No customer content import occurred before these checks.