Skip to content

SPIKE-03: Tenant and subscription readiness

Status: research spike. Read-only. No Azure resources created, updated, or deleted. Date: 2026-07-11 Author: foundry-researcher (Opus) Depends on: ai/verification/environment-readiness.md (the read-only environment check this spike synthesizes and extends), ai/plans/source/ai-voice-mai-voice-2.md, ai/plans/source/mai-image-2-5-art-match.md

Scope: for an Azure AI Foundry build in this repo, confirm which subscription and tenant should host the one shared Azure AI Foundry (AIServices, kind that also serves Speech) resource in the region that can host every required model and modality, add depth on how a credit subscription's monthly credit behaves, and specify exactly what still has to be checked before a landing-zone fallback subscription can be trusted. The concrete build this methodology was first run for (a MAI-Image-2.5 Global Standard image deployment plus MAI-Voice-2 neural narration through Azure Speech, in East US) is carried in the marked worked-example appendix. Every claim about Azure mechanics is cited to Microsoft Learn. Anything not verifiable read-only is marked UNKNOWN.


Question

  1. What is the readiness outcome, and what are the concrete, content-level reasons the primary candidate subscription is viable and the fallback (a landing-zone subscription in a different tenant) is the runner-up rather than the choice?
  2. How do the Visual Studio / MVP monthly Azure credits actually work (amount, reset cadence, what happens on exhaustion or lapse), and what does the "credit that resets soon" note in the voice plan imply for timing and for the budget-cap strategy?
  3. The environment check could only read subscription-scoped Azure Policy. How could a management-group-scoped policy, or a Cognitive Services / Azure AI Foundry deny or region restriction, still block the fallback, and precisely which read-only checks confirm or clear that?
  4. What region or quota differences between primary and fallback actually matter for MAI-Image-2.5 (rate-limit tier) and MAI-Voice-2 (Speech tier)?

Findings

1. Readiness outcome: primary is a clean GO, fallback is a conditional runner-up

The environment check reached GO on the primary and did not need the fallback. Synthesizing its content:

The primary subscription (a Visual Studio / MVP-awarded credit subscription), in the target region, is viable for these reasons, each established read-only in the check:

  • Microsoft.CognitiveServices is already Registered, so an AIServices resource can actually be created (SKU discovery does not need the provider, resource creation does).
  • AIServices SKU S0 (Standard) is listed as offerable in the target region with no restrictions.
  • MAI-Image-2.5 appears in the live regional model catalog (az cognitiveservices model list) in Preview status with a working Global Standard deployment path (usageName AIServices.GlobalStandard.MAI-Image-2.5).
  • MAI-Voice-2 is confirmed for the target region on the Azure Speech regions table (it is not a Foundry model deployment; it is selected by voice name at synthesis time), so it does not appear in, and is not expected in, the CLI model catalog.
  • Quota headroom: 0 of 100 AIServices S0 accounts used, and the MAI-Image-2.5 rate limit already sits at the higher tier (see finding 4).
  • The only policy assignment at subscription scope is an unrelated Microsoft Defender for Cloud (ASC) initiative with no deny effect on Cognitive Services.
  • It is the owner's stated preferred home, and the platform Key Vault and an existing related Speech resource already live there, keeping everything in one place.

The one non-blocking item the check flagged is that an existing single-service Speech account (kind SpeechServices, F0) cannot host a Foundry model deployment; a new AIServices-kind resource is needed regardless, and that one resource can serve both the image and the voice work.

The fallback subscription (a landing-zone subscription in a different tenant), in the target region, is the runner-up, not the choice, for these reasons:

  • On the positive side it passed the same read-only checks: provider Registered, AIServices S0 offerable in the target region, same MAI-Image-2.5 catalog entry present, 0 of 100 accounts used, and only a standard "ASC Default" Defender initiative at subscription scope (audit, not deny). It also has real precedent, an existing AIServices S0 resource that already deploys cleanly, though in eastus2, not the target region.
  • It is second, not first, because (a) its default MAI-Image-2.5 rate limit is a lower tier than the primary's (finding 4), (b) it is in a different tenant from where the platform Key Vault and existing related resources live, and (c) crucially, the check could only see subscription-scoped policy. The subscription is named to the Azure landing-zone convention, and landing zones commonly enforce guardrails at the management-group level that a subscription-scoped query does not surface (finding 3). The existing precedent resource living in eastus2 rather than the target region is a soft hint that a region guardrail may be in play.

