| MAF001 (fan-out starvation) | high | Return ValueTask<T> — the value is auto-broadcast; required on an AddFanOutEdge source (SendMessageAsync does NOT broadcast on a fan-out edge). For a plain AddEdge target, await context.SendMessageAsync(...) is also valid. | Rarely a false positive. The source-level detector already treats any handler that emits via context.SendMessageAsync/YieldOutputAsync/AddEventAsync as OK, so a MAF001 finding means the handler returns nothing and emits nothing — a genuine dead-end. (The fan-out-EDGE nuance — a SendMessageAsync-only handler that happens to sit on an AddFanOutEdge source — is resolved cross-file by MafSimulateWorkflow, not by MAF001.) |
| MAF-AP-EXEC-001 (legacy executor) | high | Delete [StreamsMessage]/[YieldsMessage]; migrate ReflectingExecutor<> → sealed partial : Executor + [MessageHandler]. | An IMessageHandler<T> that is MediatR / NServiceBus / a hand-rolled bus (no Microsoft.Agents.AI.Workflows). |
| MAF-AP-DEVUI-001 (DevUI/Hosting) | high | Wrap the unsupported preview reference in #if DEVUI_ENABLED. | A supported Microsoft.Agents.AI.Hosting.A2A[.AspNetCore] using, or a project's own namespace DevUI;. |
| MAF-AP-SEC-001 (DefaultAzureCredential) | high | ManagedIdentityCredential in production. | Already inside an env.IsDevelopment() / #if DEBUG dev-only branch. |
| MAF-AP-SEC-003 (EnableSensitiveData) | high | Make it env-driven (= env.IsDevelopment()) or fence behind #if DEBUG. | Same-named bool on an unrelated (non-OTel) type. |
| MAF-AP-CONC-001 (provider field) | high | Move per-session state into a readonly ProviderSessionState<T>. | The field already IS ProviderSessionState<T>, or an injected readonly dependency. |
MAF-AP-CONC-002 (.Result/.Wait()) | high | Make the chain await-first; propagate async + a CancellationToken. | (await x).Result (AgentResponse payload) or Match.Result(...) (Regex) — not a blocking Task. |
| MAF-AP-AGENT-001 (top-level Instructions) | high | Move Instructions into the nested ChatOptions (top-level was removed in 1.3.0). | A user type named ChatClientAgentOptions in your own namespace. |
| MAF-AP-WF-001 (sealed Executor) | high | Add sealed partial to the concrete Executor. | A non-MAF base type that happens to be named Executor. |
| COST-001 (uncapped agent call) | heuristic | Set MaxOutputTokens on the nearest ChatOptions. | app.RunAsync() (ASP.NET host), InProcessExecution.RunStreamingAsync/workflow.RunAsync (workflow runners) — not agent calls. |
| MAF-AP-SEC-002 (hard-coded key) | heuristic | Source the key from env/Key Vault; rotate the leaked one. | A non-secret string that merely starts with sk- (a SKU id, slug, or sk-xxxx placeholder). |
| MAF-AP-OBS-001 (no OpenTelemetry) | heuristic | Chain .AsBuilder().UseOpenTelemetry(...) on the client/agent. | The IChatClient is instrumented in another file and injected here. |
| MAF-AP-MID-001 (middleware) | heuristic | Provide both runFunc: and runStreamingFunc: (or the sharedFunc: overload). | A non-MAF builder whose Use(runFunc:) has no streaming concept. |
| PROMPT-001/002/003/004 (prompt lint) | heuristic | Non-empty prompt; split bloat; add refusal guidance; never interpolate untrusted input into Instructions. | An Instructions property on a non-agent type (recipe, build step, form field). |