Skip to content

feat(llmo): prompt-suggestion-schedules provisioning endpoint + trial→paid admin reaction#2848

Open
dzehnder wants to merge 1 commit into
mainfrom
feat/prompt-suggestion-upgrade-trigger
Open

feat(llmo): prompt-suggestion-schedules provisioning endpoint + trial→paid admin reaction#2848
dzehnder wants to merge 1 commit into
mainfrom
feat/prompt-suggestion-upgrade-trigger

Conversation

@dzehnder

Copy link
Copy Markdown
Contributor

What

Adds a reusable per-site prompt-suggestion schedule provisioning endpoint and an admin-side trial→paid reaction, building on the tier gate landed in #2847.

POST /sites/:siteId/prompt-suggestion-schedules

  • Server-side tier is the only mechanism. The endpoint re-derives the site's current LLMO tier via isPayingLlmoSite — the caller may not supply a tier/isPaying. Only paying sites get recurring schedules; a non-paying site is a deliberate no-op (skipped: true, reason: 'not-paying'). The onboarding trial one-shot (submitJob) is intentionally NOT reused here: submitJob is not idempotent, so a re-provision/backfill endpoint must be paying-only. The underlying createSchedule IS idempotent, so repeat calls are safe and already-existing schedules count as success.
  • Per-pipeline failure contract. Returns { siteId, isPaying, skipped, allSucceeded, results } where each result is { providerId, status, error? } (created / already-existed / submitted / failed). One pipeline failing never aborts the others.
  • Auth. Dedicated CAP_PROMPT_SUGGESTION_SCHEDULE_WRITE capability with the standard dual-layer check (isAdmin bypass, else fresh hasS2SCapability). :siteId is UUID-validated; the param is classified in FACS_NON_RESOURCE_PARAMS.

Shared ensurePromptSuggestionSchedules module

  • isPayingLlmoSite, registerPromptSuggestionSchedule, ensurePromptSuggestionSchedules, and PROMPT_SUGGESTION_PIPELINES moved from llmo-onboarding.js into src/support/prompt-suggestion-schedules.js so the onboarding side-effect, the new endpoint, the entitlements reaction, and a future reconciler all share one implementation. llmo-onboarding.js imports + re-exports them for backwards compatibility.
  • ensurePromptSuggestionSchedules now returns a real per-pipeline result envelope ({ results, allSucceeded }) instead of an opaque sentinel.

Entitlements trial→paid admin reaction

  • entitlements.createSiteEntitlement reads the prior tier before createEntitlement; on an LLMO trial→paid transition it best-effort (re)provisions recurring schedules via the shared helper. Never fails the entitlement operation (mirrors the best-effort onboarding side-effect).

Test fix (onboarding suite)

The move made the tier helpers a transitive dep of the onboarding controller. The prior test attempt mocked them tree-wide with esmock's 3rd (global) arg; that global state accumulates in global.mockKeys and slowed every later esmock in the file past its mocha timeout — 25 onboarding tests hung. Fix: esmockOnboarding now mocks the shared module at its own boundaries (TierClient + Entitlement) via a nested esmock and injects that mocked module as a local dep of the onboarding controller. The real schedule/tier logic still runs (so createSchedule/submitJob assertions hold), with no global esmock state leaking between tests.

Verification

  • test/controllers/llmo/llmo-onboarding.test.js165 passing, 0 failing (was 140 passing / 25 hanging).
  • test/support/prompt-suggestion-schedules.test.js, test/controllers/llmo/prompt-suggestion-schedules.test.js, test/controllers/entitlements.test.js — all green.
  • test/routes/{capability-constants,index,facs-capabilities}.test.js — green.
  • npm run lint clean except the known-unrelated @adobe/spacecat-shared-ticket-client unresolved-import error.
  • npm run docs:lint — API description valid.

Base note

This was authored against feat/prompt-suggestion-tier (#2847). #2847 merged into main today and its branch was deleted, so this PR targets main and the single commit was rebased --onto main (0 behind main). The #2847 dependency is satisfied by main; drs-client 1.14.0 is still the intended runtime dependency (cadence literals are kept local until it lands — see prompt-suggestion-schedules.js).

Required follow-ups

🤖 Generated with Claude Code

…rial→paid admin reaction

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dzehnder
dzehnder requested a review from MysticatBot July 17, 2026 14:33
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.46449% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/controllers/entitlements.js 91.37% 5 Missing ⚠️
...rc/controllers/llmo/prompt-suggestion-schedules.js 98.27% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@MysticatBot

Copy link
Copy Markdown

Mysticat review failed: Claude CLI crashed (exit 1): stderr= stdout={"type":"result","subtype":"error_max_budget_usd","duration_ms":5,"duration_api_ms":1022486,"is_error":true,"num_turns":1,"stop_reason":null,"session_id":"45280d65-140e-40cc-8818-d82eea968a4a","total_cost_usd":17.23579465,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_to

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