Skip to content

Blaze Woo MCP test stack#48856

Closed
j6ll wants to merge 57 commits into
trunkfrom
feature/blaze-woo-mcp-launch
Closed

Blaze Woo MCP test stack#48856
j6ll wants to merge 57 commits into
trunkfrom
feature/blaze-woo-mcp-launch

Conversation

@j6ll
Copy link
Copy Markdown
Member

@j6ll j6ll commented May 15, 2026

Summary

Consolidated feature branch for the Blaze Woo MCP stack so the end-to-end MCP surface can be tested and reviewed together.

Merged slices:

  • ADS-952 list-campaigns ability foundation
  • ADS-953 prepare-campaign write ability
  • ADS-1036 campaign preparer extraction
  • ADS-1044 safe audience targeting
  • ADS-1037 intelligent defaults
  • ADS-1038 forecast estimates
  • ADS-1039 readable preview response
  • ADS-1041 server-side prepare telemetry
  • ADS-1090 list-campaigns context
  • ADS-1091 get-campaign-stats
  • ADS-1092 stop-campaign
  • ADS-1057 portable target inputs

Umbrella Linear review ticket: ADS-1034

Testing

  • php -l projects/packages/blaze/src/abilities/class-blaze-abilities.php
  • php -l projects/packages/blaze/src/class-campaign-preparer.php
  • php -l projects/packages/blaze/tests/php/abilities/Blaze_Abilities_Test.php
  • php -l projects/packages/blaze/tests/php/Campaign_Preparer_Test.php
  • git diff --check origin/trunk...HEAD

Focused PHPUnit command was attempted but this fresh worktree is missing the local phpunit-select-config shim.

j6ll added 30 commits May 12, 2026 14:14
Adds `blaze-ads/create-campaign` to the existing Blaze_Abilities class,
opted into Woo's MCP server alongside the read-only list-campaigns
ability shipped in ADS-952.

Architecture:

- Cross-cutting guardrails (TOS / payment check, per-session spend
  ceiling) live in a registration-time wrapper applied via the
  `wp_register_ability_args` filter to any ability marked
  `meta.annotations.readonly => false`. Future Phase 3 write abilities
  inherit them automatically.

- Audit log via `wp_after_execute_ability` listener, filtered to our
  write-path slugs.

- Kill-switch via `blaze_abilities_create_campaign_enabled` filter
  (default true).

- Successful response includes a draft campaign reference plus a
  deep-link to the Blaze widget for merchant approval. Phase 2
  deliberately keeps approval in-browser; chat-native preview is
  tracked as ADS-988.

Stubs to fill in: TOS / payment check, spend ceiling enforcement,
Picard moderation (pending intent decision), integration tests.
Reading vendor/wordpress/mcp-adapter ToolsHandler.php confirms it only
forwards WP_Error->message and ->code to MCP clients — the data field
is dropped. So the original spec's "deep-link in WP_Error data" pattern
won't reach Claude / other MCP clients via the MCP route.

Update the stub example to embed the deep-link as a URL inside the
error message text, so MCP clients can present it to the merchant. Keep
the data field too as belt-and-braces for direct WP Abilities REST
callers (standard WP REST serialization preserves it).

Code change is doc-only (the stub still returns true). The real
implementation will follow this pattern when wired up.
The wrapper now enforces a TOS / Blaze-eligibility gate using the
existing Blaze::site_supports_blaze() helper (proxies the WPCOM
/sites/<id>/blaze/status endpoint with a day-long transient cache, so
per-call cost is a transient lookup). When the site isn't yet eligible
the wrapper returns a WP_Error with the deep-link embedded in the
message text (so Claude / other MCP clients pass it through to the
merchant) and also in the data field as belt-and-braces for direct
WP Abilities REST callers.

Removes the check_spend_ceiling() stub. The "session" semantics for
spend ceiling and the gate-vs-log-only call for Picard moderation are
both real product decisions that don't need to block hack-month
delivery — split out into ADS-989 as a post-RSM follow-up. The wrapper
keeps a clearly-marked insertion point where ADS-989 will plug in.
Covers:

- Wrapper passes through unowned and read-only abilities unchanged
- Wrapper no-ops when execute_callback is missing
- Wrapper replaces execute_callback for owned write abilities
- Wrapped callback delegates to original when TOS / Blaze-eligibility passes
- Wrapped callback short-circuits with WP_Error when site is not eligible
- Deep-link URL is embedded in WP_Error message text (the Woo MCP adapter
  strips WP_Error::data, so this is the only way the URL reaches MCP clients)
- Deep-link URL also lives in the data field as belt-and-braces for direct
  REST callers
- Kill-switch via blaze_abilities_create_campaign_enabled removes
  create-campaign from registration without affecting list-campaigns
- opt_into_woo_mcp toggles ON for both owned slugs and leaves foreign
  slugs at their default

Inheritance is documented inline rather than dynamically tested — adding
a new write slug to OWNED_ABILITY_SLUGS is the only step a Phase 3
ability needs to take to inherit the wrapper.

Tests follow the WorDBless + transient-pre-population pattern; no Brain
Monkey or runtime mocking needed since site eligibility is cached via
transient and the wrapper is a static method we can call directly.
…rite)

Phase 2 v1 deliberately drops the direct DSP write from the agent
path. The ability now derives sensible defaults from the target post
+ the caller's input, bundles them into a structured prefill payload,
and returns a deep-link the merchant clicks to land in the existing
Blaze widget with every field already populated. The actual DSP write
happens when the merchant submits via the widget — we trust that flow.

Why this shape:

- The full DSP creation contract is 13 fields, several of which (payment
  method, T&C acceptance, exact dates, etc.) are merchant-context the
  AI can't reasonably fill in. Forcing an MCP-side draft would either
  fail at DSP validation or land an incomplete campaign on the merchant's
  account.
- The Blaze widget already renders the proper preview, audience, and
  approval UX. Reusing it is much faster than rebuilding any of that
  inside chat.
- The widget's prefill-from-URL behaviour is a separate piece of work
  in dsp-client that this PR doesn't ship; until that lands the
  merchant can still follow the link and edit manually.

Behaviour:

- Validates target_urn, resolves the post, and returns clean WP_Errors
  for invalid URN (400) or missing post (404).
- Builds prefill payload with: target_urn, type, site_name (post title
  or override), text_snippet (post excerpt, content fallback, or
  override), target_url, main_image (featured image), budget (mode +
  amount + currency from Woo or USD), duration_days, is_evergreen
  (default true), objective (default VIEWS).
- Builds prefill_url with the payload base64url-encoded in a
  blaze_prefill query param, inserted before the SPA hash so it
  reaches the widget bootstrap.
- Returns { status: "pending_merchant_review", message, prefill_url,
  prefill }. The message embeds the URL verbatim so MCP clients that
  strip structured fields still surface the link to the merchant.

Tests cover: invalid URN, missing post, happy-path payload + URL
shape, caller overrides winning over post-derived defaults, content
fallback when no excerpt is set.
Two prefill defaults that the widget needed to render a complete form
without any post-prefill clobbering on the client side:

- `cta_text`: defaults to "Shop Now" for products, "Learn More" for
  posts/pages. The widget treats CTA as a required field; without a
  default the merchant lands on a form with a validation error
  immediately after the agent's deep-link.
- `currency`: always USD. The DSP only bills in USD, so reading the
  Woo store currency just produced a misleading number for non-USD
  merchants — the DSP would treat the amount as USD regardless. Until
  the DSP gains multi-currency support, normalize at the prefill edge.

🤖 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two new optional inputs the agent can pass through to narrow targeting:

- `languages`: array of ISO 639-1 codes (lowercased on the way through).
- `countries`: array of ISO 3166-1 alpha-2 codes (uppercased; codes
  that aren't 2 chars are dropped on the floor).

Empty arrays are stripped before they hit the payload so the widget
keeps its "all languages / worldwide" defaults instead of being forced
into an empty selection.

Schema-prose work (steering agents toward sensible defaults when the
user is vague) is intentionally out of scope here and tracked as a
Phase 2 follow-on.

🤖 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…n-ability' into feature/blaze-woo-mcp-launch
…ting-options' into feature/blaze-woo-mcp-launch
* @param string $slug The slug being registered.
* @return bool
*/
public static function guard_against_double_register( $enabled, $type, $slug ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should move this to the registrat class. that that this is the case for all jetpack registered classes and abilities.

*
* @param bool $enabled Whether to register the prepare-campaign ability. Default true.
*/
if ( ! apply_filters( 'blaze_abilities_prepare_campaign_enabled', true ) ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is also available in the registrar class do we need another filter specific for the blaze abilities?

@j6ll j6ll changed the title Blaze Woo MCP launch stack Blaze Woo MCP test stack May 21, 2026
@j6ll j6ll marked this pull request as ready for review May 21, 2026 17:09
@j6ll
Copy link
Copy Markdown
Member Author

j6ll commented May 21, 2026

Superseded by #49065 so the local, remote, and Jetpack Beta Tester branch name is consistently feature/rsm-ai-ads-manager.

@j6ll j6ll closed this May 21, 2026
@j6ll j6ll deleted the feature/blaze-woo-mcp-launch branch May 21, 2026 17:15
@github-actions github-actions Bot removed [Status] In Progress [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. labels May 21, 2026
@j6ll
Copy link
Copy Markdown
Member Author

j6ll commented May 21, 2026

Hi @enejb thanks for your comments - I will take a look (I need too give things a good review generally) but I will incorporate those suggestions too. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Blaze [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Plugin] mu wpcom jetpack-mu-wpcom plugin [Plugin] Wpcomsh [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants