Skip to content

Module B Train-the-Trainer MicroHack — Zava multi-agent AI platform on Azure - #10

Merged
NikoMix merged 20 commits into
mainfrom
nikomix-module-b-ttt-training-lab
Oct 11, 2026
Merged

NikoMix merged 20 commits into
mainfrom
nikomix-module-b-ttt-training-lab

Conversation

@NikoMix

@NikoMix NikoMix commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Overview

A complete 1-day, instructor-led Train-the-Trainer (TTT) MicroHack that covers all Module B controls of the Build and Modernize AI Applications on Microsoft Azure Advanced Specialization. Trainees build Zava, an intelligent athletic-apparel retailer powered by a multi-agent platform, in both Python and C# (.NET) on the Microsoft Agent Framework, with modular inference, full Azure deployment, and the latest GitHub agents / skills / MCP tooling.

Built by an orchestrator across 6 disjoint, parallel workstreams (path-isolated → conflict-free merges), each tracked as a GitHub Issue and validated to a strict quality bar before integration.

  • 181 files, ~26.6k insertions across 21 commits.
  • Scenario: Zava multi-agent retail platform (5 specialized agents + registry/base).
  • Free-tier path via GitHub Models; production path via azd up into real Azure.

Module B coverage

Control Deliverable(s)
B.1.1 Plan the solution docs/overview, docs/architecture, docs/module-b-mapping, lab0/1 + evidence b11
B.2.1 Build agents src/python + src/dotnet (5 agents, Agent Framework), lab2/3 + evidence b21
B.2.2 Orchestrate / tools / RAG agent registry, src/mcp-zava (7 tools), Cosmos + pgvector RAG, lab3/4 + evidence b22
B.3.1 Responsible AI Content Safety, grounding/eval guidance, lab5 + solutions
B.4.1 Deploy & operate infra/ (AVM Bicep), azure.yaml, Container Apps, OTel, lab6 + evidence b41
B.4.2 Secure Managed identity everywhere, Entra-only Postgres, Key Vault, local-auth off, evidence b42

Full matrix: docs/module-b-mapping.md; certification crosswalk: docs/cert-crosswalk.md.

Workstreams

  • WS1 — Infra (infra/, azure.yaml): azd + Bicep (AVM modules) — Container Apps, Cosmos DB, PostgreSQL Flexible Server (pgvector, Entra-only auth), AI Foundry + Azure OpenAI + AI Search + Document Intelligence + Content Safety. Managed identity throughout; local auth disabled; ACR anonymous pull off.
  • WS2 — Python app (src/python/): FastAPI + Microsoft Agent Framework; modular inference factory (GitHub Models / Azure OpenAI / Azure AI Foundry); 4 store backends; OpenTelemetry; 49 tests.
  • WS3 — .NET app (src/dotnet/): ASP.NET Minimal API + Microsoft.Agents.AI on net10.0; modular IInferenceFactory; 40 xUnit tests; .slnx.
  • WS4 — GitHub AI (.github/agents/, .github/skills/, src/mcp-zava/, mcp.json): Zava MCP server (7 tools), Copilot custom agents + skills.
  • WS5 — Enablement (slides/, docs/facilitator-guide/): Marp deck + facilitator guide with talk tracks.
  • WS6 — Labs & evidence (docs/labs/, docs/solutions/, docs/evidence-templates/): 7 student labs + 7 solutions + 5 control-mapped evidence templates.

Modular inference (per requirement)

Every AI capability runs through a single factory abstraction selecting Azure AI Foundry, Azure OpenAI, or GitHub Models via configuration — no image generation, so all three are interchangeable. Labs default to free GitHub Models; azd provisions the Azure-native path.

