Skip to main content

MediaPro Lab 2 — Multi-Account Cross-System Demo Plan

TL;DR

MediaPro Lab 2 is the killer demo for SecurityV0: a single stitched authority graph spanning three AWS accounts (mp-security, mp-workloads, mp-data), an Entra tenant, a ServiceNow PDI, and Azure Foundry. It replaces the abstract "Nimbus Enterprise" brand from the 2026-04-08 plan with the real prospect MediaPro is preparing to pilot in early May 2026. Every resource is Terraform, the lab spins up before a call and tears down after for under $5/cycle, and the platform's rendered output is the explicit acceptance gate for Streams 1 (connector control), 2 (multi-account AWS), and 3 (cross-connector graph stitching). The legacy Jira-focused jira-mediapro lab is retired — Jira is out of scope per the user; the MediaPro brand graduates to the multi-AWS arc.

Why MediaPro replaces Nimbus Enterprise as the Lab 2 brand

The 2026-04-08 demo lab plan introduced "Nimbus Enterprise" as a generic post-Series-C continuation of the Nimbus Cloud Lab 1 narrative. It was a placeholder until a real prospect crystallized. MediaPro now is that prospect:

  1. MediaPro is a real prospect, with a real pilot target (early May 2026, per sv0-documentation#195). The umbrella tracker already names them. Building Lab 2 around their plausible estate makes every demo, screenshot, and finding directly applicable to the pilot conversation.
  2. MediaPro fits the multi-account narrative natively. A post-Series-C streaming-media SaaS with AWS, Entra, ServiceNow, and Azure Foundry is the exact shape of the unique-value demo the platform was built for. Nimbus Enterprise was a fictional version of the same company; promoting MediaPro just removes the indirection.
  3. Continuity with Lab 1. The Nimbus Cloud → MediaPro arc still works: MediaPro is what Lab 1's Nimbus Cloud could look like after a Series C, an acquisition, and the introduction of Entra/ServiceNow/Foundry. The sales team already knows that arc.
  4. No real customer data. The lab uses the MediaPro brand and plausible shape only. All resources live in SecurityV0-owned AWS, Entra, ServiceNow, and Azure tenants. All employee, customer, and ticket data is synthetic.

Decision on jira-mediapro legacy lab: Retire. Per the user's de-prioritization of Jira ("we don't have strong Jira capabilities to support our use case"), the existing sv0-demo-labs/labs/jira-mediapro/ (which the user's task notes reference but which is not currently present in the repo at the time of writing — the only existing labs are sv0-demo-lab-1 and x1-foundry-mcp-servicenow) is treated as legacy. If a jira-mediapro directory exists at execution time, archive it under labs/_archived/jira-mediapro/ with a RETIRED.md pointing at this plan. No Jira resources or connector wiring appear in this lab. When the Jira connector matures, it can extend the MediaPro lab in place.

Customer persona — "MediaPro" (fictional but defensible)

Industry: Streaming media / video-on-demand SaaS. Stage: Series C, ~600 employees, ~$80M ARR, 18-month-old security org headed by a recently-hired CISO (Priya Reyes). Estate moment captured: They just consolidated three regional AWS estates (post-acquisition of "Stillwater Studios" 11 months ago) into a single AWS Organization with three accounts, adopted Entra as their corporate IdP, and standardized on ServiceNow ITSM. The ML team has begun deploying Azure Foundry agents for content metadata enrichment and ticket auto-routing in parallel with the AWS workload modernization. Nobody — including the CISO — has a single graph of what the AI agents and automations can actually reach.

Why MediaPro looks like Nimbus Cloud post-Series-C:

PropertyNimbus Cloud (Lab 1)MediaPro (Lab 2)
AWS accounts1 (single workload account)3 (security, workloads, data) under an OU
Identity providerNone — IAM users onlyEntra ID corporate tenant federated to AWS via OIDC
ITSMNoneServiceNow PDI with HR + CMDB + change-management workflows
AI surfaceBedrock agents, action-group LambdasBedrock agents AND Azure Foundry agents (cross-cloud)
Cross-system surfaceNoneServiceNow → Entra SP → Foundry path; Bedrock action-group Lambda → MCP → ServiceNow path
What CISO needs to know"Which Bedrock agent has which blast radius in this account?""Which AI agent's authority spans which accounts and which external systems? What did each one actually do?"

The Lab 1 → Lab 2 narrative arc lets an SE open with "this is the company at $20M ARR" (Lab 1 demo) and continue with "this is them 18 months later" (Lab 2 demo) without rebranding.

Architecture overview

AWS organization layout

SV0 Demo Labs (OU)
└── MediaPro (OU)
├── mp-security (~111111111111) — single ingest point for SV0 AWS connector
│ • Organization CloudTrail (multi-account, multi-region)
│ • AWS Config Aggregator
│ • IAM Access Analyzer (org-level)
│ • SecurityV0ReadOnly bootstrap role (audit hub)
│ • Entra OIDC identity provider (federation root)
├── mp-workloads (~222222222222) — AI workloads + cross-account egress
│ • Bedrock agent: mp-content-tagger
│ • Bedrock agent: mp-support-router (action-group Lambda → MCP → ServiceNow)
│ • Lambda: mp-mcp-bridge (action group, calls in-account MCP server)
│ • Step Functions: mp-content-pipeline
│ • IAM role: mp-cross-account-data-reader (assumes into mp-data)
│ • IAM role: mp-foundry-sn-router (Entra-federated, called from Foundry path)
│ • SecurityV0ReadOnly per-account role
└── mp-data (~333333333333) — sensitive data domain
• S3: mp-pii-customers (synthetic PII: name, email, phone, viewing history)
• S3: mp-content-metadata (KB sources for the content tagger)
• DynamoDB: mp-ticket-log (cross-system writes from action-group Lambda)
• Secrets Manager: mp-servicenow-creds, mp-foundry-api-key
• IAM role: mp-data-cross-account-trust (trusts mp-workloads only)
• SecurityV0ReadOnly per-account role

The bootstrap account securityv0-mgmt (already exists, account 365066817305) hosts the MediaPro OU and the StackSet that deploys SecurityV0ReadOnly into all three accounts. Stream 2 owns the role-deployment template; this plan consumes it.

Cross-system topology

A single graph the platform must render. Two flagship paths are folded into one diagram so the unified blast radius is visible.

                     ┌──────────────────────────────────────────┐
│ ServiceNow PDI │
│ ┌────────────────────────────────────┐ │
│ │ Workflow: Auto-route identity │ │
│ │ tickets (incident trigger) │ │
│ └────────┬───────────────────────────┘ │
│ │ INVOKES │
│ ┌────────▼───────────────────────────┐ │
│ │ Connection: Graph - sn-ticket- │ │
│ │ router (uses Azure Graph OAuth) │ │
│ └────────┬───────────────────────────┘ │
│ │ RUNS_AS │
└───────────┼──────────────────────────────┘

┌───────────▼──────────────────────────────┐
│ Entra SP: sn-ticket-router │
│ (Graph: User.Read.All + Group.Read.All │
│ + Directory.Read.All — drift) │
└───────────┬──────────────────────────────┘
│ SENDS_TO
┌───────────▼──────────────────────────────┐
│ Azure Foundry: gpt-nano-for-summary │
│ (model classification step; │
│ added post-baseline) │
└──────────────────────────────────────────┘

┌──────────────────────────────────────────┐
│ Bedrock agent: mp-support-router │
│ (in mp-workloads) │
└───────────┬──────────────────────────────┘
│ ACTION_GROUP
┌───────────▼──────────────────────────────┐
│ Lambda: mp-mcp-bridge (mp-workloads) │
│ Execution role: mp-mcp-bridge-exec │
└─────┬───────────────────────────┬────────┘
│ GetSecretValue │ HTTP
┌──────────▼─────────┐ ┌──────▼──────────────┐
│ Secrets Manager: │ │ MCP Server (Lambda) │
│ mp-servicenow-creds │ │ mp-mcp-server │
│ (mp-data — cross- │ │ Managed identity → │
│ account fetch) │ │ Entra SP: │
└──────────┬──────────┘ │ sp-mp-mcp-bridge │
│ └──────┬──────────────┘
┌──────────▼──────────┐ │ OAuth same client_id
│ ServiceNow REST API │◄───────────────┘ (CORRELATED edge)
│ (creates incidents) │
└──────────┬──────────┘
│ writes
┌──────────▼──────────┐
│ ServiceNow: │
│ HR employee table │
│ (synthetic PII) │
└─────────────────────┘

Two more cross-account paths the platform must materialize from mp-workloads into mp-data independent of the AI surface:

  • mp-content-tagger (Bedrock) → service role → bedrock:Retrievemp-content-metadata (mp-data, cross-account read via mp-cross-account-data-reader).
  • mp-content-pipeline (Step Functions) → invoke any Lambda in mp-workloads → DynamoDB writes in mp-ticket-log (mp-data, cross-account).

Identity story

Three federation/correlation patterns the lab exercises, all of which Stream 3's stitcher must produce:

  1. Entra → AWS OIDC federation. mp-foundry-sn-router IAM role in mp-workloads trusts the Entra OIDC IdP (the StackSet bootstrap registers the IdP in mp-security and the role in mp-workloads). The mp-foundry-sn-router role's trust policy names the Entra SP sp-mp-foundry-router (appId derived at lab-up). Stream 3 must merge the Entra SP node and the AWS role's trust principal into a single identity with two source records.
  2. Entra ↔ ServiceNow OAuth correlation. sp-mp-mcp-bridge (Entra SP) is registered in ServiceNow as an OAuth provider with the same client_id. Stream 3's existing intra-entra-servicenow CORRELATED edge handles this within one connector graph; the platform-level stitcher must propagate it to bridge graphs from the AWS connector (which sees the SP as the principal of the Lambda's managed-identity-bound credentials cache via secret reference) and Foundry.
  3. Foundry-side SP attribution. servicenow-openai-client (the canonical demo SP from the 2026-04-20 session note) carries Cognitive Services OpenAI User on gpt-nano-for-summary. The Foundry connector emits this. Stream 3 must NOT require additional federation — the platform already correctly renders this row (per the session note, dev/prod show paths=2, exec30=8). MediaPro Lab 2 simply re-creates this exact resource shape in a SecurityV0-owned demo Azure tenant with MediaPro-flavored names.

