MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1
Demo430 — Business Audit
Exécuter le workflow et relire l’effet local, puis comparer une panne injectée.
Objectifs
- Observer Demo430 et ses variantes ; relier le résultat aux concepts du chapitre.
Préparer un essai isolé
Depuis la racine BaseTechnique ou du dépôt extrait, compiler la solution Release. Le projet App appelle ObservabilityDemo dans Maf.Observability ; Demo420 et Demo430 partagent cette implémentation. Le mode documenté --deterministic ne charge aucun modèle, embedding ou collecteur. Une base neuve permet de distinguer les actions de cet essai.
dotnet build BaseTechnique.slnx -m:1 -c ReleaseLancer sans modèle
$journal = Join-Path $env:TEMP ("maf-lot012-" + [guid]::NewGuid().ToString("N") + ".db")dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --deterministic --db $journalNoter ExecutionId, TraceId et Database. Attendre le workflow accepté puis ActionCommitted et ExecutionSucceeded. Les Trace: sont des JSON SafeSpan ; les Workflow event: sont des événements de progression. Dans ce mode, aucune consommation modèle n’est mesurée. Les identifiants et durées changent à chaque exécution.
public long CommitReview(Guid executionId)
{
using var connection = Open();
using var transaction = connection.BeginTransaction();
using var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "INSERT INTO RecordedDecisions(ExecutionId,Decision) VALUES($id,'ReviewRequested') ON CONFLICT DO NOTHING";
command.Parameters.AddWithValue("$id", executionId.ToString("N"));
bool created = command.ExecuteNonQuery() == 1;
command.CommandText = "SELECT Id FROM RecordedDecisions WHERE ExecutionId=$id";
long id = (long)command.ExecuteScalar()!;
if (created) Insert(connection, transaction, executionId, JournalKind.ActionCommitted, id);
transaction.Commit();
return id;
Injecter une panne et relire
dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --deterministic --fail --db $journalCette nouvelle exécution a un autre GUID. --fail interrompt immédiatement avant CommitReview : sortie 1, Intention puis ExecutionFailed, aucun ActionCommitted pour ce GUID. Les actions antérieures restent présentes. --read attend un GUID existant ; remplacer la valeur de saisie par celle de l’exécution à examiner.
$executionId = Read-Host 'ExecutionId to inspect'dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --db $journal --read $executionIdSans --deterministic, le programme charge la connexion commune et appelle un vrai agent avec get_review_policy puis un reviewer natif. L’appel outil obligatoire est vérifié ; une panne ne déclenche aucune décision générée de secours. Exécuter uniquement avec le fournisseur configuré disponible ; les compteurs par requête peuvent rester null.
dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --db $journalVérifier la preuve, pas seulement la sortie
Dans un nouveau processus, relire le succès et vérifier ActionId avec HasAction. Relire aussi l’échec : son code de lecture peut être 0 malgré l’absence d’action, car toutes les actions présentes ont été vérifiées et il n’y en a aucune. Lire Kind et ActionId. Les tests contrôlent reprise, rejeu du même GUID, corrélation native, secrets exclus et usage manquant.
dotnet test tests/Maf.Observability.Tests/Maf.Observability.Tests.csproj -m:1 -c Release --no-build --no-restorepublic bool HasAction(Guid executionId, long actionId)
{
using var connection = Open();
using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM RecordedDecisions WHERE ExecutionId=$id AND Id=$action";
command.Parameters.AddWithValue("$id", executionId.ToString("N"));
command.Parameters.AddWithValue("$action", actionId);
return (long)command.ExecuteScalar()! == 1;
Code source · Maf.Observability · Dossier
[
{
"ActionId": null,
"ExecutionId": "50779844-cf13-4867-bce1-c4aa87657161",
"Id": 1,
"Kind": 0,
"TraceId": "cde643d10fdee1c7910ad01766baba4d",
"Utc": "2026-10-24T19:12:56.6041955+00:00"
},
{
"ActionId": null,
"ExecutionId": "50779844-cf13-4867-bce1-c4aa87657161",
"Id": 2,
"Kind": 1,
"TraceId": "cde643d10fdee1c7910ad01766baba4d",
"Utc": "2026-10-24T19:12:56.7815492+00:00"
},
{
"ActionId": 1,
"ExecutionId": "50779844-cf13-4867-bce1-c4aa87657161",
"Id": 3,
"Kind": 3,
"TraceId": "cde643d10fdee1c7910ad01766baba4d",
"Utc": "2026-10-24T19:12:56.8936463+00:00"
},
{
"ActionId": null,
"ExecutionId": "50779844-cf13-4867-bce1-c4aa87657161",
"Id": 4,
"Kind": 4,
"TraceId": "cde643d10fdee1c7910ad01766baba4d",
"Utc": "2026-10-24T19:12:56.9878252+00:00"
}
]
Sortie réellement relue le 24 octobre 2026, sans modèle, sources de l’extraction isolée identiques au code canonique. Le sérialiseur conserve Kind sous forme numérique : 0=RequestReceived, 1=Intention, 3=ActionCommitted, 4=ExecutionSucceeded. Le programme de contrôle a aussi relu RecordedDecisions dans SQLite et vérifié le même ActionId. Les GUID, timestamps UTC et TraceId appartiennent à cet essai ; ils ne sont pas à recopier dans une nouvelle commande.
Préserver la portée locale
Le commit local porte ReviewRequested ; il ne supprime, rembourse ou crée aucun effet distant. --erase supprime seulement les métadonnées de l’exécution choisie et n’est pas une annulation métier. Le journal n’est pas immuable. Une redirection de console est sous la responsabilité de son propriétaire ; aucun fichier brut n’est publié sur le site.
Suivre le code partagé
public long CommitReview(Guid executionId)
{
using var connection = Open();
using var transaction = connection.BeginTransaction();
using var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "INSERT INTO RecordedDecisions(ExecutionId,Decision) VALUES($id,'ReviewRequested') ON CONFLICT DO NOTHING";
command.Parameters.AddWithValue("$id", executionId.ToString("N"));
bool created = command.ExecuteNonQuery() == 1;
command.CommandText = "SELECT Id FROM RecordedDecisions WHERE ExecutionId=$id";
long id = (long)command.ExecuteScalar()!;
if (created) Insert(connection, transaction, executionId, JournalKind.ActionCommitted, id);
transaction.Commit();
return id;