Quality gates — all green (local, CI-equivalent)

  • Python: ruff check + ruff format ✓, mypy --strict ✓, bandit ✓, pytest 49 passed ✓, pip-audit: 0 vulns ✓.
  • .NET: restore ✓, dotnet format --verify-no-changes ✓, build Release (TreatWarningsAsErrors + analyzers) 0/0 ✓, 40 tests ✓, 0 vulnerable + 0 outdated packages ✓.
  • MCP server: npm ci (0 vulns) ✓, eslint ✓, tsc ✓, build ✓, smoke-test: all 7 tools ✓.
  • Infra: az bicep build → ARM (exit 0) ✓, az bicep lint clean ✓.
  • Docs: mkdocs build --strict ✓ (no broken links), markdownlint 0 errors across 64 files ✓, Marp deck builds ✓.
  • Dependencies: all pinned to latest; zero runtime vulnerabilities; OSS / no-paid-license libraries only.

CI (.github/workflows/ci.yml, slides.yml) makes every one of these gates blocking on PRs to main. Dependency currency is tracked by Dependabot across github-actions, pip (src/python + docs), nuget, npm (src/mcp-zava + slides), devcontainers.

Note: the dev-only markdownlint-cli2 linter is intentionally pinned as an ephemeral npx invocation (no committed lockfile). Its latest release transitively depends on js-yaml/markdown-it versions carrying moderate quadratic-complexity DoS advisories with no fixed upstream version; committing a lockfile would create permanent, unfixable open Dependabot alerts for a tool that only processes trusted first-party Markdown. Shipped/runtime surfaces remain 0-vuln. Rationale is documented in the final commit.

Try it

  • Free path: open in the dev container, set a GITHUB_TOKEN, run the Python or .NET app against GitHub Models, work through docs/labs/.
  • Azure path: azd up provisions the full stack via AVM Bicep; redeploys the agent apps to Container Apps with managed identity.

Closes #6 (Epic) and #4 (Quality gate). Workstream issues #1, #2, #3, #5, #7, #8 closed on merge.

NikoMix and others added 20 commits June 26, 2026 01:26
Establish the shared foundation for the Module B Train-the-Trainer microhack:
- .microhack/build-contract.md: authoritative shared spec (paths, env vars, HTTP API, agents, Azure + data contracts, coding standards, Module B map)
- Root hygiene: README, LICENSE (MIT), .gitignore, .editorconfig, .gitattributes
- .github: copilot-instructions, dependabot, CI/CodeQL/dependency-review/slides/infra-validate/setup workflows, issue templates
- .devcontainer: polyglot (python 3.12, dotnet 9, node 20, az/azd/gh)
- docs: index, overview, agenda, architecture, module-b-mapping; mkdocs.yml
- data: Zava seed catalog/reviews/orders/customers + policy & supplier docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Deliverables

### src/mcp-zava/ — TypeScript MCP server
- 7 tools: get_product, search_products, get_order, get_inventory,
  get_customers, search_knowledge, generate_evidence
- STDIO transport (VS Code / GitHub Copilot agent mode)
- HTTP/SSE transport (Azure Container Apps / azd service mcp-zava)
- Multi-stage Dockerfile (non-root user, node:22-alpine)
- Smoke test: builds + connects as MCP client + tests 3 tools
- ESLint 9 flat config + TypeScript strict mode
- Zero vulnerabilities (npm audit); all quality gates pass

### .github/agents/
- zava-builder.md — scaffolds/extends Zava app per build contract
- zava-evidence.md — drives Module B evidence via generate_evidence tool

### .github/skills/
- seed-data.md — seeds Cosmos DB + PostgreSQL pgvector from data/
- run-local-github-mode.md — local dev with GitHub Models (free)
- collect-evidence.md — assembles Module B audit evidence package

### mcp.json
- Wires local zava server (STDIO + dev mode)
- Wires Microsoft Learn Docs MCP server
- Documents required env vars; no secrets

Refs: #5

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Provisions full Zava AI platform on Azure using Azure Verified Modules (AVM):

