e-naxosMAF COURSE / COURS
Français

MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1

Demo430 — Business Audit

Run the workflow and read back the local effect, then compare an injected failure.

Objectives

Prepare an isolated experiment

From BaseTechnique or the extracted repository root, build the Release solution. The App project calls ObservabilityDemo in Maf.Observability; Demo420 and Demo430 share this implementation. Documented --deterministic mode loads no model, embeddings or collector. A fresh database distinguishes this experiment’s actions.

dotnet build BaseTechnique.slnx -m:1 -c Release

Run without a model

$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 $journal

Record ExecutionId, TraceId and Database. Expect an accepted workflow followed by ActionCommitted and ExecutionSucceeded. Trace: lines contain SafeSpan JSON; Workflow event: lines describe progress. No model consumption is measured in this mode. Identifiers and durations change on every execution.

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;

shared/Maf.Observability/BusinessJournal.cs · L58–L71 · 9a895c94534c

Source code · Maf.Observability · Folder

Inject a failure and read back

dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --deterministic --fail --db $journal

This new execution has another GUID. --fail interrupts immediately before CommitReview: exit 1, Intention then ExecutionFailed, no ActionCommitted for this GUID. Earlier actions remain. --read expects an existing GUID; enter the execution identifier to inspect.

$executionId = Read-Host 'ExecutionId to inspect'
dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --db $journal --read $executionId

Without --deterministic, the program loads the common connection and calls a real agent with get_review_policy followed by a native reviewer. The required tool call is checked; failure triggers no generated fallback decision. Run only with the configured provider available; request counters can remain null.

dotnet run --project demos/Demo430_BusinessAudit/Demo430.App.csproj -c Release --no-build -- --db $journal

Check evidence beyond the exit code

In a new process, read the successful execution and verify ActionId with HasAction. Also read the failed execution: readback can exit 0 despite no action, because every present action was verified and none exists. Inspect Kind and ActionId. Tests cover restart, replay of the same GUID, native correlation, excluded secrets and missing usage.

dotnet test tests/Maf.Observability.Tests/Maf.Observability.Tests.csproj -m:1 -c Release --no-build --no-restore
public 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;

shared/Maf.Observability/BusinessJournal.cs · L103–L110 · 9a895c94534c

Source code · Maf.Observability · Folder

Observed output · 2026-10-24 · lot012-journal
[
  {
    "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"
  }
]

Output actually read back on 24 October 2026 without a model; isolated extracted sources match canonical code. The serializer retains numeric Kind: 0=RequestReceived, 1=Intention, 3=ActionCommitted, 4=ExecutionSucceeded. The checker also read RecordedDecisions from SQLite and verified the same ActionId. GUIDs, UTC timestamps and TraceId belong to this experiment; do not copy them into a new command.

Preserve local scope

The local commit records ReviewRequested; it performs no remote deletion, refund or other remote effect. --erase deletes only the chosen execution’s metadata and is not a business undo. The journal is not immutable. Redirected console output is its owner’s responsibility; no raw file is published on the site.

Follow shared code

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;

shared/Maf.Observability/BusinessJournal.cs · L58–L71 · 9a895c94534c

Source code · Maf.Observability · Folder

Prerequisites

Continue reading

Complete demo folder · README

lot012-observability-1 · 2026-10-24 · 9a895c94534cd5fc6f3da883e37e5f7856e588c1