A third candidate subscription is not ready: Microsoft.CognitiveServices is NotRegistered there, so no quota baseline exists yet and there is no precedent resource. Registering the provider (a write, deferred under the read-only mandate) and re-running the checklist would be required first.

2. How the MVP / Visual Studio monthly credit works, and what "resets soon" implies

The primary is a Microsoft MVP-awarded subscription. The MVP award grants a Visual Studio (Enterprise-class) subscription, whose Azure benefit is governed by the Visual Studio subscriber monthly credit rules. The mechanics, from Microsoft docs:

  • Amount is a fixed monthly allotment tied to the subscription level: Visual Studio Enterprise is USD 150/month and Visual Studio Professional is USD 50/month (Change Azure DevTest offers and remove limits; Azure for Visual Studio subscribers FAQ). The exact level and balance for this subscription are not asserted here (not verifiable read-only, and out of scope to state).
  • It is a recurring monthly credit that does not roll over. Microsoft states plainly: "When you run out of the credit that's allotted for the month, you won't be able to continue using it until it resets the next month" (Azure for Visual Studio subscribers FAQ). Unspent credit is forfeited at the reset; a fresh, equal allotment appears for the new billing period.
  • On exhaustion, the subscription disables itself rather than billing you. These subscriptions ship with a USD 0 spending limit: when usage reaches the included credit, Azure disables the subscription for the rest of that billing period to prevent overage charges, then re-enables it at the next period (Azure spending limit; Reactivate a disabled Azure subscription). Cost Management still shows the rated retail value of what was consumed, but that is not an invoice while the spending limit is in force.
  • Removing the spending limit converts the subscription to pay-as-you-go, requires a payment method, and from that point real overage is billed to the card (Azure spending limit; Reactivate a disabled Azure subscription).
  • The credit is dev/test only, carries no SLA, and a few charges bypass the spending limit. Marketplace and third-party branded offers, support plans, and a handful of separately-sold services (for example Microsoft Entra ID P2) are billed separately even when the spending limit is set (Azure for Visual Studio subscribers FAQ; Azure spending limit). MAI-Image-2.5 and MAI-Voice-2 are first-party "Foundry Models sold by Azure" / models sold directly by Azure (Foundry Models sold by Azure), which are billed as first-party Azure usage and so should draw down the credit and sit under the spending limit rather than bypass it. That "should" is a reasonable read of the billing model, not a verified meter behavior (see UNKNOWN).

What "credit that resets soon" implies. The voice plan's owner decisions read: substantial credit that "resets soon," "burn what is needed ASAP," no per-run cap until the reset, then a USD 100/month cap. That is exactly the behavior of the recurring monthly dev/test credit above: because it does not roll over, any unspent balance is lost at the reset, so front-loading spend before the reset uses this period's allotment instead of wasting it. Two practical consequences:

  • The one-time work is small relative to one month's credit. The voice backfill is about USD 21 one-time (voice plan section 9) and the image pilot is capped at USD 10 (image plan section 7), roughly USD 30 combined, comfortably inside a single USD 150 Enterprise month. So under the pure monthly-reset reading the timing pressure is mild: even if the reset lands mid-work, the next period brings an equal allotment. The "burn ASAP" urgency only becomes real if the credit is instead a time-boxed award or sponsorship grant with a hard expiry (after which the subscription disables until upgraded to pay-as-you-go), or if the intended spend approaches or exceeds one month's allotment (for example a later full-catalog image backfill of roughly USD 17 to 70, or a full long-form voice render of about USD 18 per voice). Which of those applies is UNKNOWN from read-only checks.
  • Budget-cap strategy. Keep three independent guards rather than one. (a) Leave the Azure spending limit ON: for a credit subscription this is the only hard stop that actually prevents spend from becoming a real invoice; it caps exposure at the monthly credit automatically. (b) Add a Cost Management budget alert at the owner's post-reset USD 100/month figure. Azure Cost Management budgets are alert-only and do not stop spend, so a budget is an early-warning signal, not a backstop. (c) Keep the pipeline's own --mai-budget-usd publish guard (default set to 100 per the owner decision) as the first line, since it stops before a runaway publish loop ever reaches Azure. Only remove the spending limit if the owner deliberately chooses pay-as-you-go for a spend that must exceed the monthly credit; otherwise the credit's auto-disable is a feature, not a problem.

3. Fallback policy risk: management-group scope and Cognitive Services deny paths