Resources:
- User-Assigned Managed Identity (UAMI) with least-privilege RBAC
- Log Analytics Workspace + Application Insights (OpenTelemetry -> App Insights)
- Key Vault (RBAC auth, purge protection ON)
- Azure Container Registry (admin OFF, anonymous pull OFF)
- Azure AI Services (gpt-4o-mini + text-embedding-3-small deployments)
- Azure AI Foundry Hub + Project
- Azure AI Search (local auth disabled)
- Document Intelligence + Content Safety
- Cosmos DB NoSQL (local auth disabled, AAD RBAC data-plane, db: zava)
- PostgreSQL Flexible Server (AAD-only, pgvector enabled, db: zava)
- Container Apps Environment + 3 Container Apps (api-python, api-dotnet, mcp-zava)
- Storage Account (AI Foundry Hub artifacts)

Security: DefaultAzureCredential / Managed Identity everywhere.
No API keys, no secrets in code or outputs.

azd: azure.yaml wires all 3 services to Container Apps with Dockerfiles.
All canonical build-contract env vars emitted as azd outputs.

Validation: bicep build + bicep lint pass clean (exit code 0).

AVM modules used (verified June 2026):
- managed-identity/user-assigned-identity:0.5.1
- operational-insights/workspace:0.15.1
- insights/component:0.7.2
- key-vault/vault:0.13.3
- container-registry/registry:0.12.1
- cognitive-services/account:0.15.0
- machine-learning-services/workspace:0.13.2
- search/search-service:0.12.2
- document-db/database-account:0.19.0
- db-for-postgre-sql/flexible-server:0.15.4
- app/managed-environment:0.13.3
- app/container-app:0.22.1

Closes #3

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/main.json

main.json is the compiled ARM artifact, reproducible from main.bicep via azd/bicep build; gitignore it to keep the repo clean. Bicep validated: az bicep build exit 0, zero lint warnings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…crosswalk

Deliverables for WS6 (Lab guides + Module B evidence):

docs/labs/
  - lab0.md  Setup & GitHub Models (20 min)          [B.3.1]
  - lab1.md  First agent — Concierge (50 min)        [B.1.1, B.3.1]
  - lab2.md  RAG over Zava knowledge (50 min)        [B.1.1, B.2.1, B.3.1]
  - lab3.md  Deploy to Azure with azd (55 min)       [B.1.1, B.2.1, B.3.1, B.4.2]
  - lab4.md  Data agents: Merchandiser+Ops (45 min)  [B.1.1, B.2.1, B.2.2, B.3.1]
  - lab5.md  Trust, safety, observability (45 min)   [B.1.1, B.3.1, B.4.1]
  - lab6.md  Capstone + evidence gen (45 min)        [B.1.1-B.4.2 all]

docs/solutions/
  - solution0.md through solution6.md (facilitator answer keys)

docs/evidence-templates/
  - README.md          how generate_evidence populates templates
  - b11-capability-case-study.md  (B.1.1)
  - b21-acr-pillar-worksheet.md   (B.2.1) + Partner Center walkthrough
  - b22-customer-diversity.md     (B.2.2) + DPOR/PAL/CSP explainer
  - b41-evidence-index.md         (B.4.1) + pre-audit checklist
  - b42-onboarding-pack.md        (B.4.2) + delivery runbook

docs/cert-crosswalk.md  AZ-204/AZ-400/AI-102/DP-420 + 5-person study plan (B.3.1)

.markdownlint.json  root config (MD013 off — matches .editorconfig max_line_length=off for md)

All files: markdownlint exit 0. Build contract env vars, routes, ports,
1536-dim embeddings, provider names all consistent with .microhack/build-contract.md.

Closes #7

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Postgres runtime is already Entra-only (passwordAuth disabled, UAMI as AAD admin). Default the mgmt-plane password to newGuid() and drop the parameter mappings so provisioning is fully hands-off with no human-handled secret. Bicep build + lint clean (exit 0, 0 warnings).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marp deck (slides/zava-microhack-deck.md):
- Full-day deck covering all agenda sections in canonical order
- Sections: welcome/TTT, Zava story, AI Apps Advanced Specialization,
  Module B controls (B.1.1-B.4.2), solution architecture, 3 ACR pillars,
  modular inference (GitHub Models / Azure OpenAI / Azure AI Foundry),
  Microsoft Agent Framework (Python + .NET), GitHub agents/skills/MCP,
  per-lab intro slides (Lab 0-6), evidence review, TTT debrief
