Skip to content

feat(onboarding): SERENITY_SITE_ALLOWLIST cohort gate + markets[] DTO (LLMO-5201, LLMO-5202)#2513

Open
luis6156 wants to merge 5 commits into
mainfrom
feat/LLMO-5201-5202-cohort-gate-markets
Open

feat(onboarding): SERENITY_SITE_ALLOWLIST cohort gate + markets[] DTO (LLMO-5201, LLMO-5202)#2513
luis6156 wants to merge 5 commits into
mainfrom
feat/LLMO-5201-5202-cohort-gate-markets

Conversation

@luis6156
Copy link
Copy Markdown

@luis6156 luis6156 commented May 29, 2026

Summary

Implements T1 (LLMO-5201) and T2 (LLMO-5202) from the Semrush onboarding orchestration epic (LLMO-5007).

  • T1 — Add SERENITY_SITE_ALLOWLIST cohort gate: orgs in the allowlist enter the Semrush provisioning path (M5–M8); all others fall through to the existing v1/v2 flow unchanged. Env-driven — no DB flag required for the prototype phase.
  • T2 — Accept optional markets[{market, language}] in POST /llmo/onboard. Validates market (^[A-Z]{2}$) and language (BCP-47 subtag) per entry. Backward-compat: synthesizes [{market: region, language: 'en'}] when region is supplied without markets. When both are present, markets wins. cadence preserved unchanged. markets is threaded into performLlmoOnboarding for the T3b fan-out.

What changed

src/support/llmo-onboarding-mode.js

  • Export SERENITY_SITE_ALLOWLIST = 'SERENITY_SITE_ALLOWLIST' constant (consistent with LLMO_BRANDALF_FLAG pattern)
  • Add isSerenityOnboardingEnabled(organizationId, imsOrgId, env) — checks the comma-separated allowlist against both SpaceCat org ID and IMS org ID; whitespace-tolerant

src/controllers/llmo/llmo.js

  • Destructure markets from request body
  • Validate each entry: market must be ^[A-Z]{2}$, language must be BCP-47 (^[a-z]{2,3}(-[a-z]{2,4})?$)
  • Backward-compat fallback: synthesize from region when markets absent; markets wins when both present
  • Pass resolvedMarkets into performLlmoOnboarding

src/controllers/llmo/llmo-onboarding.js

  • Import isSerenityOnboardingEnabled
  • Destructure markets from params
  • After upsertBrand in the v2 path, enter the serenity gate block when the org is allowlisted — placeholder for T3a/b/c (LLMO-5203–5205)

docs/openapi/llmo-api.yaml

  • markets[] request field with per-item validation patterns
  • Updated region deprecation note
  • requested/succeeded/failed fields on 200 response
  • New 207 response schema

Branch note for T3

T3a (LLMO-5203), T3b (LLMO-5204), T3c (LLMO-5205) should branch from this branch (feat/LLMO-5201-5202-cohort-gate-markets), not from main. The markets variable and the serenity gate block are already in place — T3 only needs to fill in the M5/M7/M8 logic inside the gate.

Test plan

  • isSerenityOnboardingEnabled: 6 unit tests (missing env, SpaceCat org match, IMS org match, no match, whitespace trimming, undefined env)
  • performLlmoOnboarding gate: serenity log fires when allowlisted; skipped when not allowlisted
  • onboardCustomer markets[]: valid markets forwarded, region synthesized, markets wins over region, invalid market code → 400, invalid language → 400, empty array → 400, neither supplied → no markets key
  • Non-allowlisted orgs: all pre-existing tests pass unchanged

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 29, 2026 07:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a cohort gate for the upcoming Serenity (Semrush) provisioning path in LLMO onboarding. An env-var-based allowlist (SERENITY_SITE_ALLOWLIST) is checked after upsertBrand in the v2 flow; matching orgs currently only log a placeholder message, with actual provisioning to follow in later tasks.

Changes:

  • Export SERENITY_SITE_ALLOWLIST constant and add isSerenityOnboardingEnabled(orgId, imsOrgId, env) helper that matches against a comma-separated, whitespace-tolerant allowlist.
  • Insert a gated placeholder log in performLlmoOnboarding right after the v2 upsertBrand step.
  • Add unit tests for the helper and integration tests covering allowlisted vs non-allowlisted paths.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/support/llmo-onboarding-mode.js New constant and isSerenityOnboardingEnabled helper.
src/controllers/llmo/llmo-onboarding.js Calls the helper after v2 brand upsert and logs a placeholder.
test/support/llmo-onboarding-mode.test.js Six unit tests for the new helper.
test/controllers/llmo/llmo-onboarding.test.js Two integration tests: allowlisted logs, non-allowlisted does not.

@github-actions
Copy link
Copy Markdown

This PR will trigger a minor release when merged.

Florian-Luis Micu added 4 commits May 29, 2026 13:27
Add isSerenityOnboardingEnabled() to llmo-onboarding-mode.js and wire it
into performLlmoOnboarding after upsertBrand. Orgs in the allowlist enter
the Semrush provisioning path (M5–M8); all others fall through to the
existing v1/v2 flow unchanged. Env-driven — no DB flag required for
the prototype phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Ai-Assisted-By: claude-code
…t (LLMO-5201)

Consistent with LLMO_BRANDALF_FLAG pattern — the env var name is now
exported so callers and tests reference the constant instead of a
hardcoded string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Ai-Assisted-By: claude-code
…MO-5202)

Accept optional markets[{market,language}] in POST /llmo/onboard.
Validates market (^[A-Z]{2}$) and language (BCP-47 subtag) per entry.
Backward-compat: synthesizes [{market:region,language:'en'}] when region
is supplied without markets. When both are present, markets wins.
cadence is preserved unchanged. markets is threaded into
performLlmoOnboarding for the T3b fan-out.

OpenAPI spec updated with markets[] request field, partial-success
response fields (requested/succeeded/failed), and 207 response schema.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Ai-Assisted-By: claude-code
- llmo-onboarding.js: reference markets in log message to satisfy no-unused-vars
- llmo-onboarding-mode.js: add curly braces to if(!allowlist) return
- llmo-onboarding.test.js: wrap two long createMockSharePointClient calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Ai-Assisted-By: claude-code
@luis6156 luis6156 force-pushed the feat/LLMO-5201-5202-cohort-gate-markets branch from 3350e52 to 81f47ca Compare May 29, 2026 10:28
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

- Remove 207/partial-success fields from OpenAPI (not yet produced by code;
  will land with T3 — LLMO-5203–5205)
- Fix IMS org ID allowlist matching to be case-insensitive (IMS_ORG_ID_REGEX
  uses /i so mixed-case input is valid upstream)
- Change region-synthesis log from warn to debug (non-cohort region usage
  is the normal happy path, not a warning condition)
- Hoist ^[A-Z]{2}$ and BCP-47 patterns to named consts ISO_ALPHA2_UPPER_REGEX
  and BCP47_LANGUAGE_REGEX (were duplicated; one const prevents drift)
- Fix BCP-47 language description in OpenAPI (accepts primary + optional
  script/region subtag, all lowercase by normalization choice)
- Add test for non-object markets[] entries (null, string, number) —
  the !entry || typeof entry !== 'object' guard was previously uncovered

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Ai-Assisted-By: claude-code
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