AIVIS WordPress Connector — Full Specification
AIVIS-WP · Full specification 08 Aug 2026 · plugin 1.0.0 target · adapted rev 1

WordPress Connector — Full Specification

The build spec for the implementing agent: an open-source WordPress plugin that syncs approved JSON-LD from the AIVIS Public API into local storage and injects exactly one script per page — fail-open, local-only render path, zero telemetry.

Builder hand-off document Adapted from developer draft 0.9.0 (08 Aug 2026) Siblings: Edge architecture ⚡ · Edge spec 📘

00 · Front matter

How to use this spec

Doctrine mapping — edge connector → WordPress

Edge principleWordPress implementation
Pull approved JSON-LD from Public API v1Background synchronization from the same read-only API
Cache close to the serving pathLast-known-good rows in the WP database; block then rides in any full-page cache/CDN HTML
One additive script before </head>One tagged script via wp_head
Fail open (edge I1)WP-I1 — public rendering never calls AIVIS; serves stored artifact or nothing
User-agent parity (edge I3)WP-I3 — no crawler classification or conditional output
Zero-trust ingestion (edge I7 / S-01…S-06)WP-I7 + ZT-01…ZT-06
Retraction wins over resilience (edge C-10)R-01…R-03 (added in this revision)
Targeted invalidation (edge C-07)Cache-adapter contract + honest publication state (WP-I10)
Reversibility (edge I6)Disable/deactivate + cache purge; content never rewritten (WP-I5)
Open-source reviewability (edge D10/§12)Public GPL repo, CI-built reproducible release ZIPs (§18)
Crawler analytics (edge A-*)Permanently out of WordPress — measured at the edge instead (§22)

Two intentional architecture differences: (1) WordPress syncs asynchronously instead of fetching on cold public requests — PHP origin latency must never depend on the remote API; (2) analytics is excluded (§22). Shared prerequisite with the edge connector: business-scoped API tokens (edge spec V-02) — a user-scoped token inside a customer's WordPress database (backups, exports, migrations) is a wider exposure than a Worker secret, so V-02 lands before any customer-managed install.

0R · Review verdict

Changes vs developer draft 0.9.0

Verdict: the draft is sound and is accepted as the base. Its architecture (async local sync, local-only render path, no republishing, zero-trust pipeline, honest cache states, GPL) is exactly right for WordPress. This revision makes six changes:

  1. Retraction semantics added (R-01…R-03). The draft retired artifacts only after absence in two consecutive complete syncs — meaning a deliberately unpublished ("bad") JSON-LD would keep serving for ≥ 2 sync cycles plus cache TTL. Now a confirmed fetch-404 deactivates immediately, mirroring edge C-10. WP-I8 amended to match.
  2. Analytics fenced permanently, with an architecture answer (§22). The draft excluded it from v1 as "not forgotten." This revision closes the question: WordPress-side crawler analytics is structurally biased, not just incomplete — so measurement moves to the edge connector, which gains an analytics-only mode for composition.
  3. Per-URL "Refresh now" admin action plus honest retraction-latency display (R-03).
  4. Business-scoped tokens elevated from release question (draft Q-02) to shared prerequisite for customer-managed installs (§00).
  5. Marked assumptions: the /jsonld?url= multi-chain "winner" rule (non-stale first, then newest) and the loopback self-fetch used by live verification are flagged verify at build with fallbacks.
  6. Format: restructured into the AIVIS-EDGE spec-sheet format with cross-connector doctrine map, AC-17, and retraction tests. All other normative content from 0.9.0 is preserved.

01 · Scope

In, out, and the customer's own responsibility

Interpretation note carried from the draft: "inject all available AIVIS plugins" means "inject all available JSON-LD artifacts exposed by Public API v1." The v1 API exposes JSON-LD and browsing/status endpoints only; any future AIVIS output types need their own versioned schemas and delivery specs — nothing generic is implemented speculatively.

In scope — v1

The delivery connector

  • API-token configuration + connection testing (/me)
  • One AIVIS business per WordPress site; host binding
  • Discovery of all non-archived chains + URLs (cursor pagination)
  • Sync of every distinct URL with jsonLd.ready = true
  • Site-wide enable/disable; render-time injection on matching public pages
  • Persistent last-known-good storage; scheduled + manual sync
  • Targeted cache invalidation with explicit manual fallback
  • Admin status: connection, sync, coverage, freshness, live output
  • Safe deactivation, uninstall, rollback; public GitHub repo + reproducible ZIPs