The CORRELATED edges Stream 3 must produce in MediaPro Lab 2 (these are explicit acceptance criteria for Stream 3):

EdgeSource connectorTarget connectorCorrelation key
sp-mp-foundry-router (Entra SP) ↔ mp-foundry-sn-router (AWS IAM role)entra-servicenowawsOIDC sub claim in trust policy → matches Entra SP appId
sp-mp-mcp-bridge (Entra SP) ↔ ServiceNow OAuth Azure MP MCP OAuth Cliententra-servicenow (same connector)(intra)client_id — already implemented
sp-mp-mcp-bridge (Entra SP) ↔ Lambda execution-role assumed-credential proof in CloudTrailentra-servicenowawsclient_id appears in Secrets Manager secret value (out of scope for read; documented gap)
servicenow-openai-client (Entra SP) ↔ gpt-nano-for-summary (Foundry resource)entra-servicenowazure-foundryRBAC role assignment on Foundry account — already working per session note

Scenarios covered

The 2026-04-08 plan and 12-deployment-approval.md define a scenario taxonomy. MediaPro Lab 2 covers six scenarios end-to-end. Each one is mapped to specific lab resources so a single make demo proves all of them at once.

ScenarioSource docWhat it provesLab resources that demonstrate it
B1 Customer Support Agent (tiered Bedrock)12-deployment-approval.md §AWS Bedrock Demo LabTiered permission model — what's lost at Tier 1 vs Tier 2 vs Tier 3 against a realistic Bedrock agentmp-support-router agent + action-group Lambda + execution role with overprivileged DynamoDB managed policy
B2 Multi-Agent Supervisor / Collaborator12-deployment-approval.md §Scenario B2Transitive authority through bedrock:InvokeAgent — supervisor reaches collaborator's blast radiusmp-content-orchestrator (supervisor) + mp-content-tagger (collaborator) + mp-support-router (collaborator) — both reachable via bedrock:InvokeAgent
B3 Cross-Account Bedrock → S3 PII12-deployment-approval.md §Scenario B3Cross-account authority path crosses account boundary into PII data domainmp-content-tagger (mp-workloads) → mp-cross-account-data-readermp-pii-customers (mp-data)
M2 MCP as Bedrock Action Group Backend12-deployment-approval.md §Scenario M2Lambda proxies to MCP server — IAM authority visible, MCP tools opaquemp-mcp-bridge Lambda → mp-mcp-server Lambda (MCP protocol) → ServiceNow REST
X3 Bedrock → Lambda → ServiceNow12-deployment-approval.md §Scenario X3Cross-system authority path from AWS into ServiceNow under one identitymp-support-routermp-mcp-bridgesp-mp-mcp-bridge (Entra SP) → ServiceNow OAuth → HR table writes
X4 Multi-Platform Agent Ecosystem (Foundry money-shot)12-deployment-approval.md §Scenario X4 + auto-route-identity-tickets.mdTwo AI agents on different cloud platforms reach same ServiceNow instance via different identity paths; Foundry classification step part of one pathThe Sergey canonical scenario: Auto-route identity tickets workflow → sn-ticket-router (Entra) → Microsoft Graph → gpt-nano-for-summary (Foundry) — exactly as already live on dev/prod per the 2026-04-20 session note, replicated in MediaPro-flavored names

Explicitly not covered (with rationale):

  • M1 (MCP as Foundry connection direct) — covered by Lab x1-foundry-mcp-servicenow already; Lab 2 includes the X3 variant (MCP as Bedrock action-group backend) instead.
  • X1 (the x1-foundry-mcp-servicenow flagship) — that lab stays as-is; MediaPro Lab 2 reuses its MCP-server Azure Function code as a module but rebrands and rewires it for the MediaPro narrative.
  • X2 (Logic App) — adds Azure Logic Apps surface area without commensurate value; defer.

Terraform layout

The lab lives at sv0-demo-labs/labs/mediapro/. It composes per-account Terraform modules with Entra and ServiceNow provisioning modules. The composition root is a single make up that runs three Terraform applies in topological order plus two non-Terraform provisioning steps for ServiceNow + Foundry.

sv0-demo-labs/
├── bootstrap/
│ └── mediapro-org/ # NEW. Run once, ever.
│ ├── main.tf # OrganizationsCreateAccount × 3, MediaPro OU
│ ├── stackset-securityv0-readonly.tf # StackSet from Stream 2's template
│ ├── outputs.tf # account IDs, OU id
│ └── README.md # one-time runbook + state bucket bootstrap
├── modules/ # NEW. Shared between accounts.
│ ├── tf-account-baseline/ # VPC, CloudTrail, log retention
│ ├── tf-bedrock-agent/ # Bedrock agent + service role
│ ├── tf-action-group-lambda/ # Lambda + exec role + Bedrock invoke perm
│ ├── tf-mcp-server-lambda/ # MCP Lambda packaged from /mcp-server source
│ ├── tf-cross-account-trust/ # mp-data trust policy with mp-workloads as principal
│ ├── tf-entra-oidc-federation/ # IAM OIDC IdP + role trust statement
│ └── tf-pii-data-bucket/ # S3 bucket + synthetic CSV seed
└── labs/
└── mediapro/ # NEW.
├── README.md # Lab overview + lifecycle
├── Makefile # up / scan / down / refresh / validate
├── DEMO-SCRIPT.md # SE-runnable walkthrough
├── COSTS.md # per-resource cost table, $5/cycle envelope
├── .env.1password.example
├── shared/
│ ├── backend.tf # remote state, per-account workspace
│ ├── providers.tf # 3 aws providers (security/workloads/data)
│ ├── variables.tf # account IDs, region, lab_id (cycle salt)
│ └── locals.tf # naming conventions: mp-{lab_id}-{resource}
├── account-mp-security/
│ ├── main.tf # Org CloudTrail, Config Aggregator, Access Analyzer
│ ├── oidc-idp.tf # Entra OIDC IdP registration
│ └── outputs.tf # trail_arn, idp_arn for cross-stack
├── account-mp-workloads/
│ ├── main.tf # Bedrock agents (B1, B2, X3) wiring
│ ├── content-pipeline.tf # Step Functions, Lambdas, B2 collaborators
│ ├── mcp-bridge.tf # mp-mcp-bridge + mp-mcp-server Lambdas (M2)
│ ├── cross-account-roles.tf # mp-cross-account-data-reader, mp-foundry-sn-router
│ └── outputs.tf # agent IDs, Lambda ARNs, role ARNs
├── account-mp-data/
│ ├── main.tf # S3 PII + KB buckets, DynamoDB
│ ├── secrets.tf # Secrets Manager: ServiceNow creds, Foundry key
│ ├── trusts.tf # cross-account trust to mp-workloads only
│ └── outputs.tf # bucket ARNs, secret ARNs
├── entra/
│ ├── main.tf # azuread provider — sp-mp-mcp-bridge,
│ │ # sp-mp-foundry-router, servicenow-openai-client,
│ │ # sn-ticket-router
│ ├── federations.tf # OIDC subject claims for AWS roles
│ └── outputs.tf # appIds, client_secrets (to TF state, not stdout)
├── azure-foundry/
│ ├── main.tf # azurerm — Foundry account, project,
│ │ # gpt-nano-for-summary deployment, RBAC
│ ├── role-assignments.tf # Cognitive Services OpenAI User on
│ │ # servicenow-openai-client
│ └── outputs.tf
├── servicenow/ # NOT Terraform — Python provisioner
│ ├── provision.py # uses ServiceNow REST APIs
│ ├── workflows/
│ │ ├── auto-route-identity-tickets.json
│ │ └── sn-ticket-router-graph.json
│ ├── tables/
│ │ ├── u_mp_hr_employee.json # synthetic HR PII table schema
│ │ └── u_mp_cmdb_app.json # synthetic CMDB
│ ├── seed-data/
│ │ ├── hr-employees.csv # 12 fake employees
│ │ └── cmdb-apps.csv # 8 fake CIs
│ └── teardown.py
├── mcp-server/ # MCP Lambda source (reused/forked from
│ │ # x1-foundry-mcp-servicenow)
│ ├── handler.py # Lambda handler (mcp protocol over HTTP)
│ ├── tools.py # search_employee, get_ticket, create_ticket
│ ├── servicenow_client.py
│ └── requirements.txt
├── scripts/
│ ├── up.sh # orchestrates everything
│ ├── scan.sh # invokes Stream 1 CLI for AWS+Entra+SN+Foundry
│ ├── down.sh # teardown in reverse order
│ ├── refresh.sh # idempotent re-apply
│ ├── validate.sh # runs the validation matrix from this plan
│ ├── seed-execution.sh # nudges agents to run so exec30 > 0
│ └── cost-report.sh # AWS Cost Explorer query for the lab tag
└── tests/
├── test_validation_matrix.py # asserts node/edge/path/finding counts
└── test_lifecycle.py # up → scan → validate → down idempotency