The environment check ran az policy assignment list at subscription scope only and found nothing that denies Cognitive Services creation. That is necessary but not sufficient for the fallback, for a documented reason:

  • Management-group policy inherits down and cannot be seen from a strict subscription-scoped list. A policy or initiative assigned at a management group cascades by inheritance to every child management group, subscription, resource group, and resource, and even a subscription owner cannot override it (Understand scope in Azure Policy). A plain subscription-scoped az policy assignment list returns assignments at that scope; inherited (parent) and child assignments are only returned when you add --disable-scope-strict-match / -d, which "include[s] policy assignments either inherited from parent scopes or at child scopes" (az policy assignment list). So the fallback could carry landing-zone guardrails the original check simply did not list.

The deny-capable policies that would actually block or degrade this specific workload:

  • Allowed locations (Deny). The built-in "Allowed locations" policy restricts the regions a subscription may deploy to, with Audit, Deny, Disabled effects (Azure Policy built-in definitions, General). If a management-group assignment allows, say, only eastus2 and not the target region, an AIServices create in the target region fails at request time with RequestDisallowedByPolicy (Resolve errors for request disallowed by policy). This is the single highest-probability fallback blocker, and the existing precedent resource living in eastus2 is consistent with exactly such a restriction.
  • Allowed resource types (Deny). If a management group enforces an allow-list of resource types that omits Microsoft.CognitiveServices/accounts, the create is denied (Azure Policy built-in definitions, General; Fix the RequestDisallowedByPolicy error).
  • Cognitive Services / Azure AI Services key-access deny. "Azure AI Services resources should have key access disabled (disable local authentication)" carries Audit, Deny, Disabled effects; assigned as Deny it blocks creating a resource that leaves local (API-key) auth enabled (Microsoft cloud security benchmark v2 mapping; Disable local authentication in Foundry Tools). This would not stop an Entra-ID-only design, but it would break any API-key path the pipeline used.
  • Modify / DeployIfNotExists policies that silently reshape the resource. "Configure Cognitive Services accounts to disable public network access" (Modify) and "Configure Cognitive Services accounts to disable local authentication methods" (Modify), and the equivalent Azure AI Services DeployIfNotExists variant, do not deny the create; they mutate it (Azure Policy built-in definitions for Foundry Tools; Azure Policy built-in definitions, Cognitive Services). That is a subtler risk than a deny: a resource created under a "disable public network access" Modify would come up with publicNetworkAccess = Disabled, which breaks the publish machine's ability to reach the endpoint over the public internet (the whole Option A pipeline synthesizes from a developer machine, not inside a VNet). A "disable local auth" Modify would strip the API key silently and force Entra ID.

The exact read-only checks that confirm or clear this before relying on the fallback:

  1. Enumerate inherited policy. Run az policy assignment list --disable-scope-strict-match at the fallback subscription scope, and/or az policy assignment list --management-group <mgName> walking each ancestor management group of the fallback subscription, to list assignments the strict subscription query hid (az policy assignment list). For each hit, read the definition with az policy definition show / az policy assignment show and inspect its effect and parameters (Resolve errors for request disallowed by policy). Specifically confirm: no Allowed-locations assignment that excludes the target region; Microsoft.CognitiveServices/accounts is not excluded by an Allowed-resource-types assignment; no Deny on key access; and note any Modify/DINE touching public network access or local auth.
  2. Non-destructive deployment preflight. Run az deployment group what-if (or az deployment group validate / Test-AzResourceGroupDeployment) for the AIServices S0 account in the target region. Preflight runs server-side validation with no side effects and explicitly "validat[es] policy compliance for Azure Policy assignments that run in preflight mode," surfacing a RequestDisallowedByPolicy before anything is created (Preflight: server validation before deployment; Enable preflight validation in the AzAPI Terraform provider). Caveat: preflight catches Deny effects that evaluate at preflight; it will not reveal a Modify/DINE effect (those mutate rather than block), so step 2 confirms denies and step 1 remains necessary for the silent-mutation policies.
  3. Region cross-check. If step 1 shows the fallback is region-restricted to eastus2, do not treat that as merely a different region; it is a hard blocker for the image half of the workload (see finding 4).

If steps 1 and 2 come back clean and the target region is permitted, the fallback is genuinely usable. This caveat does not apply to the primary, whose subscription-scoped check found no deny and which is not a landing-zone-style subscription.

4. Region and quota differences that matter, per model