Out of scope — v1

Explicitly not built

  • Generating/validating Schema.org inside WordPress
  • Editing or republishing any WordPress content
  • Detecting, merging, replacing, or removing other plugins'/themes' JSON-LD
  • Visible FAQ injection · llms.txt delivery
  • Crawler analytics or visitor telemetry (§22 — permanent, not deferred)
  • Bot-only output · editor metabox for AIVIS JSON-LD
  • Generic future-module mechanism · bespoke auto-updater
  • Network-wide Multisite administration (§15)

Customer responsibility for other JSON-LD. The customer ensures no other plugin, SEO tool, theme, tag manager, or custom code emits JSON-LD on AIVIS-enabled pages. The connector assumes there is none: it must not scan plugins, inspect HTML for other JSON-LD, keep SEO-plugin lists, remove third-party markup, block activation, or vouch for combined validity. The settings screen states this as information — it never runs a conflict check.

02 · Guarantees

Ten invariants — each maps to automated tests

IDInvariant
WP-I1Fail open. Any connector failure returns the normal WordPress page — never an error page, redirect, maintenance response, or non-2xx on the public path.
WP-I2Local-only render path. No public request makes a blocking network call to AIVIS. A render performs at most one indexed local lookup + serialization.
WP-I3User-agent parity. Identical JSON-LD for humans, search crawlers, AI crawlers, logged-in and anonymous viewers of the same canonical URL.
WP-I4Additive output only. Exactly one tagged AIVIS script when a valid artifact matches; no other markup modified or removed.
WP-I5No content mutation. Never wp_update_post(), status changes, revisions, or post_modified updates from sync or invalidation.
WP-I6Secret containment. The bearer token never appears in HTML, JS, REST responses, logs, exceptions, Site Health, or support bundles.
WP-I7Zero-trust artifact handling. AIVIS responses are size-limited, strictly decoded, schema-checked, business- and host-bound, re-serialized, and escaped so a JSON string can never close the script element or execute (ZT-01…06).
WP-I8Last-known-good delivery — bounded by retraction. A failed refresh never overwrites a valid artifact; transient API/auth/rate-limit/parse failures keep serving it. It is withdrawn only when an administrator disables injection, an authoritative fetch-404 confirms absence (R-01), or the inventory retirement rule fires (R-02).
WP-I9No telemetry. No visitor, crawler, page-view, IP, user-agent, or WP-user data is sent to AIVIS — the only outbound data is API auth plus the URLs/IDs needed to retrieve content. Permanent, not v1-only (§22).
WP-I10Honest cache status. "Live on the site" is reported only after a supported adapter confirms invalidation or public-page verification finds the marker + expected hash — never merely because the database was updated.

03 · Architecture

Sync path and render path never meet

CUSTOMER'S WORDPRESS Visitor · crawler every user agent Page cache / CDN may serve without PHP WordPress render wp_head · one lookup Administrator settings · sync now aivis_jsonld table last-known-good rows Synchronizer WP-Cron · resumable miss + data-aivis local lookup only (WP-I2) configure · sync now upsert purge changed URLs (adapter) AIVIS — EXISTING APP Public API v1 Bearer GET · paginated zero-trust validate (ZT)
The render path (left) reads only local rows; the sync path (right) is the only thing that talks to AIVIS. The cache sits between visitors and PHP — which is why publication state must be tracked honestly (WP-I10) and why crawler analytics cannot live here (§22).

Component boundaries

ComponentResponsibilityMust not do
API clientAuthenticated, bounded, version-pinned requestsInterpret Schema.org semantics
Inventory serviceTraverse businesses/chains/URLs + paginationEdit WordPress content
SynchronizerFetch changed artifacts, commit valid rowsRun on the visitor's critical path
Artifact validatorStructural, size, scope, output-safety checksRepair or improve AIVIS JSON-LD
RepositoryPersistent URL-keyed last-known-good storageDepend on expiring transients alone
URL resolverDetermine the canonical current URLCrawl the site
InjectorEmit one safe script in wp_headDetect or alter other JSON-LD
Cache invalidatorPurge changed public URLs via adaptersRepublish pages; flush unrelated caches indiscriminately
Admin UIConfiguration, status, actions, noticesExpose the token or raw sensitive diagnostics
SchedulerResumable batches + retriesSleep in-request; create overlapping jobs

04 · API contract

AIVIS Public API v1 — endpoints, pagination, errors

Base /api/public/v1; every request carries Authorization: Bearer aivis_… and Accept: application/json.

EndpointPlugin use
GET /meValidate token; display account/token name
GET /businessesPopulate the business selector
GET /businesses/{id}/chainsDiscover non-archived chains + pipeline state
GET /chains/{id}/urlsDiscover URLs with jsonLd.ready / stale / generatedAt
GET /jsonld?url={absoluteUrl}Retrieve the artifact per distinct URL. Draft assumes AIVIS resolves multi-chain membership "non-stale first, then newest" verify at build
GET /urls/{urlId}/jsonldDiagnostics / exact-ID verification only
StatusRequired behaviour
200Validate through ZT-01…06 before storing or displaying anything
400Mark the URL request invalid; no retry without changing the request
401Stop the sync, keep last-known-good rows, show "API key invalid or revoked"
403Stop the sync, keep rows, show "AIVIS account unavailable or deactivated"
404 (new URL)Negative-cache the miss; retry only after inventory change/expiry
404 (stored URL)Retraction R-01: if API reachability is confirmed in the same run, deactivate the row immediately + purge that URL; if reachability is unconfirmed, keep serving and re-check next run
429Honor Retry-After; schedule a later batch; never sleep in-process
5xx / networkKeep last-known-good; retry via scheduled backoff

05 · Administrator experience

Settings → AIVIS OS

WordPress Settings API, standard components, accessible labels, nonces, manage_options by default (filterable, §16).

Connection

Token & account

  • Password-style API-key field; saved values never rendered back
  • Test connection/me; escaped account/token name shown
  • Explicit Replace key and confirmed Disconnect (never silently deletes last-known-good data)
  • States: connected · invalid · deactivated · unreachable · not configured
  • Prefer AIVIS_API_TOKEN in wp-config.php (UI shows "Managed in wp-config.php"); else a dedicated non-autoloaded option; masked placeholder ≠ new value
Scope

Business binding

  • Paginated business list: name, base URL, industry, chain count
  • Exactly one business per site; base host must match the WP public host or an explicit alias — blocking error otherwise
  • Changing business disables injection until a new complete initial sync succeeds
  • All non-archived chains sync; no per-chain toggle in v1 ("entire site" is the product behaviour)
Delivery

Controls

  • Enable site-wide master switch — disabled until initial sync succeeds
  • Synchronize entire site now (resumable, async)
  • Refresh this URL now — per-URL immediate fetch (R-03, added)
  • Interval: 15 min default; 5 min / hourly / manual options
  • Verify live output — bounded public-URL sample, marker + hash check
  • Disable injection (keeps data) · Clear local data & resync (destructive, confirmed)
  • Mandatory notice: AIVIS assumes no other JSON-LD source; the connector does not check for or remove any
Status

Observable freshness

  • Business + base URL · injection on/off · connection state
  • Last started/completed sync · next scheduled · full/partial/failed
  • Chains traversed · URLs discovered · ready · locally active · stale · changed last sync · negative/missing
  • Last sanitized error code + time · cache-invalidation state · live-verification state · worst-case retraction latency (interval + purge, R-03)
  • No raw JSON-LD by default; capability-protected single-URL diagnostic view allowed (escaped, no token/headers)

06 · Synchronization & retraction

Resumable background jobs; retraction beats retention

Initial synchronization

  1. 1Verify./me, then the selected business is still accessible.
  2. 2Traverse.All pages of chains, then all pages of URLs per chain; build the unique set of absolute URLs with at least one jsonLd.ready = true.
  3. 3Fetch./jsonld?url=… per unique URL (AIVIS applies its winner rule); validate through ZT-01…06; upsert only valid artifacts.
  4. 4Commit.Sync is complete only when the full traversal and all artifact batches finish; per-URL failures make it "completed with errors" with URL + reason shown; existing valid rows stay live.
  5. 5Publish.Enable injection only after first complete sync + admin master switch; purge changed URLs; verify a bounded public sample.

Incremental synchronization

Each scheduled run traverses inventory metadata and refetches a URL only when: no local artifact exists; any candidate's generatedAt changed; readiness flipped to true; a forced refresh was requested; a prior failure's retry is due; or the local row failed its integrity check. If the fetched content hash is unchanged: update metadata, do not purge.

Batching, locking, scheduling

R-01R-03 Retraction (added — mirrors edge C-10)

R-01 — authoritative 404 deactivates immediately. When /jsonld?url=… returns HTTP 404 for a stored URL and API reachability is confirmed within the same run (another request succeeded, or a /me probe passes), the row is deactivated at once (soft-retire, error code AIVIS_RETRACTED) and that URL's page cache is purged. A confirmed 404 is a statement of absence, not a failure — last-known-good exists to absorb transport problems only (WP-I8). Without this rule, a deliberately unpublished bad JSON-LD would keep serving for two full sync cycles.

On-demand miss behaviour

Public request with no local row: output nothing, never call the API synchronously, schedule one deduplicated background refresh (if connected + enabled), and negative-cache that scheduling decision for 15 minutes to prevent bot-driven job floods.

07 · URL identity

Canonical URLs, not raw Host headers

AIVIS matches exactly plus a trailing-slash variant — so the plugin derives a stable canonical URL per request:

  1. Singular post/page/attachment/public CPT → WordPress canonical permalink.
  2. Front page / posts page → configured canonical WordPress URL.
  3. Taxonomy/author/date archives → corresponding WP link API.
  4. Plugin-defined routes (e.g. commerce) → the canonical URL WordPress + the owning plugin expose.
  5. Fallback only: configured home origin + routed request path — never an untrusted Host header.
  6. aivis_connector_current_url filter for compatibility integrations.

Normalization contract (local keys): http/https only; lowercase scheme+host; strip default ports and fragments; drop tracking-only params (utm_*, gclid, fbclid, msclkid, _ga); keep semantically meaningful params, sorted deterministically; preserve path + percent-encoding semantics; treat both trailing-slash variants as aliases; key = SHA-256 of the normalized result. The AIVIS response url is stored for audit. Normalization must never make two semantically distinct WP URLs share one artifact.

Host + business binding before storing: response businessId equals the selected business; response host ∈ allowed site hosts (defaults from home_url()/site_url(), aliases configurable for domain-mapped/multilingual setups); requested vs returned URL exact or approved alias; urlId/chainId non-empty; chain belongs to the selected business when inventory context exists.

08 · Storage

A URL-keyed table — transients are not a store