Per-account Terraform vs shared modules. Each account is its own terraform apply (separate state file in S3 backend) so a partial failure in mp-workloads does not lock mp-security's state. Cross-account ARNs are passed via terraform_remote_state data sources, not hardcoded outputs.

State backend strategy. A single S3 backend bucket sv0-demo-labs-tfstate (already exists for Lab 1, in securityv0-mgmt) with separate keys per (lab × account × cycle):

sv0-demo-labs-tfstate/
├── mediapro/security/{lab_id}/terraform.tfstate
├── mediapro/workloads/{lab_id}/terraform.tfstate
├── mediapro/data/{lab_id}/terraform.tfstate
├── mediapro/entra/{lab_id}/terraform.tfstate
└── mediapro/foundry/{lab_id}/terraform.tfstate

{lab_id} defaults to default. Power-users can spin up parallel cycles (LAB_ID=alice / LAB_ID=bob) — resource names use mp-{lab_id}- prefix so two cycles do not collide. State bucket persists across cycles; resources die.

Account bootstrap. bootstrap/mediapro-org/ is run once, ever, by an operator with the management account's Organizations admin role. It:

  1. Creates the MediaPro OU under SV0 Demo Labs.
  2. Calls aws organizations create-account × 3 (with mp-security@securityv0.com, etc. — addresses already aliased in Mercury Mail).
  3. Waits for accounts (~60s each).
  4. Deploys the SecurityV0ReadOnly StackSet (Stream 2's template) into the OU.
  5. Outputs the three account IDs into a Parameter Store entry /sv0-demo-labs/mediapro/account-ids so the lab Terraform can data "aws_ssm_parameter" them.

This bootstrap is gated behind a make bootstrap target with a typed-confirm prompt to prevent accidental account creation.

Up / scan / teardown lifecycle

make up

cd sv0-demo-labs/labs/mediapro
make up # ~12-18 min wall clock

Steps (each is idempotent and re-runnable):

  1. Pre-flight (scripts/up.sh:preflight) — verify bootstrap/mediapro-org has run (account IDs in SSM Param Store), verify SecurityV0ReadOnly role exists in all three accounts, verify required env: MP_ENTRA_TENANT_ID, MP_FOUNDRY_SUBSCRIPTION_ID, MP_SN_INSTANCE, MP_SN_USERNAME/MP_SN_PASSWORD (from 1Password). Fail-fast with a one-line remediation per missing var.
  2. Entra resourcesterraform apply in entra/. Creates 4 SPs + their secrets. Outputs appIds.
  3. mp-dataterraform apply in account-mp-data/. Creates buckets, secrets, DynamoDB. Cross-account trust still wide-open at this point because mp-workloads role ARN is not yet known.
  4. mp-workloadsterraform apply in account-mp-workloads/. Reads Entra appIds from remote state; creates Bedrock agents, Lambdas, MCP server, cross-account roles. Lambda ZIPs built locally from mcp-server/.
  5. mp-securityterraform apply in account-mp-security/. Org CloudTrail, Config Aggregator, Access Analyzer. (Last so the trail captures the prior steps' API activity for execution evidence.)
  6. Tighten mp-data trust — second terraform apply in account-mp-data/ with the now-known mp-workloads role ARN.
  7. Azure Foundryterraform apply in azure-foundry/. Foundry account, project, gpt-nano-for-summary deployment, RBAC assignments naming the Entra SPs from step 2.
  8. ServiceNow provisioningpython servicenow/provision.py creates HR table, CMDB table, OAuth providers (registering Entra SP client_ids from step 2), the two demo workflows, business rules, and seed records.
  9. Execution seedscripts/seed-execution.sh invokes each Bedrock agent twice and each ServiceNow workflow twice so exec30 > 0 for the demo. Emits ~30 CloudTrail events, ~6 ServiceNow flow executions, ~4 Foundry thread creations.
  10. Print success banner — outputs the three account IDs, Foundry endpoint, ServiceNow instance, and the make scan command.

make scan

make scan              # ~6-10 min wall clock

Invokes Stream 1's connector CLI (the ConnectorInstance / ScanScope / ScanRun surface) to:

  1. Provision four ConnectorInstance records in the platform tenant enterprise-nimbus (one each for aws, entra-servicenow, azure-foundry; the AWS instance is configured with --scope-mode multi-account and the three account IDs from SSM Param Store, per Stream 2).
  2. Trigger four ScanRun records targeting the enterprise-nimbus tenant.
  3. Poll until all four scans report status=succeeded (timeout 8 min; surface partial failure with the scan IDs to inspect).
  4. Print a one-line summary per connector: nodes-emitted / edges-emitted / scan duration.

The actual Stream 1 CLI surface is owned by that stream; this script consumes whatever shape it lands as. Pseudocode:

sv0 connector create --tenant enterprise-nimbus --type aws \
--scope multi-account --accounts "$(aws ssm get-parameter ...)"
sv0 scan trigger --tenant enterprise-nimbus --connector aws --wait
# repeat for entra-servicenow, azure-foundry
sv0 scan summary --tenant enterprise-nimbus --since 10m

make down

make down              # ~8-12 min wall clock

Reverse topological order. Each step is idempotent (re-run safe) and skips on not found:

  1. ServiceNow teardown (python servicenow/teardown.py removes workflows, OAuth providers, tables — preserves the PDI itself).
  2. Azure Foundry terraform destroy.
  3. mp-security terraform destroy (CloudTrail logs flush to S3 first via force_destroy = true on the trail bucket).
  4. mp-workloads terraform destroy — Bedrock agents go first via dependency order.
  5. mp-data terraform destroyforce_destroy = true on PII/KB/trail buckets so cycle is clean.
  6. Entra terraform destroy — SPs + secrets removed.
  7. Verify no stray resources via scripts/cost-report.sh --since today — should print zero in-scope resources.

State bucket persists. If make down partial-fails, make down --resume continues from the last successful step.

make refresh / make validate

make refresh is terraform apply across all stacks without re-bootstrapping anything — for fixing drift or applying a spec change mid-cycle. make validate runs tests/test_validation_matrix.py against the running platform (after make scan) to confirm the demo will land.

Idempotency

  • All terraform apply calls are inherently idempotent.
  • ServiceNow provision.py uses sys_id lookups before POST (PATCH on existing).
  • Execution seed checks for prior recent invocations and skips if exec30 ≥ 4 already.
  • up.sh writes a .lab-state file with the last completed step. Re-running picks up from the next step. up.sh --force re-runs everything.

Cost expectation

Designed for < $5 per up/scan/down cycle, assuming a 2-3 hour live demo window.

ResourceQuantityPer-hourPer-cycle (3h)Notes
Bedrock agent invocations (Claude Haiku 4.5)~30 invocations × ~2k tokens$0.001/invocation~$0.04Seed only; demo viewer doesn't re-invoke
Lambda invocations (Bedrock + MCP + ops)~80 invocations × <100msincluded free tier~$0.00Free tier covers it
S3 storage (KB + PII synthetic)~5 MB totalincluded free tier~$0.00Trivial
S3 + CloudTrail PUTs (org trail)~500 events$0.000005/event~$0.003Single-region trail to bound cost
DynamoDB on-demand~50 writes$1.25/M writes~$0.00
Step Functions state transitions~20 transitions$0.025/1k~$0.001
Secrets Manager secrets4 secrets × 3h$0.40/secret/month~$0.002Pro-rated
KMS key (Foundry)1 key × 3h$1/key/month~$0.004
AWS Config recorderper-account × 3$0.003/item recorded~$0.30Recorders ON during cycle only
Azure Foundry account + Cognitive Services1 account, ~10 model callsmodel: $0.15/1M tokens~$0.05gpt-nano is cheap
Azure Function (MCP server) — Lab 2 reuses Lambda not Functionn/an/a$0.00We use a Lambda-hosted MCP server in Lab 2 to keep cost in AWS
ServiceNow PDIshared, persistent$0 (free)$0.00PDI keep-alive workflow elsewhere prevents hibernation
Entra ID (free tier — same as demo tenant per session note)n/a$0$0.00Sign-in log fidelity gap noted in scenario X4 caveat
Org-bootstrap (one-time, amortized)3 accounts$0 to create$0.00
Total per cycle~$0.40 — $1.50Comfortably under $5

Risks to the budget:

  • Forgetting to make down → CloudTrail/Config keep recording (~$0.30/day each), Bedrock agents idle ($0), KMS keys ($1/month). Worst case ~$30/month if abandoned. Mitigate with a CloudWatch billing alarm on the OU set to $25 and a daily cron cost-report.sh that nags via Slack.
  • AWS Config in continuous-recorder mode is the line-item to watch; the tf-account-baseline module deploys it in periodic mode (daily snapshot) instead of continuous to keep this < $0.50/day even if a teardown is missed.
  • If the Foundry connector starts pulling thread history aggressively, Cognitive Services billing can climb. Cap with quota: 100 RPM on the deployment.

Cost gate. make up refuses to apply if cost-report.sh --since 30d --ou MediaPro exceeds $50 — surfaces a stale resource issue before adding more.

Validation matrix (acceptance criteria for Streams 1/2/3)

After make up && make scan, the platform tenant enterprise-nimbus must render the following. Each row is an automated assertion in tests/test_validation_matrix.py and an explicit acceptance criterion for the named upstream stream. When all rows pass, Streams 1 + 2 + 3 are done.

#AssertionStream gatedHow verified
V1Three aws_account nodes exist with IDs matching mp-security, mp-workloads, mp-data and parent_ou_id = the MediaPro OUStream 2API: GET /api/v1/entities?type=aws_account&tenant=enterprise-nimbus returns ≥3
V2Each AWS resource node has account_id populated and BELONGS_TO edge to its aws_account nodeStream 2Spot-check: mp-pii-customers bucket → aws_account:333333333333
V3A single ScanRun for connector aws covered all three accounts in one run (not three separate runs) — scan_scope.accounts.length === 3Stream 1 + 2API: GET /api/v1/scans/{id} shows scope manifest
V4Per-(account × category) scan progress is reported: e.g., mp-workloads:bedrock, mp-data:s3 are independent line items in scan progressStream 1UI: scan-detail page renders the matrix
V5Authority path mp-content-tagger (mp-workloads, Bedrock) → mp-cross-account-data-reader → mp-pii-customers (mp-data, S3) materializes as one path crossing the account boundary, length ≥4, with crosses_account_boundary=trueStream 2 + Stream 3API: GET /api/v1/authority-paths?identity=mp-content-tagger returns this path
V6Authority path mp-support-router (Bedrock) → mp-mcp-bridge (Lambda) → sp-mp-mcp-bridge (Entra SP) → ServiceNow OAuth → u_mp_hr_employee (ServiceNow table) materializes as one stitched path spanning AWS + Entra + ServiceNow connectorsStream 3API: identity = mp-support-router, expect connector_systems = [aws, entra-servicenow] on the path
V7The Auto-route identity tickets path is rendered identically to dev/prod's current state per the 2026-04-20 session note: servicenow-openai-client → gpt-nano-for-summary row exists with paths≥1, exec30≥1, dests=['gpt-nano-for-summary']Stream 3 (no regression)API: GET /api/v1/authority-paths?identity=servicenow-openai-client
V8Stitched identity node for sp-mp-foundry-router exists with source_records = 2 (entra connector + aws connector); UI shows it as one identity, not twoStream 3API: GET /api/v1/identities/{node_id} returns source_systems: ['entra', 'aws']
V9Bedrock supervisor mp-content-orchestrator shows bedrock:InvokeAgent authority paths to BOTH collaborators (mp-content-tagger, mp-support-router); transitive blast radius reaches PII (V5) and ServiceNow HR (V6)Stream 2 + Stream 3API: paths from supervisor have transitive=true flag
V10Finding(reachable_sensitive_domain) fires for the cross-account PII path (V5) and the cross-system ServiceNow PII path (V6) — exactly 2 distinct finding IDs, severities criticalStreams 2 + 3 (correctness)API: GET /api/v1/findings?type=reachable_sensitive_domain returns 2
V11Finding(scope_drift) fires on mp-mcp-bridge-exec Lambda role (overprivileged DynamoDB) — singular, severity highStream 2API filter
V12Finding(orphaned_ownership) fires on the dormant mp-content-export Lambda (modeled after Lab 1's contractor pattern)Stream 2API filter
V13Evidence pack downloads cleanly for every critical finding; SHA256 integrity validates; pack contains source-system references for AT LEAST 3 distinct connectors per cross-system findingStreams 1 + 2 + 3E2E: download + verify hash + parse sources array
V14Re-running make scan (with no infra changes) produces zero net entity churn (entities_created=0, entities_removed=0); diff-engine does not falsely flag cross-connector entities (regression test for sv0-platform#460/#461)Stream 1 (idempotence) + Stream 3Compare two consecutive ScanRun posture deltas
V15Lab cost (scripts/cost-report.sh --since-up) reports < $5 for a typical 3h cycleThis planDirect measurement
V16make down followed by make up works end-to-end without manual interventionThis planCI smoke (nightly, gated by cost)

A scenario-to-assertion crosswalk:

ScenarioValidation rows that must pass
B1V1, V2, V11, V13
B2V9, V10, V13
B3V5, V10, V13
M2V6 (the MCP hop), V13
X3V6, V8, V10, V13
X4V7 (Sergey path) + V8 (Foundry SP correlation)

Demo walkthrough script

Revision-1 update (per umbrella D10/D16/D17): the v0 walkthrough uses V5 (cross-account Bedrock blast) as the climax, not V6 (cross-system MCP path). V6 is deferred to "full" because Stream 3's mcp-server-to-entra-sp rule is opt-in / known-fragile. Path 3 (V7 Foundry) runs in a second browser tab against the existing live dev/prod Foundry environment, not in the MediaPro Lab 2 (per D16 — Foundry Terraform deferred to "full"). The "cross-system MCP" segment of the original Path 2 is replaced with a one-screenshot teaser pointing at "full" Lab 2.

A 6-minute SE-runnable script (v0). Pre-condition: make up && make scan && make validate clean against MediaPro Lab 2 + dev/prod Foundry tenant available in a second tab. SE opens the platform UI for tenant enterprise-nimbus in one tab and the existing dev/prod Foundry tenant in a second tab.

[0:00–0:30] Set the scene (no clicks). "MediaPro is a streaming-media SaaS that just closed Series C. Three AWS accounts under one Organization, Entra for SSO, ServiceNow for ITSM, and the ML team has started shipping Foundry agents. CISO Priya was hired 90 days ago. She has zero idea what the AI agents and automations can actually reach."

[0:30–1:30] Land on Overview. Click Overview for tenant. Point at the count tiles: "Three AWS accounts, one Entra tenant, one ServiceNow instance — and we're stitching to a Foundry project. One authority graph across all of them. 5 critical findings, 11 high. We'll go through 2."

[1:30–4:00] Path 1 — the cross-account Bedrock blast, the v0 climax (B3 / V5). Open Authority Paths → search mp-content-tagger. Expand the path that crosses into mp-pii-customers. Talk track:

  • "This is a Bedrock agent in the workloads account."
  • "It assumes a cross-account role into the data account."
  • "It can read every file in your customer-PII bucket. The cross-account boundary did not contain it."
  • "Nobody on the security team approved this combined path. Each piece — the agent, the role, the bucket — was approved separately."
  • "This is the kind of finding that the question 'who has the authority to do what' produces, when you can answer it across accounts in one graph."

Click into the evidence pack. "SHA256-integrity-checked. The pack lists every source-system ARN. Auditor-ready."

Then point at the V8 stitched-identity row: sp-mp-foundry-router shows source_records=2 (entra+aws) — "and just so you know we can stitch identities — here's the Entra SP that's federated to an AWS role we found via OIDC. One identity, two source systems, one row. We do this everywhere a deterministic anchor exists."

Optional teaser (10 sec, one screenshot): show a static screenshot of the V6 cross-system MCP path. "When you bring in MCP-fronted Lambdas and the credentials live in Secrets Manager, we can stitch that too — that's full Lab 2, end of May. Today, we ship the cross-account half."

[4:00–5:30] Path 2 — Sergey's canonical Foundry path, in the second tab (X4 / V7). Switch tabs to the live dev/prod Foundry tenant. Open identity servicenow-openai-client. Expand the row. "And in production today — same shape. ServiceNow workflow, runs as a Graph SP, sends classification context to a Foundry model. The Foundry hop was added after the workflow's baseline. The owner record is stale. The Graph scopes drifted to Directory.Read.All. We show all three changes on the same path."

Reference [auto-route-identity-tickets.md] talk-track for the bounded remediation pitch (narrow Graph scope, assign one owner, approve or remove the Foundry hop).

[6:30–7:00] Close on positioning. Per positioning-snapshot.md: "SecurityV0 is the system of record for what AI agents actually did with delegated authority. Not what they were granted — what they did and what they can reach. MediaPro is going from blind to provable in one scan."

Demo reset. make down && make up && make scan — ~25 min total turnaround. Or per scripts/refresh.sh, hot-swap the lab between two LAB_ID values so a second SE can demo while the first resets.

Implementation plan (writing-plans format)

Each phase produces a small, reviewable PR. TDD where applicable; for IaC, the equivalent is terraform plan against a real AWS account with cost ceiling, then apply, then validate against the success criterion stated in the task.

v0 total: 25 tasks across 9 active phases (Phase 8 Foundry deferred per D16; Phase 3.3/3.4 deferred per D17). Estimated 2-3 person-weeks for v0 once Stream 2 (multi-account AWS) and Stream 3 (graph stitching M1–M10) ship. Full (post-pilot) total: 32 tasks (re-adds Phase 8 + Phase 3.3 + Phase 3.4 + Q1's Lambda-secret stitching rule).

Phase 1: Account bootstrap (3 tasks)

1.1. Add bootstrap/mediapro-org/main.tf with aws_organizations_organizational_unit "mediapro" and three aws_organizations_account resources. Acceptance: terraform plan shows three account creates and one OU; terraform apply (when manually run) returns three account IDs to SSM Parameter Store at /sv0-demo-labs/mediapro/account-ids.

1.2. Add Stream 2's SecurityV0ReadOnly StackSet wiring in bootstrap/mediapro-org/stackset-securityv0-readonly.tf. Acceptance: After bootstrap, aws iam get-role --role-name SecurityV0ReadOnly --profile mp-security-IF-AdminAccess returns the role in all three accounts.

1.3. Add bootstrap/mediapro-org/README.md runbook with the typed-confirm prompt mechanism. Acceptance: Following the runbook from a clean checkout produces three accounts under MediaPro OU. (One-time.)

Phase 2: Per-account Terraform skeleton (4 tasks)

2.1. Create modules/tf-account-baseline/ (VPC stub, log group, periodic AWS Config recorder). Acceptance: Module applies cleanly into any of the three accounts; aws config get-status shows recorder active in periodic mode.

2.2. Create labs/mediapro/shared/{providers,backend,locals,variables}.tf with three named aws providers (one per account), LAB_ID variable, MediaPro naming locals. Acceptance: terraform validate passes in account-mp-security/ after this is in place.

2.3. Create account-mp-security/main.tf — Org CloudTrail (single-region, multi-account), Config Aggregator (across the three accounts), IAM Access Analyzer org-level. Acceptance: Trail captures events from all three accounts after make up.

2.4. Create account-mp-security/oidc-idp.tf — Entra OIDC IdP registration. Acceptance: aws iam list-open-id-connect-providers from mp-security shows the Entra IdP after apply.

Phase 3: mp-workloads — Bedrock + Lambda + MCP (3 tasks in v0; 2 tasks deferred to "full")

3.1. Create modules/tf-bedrock-agent/ and modules/tf-action-group-lambda/. Acceptance: A standalone test stack creates one Bedrock agent + Lambda action group; agent invocation succeeds.

3.2. Create account-mp-workloads/main.tf for B1 — mp-support-router agent + mp-mcp-bridge action-group Lambda + execution role with AmazonDynamoDBFullAccess (intentional finding). Acceptance: bedrock:InvokeAgent works end-to-end.

3.5. Create account-mp-workloads/cross-account-roles.tfmp-cross-account-data-reader (assumes into mp-data), mp-foundry-sn-router (Entra-OIDC-trusted). Acceptance: AssumeRole from mp-workloads into mp-data:mp-data-cross-account-trust succeeds; OIDC role trust verifiable via simulated token.

Deferred to "full" (per umbrella D17 + D10):

  • 3.3. content-pipeline.tf for B2 (Multi-Agent Supervisor scenario) — V9 covers this in full. Not on v0 demo walkthrough.
  • 3.4. mcp-bridge.tf for M2 (MCP server Lambda) — V6 deferred to full because Stream 3's mcp-server-to-entra-sp rule is opt-in. Without that rule, the MCP path renders as two disconnected segments — not demo-ready.

Phase 4: mp-data — S3 PII + DynamoDB + Secrets + cross-account trust (3 tasks)

4.1. Create modules/tf-pii-data-bucket/ + account-mp-data/main.tfmp-pii-customers bucket with synthetic PII CSV, mp-content-metadata KB bucket with synthetic content records, mp-ticket-log DynamoDB. Acceptance: Buckets created, blocks public access, CSV contents visible via aws s3 cp from mp-data console.

4.2. Create account-mp-data/secrets.tfmp-servicenow-creds, mp-foundry-api-key. Values pulled from 1Password at apply time via external provider, never committed. Acceptance: Secret values readable from mp-workloads via cross-account fetch.

4.3. Create account-mp-data/trusts.tf and modules/tf-cross-account-trust/mp-data-cross-account-trust role with trust principal = mp-workloads role ARN (read from remote state). Acceptance: mp-content-tagger Bedrock service role can s3:GetObject against mp-pii-customers via assume-role.

Phase 5: mp-security finalization (1 task)

5.1. Apply account-mp-security/ with the trail event selector wired for Lambda + S3 data events (so V13 evidence packs see invocations). Acceptance: After seed-execution.sh, querying CloudTrail for a known Lambda invocation returns the event within 5 min.

Phase 6: Entra resources via Terraform (2 tasks)

6.1. Create entra/main.tf with azuread provider. Provision four SPs: sn-ticket-router, servicenow-openai-client, sp-mp-mcp-bridge, sp-mp-foundry-router. Acceptance: All four SPs visible in Entra portal; appIds emitted to remote state.

6.2. Create entra/federations.tf — federated credential on sp-mp-foundry-router with subject claim matching the AWS IAM role's OIDC trust. Acceptance: Token exchange from Entra → AWS (mp-foundry-sn-router) succeeds end-to-end via a manual smoke.

Phase 7: ServiceNow PDI seed (3 tasks)

7.1. Create servicenow/provision.py skeleton: idempotent ServiceNow REST client, --provision and --teardown modes, secrets from MP_SN_* env. Acceptance: python servicenow/provision.py --check returns ServiceNow instance metadata.

7.2. Add servicenow/tables/u_mp_hr_employee.json + seed CSV; provisioner creates the table and seeds 12 records via /api/now/table/sys_db_object and /api/now/table/u_mp_hr_employee. Acceptance: ServiceNow UI shows the table populated with synthetic PII.

7.3. Add servicenow/workflows/auto-route-identity-tickets.json (re-using the canonical scenario from flow-service-now.md) and the sn-ticket-router-graph connection + Azure Graph OAuth Client. Provisioner registers OAuth provider for sp-mp-mcp-bridge and the Graph connection for sn-ticket-router. Acceptance: Triggering an incident runs the workflow; ServiceNow + Entra log show the SP made Graph + (separately) MCP calls.

Phase 8: Azure Foundry resources — DEFERRED to "full" per umbrella D16

Revision-1 (per umbrella D16): v0 does not stand up Foundry resources in MediaPro Lab 2. The V7 Foundry path already runs on the live dev/prod tenant (see 2026-04-20 session note). The early-May demo switches browser tabs from MediaPro Lab 2 → existing dev/prod Foundry env to show V7. Standing up duplicate Foundry resources adds Terraform complexity without visibly improving the buyer story.

Tasks 8.1 and 8.2 below ship in the post-pilot "full" Lab 2 build (end-of-May target):

8.1. Create azure-foundry/main.tf — Foundry account, project, gpt-nano-for-summary deployment via azurerm provider. (deferred to full)

8.2. Create azure-foundry/role-assignments.tfCognitive Services OpenAI User on gpt-nano-for-summary for servicenow-openai-client. (deferred to full)

Phase 9: up/scan/down lifecycle scripts (5 tasks)

9.1. Write scripts/up.sh orchestrating Phases 2–8 with .lab-state checkpointing and pre-flight validation. Acceptance: make up from clean state succeeds in ≤20 min wall clock.

9.2. Write scripts/down.sh with reverse-order destroy and --resume support. Acceptance: make down from any state finishes with zero in-scope resources per cost-report.sh.

9.3. Write scripts/scan.sh consuming Stream 1's connector CLI surface (interface contract documented in this plan; if Stream 1's CLI shape differs, this script adapts). Acceptance: Four ScanRun records reach succeeded in ≤8 min.

9.4. Write scripts/seed-execution.sh to drive ≥4 invocations per agent + 2 per workflow. Acceptance: Per-path exec30 ≥ 1 after 5-minute settle for CloudTrail / Foundry threads / ServiceNow logs.

9.5. Write scripts/cost-report.sh querying Cost Explorer with MediaPro tag filter; make up gates on its output. Acceptance: Returns a number; gate trips when seeded with $50 of fake cost.

Phase 10: Demo script + validation harness (4 tasks)

10.1. Write tests/test_validation_matrix.py covering V1–V14 against the live platform. Acceptance: All pass on the canary enterprise-nimbus tenant after a clean up + scan.

10.2. Write tests/test_lifecycle.py for V16 (up → scan → down → up idempotence). Acceptance: Runs in CI nightly; failure pages on-call.

10.3. Write DEMO-SCRIPT.md (the 7-minute SE script) with screenshot placeholders. Acceptance: Sergey or another SE can run it on a fresh make up without instructor input. (Validate by getting one SE to dry-run.)

10.4. Write README.md and COSTS.md for the lab. Acceptance: A new engineer can spin up, demo, and tear down using only the README.

Coordination with sv0-connectors#27 (Victor)

Victor owns sv0-connectors#27 — the X1 Foundry → MCP → ServiceNow PII lab — and that lab already shipped to sv0-demo-labs/labs/x1-foundry-mcp-servicenow/. Two integration points:

  1. Reuse, don't fork, the MCP server. The mcp-server/ directory in x1-foundry-mcp-servicenow/ is a working Azure Function. MediaPro Lab 2 needs an AWS Lambda hosted MCP server (different runtime; same protocol surface). Action: extract the MCP tool implementations (tools.py-equivalent) to a shared module under sv0-demo-labs/modules/mcp-server-shared/ and let both labs import from there. PR sequence: extract first (no behavior change, X1 lab still passes), then MediaPro Phase 3.4 adds the Lambda packaging. Coordinate with Victor before extracting.

  2. Don't re-cover X1. MediaPro Lab 2 covers M2 (MCP-as-Bedrock-action-group) instead of X1's M1 (MCP-as-Foundry-connection-direct). Both should remain demoable independently — X1 stays as a focused single-scenario lab; MediaPro Lab 2 is the multi-scenario lab. Confirm with Victor that he is OK with Lab 2 referencing X1 for the deeper MCP visibility story rather than duplicating it.

  3. Validation matrix sharing. V8 (CORRELATED edge via client_id) is asserted in both X1 and MediaPro Lab 2; if Stream 3 lands client_id correlation for the entra-servicenow case before the cross-connector case, X1 will pass V8 first and MediaPro Lab 2 will pass it later. Track that ordering explicitly in sv0-platform#300.

Open questions

  1. Stream 1's CLI surface shape. This plan assumes a sv0 connector create / sv0 scan trigger / sv0 scan summary command set. If Stream 1 lands ConnectorInstance as an HTTP API only (no CLI), scripts/scan.sh becomes a curl script — that is fine, but worth confirming early so Phase 9.3 isn't reworked.

  2. Stream 2's per-(account × category) scoping granularity. This plan assumes scoping like mp-workloads:bedrock exists at scan-trigger time (V4). If Stream 2 lands account-level scoping only (no per-category), V4 either drops or becomes a "scan progress is reported per account, with category breakdown in the summary" softer assertion. Worth pinning in the multi-account-aws-connector architecture plan that lands alongside this one.

  3. Stream 3's stitching for the AWS-Lambda-MCP-server identity. Lambda has no Entra managed identity natively. The MediaPro lab fakes it by storing sp-mp-mcp-bridge credentials in Secrets Manager and having the Lambda load them at runtime. The AWS connector sees the Lambda's IAM role and the secret reference; it does NOT see the Entra SP. Stream 3 must stitch via the OAuth client_id registered in ServiceNow (which links Entra SP ↔ ServiceNow) and a separate edge from the Lambda execution role to the secret to the SP. This is a new correlation rule beyond OIDC federation. If Stream 3 cannot land this in time, V6 weakens to "the path renders as two segments (AWS half + Entra/SN half) joined by a manual-correlation edge labeled 'Lambda fetches Entra SP credentials from secret'." Decide before Stream 3 commits its design.

  4. Entra P1 license decision (per session note + sv0-connectors#86). MediaPro Lab 2 inherits the same Entra free-tier limitation: signIns API rejected. The validation matrix doesn't depend on signIns for any V row, so the lab stands without P1 — but the demo script's "what changed" narrative (per auto-route-identity-tickets.md) is stronger if sign-in proof is available. Recommend: park as a Phase 11 enhancement, depend on the parent sv0-connectors#86 decision.

  5. ServiceNow PDI separation. Should MediaPro Lab 2 use a dedicated PDI (separate from the existing demo PDI used by X1 and the Sergey demo path), or share? Sharing risks data bleed and brand confusion ("Why does the MediaPro demo show employees from the wrong company?"). Recommend a dedicated PDI mp-pilot-demo with the keep-alive workflow already in place.

  6. Are the three account creates reversible? AWS account closure has a 90-day cool-down. If we close MediaPro accounts later, we cannot recreate them in the same OU within that window. Recommend treating these accounts as long-lived (OU + StackSet permanent; per-cycle resources ephemeral). The cost envelope analysis assumes accounts persist.

  7. Timeline against MediaPro pilot (early May 2026, sv0-documentation#195). Phases 1–10 of this plan total ~3-4 person-weeks of SE/IaC work, plus the upstream prereqs (Stream 2 multi-account AWS, Stream 3 graph stitching). Realistically the lab is demoable end-of-May, not start-of-May. If the May 5 pilot is hard, Lab 2 v0 ships with V1–V8 only (no scenario X3 / V6) — the cross-system AWS path does not render until Stream 3 cross-Lambda-credential stitching lands. The auto-route-identity-tickets Foundry path (V7) works today on dev/prod and can be the headline path for an earlier MediaPro session. Flag to user.

References

Plans:

Architecture:

Product:

Existing infrastructure:

  • sv0-demo-labs/labs/sv0-demo-lab-1/ — Lab 1; module + lifecycle pattern this plan extends.
  • sv0-demo-labs/labs/x1-foundry-mcp-servicenow/ — Victor's X1 lab; MCP server source to be shared.
  • sv0-platform/docs/session-notes/2026-04-20-foundry-demo-resolution-session-handoff.md — what works on dev/prod today; V7 baseline.

Issues:

  • sv0-documentation#195 — MediaPro pilot readiness umbrella.
  • sv0-connectors#27 — X1 lab (Victor) — coordinate per §Coordination above.
  • sv0-connectors#32 — multi-account AWS scanning (Stream 2 prereq).
  • sv0-platform#300 — cross-connector graph stitching (Stream 3 prereq).
  • sv0-connectors#86 — Entra P1 decision (affects X4 / V7 fidelity).