MAI-Image-2.5 (rate-limit tier): a real, measured difference. MAI image models are rate-limited in Requests Per Minute by a tier that "depends on your subscription and deployment configuration." The current Global Standard table is Tier 1 = 2 RPM, Tier 2 = 4, Tier 3 = 6, Tier 4 = 8, Tier 5 = 10, Tier 6 = 12 RPM for MAI-Image-2.5 (Deploy and use MAI image models, API quotas and limits). The environment check observed the primary at 10 RPM (Tier 5) and the fallback at 2 RPM (Tier 1), a 5x throughput gap. Both are the same regional catalog entry and both start with 0 used, so this is purely a starting-tier difference, not a regional one. Practical impact: 2 RPM is fine for the pilot (about 12 to 20 images) but slow for the roughly 340-image full-catalog backfill the image plan flags. The remedy on the fallback is a quota-increase request via the form at aka.ms/oai/stuquotarequest, processed in order received with priority to subscriptions actively using their allocation (Deploy and use MAI image models). Note the inversion worth stating plainly: Visual Studio subscriber subscriptions "may... have a lower default quota than on paid subscriptions" (Azure for Visual Studio subscribers FAQ), yet here the MVP primary shows the higher image tier and the landing-zone fallback the lower one, so the observed data beats the generic caveat.

MAI-Voice-2 (Speech tier): no measurable primary-versus-fallback difference at the subscription level. Speech real-time TTS quota is enforced per resource, not per subscription, and is not exposed through the ARM usage API (F0 = 20 transactions per 60 seconds, S0 = 200 transactions per second by default) (Speech service quotas and limits); the environment check confirmed no Speech meter appears in az cognitiveservices usage list in any candidate. So the Speech "tier" that matters is chosen at resource creation (S0), and both subscriptions can create an S0 AIServices resource in the target region. The voice plan already assumes S0 because F0 eligibility for MAI voices is undocumented (UNKNOWN, carried from the voice plan and SPIKE for the voice model).

The region interaction is where the two models diverge, and it is the fallback's real trap. MAI-Image-2.5 Global Standard is available in only seven regions: West Central US, East US, West US, West Europe, Sweden Central, South India, UAE North (Deploy and use MAI image models). eastus2 is not one of them. MAI voices, by contrast, are supported in eastus2 per the Azure Speech regions table (Speech service supported regions). Therefore, if a management-group Allowed-locations policy forces the fallback to eastus2 (finding 3), MAI-Voice-2 would still work there but MAI-Image-2.5 would not deploy at all, which breaks the one-shared-resource design both plans depend on and would force either a region exemption request or two separate resources. Additionally, only a small number of regions are flagged for "Voices and styles in preview," which a chosen preview voice style relies on; whether a forced fallback region carries that flag is a further check.


What is still UNKNOWN

  • The primary's exact credit offer type, amount, balance, and reset/expiry date. Not verifiable read-only and out of scope to state. The recurring monthly dev/test credit is the reading most consistent with the owner's "resets soon" and "then USD 100/month cap" language, but a time-boxed award or sponsorship credit with a hard expiry cannot be ruled out from here. Confirm in Cost Management + Billing before assuming the reset is non-destructive.
  • Whether MAI Foundry Models bill as first-party credit-eligible usage or as a separately-billed offer. They are first-party "models sold directly by Azure," which should draw down the credit and sit under the spending limit, but the actual meter behavior (and therefore whether the spending limit truly backstops MAI spend) is not verified. Read the first metered runs against Cost Management to confirm.
  • Whether the fallback subscription carries any inherited management-group policy affecting target-region AIServices creation. The environment check was subscription-scoped only; the finding-3 checks (-d enumeration, definition inspection, what-if/validate) have not yet been run. Until they are, the fallback's "GO" is provisional.
  • Whether the fallback is region-restricted to eastus2. The existing precedent resource in eastus2 is a hint, not proof. If it is restricted, the image model cannot deploy there (region asymmetry above).
  • Whether a forced fallback region carries the Speech "voices and styles in preview" flag needed for a chosen preview voice style.
  • F0 eligibility for MAI-Voice-2 and tokens-per-image for MAI-Image-2.5. Both are product-behavior and pricing unknowns owned by the voice and image spikes respectively, not infrastructure questions; they do not change the subscription choice but do affect the cost model.

Recommendation

