Skip to content

feat: add VIP integration scaffolds and lens infrastructure - #63

Open
Adi-ty wants to merge 2 commits into
mainfrom
v1.0.0/task/vip-integrations-and-scaffold-fixes
Open

Adi-ty wants to merge 2 commits into
mainfrom
v1.0.0/task/vip-integrations-and-scaffold-fixes

Conversation

@Adi-ty

@Adi-ty Adi-ty commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds four WordPress VIP Go integration scaffolds (vip-cron, vip-remote-request, vip-search, vip-webhook), introduces the lens manifest key for post-scaffold skill routing, and overhauls the PHPCS scaffolds to use rtCampWP/rtCampWP-Basic.

Part of

Part of rtcamp/wp-devtools#60

Changes

  • Add integration/vip-cron scaffold — WP-Cron/Action Scheduler dual-runner with Cron Control concurrency support
  • Add integration/vip-remote-request scaffold — cached HTTP client using wpcom_vip_file_get_contents on VIP, enum-constrained timeout (1-3s) and cache TTL (300-86400s)
  • Add integration/vip-search scaffold — ElasticPress offload for meta/taxonomy queries with fallback action on null results
  • Add integration/vip-webhook scaffold — HMAC-SHA256 verified webhook receiver with 64KB body cap, deduplication, and Action Scheduler/WP-Cron queuing
  • Add lens manifest key with closed enum (accessibility, i18n, performance, security, seo, vip-readiness), validated and exposed in list --json and add result shape
  • Add plugin-header discovery source for discover_from (reads Text Domain: from plugin entry file or style.css)
  • Extend PSR-4 path grafting to autoload-dev.psr-4 and handle root-level autoload directories
  • Add enum constraint validation on inputs post-transform (throws EINVALIDINPUT with allowed list)
  • Sort rendered PHP use statements in the engine so templates don't need to guess namespace order
  • Skip wiring targets resolving outside the project root with a warning instead of broken file paths
  • Overhaul lint/phpcs/full and lint/phpcs/core to extend rtCampWP/rtCampWP-Basic from rtcamp/wp-phpcs with auto-scaffolded allow-plugins wiring
  • Fix lint/phpcs/vip package name from non-existent automattic/vip-coding-standards to automattic/vipwpcs
  • Fix setup/phpunit bootstrap @package annotation from project's PSR-4 test namespace
  • Update all wp/* scaffolds for use-block sorting, _doing_it_wrong notice avoidance, and PHPUnit compatibility

How I verified

npm run check

Acceptance criteria

Runtime behavior

  • wp-tooling add integration/vip-cron renders a working dual-runner job class
  • wp-tooling add integration/vip-remote-request renders a cached HTTP client respecting VIP timeout/TTL limits
  • wp-tooling add integration/vip-search renders an ElasticPress offload class that no-ops without EP_VERSION
  • wp-tooling add integration/vip-webhook renders a webhook receiver with HMAC verification and deduplication
  • Enum-constrained inputs reject out-of-range values with clear error messages
  • lens field appears in wp-tooling list --json output
  • Plugin header discovery resolves text-domain from entry file

Code quality

  • Lint — zero errors
  • Static analysis — zero errors
  • Tests pass

Housekeeping

  • CHANGELOG.md entry under ## Unreleased

Reviewer notes

  • lint/phpcs/vip still exists — open question whether to retire it now that full/core cover VIP-adjacent standards
  • Rest.php vs REST.php module naming is deferred — affects wp/rest and integration/vip-webhook

@Adi-ty

Adi-ty commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Requires Abstract Job class here: rtCamp/wp-primitives#85 to be merged.

@Adi-ty
Adi-ty requested a review from 00kaku September 17, 2026 07:17
Base automatically changed from v1.0.0/task/modern-wp-api-scaffolds to main September 29, 2026 06:14
Add four new integration scaffolds for WordPress VIP Go projects:
- vip-cron: WP-Cron/Action Scheduler dual-runner with Cron Control support
- vip-remote-request: cached HTTP client using wpcom_vip_file_get_contents
- vip-search: ElasticPress offload for meta/taxonomy queries with fallback
- vip-webhook: HMAC-SHA256 verified webhook receiver with deduplication
@Adi-ty
Adi-ty force-pushed the v1.0.0/task/vip-integrations-and-scaffold-fixes branch from bd24b42 to 92058cc Compare October 8, 2026 11:33
@Adi-ty

Adi-ty commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Dropped integration/vip-cron from this PR. It builds on AbstractJob, which only exists in rtCamp/wp-primitives#85 (Decision pending)

@Adi-ty
Adi-ty marked this pull request as ready for review October 8, 2026 13:41
Copilot AI balanced review requested due to automatic review settings October 8, 2026 13:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The promised VIP cron scaffold is absent, while off-VIP caching and webhook deduplication guarantees remain incomplete.

4 open findings
What changed in this PR

Adds lens-based post-scaffold routing and VIP integration scaffolds, although the promised vip-cron scaffold is absent.

Changes:

  • Adds lens schema validation and API exposure.
  • Adds VIP search, remote-request, and webhook scaffolds with generated tests.
  • Expands scaffold documentation and catalogue coverage.
File Description
tests/​scaffolds/​validate.test.js Tests lens validation.
tests/​scaffolds/​schema-parity.test.js Covers lens schema parity.
tests/​scaffolds/​registry.test.js Verifies lens result shape.
tests/​scaffolds/​list.test.js Tests lens listing output.
tests/​scaffolds/​bundled-manifests.test.js Covers VIP scaffold rendering.
src/​scaffolds/​validate.js Validates lens declarations.
src/​scaffolds/​schema.js Defines allowed lenses.
src/​scaffolds/​registry.js Exposes scaffold lenses.
src/​scaffolds/​list.js Includes lenses in listings.
skills/​scaffold/​SKILL.md Documents VIP scaffold guidance.
scaffolds/​setup/​claude-skills/​templates/​scaffold-SKILL.md Updates generated skill guidance.
scaffolds/​integration/​vip-webhook/​templates/​webhook.php.mustache Implements webhook handling.
scaffolds/​integration/​vip-webhook/​templates/​test.php.mustache Generates webhook tests.
scaffolds/​integration/​vip-webhook/​scaffold.json Defines webhook scaffold.
scaffolds/​integration/​vip-search/​templates/​vip-search.php.mustache Implements search offloading.
scaffolds/​integration/​vip-search/​templates/​test.php.mustache Generates search tests.
scaffolds/​integration/​vip-search/​scaffold.json Defines search scaffold.
scaffolds/​integration/​vip-remote-request/​templates/​test.php.mustache Generates HTTP client tests.
scaffolds/​integration/​vip-remote-request/​templates/​remote-request.php.mustache Implements cached requests.
scaffolds/​integration/​vip-remote-request/​scaffold.json Defines remote-request scaffold.
docs/​authoring-scaffolds.md Documents lenses and integrations.
docs/​ai-orchestration.md Documents lens API behavior.
CHANGELOG.md Records the new functionality.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment on lines +67 to +71
{
"key": "signature_header",
"description": "Request header carrying the hex HMAC-SHA256 of the raw body. Match your sender; adapt verify_signature() if it prefixes the digest or signs a timestamp too.",
"default": "x-signature"
},
Comment on lines +176 to +180
if ( false !== get_transient( self::CACHE_GROUP . '_' . $delivery ) ) {
return false;
}

return set_transient( self::CACHE_GROUP . '_' . $delivery, 1, DAY_IN_SECONDS );
Comment on lines +13 to +15
- `integration/vip-search` scaffold — a `Registrable` that sends heavy meta and taxonomy main queries on one post type to VIP Search through `ep_integrate`, which works on any ElasticPress backend too. Adds `META_KEYS` to VIP Search's post meta allow list (it indexes none by default), preserving whichever list or map format the allow list arrived in, since VIP discards entries that do not match it. Fires a prefixed action whenever a query that asked for the index falls back to MySQL — the silent outcome when query integration is not enabled for the environment, under VIP search rate limiting, or on an index error. Changes only the main query from `pre_get_posts`, resolving an archive's empty `post_type` the way `WP_Query` does, so category, tag and custom taxonomy archives on the post type are offloaded; secondary queries opt in where they are built. No-ops without `EP_VERSION`.
- `integration/vip-remote-request` scaffold — a service that fetches remote data over GET without an uncached request on the page path. On VIP it delegates to `wpcom_vip_file_get_contents()` (cached, stale-on-failure, backs off a failing host); `vip_safe_wp_remote_get()` is deliberately not used because it caches nothing. Elsewhere it caches successful responses only in the object cache via `rtCamp\WPPrimitives\Utils\Cache` and fetches with `wp_safe_remote_get()`. Internal hosts are refused on both paths, and only when a request is actually sent, so a cached or stale copy never waits on a DNS lookup. `timeout` and `cache_ttl` are `enum`-constrained to what `RemoteRequestTimeout` (at most 3s) and `LowExpiryCacheTime` (at least 300s) accept.
- `integration/vip-webhook` scaffold — a REST controller that verifies an HMAC-SHA256 signature over the raw body in constant time, refuses every delivery until a shared secret is set (a VIP environment variable, or a constant of the same prefixed name elsewhere — never written by the scaffold), caps the body at 64 KB, accepts a JSON object or an array (as batch senders post), acknowledges a repeated delivery to the same webhook with 200 without queueing it twice for a day (atomically in a persistent object cache, in a transient otherwise, so retries are caught without one), and queues the payload on Action Scheduler or WP-Cron before answering 202 instead of doing the work in the request. The REST module it wires into is the `module_path` input, so a project whose module is `REST.php` is not sent to a `Rest.php` that does not exist.
Comment on lines +84 to +86
$key = md5( (string) wp_json_encode( [ $url, $args ] ) );
$found = false;
$body = $this->cache->get( $key, self::CACHE_GROUP, false, $found );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants