Skip to content

AI: defer WordPress.com plan capability checks to plan.features.active#3331

Draft
lezama wants to merge 3 commits into
trunkfrom
fix-wpcom-plan-tier-accuracy
Draft

AI: defer WordPress.com plan capability checks to plan.features.active#3331
lezama wants to merge 3 commits into
trunkfrom
fix-wpcom-plan-tier-accuracy

Conversation

@lezama
Copy link
Copy Markdown
Contributor

@lezama lezama commented May 4, 2026

Related

A user on the Premium plan asked Studio Code (in remote-session mode) whether they needed to upgrade to push a plugin that registers a custom post type. The agent replied that "custom post types like the zine CPT also require Business", conflating CPTs (a core WordPress feature) with the custom-plugin-upload capability and confidently restating WP.com plan-tier rules from training data.

A first attempt at this PR replaced the prompt's tier description with a more detailed tier table — but Tess pointed out that table was also wrong (Personal and Premium do support plugin install, the top tier is "Commerce" not "eCommerce", etc.). Plan tiers and feature gating change frequently enough that any hardcoded summary in the prompt is going to drift. So this PR pivots: instead of putting any prescriptive tier copy in the prompt, point the agent at plan.features.active (the per-site authoritative feature list the WP.com /sites/{id} endpoint already returns).

Proposed Changes

  • Add a new WPCOM_PLAN_CAPABILITIES block to both the local and remote system prompts. It explicitly tells the agent not to assert what specific tier names support, and instructs it to consult plan.features.active (or ask the user) instead.
  • Add an explicit "Custom post types are core WordPress, not plan-gated" clause directly addressing the original support thread, with the right framing: the question is whether the user can install/upload the plugin or theme that defines the CPT, not whether their plan supports CPTs as a concept.
  • Update the existing IMPORTANT: Before doing ANY work… and ## Workflow instructions in the remote prompt so they no longer mandate plan.product_slug-based feature gating; plan.is_free is the only fixed plan-level rule (the free-plan refusal), everything else defers to plan.features.active.
  • Trim REMOTE_DESIGN_GUIDELINES to just the action rules and the free-plan refusal — the inaccurate (Personal, Premium, Business, eCommerce) — progressively more control line is removed.
  • Fix apps/cli/ai/wpcom-tools.ts stripOversizedFields: it was stripping plan.features entirely (because the old prompt hardcoded tier behaviour), which would silently make plan.features.active unreachable for the agent. Now features.active is preserved (small array of slugs) and only the bulky features.available and other sub-fields are dropped.
  • Add apps/cli/ai/tests/system-prompt.test.ts covering both prompt modes, asserting the new plan.features.active instruction is present, the CPT-not-plan-gated clause is present, and the previously-deleted (Personal, Premium, Business, …) tier table cannot be reintroduced silently.

What this leaves for follow-up

Tess and @alexapeduzzi plan to do a wholesale review of how the agent talks about WP.com plans. This PR intentionally scopes itself to removing wrong content and pointing at the right data source; it doesn't introduce any new prescriptive copy about specific plans. Any richer guidance (a curated plan.features.active slug glossary, dynamically-fetched plan info, etc.) is a follow-up.

Testing Instructions

  • npm test -- apps/cli/ai/tests/system-prompt.test.ts — 6 assertions, all green.
  • npm test -- apps/cli/ai/tests/ — full AI test suite (112 tests) passes.
  • npm run typecheck --workspace apps/cli — passes.
  • Manual sanity check (optional): run studio ai, ask "I'm on the Premium plan on WordPress.com — can I use a custom post type?". The agent should redirect to plan.features.active / the install-plugins capability question, not assert that any particular tier is required.

Pre-merge Checklist

  • Tests pass locally
  • Typecheck passes for the touched workspace
  • No user-visible UI surface — prompt-string + tool-output filter

@lezama lezama force-pushed the fix-wpcom-plan-tier-accuracy branch from 11d52a1 to c800e59 Compare May 4, 2026 12:54
@lezama lezama changed the title AI: correct WordPress.com plan tier capabilities in system prompt AI: defer WordPress.com plan capability checks to plan.features.active May 4, 2026
@lezama lezama force-pushed the fix-wpcom-plan-tier-accuracy branch from c800e59 to c5ac208 Compare May 4, 2026 13:00
@youknowriad
Copy link
Copy Markdown
Contributor

Add a new WPCOM_PLAN_CAPABILITIES block to both the local and remote system prompts. It explicitly tells the agent not to assert what specific tier names support, and instructs it to consult plan.features.active (or ask the user) instead.

Why do we need to add this to the "local system prompt"?

@youknowriad
Copy link
Copy Markdown
Contributor

Add an explicit "Custom post types are core WordPress, not plan-gated" clause directly addressing the original support thread, with the right framing: the question is whether the user can install/upload the plugin or theme that defines the CPT, not whether their plan supports CPTs as a concept.

I'd love to avoid this kind of specifics in the system prompt. if we can do without this kind of things it's better as otherwise we'll have to do it for all core features.

lezama added 2 commits May 4, 2026 19:41
…-out

Address review feedback on the WP.com plan capabilities block:

- Local Studio sites have no plan concept, so the WPCOM_PLAN_CAPABILITIES
  block is irrelevant noise there; render it only in the remote prompt.
- Remove the custom-post-type-specific paragraph. The general rule (defer
  to plan.features.active) is enough; per-feature carve-outs would have to
  be repeated for every other core feature and invite the same drift the
  rest of this change is trying to prevent.
- Update tests: assert the plan guidance appears only in remote mode, and
  keep the regression guard against the deleted tier table for both modes.
@lezama lezama force-pushed the fix-wpcom-plan-tier-accuracy branch from c5ac208 to 8144a4c Compare May 4, 2026 22:42
@lezama
Copy link
Copy Markdown
Contributor Author

lezama commented May 4, 2026

Both fair, addressed in 8144a4c:

  1. Local prompt — you're right, local Studio sites have no plan concept. Pulled WPCOM_PLAN_CAPABILITIES out of the local branch entirely; it now only renders in remote mode. Added a test asserting the local prompt mentions neither plan.features.active nor the capabilities heading so it can't drift back.
  2. CPT carve-out — removed. The general "consult plan.features.active or ask the user" rule is enough; baking in per-feature exceptions would have to be repeated for every other core feature and invites the same drift the rest of this change is trying to prevent. The original support-thread misconception was the agent confidently restating tier rules from training data — fixing that at the root (no tier names in the prompt at all) should cover the CPT case without naming it.

…ypass

Previous commit on this branch let `plan.features.active` survive
stripOversizedFields, which meant every `GET /` tool response (the agent
is required to call this first) carried an extra payload alongside the
actual site fields — and risked re-introducing the 60K bloat the strip
exists to prevent.

Switch to a one-shot prefetch:

- `getWpComSitePlanFeatures(token, siteId)` calls `/sites/{id}?fields=plan`
  once and returns the active feature slugs. Errors are swallowed — a
  broken feature lookup shouldn't block the agent.
- `runCommand` populates `ui.activeSite.planFeaturesActive` on the first
  remote turn. The cache rides the `SiteInfo` so subsequent turns reuse
  it without another roundtrip.
- The system prompt's remote intro now lists the active features inline
  (or falls back to "ask the user" when the prefetch returned nothing),
  and both the workflow step and `WPCOM_PLAN_CAPABILITIES` block point
  the agent at the prefetched list rather than telling it to call `GET /`
  to consult features.
- Revert `wpcom-tools.ts` to drop `plan.features` entirely from tool
  output, restoring the original bloat-prevention behaviour.

Tests cover both the prefetched and unprefetched render paths.
@lezama
Copy link
Copy Markdown
Contributor Author

lezama commented May 4, 2026

Follow-up: per-request strip-bypass replaced with a one-shot prefetch in f470276. The previous "preserve features.active in stripOversizedFields" was a per-tool-call hack that risked re-introducing the 60K bloat the strip exists to prevent.

New shape:

  • getWpComSitePlanFeatures(token, siteId) fetches /sites/{id}?fields=plan once and returns just the active feature slugs.
  • runCommand populates ui.activeSite.planFeaturesActive on the first remote turn; cached on SiteInfo so subsequent turns reuse it.
  • The remote system-prompt intro lists the active features inline (or falls back to "ask the user" if the prefetch returned nothing). The workflow step and WPCOM_PLAN_CAPABILITIES block now point the agent at the prefetched list instead of telling it to call GET / to consult features.
  • stripOversizedFields is back to its original behaviour: drop plan.features entirely from tool output.

Tradeoffs: one extra request at agent start; list goes stale if the user upgrades mid-session (rare — they can re-pick the site to refresh). Net: tool output stays minimal and the agent never has to make a tool call to reason about features.

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