- Self-contained Zava CSS theme via front-matter style block
- Reusable theme also at slides/themes/zava.css for --theme-set usage
- Builds cleanly to HTML + PDF via slides.yml workflow

Facilitator guide (docs/facilitator-guide/):
- index.md: overview and navigation hub
- run-of-show.md: minute-by-minute timing for the full day
- prerequisites.md: environment setup (devcontainer, GitHub token, azd)
- pitfalls.md: common problems and fixes across all labs
- av-room-checklist.md: A/V setup and room logistics checklist
- ttt-notes.md: Train-the-Trainer re-delivery guide
- talk-tracks/index.md: talk-tracks navigation table
- talk-tracks/lab-00-welcome.md through lab-06-capstone.md: per-lab
  lecture notes, demo cues, expected outcomes, evidence checkpoints

Quality gates:
- markdownlint-cli2: 0 errors across all 18 files
- Marp CLI: HTML + PDF build exit code 0
- OSS/license-free assets only (system fonts, SVG icons)

Closes #2

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Disable cosmetic MD060 (table-pipe spacing) at repo root; tables render
  correctly in MkDocs/GitHub and the rule is markdownlint-version-sensitive
- Remove redundant per-directory .markdownlint.json files (labs/solutions/
  evidence-templates) so the root config governs all docs consistently
- Point labs build-contract reference to the GitHub blob URL so it resolves
  in the published MkDocs site (file lives outside docs_dir)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the full Zava AI Agent Platform Python track (src/python/).

## Agents (Microsoft Agent Framework 1.9.0)
- concierge: order lookup, product Q&A, knowledge-base RAG, returns
- merchandiser: catalog search, reviews, sales trend analysis
- operations: inventory, supplier doc parsing (Doc Intelligence), restock
- trust: content safety, policy retrieval, Module B evidence (B.1.1-B.4.2)
- orchestrator: triage via specialist.as_tool() handoff pattern

## HTTP API (build-contract section 4)
- GET  /health        -> {"status":"ok"}
- GET  /agents        -> list of {key, name, description}
- POST /chat          -> {reply, agent, citations[], traceId}
- POST /chat/stream   -> SSE token stream with done event

## Modular Inference (section 3)
- github mode:   AsyncOpenAI + GitHub Models endpoint + GITHUB_TOKEN
- azure-openai:  AsyncAzureOpenAI + DefaultAzureCredential (no API keys)
- foundry:       FoundryChatClient / AzureOpenAI fallback
- INFERENCE_PROVIDER / EMBEDDINGS_PROVIDER env vars control selection
- text-embedding-3-small (1536-dim) for all embeddings

## Data and Store
- LocalZavaStore: JSON+Markdown seed data, keyword+cosine search (github mode)
- AzureZavaStore: Cosmos DB NoSQL + pgvector + AI Search (Azure mode)
- scripts/seed.py to load data/ into Azure services

## Observability
- OpenTelemetry -> Application Insights (when APPLICATIONINSIGHTS_CONNECTION_STRING set)
- Every /chat reply returns real OTel traceId

## Quality gates (all passing)
- ruff check: 0 issues
- ruff format: 28 files formatted
- mypy: 0 errors in 22 source files
- pytest: 49/49 passed
- pip-audit: 0 known vulnerabilities
- bandit: 0 issues

## Infrastructure
- Dockerfile: multi-stage slim build, non-root user
- pyproject.toml: latest pinned deps (agent-framework==1.9.0)
- README.md: run instructions for github and Azure modes

Closes #8

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…erge

Slides tooling (deterministic + Dependabot-tracked):
- Add slides/package.json + lockfile pinning @marp-team/marp-cli@4.4.0
  (0 vulnerabilities); the existing npm /slides Dependabot entry now resolves
- slides.yml: build docs (mkdocs --strict) first, then render the deck into
  site/slides so mkdocs' clean step no longer wipes the decks; HTML export is
  required (blocking), PDF/PPTX remain best-effort; drop unpinned marp@latest