Custom table {$wpdb->prefix}aivis_jsonld (posts, pages, CPTs, archives, taxonomy URLs, commerce routes, and multilingual URLs don't all map to post meta). Created/upgraded with dbDelta() + a schema-version option.

ColumnTypePurpose
idbigint unsignedPrimary key
url_keychar(64)SHA-256 normalized-URL key — unique index
source_urltextAbsolute URL returned by AIVIS (audit)
url_id / chain_id / business_idvarchar(191)AIVIS identities; winning chain
language_codevarchar(16)AIVIS language
json_ldlongtextSafely re-serialized JSON document (ZT-05)
content_hashchar(64)SHA-256 of the exact stored serialization
source_generated_atdatetimeAIVIS generation time (UTC)
source_staletinyint(1)AIVIS stale flag — stale artifacts remain serviceable (serve-gate is AIVIS-side, edge V-04)
activetinyint(1)Runtime injection permitted
local_post_idbigint unsigned nullOptional WP object mapping for cache invalidation
last_seen_sync_idchar(36)Last job that observed the URL
missing_complete_runssmallint unsignedConsecutive authoritative absences (R-02)
last_synced_at / retired_atdatetime / datetime nullLast successful validation · soft-retirement time

Indexes: PK; unique url_key; (business_id, active); url_id; last_seen_sync_id; retired_at. Options (all non-autoloaded, separate): token source/status + DB fallback; selected business + allowed hosts; delivery settings; sync state/cursors; capped diagnostics; schema version; uninstall-retention preference. Transients may vanish before expiry — never the only artifact store.

09 · Zero-trust pipeline

Every artifact, every gate — the WP mirror of edge S-01…S-06

GateRequirements
ZT-01 TransportHTTPS only · TLS verified · zero redirects · fixed AIVIS host · 1 MiB cap · JSON content type (charset param allowed)
ZT-02 EnvelopeRequire v1 fields: urlId, chainId, businessId, url (absolute), languageCode, stale (bool), generatedAt (valid timestamp), jsonLd (object|array). Unknown additional fields are ignored (forward-compatible); violations of the pinned schema reject
ZT-03 ScopeURL, host, business, chain binding per §07
ZT-04 StructureException-based decode, bounded depth; object/array root only; reject invalid UTF-8, non-finite numbers, scalar roots, excess nesting, oversize. Never validate Schema.org semantics — that is AIVIS business logic
ZT-05 Safe re-serializationStore/output a plugin-generated serialization, never the raw API substring. PHP flags: JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION. Hex-encoding < makes </script> breakout impossible
ZT-06 Atomic commitValidate + serialize fully before the write transaction; atomic upsert; prior row preserved on any failure; hash computed from the exact stored bytes; purge fires only after successful commit and only when hash or activation state changed

10 · Front-end injection

One hook, one element, zero network

11 · Cache & publication

Stored is not live — publication is a tracked state

An artifact is "stored" after local commit; it is "publicly live" only after a compatible adapter confirms invalidation for the URL or live verification finds data-aivis="1" with the expected hash in public HTML (WP-I10). Cache invalidation is infrastructure, never a content edit (WP-I5).

  1. Collect + deduplicate changed public URLs after commit.
  2. Resolve a post ID when possible → clean_post_cache() (object caches only — not assumed to purge page caches/CDNs).
  3. Pass the URL batch to the cache-adapter interface; fire do_action( 'aivis_connector_purge_urls', $urls, $context ).
  4. Record per-provider result: confirmed · requested-not-confirmed · unsupported · failed.
  5. Run bounded live verification after a confirmed/requested purge. The self-fetch may be blocked by loopback restrictions on some hosts verify at build — fall back to an admin-browser check or WP-CLI verify.

Adapter interface: is_available(): bool; purge_urls(array $urls): PurgeResult; optional purge_all() (first activation/deactivation only); provider-safe batching; sanitized errors; no AIVIS credentials. Targeted purges preferred; full-site purge only when the provider can't purge URLs and the admin initiated enable/disable/deactivate/full-resync. Never flush the global WP object cache just to publish JSON-LD. No supported adapter: finish the sync, mark "manual purge required" with affected-URL count + instructions, never claim live, allow verification after the manual purge. Bundled adapter matrix is a release decision (Q-03); the neutral interface + manual fallback are mandatory.

12 · Failure behaviour

Every failure, what happens instead

FailurePublic pageBackground / admin
AIVIS DNS/TLS/timeoutStored artifact or no AIVIS outputRetain data; back off; sanitized status
401 / revoked tokenLast-known-goodStop sync; request new token
403 / deactivated accountLast-known-goodStop sync; show account status
404 new URLNo AIVIS outputNegative-cache; retry on inventory change/expiry
404 stored URL, API reachableDeactivated immediately (R-01)Purge URL; record AIVIS_RETRACTED
404 stored URL, reachability unconfirmedKeep servingRe-check next run
429Last-known-goodHonor Retry-After; reschedule
Invalid/malformed JSONPrior valid artifactReject; record validation code only
URL/business mismatchPrior valid artifactReject as security error; never cache
DB write failurePrior valid artifactRoll back; no purge
Cache purge failureOrigin new; cached HTML may be oldReport not-live; retry or request manual purge
Theme lacks wp_head()No injectionSite Health warning; no fallback rewriting
Plugin exception during outputNormal WordPress responseEmit nothing; sanitized error when debugging
WP-Cron delayed/disabledCurrent artifact keeps servingOverdue status; document system-cron/WP-CLI

Stable error codes only — e.g. AIVIS_AUTH_401, AIVIS_HTTP_TIMEOUT, AIVIS_SCHEMA_INVALID, AIVIS_SCOPE_MISMATCH, AIVIS_RETRACTED, AIVIS_DB_WRITE, AIVIS_PURGE_UNSUPPORTED. Raw bodies and authorization headers are never logged.

13 · Security & privacy

WordPress hygiene, secret honesty, zero telemetry

14 · Plugin lifecycle

Activate, deactivate, uninstall, upgrade — all reversible

Activation

Nothing automatic

  • Check WP/PHP versions; dbDelta() table create/upgrade; non-autoloaded defaults
  • Register cron hooks only once configured; no AIVIS calls, no auto-enable
  • Setup redirect only for the activating admin, per WP conventions
Deactivation

Stop cleanly, keep data

  • Stop injection; unschedule hooks; clear job locks
  • Preserve settings + last-known-good rows
  • Request page-cache purge; record if manual external purge remains needed
Uninstall

Respect the retention choice

  • uninstall.php / register_uninstall_hook()
  • Delete tables/options only if "Delete AIVIS data on uninstall" was enabled; else preserve + document removal
  • Never touch posts, revisions, terms, users, media, or other plugins' data
Upgrade / rollback

Forward-only migrations

  • Schema-versioned migrations; compatible rows preserved
  • Failed migration keeps the last compatible read path or disables only the connector with a notice — never the site response
  • GitHub releases carry upgrade + rollback notes

15 · Compatibility

Baseline, routes, Multisite, i18n

16 · Extension contract

Stable hooks, no business-logic leaks

apply_filters( 'aivis_connector_current_url', $url, $query_context );
apply_filters( 'aivis_connector_allowed_hosts', $hosts );
apply_filters( 'aivis_connector_manage_capability', 'manage_options' );
apply_filters( 'aivis_connector_sync_interval', $seconds );

do_action( 'aivis_connector_artifact_changed', $url, $old_hash, $new_hash );
do_action( 'aivis_connector_purge_urls', $urls, $context );
do_action( 'aivis_connector_sync_completed', $summary );
do_action( 'aivis_connector_sync_failed', $error_code );

17 · Observability

Local diagnostics + Site Health — nothing leaves the site

18 · Open source & releases

GPL, reproducible ZIPs, CI-built releases

aivis-wordpress-connector/
├── aivis-os.php                  bootstrap + plugin headers (incl. Update URI)
├── src/ {Admin, Api, Cache, Delivery, Domain, Security, Storage, Sync}
├── assets/  ├── languages/
├── docs/ {SPECIFICATION, ARCHITECTURE, CACHE-INTEGRATIONS, PRIVACY, RUNBOOK, THREAT-MODEL}.md
├── tests/ {Unit, Integration, EndToEnd}
├── .github/ {ISSUE_TEMPLATE, workflows, dependabot.yml}
├── composer.json · composer.lock · phpcs.xml.dist · phpunit.xml.dist
├── readme.txt · uninstall.php
└── CONTRIBUTING.md · SECURITY.md · CHANGELOG.md · LICENSE

19 · Testing

Proving the invariants, not just the features

SuiteKey cases
API clientValid /me; 401/403/404/429/5xx/DNS/TLS/timeout/oversize/redirect/wrong content type/malformed JSON; pagination past 200 items; no bearer forwarded on redirect; token absent from all exception/log output
SynchronizationInitial sync covers every ready distinct URL across chains; not-ready listed but not fetched; duplicates use /jsonld?url= winner; unchanged generatedAt ⇒ no refetch; unchanged hash ⇒ no purge; failed replacement preserves LKG; partial inventory never retires; R-02: two authoritative absences retire; jobs resume from cursors; lock prevents overlap + recovers
Retraction (added)R-01: fetch-404 with confirmed reachability deactivates immediately + purges + records AIVIS_RETRACTED; 404 with unconfirmed reachability keeps serving; deactivated/retired rows never inject; a subsequent 200 for the same URL reactivates cleanly
Security</script>/HTML-like strings stay encoded and non-executable; depth/UTF-8/scalar-root/oversize/timestamp/host/business/URL violations rejected; CSRF + capability enforcement; API base immutable via untrusted settings; token absent from page source, REST, notices, logs, support data, snapshots
InjectionOne matching row ⇒ exactly one data-aivis="1" script in head (object + array roots); no row/disabled/404/feed/REST/sitemap/preview/admin ⇒ nothing; human vs crawler UA byte-identical; third-party JSON-LD untouched and non-suppressing; repeated wp_head cannot duplicate; zero remote requests on render
Cache / publicationChanged content ⇒ one deduplicated purge batch after commit; failed commit ⇒ no purge; clean_post_cache() without post updates; no revisions/modified-date/editorial hooks from sync; unsupported provider ⇒ "manual purge required", never "live"; enable/disable/deactivate purge behaviour; verification distinguishes stored / purge-requested / live
Compatibility / E2ESupported WP/PHP matrix; pretty + plain permalinks; homepage/post/page/CPT/taxonomy/plugin route; www + trailing-slash + tracking-param + translated-domain aliases; with and without persistent object cache; ≥ 1 page-cache adapter + the unsupported path; release ZIP installs → activates → configures → syncs → injects → disables → deactivates → uninstalls cleanly

20 · Acceptance criteria

Demonstrated on staging against the designated AIVIS environment

IDCriterion
AC-01Valid token connects via /me; invalid token rejected without exposure
AC-02Admin selects a matching business and completes a paginated full sync
AC-03Every AIVIS-ready distinct URL has a valid active local artifact or an explicit per-URL error
AC-04Enabling site-wide injection changes no WP content records and creates no revisions
AC-05A matched public page contains exactly one safe data-aivis="1" script in <head>
AC-06A page without a ready artifact is unchanged
AC-07Existing non-AIVIS JSON-LD is neither inspected nor changed
AC-08Public requests make no AIVIS call and survive a complete AIVIS outage
AC-09Script-breakout payloads cannot create executable markup
AC-10Refresh failure preserves and serves last-known-good
AC-11Changed artifacts invalidate affected caches without republishing content
AC-12Unsupported cache infra reported as manual-purge-required — never falsely "live"
AC-13Identical markup for browser, Googlebot, GPTBot, and arbitrary user agents
AC-14Disable/deactivate + purge restores pre-connector output
AC-15No token, telemetry, IP, or raw UA in public output or diagnostics
AC-16Official release ZIP reproducibly built, checksummed, installable, matrix-green
AC-17Unpublishing in AIVIS deactivates on the next fetch-404 (R-01) with cache purge; the block does not resurrect from last-known-good during a subsequent outage

21 · Milestones

M0 → M6

  1. M0Contract lock.Production API base; repo org/name; WP/PHP baseline; token scope + rotation (V-02 dependency); cache-adapter launch matrix. Resolves Q-01…Q-08.
  2. M1Skeleton, storage, API client.Public GPL repo from first commit; bootstrap + DI boundaries; settings/secret storage; custom table + migrations; hardened API client with mock contract tests.
  3. M2Inventory & synchronization.Business selection + host binding; cursor traversal; resumable initial/incremental jobs; LKG writes, retries, retirement and retraction R-01…R-03.
  4. M3Delivery.Canonical URL resolver; safe wp_head injector; performance + fail-open tests; UA parity + zero-trust tests.
  5. M4Cache publication & operations.Adapter interface + launch adapters; manual fallback; live verification; status dashboard, Site Health, disable/deactivate runbooks.
  6. M5Hardening & OSS readiness.Full compatibility matrix; threat model, privacy + external-service disclosure, contribution/security policies; CI gates; release packaging + provenance.
  7. M6Pilot & 1.0.0.Staging smoke against live API; pilot on an AIVIS-controlled WP site with real page cache/CDN; failure drills (API outage, invalid token, malformed artifact, delayed cron, failed purge, retraction, rollback); tagged 1.0.0 + customer runbook.

22 · Analytics decision

Permanently out of WordPress — measured at the edge instead

AN-01 (decision): AI-crawler analytics is permanently excluded from the WordPress connector — not deferred. The developer's v1 exclusion reasons (no ingest endpoint yet; PHP-only visibility; minimal-scope priority) are correct, but the deeper problem decides it: a PHP plugin only sees cache-miss traffic, and AI crawlers overwhelmingly hit cached, popular pages. The sample isn't just incomplete — it is systematically biased. Selling the Monitoring subscription on skewed counts would contradict the Evidence & Monitoring positioning that is AIVIS's entire brand promise. A JS/pixel beacon can't fix it either: AI crawlers don't execute JavaScript.

The architecture answer — measure where every request is visible:

Appendix · Release decisions

To confirm in M0

IDDecisionRecommended default
Q-01Production AIVIS API base URLDedicated production hostname; never ship the dev hostname as release default
Q-02API token scopeBusiness-scoped read-only token (edge V-02 — treated as prerequisite for customer-managed installs, §00); until then, account token with strict business/host binding on AIVIS-controlled pilots only
Q-03Bundled cache adaptersPick from actual pilot/customer infrastructure; core stays provider-neutral; manual purge always supported
Q-04Default freshness target15-minute polling; 5 minutes for high-freshness/retraction-sensitive managed sites with reliable system cron
Q-05Minimum platformsWordPress 6.5+ · PHP 8.1+, subject to target-customer hosting survey
Q-06MultisitePer-site only if fully test-covered; otherwise block network activation in 1.0
Q-07Distribution beyond GitHubGitHub Releases for v1; evaluate WordPress.org after pilot
Q-08Public repo coordinatesaivis-wordpress-connector under the org chosen in the shared edge Q-8 decision