Collapse the surge. When a storm, outage, or recall makes 40 people report the same thing, All Clear deduplicates those signals into a handful of real incidents, routes each by severity and SLA, and drives a live map that flips green when everything is resolved.
𧬠Heritage. All Clear is the production pivot of 47 Doors. The same three-agent shape β classify β route β act β is rebuilt on the Microsoft Agent Framework (MAF) for incident triage in public safety, customer comms, and regulated industries.
All Clear is a MAF-based triage pipeline that turns a flood of inbound signals into a small, accurate set of incidents so responders work the event, not the noise. Each signal flows through one coordinated pipeline that:
- π― Classifies intent from a single inbound signal (chat, voice, phone, or report)
- π§² Deduplicates by embedding similarity β duplicate signals attach to an open incident instead of spawning new ones
- π Tracks magnitude β every attached report increments the incident's public-impact counter
- π Routes by queue (field-operations, customer-comms, compliance-desk, engineering, escalations)
- π¦ Maps severity & SLA deterministically (SEV1βSEV4) β rules, never model vibes
- π« Opens incidents and searches knowledge only on the non-duplicate path (keeps surge latency flat)
- π Generates sitreps β citation-grounded situation reports where every claim cites a source
- π‘οΈ Escalates to humans on safety/PII/sentiment rules β a security control, not a refactor
- πΊοΈ Drives the ClearBoard β a live map where incident pins visibly merge as reports attach, SLA breaches highlight, and the board flips to its green all-clear state
π― The hero scenario: a surge where most signals are duplicates of a few incidents. All Clear keeps the responder's queue proportional to incidents, not signal volume.
One canonical term per concept (see CONTEXT.md β if code and that doc disagree, the doc wins).
| π§© Term | π Meaning |
|---|---|
| π‘ Signal | One inbound communication on any channel. Never deduplicated away; always attributable. |
| π₯ Incident | The real-world event signals describe (AC-####). Has severity, queue, SLA clock, magnitude, status. |
| π Report | The association of a signal to an incident; attaching one increments magnitude. |
| π Magnitude | Count of reports on an incident β a proxy for scale; drives ClearBoard weight. |
| πͺ Queue | Destination work stream (replaces 47 Doors' "department"). |
| π Sitrep | Citation-grounded situation report from generate_sitrep. |
| β All clear | Terminal state β every incident resolved, every SLA satisfied. Also the product name. |
| π Surge | Inbound volume spike where most signals are duplicates. The hero scenario. |
| πΊοΈ ClearBoard | Live map view: pins merge on dedup, magnitude counters, SLA breach highlighting. |
Three input modalities β text chat, browser voice (WebRTC), and phone (ACS/PSTN) β all route through the same pipeline. Each agent has bounded authority: it can do only what its role and tools permit.
- π― QueryAgent (MAF agent,
app/agents/query_agent.py) β classifies one signal into intent, entities, severity indicators, and PII flags. Authority: classify only. - π RouterExecutor (deterministic MAF workflow,
app/agents/router_agent.py) β zero LLM calls by design and by test. Runs dedup β severity/SLA mapping β escalation rules β aRoutingDecision. - β‘ ActionAgent (MAF agent,
app/agents/action_agent.py) β exactly three tools:create_incident,search_knowledge,generate_sitrep. Authority: only what its tools permit.
π§² Dedup keeps surges flat. At or above
DEDUP_THRESHOLD(default 0.83 cosine) a signal attaches to an open incident (ATTACH_TO_INCIDENT) β magnitude increments, the reporter gets a short ack, and no knowledge search runs. Below it, a new incident opens (OPEN_INCIDENT) and the full ActionAgent path executes.
Severity is mapped from classification indicators by RouterExecutor rules β never by the model. Thresholds live in config.py, never in code.
| πΊ Severity | π Meaning | β±οΈ Response SLA |
|---|---|---|
| π΄ SEV1 | Life safety, total outage, statutory clock running β immediate escalation | 15 min |
| π SEV2 | Major impairment, public-facing, spreading | 1 hr |
| π‘ SEV3 | Contained, single-party impact | 4 hrs |
| π’ SEV4 | Informational, routine request | Next business day |
βοΈ A statutory clock (breach-notification / recall windows) forces SEV1 regardless of other indicators. Breached SLA clocks highlight on the ClearBoard and are written to the audit log.
Chat runs through FailoverChatClient, which wraps an ordered list of models (primary first). When the primary returns a model-unavailability condition (404 DeploymentNotFound, 401/403 access denied, 503 service unavailable), classification automatically advances to the next configured model β so a model being pulled or restricted doesn't stop triage. It does not route around 429 rate limits (those stay on the retry/back-off path) or content-filter / Prompt-Shield blocks (a safety block is the system working, not an outage). The layer is a no-op until a fallback is configured (AZURE_OPENAI_FALLBACK_DEPLOYMENT), so single-model deployments are unchanged. GET /api/health/models and the ClearBoard model badge surface the active model, the fallback chain, and whether failover is active.
| π§ Service | π Purpose |
|---|---|
| π‘οΈ API Management | AI gateway in front of the API/model β rate limits Β· token budgets Β· JWT validation Β· usage metrics (Day-1 production posture; not provisioned by azd up) |
| π€ Azure OpenAI | Signal classification + sitrep generation (gpt-5.1) β model-agnostic via FailoverChatClient: set AZURE_OPENAI_FALLBACK_DEPLOYMENT to arm automatic chat failover |
| π§ Azure OpenAI Embeddings | text-embedding-3-small (1536-dim) for dedup similarity |
| π Azure AI Search | Knowledge base retrieval (text-embedding-3-small index) |
| π¦ Container Apps | Backend API hosting (managed ingress Β· scale-to-zero) |
| πΎ Cosmos DB | Incident / audit persistence |
| π Communication Services | Phone (PSTN) intake + call automation |
| π Key Vault | Secrets management |
| π Container Registry | Backend container image |
| π§ͺ Azure AI Foundry | Red team Β· AI-quality evals Β· content-filter guardrails (East US 2) |
| π Azure Monitor + Log Analytics | Observability / telemetry |
- Responsible AI control map (SB 818 + DoIT concepts)
- Lab to Production leave-behind
- What does it cost? β token economics & UBB explainer
The entire pipeline runs offline against mock twins of every Azure service. Every live service has a mock twin and they stay in lockstep.
cd backend
python -m venv .venv
.venv\Scripts\activate # Windows (use: source .venv/bin/activate on macOS/Linux)
pip install -r requirements.txt
# Run the full pipeline offline β deterministic, no Azure needed
$env:ENVIRONMENT="test"; $env:MOCK_MODE="true"
uvicorn app.main:app --reload --port 8000# Frontend (new terminal)
cd frontend
npm install
npm run devπ§ͺ Mock mode is enabled by
MOCK_MODE=true/USE_MOCK_MODE=true.Settings.use_mock_servicesis also true in thetestenvironment.
azd auth login
azd upazd up provisions the Bicep stack in infra/ and deploys the backend to Container Apps. The postdeploy hook prints the backend URL and its /api/health endpoint.
| π§ Method | π Endpoint | π Description |
|---|---|---|
POST |
/api/signals |
π‘ Submit an inbound signal to the pipeline |
POST |
/api/chat |
π¬ Submit a signal (chat alias of /api/signals) |
GET |
/api/knowledge/search |
π Search the knowledge base |
GET |
/api/health |
π Service health |
GET |
/api/health/models |
π Active chat model, fallback chain, last-served model, and failover state |
POST |
/api/realtime/session |
π€ Create an ephemeral realtime (voice) session |
WS |
/api/realtime/ws |
π€ Realtime tool relay |
GET |
/api/realtime/health |
π€ Realtime availability |
POST |
/api/phone/incoming |
π ACS incoming-call webhook |
POST |
/api/phone/callbacks |
π ACS call callbacks |
GET |
/api/phone/health |
π Phone service health |
GET |
/api/phone/transcripts/stream |
πΊ SSE transcript stream for the ClearBoard |
WS |
/ws/acs-media |
π ACS media relay |
| Suite | Tests | Status |
|---|---|---|
| Backend (pytest, mock mode) | 348/348 | β Passing |
| Backend CI (clean venv) | allclear-backend-ci.yml |
β |
| Smoke (agents Β· evals Β· models Β· spec) | smoke-test.yml |
β |
| Frontend (vitest) | 24/24 | β |
Backend tests run with
ENVIRONMENT=testandMOCK_MODE=trueβ no Azure credentials required.
cd backend
python -m pytest tests/ -v --tb=shortcd frontend
npm test # vitest unit tests
npm run test:e2e # Playwright E2Eall-clear/
βββ π§ backend/ # FastAPI + Microsoft Agent Framework
β βββ app/
β βββ π€ agents/ # QueryAgent Β· RouterExecutor Β· ActionAgent Β· pipeline
β βββ π‘ api/ # signals, knowledge, realtime, phone, transcripts
β βββ βοΈ services/ # Azure twins (LLM, search, phone) + mock twins
β βββ βοΈ core/ # config (SLA, dedup threshold), dependencies
βββ π¨ frontend/ # React + Vite + TypeScript ClearBoard
βββ βοΈ infra/ # Azure Bicep templates
βββ π specs/ # MAF rehost + production-deployment specs
βββ π docs/ # Architecture + product docs
βββ π οΈ scripts/ # quickstart / smoke / validation
βββ π CONTEXT.md # Ubiquitous domain language (source of truth)
βββ π³ docker-compose.yml
βββ π azure.yaml # azd deployment manifest
π§Ή Some directories (
coach-guide/,coach-site/,hackathon-site/,workshop-site/,labs/,allclear-dropin/) are 47 Doors bootcamp leftovers retained during the rehost.
All Clear adopts a CJIS mindset everywhere β even where it doesn't legally apply: least privilege, full audit, no PII echo. Escalation logic is a safety control: code that weakens it is a security blocker, not a refactor. Each agent operates under bounded authority enforced by code structure (tools, interfaces), not prompt hope.
- π΄ Fork the repository
- πΏ Create a feature branch (
git checkout -b feature/amazing-feature) - β
Run
python -m pytestinbackend/(mock mode) before committing - πΎ Commit your changes
- π Open a Pull Request
- Sean Gayle (@msftsean) β Operational dashboards, foundry integration, evals harness, guardrails infrastructure
This project is licensed under the Apache License 2.0 β see the LICENSE file for details.
This software is provided "AS IS", without warranties or conditions of any kind. Use of this software is at your own risk. The authors and contributors are not liable for claims, damages, or other liability arising from its use.