Dependency hygiene:
- dependabot.yml: fix src/mcp-zava ecosystem nuget -> npm (it is a TypeScript
  project) so its packages are actually scanned and updated

Markdown quality (now genuinely clean, not advisory):
- ci.yml markdownlint: pin markdownlint-cli2@0.22.1, robust nested excludes,
  and make it blocking (drop "|| true")
- Consolidate config: remove redundant docs/facilitator-guide per-dir config so
  the root governs all docs; keep slides/ Marp-specific config
- Fix all 91 real-file findings across .github, .microhack, data, docs, infra,
  and src/mcp-zava (blanks-around-headings/lists/fences, trailing newlines, and
  language tags on fenced blocks) -> 0 errors repo-wide
- Point facilitator-guide out-of-docs links (build-contract, slides) at GitHub
  URLs so mkdocs build --strict passes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ASP.NET Core 10 Minimal API with 4 routes matching build-contract §4:
  GET /health, GET /agents, POST /chat, POST /chat/stream (SSE)
- 5 agents on Microsoft Agent Framework (ME.AI 1.11.1):
  concierge (RAG+FAQ), merchandiser (product search), operations (orders),
  trust (compliance + Module B evidence), orchestrator (triage + handoff)
- Modular inference factory (INFERENCE_PROVIDER/EMBEDDINGS_PROVIDER):
  github (GitHub Models, default/free), azure-openai, foundry
  GitHub Models uses OpenAI-compatible client with DefaultAzureCredential
  skipped; Azure paths use Azure.Identity DefaultAzureCredential
- ZavaDataStore: in-memory cosine-similarity RAG over products/orders/
  customers/reviews/knowledge documents
- ZavaSeeder: loads data/ JSON + MD seed files, batches embeddings
- OpenTelemetry wired to Application Insights (optional); traceId in reply
- 40 xUnit tests (no network): provider switch, agent tools, API routes
- Dockerfile: multi-stage, non-root user (UID 1000), container-app ready
- .editorconfig, README with both GitHub and Azure run modes
- Quality gates: build (0 warn/err), format clean, tests green, 0 vulns
  Packages updated to latest stable:
  DotNetEnv 3.2.0, Newtonsoft.Json 13.0.4, OTel.*.AspNetCore 1.16.0,
  Pgvector 0.3.2, FluentAssertions 8.10.0, coverlet 10.0.1, SDK 18.7.0

Closes #1 (WS3 .NET deliverable)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…blocking

WS2 integration hardening:

- pyproject.toml: replace the 'agent-framework' meta-package (which resolves to agent-framework-core[all] and drags in the unversioned, pre-release-only agent-framework-azure-ai-search connector) with the three connectors actually used: agent-framework-core==1.9.0, agent-framework-openai==1.8.2, agent-framework-foundry==1.8.2. Installs are now deterministic and resolve under both pip and uv without a global --pre flag (the lone transitive pre-release, azure-ai-inference==1.0.0b9, is pulled via an explicit pre-release specifier).

- ci.yml: drop advisory '|| true' escapes so the quality gates actually block. Python job now fails on mypy, bandit, and pip-audit findings (added bandit; removed dead requirements-dev.txt fallback). .NET job now fails on dotnet format drift and on any vulnerable NuGet package (parse 'dotnet list package --vulnerable').

Validated locally (Py 3.12.13): ruff check + format clean, mypy --strict 22 files clean, bandit clean, 49 tests pass, pip-audit reports no known vulnerabilities.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WS3 integration hardening:

- ci.yml: bump setup-dotnet from 9.0.x to 10.0.x; the projects target net10.0, so the .NET 9 SDK could not restore/build them.

- src/dotnet/README.md: add language tags to two bare fences (SSE stream + ASCII architecture diagram) and surround fences with blank lines so the now-blocking markdownlint passes.

Validated locally (SDK 10.0.301): dotnet build Release with TreatWarningsAsErrors + analyzers = 0 warnings/0 errors; dotnet format --verify-no-changes clean; 40 tests pass; dotnet list package --vulnerable = none; --outdated = none.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…racks link

