feat(onboarding): SERENITY_SITE_ALLOWLIST cohort gate + markets[] DTO (LLMO-5201, LLMO-5202)#2513
Open
luis6156 wants to merge 5 commits into
Open
feat(onboarding): SERENITY_SITE_ALLOWLIST cohort gate + markets[] DTO (LLMO-5201, LLMO-5202)#2513luis6156 wants to merge 5 commits into
luis6156 wants to merge 5 commits into
Conversation
Contributor
There was a problem hiding this comment.
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_ALLOWLISTconstant and addisSerenityOnboardingEnabled(orgId, imsOrgId, env)helper that matches against a comma-separated, whitespace-tolerant allowlist. - Insert a gated placeholder log in
performLlmoOnboardingright after the v2upsertBrandstep. - 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. |
|
This PR will trigger a minor release when merged. |
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
3350e52 to
81f47ca
Compare
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements T1 (LLMO-5201) and T2 (LLMO-5202) from the Semrush onboarding orchestration epic (LLMO-5007).
SERENITY_SITE_ALLOWLISTcohort 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.markets[{market, language}]inPOST /llmo/onboard. Validates market (^[A-Z]{2}$) and language (BCP-47 subtag) per entry. Backward-compat: synthesizes[{market: region, language: 'en'}]whenregionis supplied withoutmarkets. When both are present,marketswins.cadencepreserved unchanged.marketsis threaded intoperformLlmoOnboardingfor the T3b fan-out.What changed
src/support/llmo-onboarding-mode.jsSERENITY_SITE_ALLOWLIST = 'SERENITY_SITE_ALLOWLIST'constant (consistent withLLMO_BRANDALF_FLAGpattern)isSerenityOnboardingEnabled(organizationId, imsOrgId, env)— checks the comma-separated allowlist against both SpaceCat org ID and IMS org ID; whitespace-tolerantsrc/controllers/llmo/llmo.jsmarketsfrom request bodymarketmust be^[A-Z]{2}$,languagemust be BCP-47 (^[a-z]{2,3}(-[a-z]{2,4})?$)regionwhenmarketsabsent;marketswins when both presentresolvedMarketsintoperformLlmoOnboardingsrc/controllers/llmo/llmo-onboarding.jsisSerenityOnboardingEnabledmarketsfrom paramsupsertBrandin 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.yamlmarkets[]request field with per-item validation patternsregiondeprecation noterequested/succeeded/failedfields on 200 responseBranch 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 frommain. Themarketsvariable 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)performLlmoOnboardinggate: serenity log fires when allowlisted; skipped when not allowlistedonboardCustomermarkets[]: valid markets forwarded, region synthesized, markets wins over region, invalid market code → 400, invalid language → 400, empty array → 400, neither supplied → no markets key🤖 Generated with Claude Code