@@ -199,6 +199,7 @@ describe('SerenityController', () => {
199199 let resolveWorkspaceIdStub ;
200200 let resolveBrandWorkspaceStub ;
201201 let isSerenityActiveStub ;
202+ let isAsyncProvisioningKillSwitchedStub ;
202203 let createTransportStub ;
203204 let resolveBrandUuidStub ;
204205 let getBrandAliasesStub ;
@@ -237,6 +238,9 @@ describe('SerenityController', () => {
237238 // existing assertion that drives a brand-level route reaches its handler.
238239 // The "serenity inactive" describe overrides this to false.
239240 isSerenityActiveStub = sinon . stub ( ) . resolves ( true ) ;
241+ // LLMO-7418 external-review Finding 15: kill switch off by default (async provisioning
242+ // available); specific tests override it to resolve(true) to exercise the 503 gate.
243+ isAsyncProvisioningKillSwitchedStub = sinon . stub ( ) . resolves ( false ) ;
240244 decommissionStub = sinon . stub ( ) . resolves ( ) ;
241245 ensureSubworkspaceStub = sinon . stub ( ) . resolves ( SUBWS ) ;
242246 clearBrandWorkspaceCacheStub = sinon . stub ( ) ;
@@ -352,6 +356,7 @@ describe('SerenityController', () => {
352356 } ,
353357 '../../src/support/serenity/serenity-active.js' : {
354358 isSerenityActiveForBrand : isSerenityActiveStub ,
359+ isAsyncProvisioningKillSwitched : isAsyncProvisioningKillSwitchedStub ,
355360 } ,
356361 '../../src/support/access-control-util.js' : MockAccessControlUtil ,
357362 '../../src/support/prompts-storage.js' : {
@@ -1711,6 +1716,20 @@ describe('SerenityController', () => {
17111716 expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
17121717 } ) ;
17131718
1719+ it ( 'createMarket answers 503 without enqueuing anything when the async kill switch is on (LLMO-7418 external-review Finding 15)' , async ( ) => {
1720+ isAsyncProvisioningKillSwitchedStub . resolves ( true ) ;
1721+ const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
1722+ const response = await controller . createMarket ( fakeContext ( {
1723+ data : {
1724+ market : 'us' , languageCode : 'en' , brandDomain : 'x.com' , brandNames : [ 'X' ] , async : true ,
1725+ } ,
1726+ } ) ) ;
1727+ expect ( response . status ) . to . equal ( 503 ) ;
1728+ expect ( guardAgainstConcurrentProvisioningStub ) . to . not . have . been . called ;
1729+ expect ( beginProvisioningAttemptStub ) . to . not . have . been . called ;
1730+ expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
1731+ } ) ;
1732+
17141733 it ( 'createMarket runs the SAME synchronous orchestration it always has when async is absent (regression: default behavior unchanged)' , async ( ) => {
17151734 orchestrateCreateMarketSubworkspaceStub . resolves ( {
17161735 status : 201 , body : { brandId : BRAND , geoTargetId : 2840 , languageCode : 'en' } ,
@@ -2262,6 +2281,21 @@ describe('SerenityController', () => {
22622281 expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
22632282 } ) ;
22642283
2284+ it ( 'activate answers 503 without enqueuing when async: true and the async kill switch is on (LLMO-7418 external-review Finding 15)' , async ( ) => {
2285+ isAsyncProvisioningKillSwitchedStub . resolves ( true ) ;
2286+ const brand = makeBrandModel ( { getStatus : ( ) => 'active' } ) ;
2287+ const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
2288+ const response = await controller . activate ( fakeContext ( {
2289+ brand,
2290+ data : {
2291+ brandDomain : 'x.com' , brandNames : [ 'X' ] , markets : [ { market : 'us' , languageCode : 'en' } ] , async : true ,
2292+ } ,
2293+ } ) ) ;
2294+ expect ( response . status ) . to . equal ( 503 ) ;
2295+ expect ( beginProvisioningAttemptStub ) . to . not . have . been . called ;
2296+ expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
2297+ } ) ;
2298+
22652299 it ( 'activate 400s when async is present but not a boolean' , async ( ) => {
22662300 const brand = makeBrandModel ( { getStatus : ( ) => 'active' } ) ;
22672301 const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
@@ -2462,6 +2496,19 @@ describe('SerenityController', () => {
24622496 expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
24632497 } ) ;
24642498
2499+ it ( 'Phase 4: pending→active activation answers 503 without enqueuing when the async kill switch is on (LLMO-7418 external-review Finding 15)' , async ( ) => {
2500+ getBrandBaseSiteIdStub . resolves ( 'primary-site' ) ;
2501+ isAsyncProvisioningKillSwitchedStub . resolves ( true ) ;
2502+ const brand = makeBrandModel ( { } ) ;
2503+ const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
2504+ const response = await controller . activate ( fakeContext ( {
2505+ brand, data : { brandNames : [ 'X' ] , async : true } ,
2506+ } ) ) ;
2507+ expect ( response . status ) . to . equal ( 503 ) ;
2508+ expect ( beginProvisioningAttemptStub ) . to . not . have . been . called ;
2509+ expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
2510+ } ) ;
2511+
24652512 it ( 'Phase 4: pending→active activation 400s when async is present but not a boolean' , async ( ) => {
24662513 getBrandBaseSiteIdStub . resolves ( 'primary-site' ) ;
24672514 const brand = makeBrandModel ( { } ) ;
@@ -2529,6 +2576,18 @@ describe('SerenityController', () => {
25292576 expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
25302577 } ) ;
25312578
2579+ it ( 'Phase 4: bare reactivation answers 503 without enqueuing when the async kill switch is on (LLMO-7418 external-review Finding 15)' , async ( ) => {
2580+ isAsyncProvisioningKillSwitchedStub . resolves ( true ) ;
2581+ const brand = makeBrandModel ( { getStatus : ( ) => 'active' } ) ;
2582+ const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
2583+ const response = await controller . activate ( fakeContext ( {
2584+ brand, data : { brandNames : [ 'X' ] , async : true } ,
2585+ } ) ) ;
2586+ expect ( response . status ) . to . equal ( 503 ) ;
2587+ expect ( beginProvisioningAttemptStub ) . to . not . have . been . called ;
2588+ expect ( createAndEnqueueJobStub ) . to . not . have . been . called ;
2589+ } ) ;
2590+
25322591 it ( 'Phase 4: bare reactivation 400s when async is present but not a boolean' , async ( ) => {
25332592 const brand = makeBrandModel ( { getStatus : ( ) => 'active' } ) ;
25342593 const controller = SerenityController ( { env : { } } , fakeLog ( ) , { } ) ;
0 commit comments