Provision on the primary subscription (the credit subscription that cleared the readiness check), in the region that lies in the intersection of every required model's availability, one shared AIServices (kind that also serves Speech) S0 resource hosting both the MAI-Image-2.5 Global Standard deployment and the MAI-Voice-2 Speech work. It cleared every read-only gate, already holds the higher image rate-limit tier, and co-locates with the platform Key Vault and existing Speech resource. No fallback is needed unless the primary becomes unusable.

On credit and budget: front-load the small one-time spend (about USD 21 voice backfill plus the sub-USD 10 image pilot, roughly USD 30 together, well inside one Enterprise month) now, while the current allotment is available and before the reset forfeits any unspent balance. Keep three guards: leave the Azure spending limit ON as the only hard backstop for a credit subscription, add a Cost Management budget alert at the owner's post-reset USD 100/month figure (budgets alert but do not stop spend), and keep the pipeline's --mai-budget-usd guard at 100. Do not remove the spending limit unless the owner deliberately elects pay-as-you-go for a spend that must exceed the monthly credit. Confirm the offer type and reset date in Cost Management + Billing so "resets soon" is treated as monthly-recurring (non-destructive to future work) and not a one-time expiry.

Before ever relying on the fallback subscription, run three read-only checks and clear all three: (1) enumerate inherited management-group policy with az policy assignment list --disable-scope-strict-match at the subscription scope and --management-group at each ancestor, then read each definition's effect, confirming no Allowed-locations exclusion of the target region, no Allowed-resource-types exclusion of Microsoft.CognitiveServices/accounts, and no Deny on key access; (2) note any Modify / DeployIfNotExists policy that would silently disable public network access (which would break the publish-from-developer-machine pipeline) or local auth; (3) run a non-destructive az deployment group what-if / validate of the S0 AIServices create in the target region to surface any RequestDisallowedByPolicy. Treat a region restriction to eastus2 as a hard blocker, not a preference: MAI-Voice-2 tolerates eastus2 but MAI-Image-2.5 is not offered there, so a forced region would break the shared-resource model and require a region exemption or a resource split.


<!-- safety-scan-worked-example:start -->

Worked example: Brand A / Brand B

This subsection records the concrete tenant and subscription facts this spike was first run for (read-only checks 2026-07-11, owner-locked GO in the MASTER-PLAN), serving the Brand A and Brand B reader apps. The findings and recommendation above are the reusable methodology; the names, numbers, and region below are the historical facts of that build.

  • Models and modalities: one shared Azure AI Foundry (AIServices) resource hosting a MAI-Image-2.5 Global Standard deployment (scene art) and serving MAI-Voice-2 through Azure Speech (neural narration).
  • Primary subscription (decided): the MVP credit subscription (a Tier-5 / MVP-tier subscription in the primary tenant), region East US. Provider Registered, AIServices S0 offerable, MAI-Image-2.5 present in the live East US catalog (Preview, Global Standard path), MAI-Voice-2 confirmed for East US, 0 of 100 S0 accounts used, MAI-Image-2.5 rate limit at 10 RPM (Tier 5), only an unrelated Microsoft Defender for Cloud initiative at subscription scope. Co-located with the platform Key Vault kv-<workload>-<env>-01 and the existing legacy narrator Speech resource (kind SpeechServices, F0).
  • Fallback subscription: the Azure Local tenant (the fallback tenant), region East US. Passed the same subscription-scoped checks (provider Registered, S0 offerable, same catalog entry, 0 of 100 used, only an "ASC Default" audit policy) and has precedent (an existing AIServices S0 resource in eastus2). It ranks second: default MAI-Image-2.5 rate limit 2 RPM (Tier 1) versus the primary's 10, a different tenant from the Key Vault and existing Speech resource, and subscription-scoped policy visibility only (its landing-zone management group follows a <...>-lz-core-... naming convention, and the precedent resource sitting in eastus2 is a soft hint that an Allowed-locations restriction may be in play).
  • Not ready: a third management scope (<management-scope>) has Microsoft.CognitiveServices NotRegistered, so no quota baseline and no precedent resource.
  • Region intersection: MAI-Image-2.5 Global Standard is offered in seven regions (see finding 4); eastus2 is not one of them, while MAI-Voice-2 is supported in eastus2. East US satisfies both models and also carries the Speech "voices and styles in preview" flag the chosen Ethan excited voice style relies on.
  • Voice set (owner-decided in the voice plan): Harper, Lisa (en-AU), and Ethan with the excited style. <!-- safety-scan-worked-example:end -->

Sources