Close the last dependency-currency gaps from the final quality gate so every
shipped dependency surface is pinned, reproducible, and vulnerability-tracked.

Docs site tooling (MkDocs Material)
- Add requirements-docs.txt pinning mkdocs-material==9.7.6 (pip-audit: no known
  vulnerabilities across its full transitive tree).
- slides.yml now installs `-r requirements-docs.txt` instead of an inline pin, so
  the workflow and Dependabot read from one source of truth.
- dependabot.yml: add a `pip` ecosystem entry for `/` (requirements-docs.txt),
  grouped as docs-deps, weekly.

Markdown linter (intentionally left ephemeral)
- markdownlint-cli2@0.22.1 stays an `npx` pin in ci.yml with NO committed
  lockfile. Its latest release transitively depends on js-yaml (<=4.1.1) and
  markdown-it (<=14.1.1), which carry moderate quadratic-complexity DoS
  advisories with no fixed upstream version (npm audit fix only downgrades the
  linter). Committing a root lockfile would surface permanent, unfixable open
  Dependabot alerts for a dev-only tool that processes trusted first-party
  Markdown. Keeping it ephemeral avoids the alert surface while pinning the exact
  linter version. Runtime apps (Python, .NET, mcp-zava, slides) remain 0-vuln.

Docs fix
- facilitator-guide/index.md: point the talk-tracks link at talk-tracks/index.md
  so `mkdocs build --strict` resolves the directory reference cleanly.

Validation (local, CI-equivalent)
- markdownlint-cli2 0.22.1: 0 errors across 64 files.
- mkdocs build --strict via requirements-docs.txt: success, no broken links.
- YAML parse: ci.yml, slides.yml, dependabot.yml all valid.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@NikoMix

NikoMix commented Jun 26, 2026

Copy link
Copy Markdown
Owner Author

⚠️ CI runner status: blocked by GitHub Actions billing (external)

All workflow jobs on this PR report "the job was not started because recent account payments have failed or your spending limit needs to be increased" and fail in ~2 seconds without ever starting. This affects every runner-billed workflow uniformly (ci.yml, codeql.yml, dependency-review.yml, infra-validate.yml, slides.yml). The only check that passes is dependabot.yml, which needs no runner — confirming the configs are valid and the block is purely account billing / spending limit, not a code or workflow defect.

Action required (repo/org owner): restore GitHub Actions minutes under Settings → Billing & plans, then re-run the checks (gh run rerun or the Actions UI). No code changes are needed — the workflows are valid and will execute once billing is restored.

Local CI-equivalent validation (all green)

Every gate the CI workflows enforce was run locally against this exact integrated tree:

Area Checks Result
Python (src/python) ruff check, ruff format --check, mypy --strict, bandit, pytest, pip-audit ✅ 49 tests, 0 vulns
.NET (src/dotnet, net10.0) restore, format --verify-no-changes, build Release (warnaserror+analyzers), test, list --vulnerable/--outdated ✅ 0/0 build, 40 tests, 0 vulnerable + 0 outdated
MCP server (src/mcp-zava) npm ci, eslint, tsc, build, smoke-test ✅ 0 vulns, 7 tools
Infra (infra/) az bicep build (→ARM), az bicep lint ✅ exit 0, clean
Docs mkdocs build --strict, markdownlint-cli2 (64 files), Marp build ✅ no broken links, 0 lint errors

Tooling versions: node 24.16, dotnet 10.0.301, uv 0.11.21, Bicep 0.44.1, markdownlint-cli2 0.22.1, mkdocs-material 9.7.6, marp-cli 4.4.0.

@NikoMix
NikoMix merged commit 9af92ef into main Oct 11, 2026
1 of 10 checks passed
@NikoMix
NikoMix deleted the nikomix-module-b-ttt-training-lab branch October 11, 2026 21:27
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.

Epic: Zava AI Agent Platform — Module B Train-the-Trainer MicroHack (1-day)

1 participant