> ## Content Index
> Fetch the complete content index at: https://devinside.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Tool Calls You Can Audit: Deterministic Controls Around Agents
- URL: https://devinside.cloud/tool-calls-you-can-audit-deterministic-controls-around-agents/
- Published: 2026-10-09T11:00:00.000Z
- Updated: 2026-11-12T17:08:33.000Z
- Description: An agent can explain why it wants to perform an action without establishing that it may perform it. It can produce a well-formed tool call without establishing that the arguments are safe. It can report success without proving that the external effect occurred exactly once.
- Author: Marcin Borecki
- Tags: Engineering, Microsoft AI Engineering, #m34, #devinside-review

START WITH THE MECHANISM

Interactive companion and laboratory update: 12 November 2026\. The editorial date places the topic on the timeline; this current explanation and its measured evidence retain their actual preparation and execution dates.

THE FULL INVESTIGATION

## Tool Calls You Can Audit: Deterministic Controls Around Agents

Editorial context: 9 October 2026 · Prepared and updated: 12 November 2026

Dates and technology context

This is a retrospective editorial timeline. Topic context: 9 October 2026\. First publicly available: 12 November 2026\. Current text, visuals and laboratory revisions were prepared on 12 November 2026.

The durable control fixture adds Microsoft.Extensions.AI11.0.0, Microsoft.Agents.AI1.28.0 and .NET10.0.15 in November2026\. These exact later packages must not be attributed to October9.

An agent can explain why it wants to perform an action without establishing that it may perform it. It can produce a well-formed tool call without establishing that the arguments are safe. It can report success without proving that the external effect occurred exactly once.

These gaps are architectural. A better prompt can improve planning, but authorization, approval binding and execution evidence require application controls. The model should operate inside a system whose important invariants remain true even when its proposed action is mistaken.

My central distinction is between a proposed action and an authorized effect. The proposal is an input to a deterministic process. The effect is the result of policy, durable state and an executor whose behavior can be inspected. An audit trail connects them without pretending that a transcript is a transaction log.

## Begin with an action that matters

Consider an agent helping prepare a customer refund. It can gather order information, explain a policy and propose an amount. The consequential step is issuing the refund. The business needs to know who authorized it, which order and amount were approved, whether conditions still held at execution time, and what the payment system actually did.

A log entry saying the agent called `refund_order` is inadequate. It may omit the authenticated actor, policy version, approval scope or external transaction reference. It may have been sampled, dropped or written after the effect. It may describe an attempt whose result is uncertain.

Define the invariant first: no refund occurs without an authorized actor, an eligible order, a bounded amount and approval of that exact proposal. Then define what evidence would show that the invariant held. The tool interface follows from these requirements.

This reasoning applies beyond payments. Publishing an article, deleting data, provisioning cloud resources and changing permissions all create effects that outlive the conversation. Their control model should be understandable without reading the model's internal reasoning.

## Authenticate outside the model

01 / See the idea

### The protocol boundary is not the policy

![A model proposal crosses schema, identity and policy boundaries before any external effect.](https://devinside.cloud/content/images/2026/11/devinside/M34-v1.svg)

[Enlarge diagram](https://devinside.cloud/content/images/2026/11/devinside/M34-v1.svg)

A hypothetical tool request contains a refund target and amount. Trusted identity and resource policy decide whether it may reach the executor; a valid tool schema alone does not authorize the refund.

Interpretation and evidence
- Model proposes intent.
- Application supplies authority.
- Executor receives an authorized action.
conceptual/hypothetical, not measured

The application obtains identity from its trusted authentication mechanism. It does not accept an actor ID simply because the model placed one in tool arguments. Resource authorization is evaluated against that identity and the target resource.

ASP.NET Core supports resource-based authorization, which is useful when a decision depends on a loaded object rather than only an endpoint-level rule. The application still defines the policy and supplies the correct resource. [ASP.NET Core resource-based authorization](https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resource-based?view=aspnetcore-10.0&ref=devinside.cloud)

Carry identity through a controlled request or job context. If work continues asynchronously, decide how delegated authority is represented and when it expires. Replaying a message should not revive an authorization that has been revoked or extend a user's permission indefinitely.

Tool results and retrieved documents are untrusted inputs for this purpose. A page saying that an administrator has approved an operation is content, not an authenticated approval. This distinction must survive prompt injection, accidental ambiguity and ordinary model error.

MCP defines a standard way to describe and call tools. It does not turn a model-selected tool invocation into a business authorization decision. Keep the protocol boundary separate from the policy boundary. [MCP tools specification, version 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/server/tools?ref=devinside.cloud)

## Approve an immutable proposal

An approval must bind to the action the reviewer saw. If the agent can change the amount or destination after approval, the interaction approves a category of action rather than a concrete effect.

Persist a canonical proposal containing the operation ID, action type, target, normalized arguments, relevant resource version, expiry and policy version. Compute an identifier or digest over a precisely defined representation. Store the approval against that proposal, including the approving actor and time.

Canonicalization matters. Hashing arbitrary JSON without controlling representation can make equivalent objects look different. More dangerously, normalizing values differently during approval and execution can make different operations look equivalent. Use one application-owned representation and test the boundary cases that matter to the action.

The following C# types illustrate the contract. They are application-owned .NET 10 types, not Microsoft Agent Framework or MCP SDK classes. The fragment has not been compiled or executed.

```csharp
public sealed record RefundProposal(
    Guid OperationId,
    string OrderId,
    long AmountMinorUnits,
    string Currency,
    string OrderVersion,
    string PolicyVersion,
    DateTimeOffset ExpiresAt);

public sealed record ApprovalBinding(
    Guid OperationId,
    string ProposalDigest,
    string ApproverId,
    DateTimeOffset ApprovedAt);

public enum ActionState
{
    Proposed, Approved, Executing,
    Succeeded, Rejected, Failed, OutcomeUnknown
}

```

Money uses an integer number of minor units here to make the proposed representation explicit, but currency rules still require validation. A record type alone does not establish immutability in storage, authorization or correct concurrency control.

At execution, reload the proposal and compare the approval binding. Recheck expiry, resource version and permissions according to the business contract. A previously valid proposal can become invalid when an order changes. Make that result visible instead of silently regenerating and executing a different proposal.

## Separate the ledger from telemetry

02 / A concrete example

### An approval must reject a changed action

![A hypothetical approval digest matches one amount and rejects a later mutation.](https://devinside.cloud/content/images/2026/11/devinside/M34-v2.svg)

[Enlarge diagram](https://devinside.cloud/content/images/2026/11/devinside/M34-v2.svg)

Proposal P7 requests 2,500 minor units and receives approval for digest A. Reusing that approval for 3,000 units produces digest B and must stop before any effect.

Interpretation and evidence
- Normalize content consistently.
- Bind approval to the digest.
- Recheck expiry and resource version.
conceptual/hypothetical, not measured

Telemetry helps explain system behavior. A durable action ledger establishes the state of a consequential operation. They can share correlation identifiers, but they should not share an accidental loss policy.

The ledger records intent before the external effect, then records attempts and outcomes. Its state transitions use concurrency control so competing workers cannot both claim an operation without a defined coordination rule. Authorization decisions and approval references remain associated with the operation.

A trace can contain useful timing and dependency details, but sampling or exporter failure must not erase the business record. Conversely, the ledger should not become an uncontrolled dump of prompts, credentials and customer data. Store the fields necessary to establish the action and its authority, with an explicit retention and access policy.

Tamper resistance requires more than a table named Audit. Define who can append, who can correct, how corrections are represented, and what administrators can alter. Stronger requirements may justify append-only storage, external integrity records or independent retention. The required assurance depends on the threat model.

Do not claim cryptographic certainty from an ordinary database row. State what the design protects against, which trusted operators remain capable of changing evidence, and how a reviewer would detect a missing or inconsistent transition.

## The hardest state is an uncertain outcome

An executor sends a request to an external system and then loses the connection. The external system might have performed the action. Retrying blindly can duplicate it; declaring failure can mislead the user; declaring success invents evidence.

Represent this as `OutcomeUnknown`. Reconcile using an external operation identifier, an idempotency key supported by the destination, or a query of the destination's authoritative state. If the destination offers no reliable reconciliation mechanism, the application needs a documented manual path and a narrower automation promise.

HTTP method semantics alone do not make an arbitrary business action exactly once. A POST endpoint needs an application contract if callers rely on idempotency. Even for an idempotent method, response loss and concurrent state changes still require careful interpretation. [HTTP semantics, RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html?ref=devinside.cloud)

The following pseudocode describes a proposed executor boundary. It is intentionally not a runnable SDK example.

```text
load persisted proposal and approval
validate actor, expiry, resource version and proposal digest
atomically claim operation or return its existing state
persist execution attempt with stable external idempotency key
send exact approved action to destination
if confirmed:
    persist destination reference and succeeded state
else if definitely rejected before effect:
    persist rejected or failed state with evidence
else:
    persist outcome-unknown state and schedule reconciliation

```

The gap between a local transaction and an external effect remains visible in this design. An outbox can coordinate local state with dispatch intent, but it does not by itself force the remote service to perform an action exactly once. Destination behavior is part of the contract.

## Make the agent's freedom legible

Not every tool call needs a human approval dialog. A read-only lookup within an authorized scope may be routine. A low-impact reversible change may fit a bounded preauthorization. A consequential or difficult-to-reverse action may require approval of a concrete proposal.

Define these categories in policy, with limits on resources, amounts, destinations and duration where relevant. The agent should not classify its own action as harmless and thereby grant itself broader authority. Trusted code selects the applicable policy from the actual operation.

Excessive confirmation can also damage control. If every harmless lookup produces a prompt, reviewers learn to approve mechanically. Reserve attention for decisions where human judgment changes the outcome, and make those prompts specific enough to review.

Show the target, arguments, expected effect and meaningful uncertainty. A button labelled Continue beside a conversational summary is weaker than a review of the exact proposal. The interface should also explain when a proposal expired or changed and therefore needs a new decision.

## Test invariants with hostile and boring inputs

03 / Watch the mechanism

### Unknown is a state with a next action

![An execution ledger records intent, an uncertain attempt and authoritative reconciliation.](https://devinside.cloud/content/images/2026/11/devinside/M34-v3.svg)

Unknown is a state with a next actionAn execution ledger records intent, an uncertain attempt and authoritative reconciliation.M34-V3 / TECHNICAL EXPLANATIONUnknown is a state with a next actionConceptual / hypothetical example. Not measured results.Local durable ledgerDestinationIntent: K7Effect performedOutcome unknownreply lostFind K7 → ref R7Reconcile, do not repeat.

Play animation[Enlarge diagram](https://devinside.cloud/content/images/2026/11/devinside/M34-v3.svg)

Static view. Play to see how the mechanism unfolds.

The hypothetical destination performs action K7 but its reply is lost. Reconciliation queries K7 and records the destination reference, while a blind repeat remains blocked.

Interpretation and evidence
- Write intent before the effect.
- Keep unknown distinct from failed.
- Use the destination identity to reconcile.
conceptual/hypothetical, not measured

Begin with cases that should never produce an effect: forged actor IDs, unauthorized targets, expired approvals, changed amounts, changed resource versions, duplicated deliveries and instructions embedded in retrieved text. Verify the absence of the external action, not merely the presence of an error message.

Then test uncertain boundaries. Interrupt the connection after the destination accepts a request. Restart a worker between recording an attempt and recording its result. Deliver the same operation concurrently. Confirm that reconciliation uses the same external identity and that the user sees uncertainty until evidence resolves it.

Use a controlled destination simulator or an isolated test service. Do not run these experiments against real customer accounts. The simulator should expose whether an effect happened, so the test can compare application state with an independent fact.

The happy path matters too. A valid, approved operation should complete without unnecessary reapproval. The audit record should explain the path clearly enough that someone outside the implementation team can review it. Security controls that make legitimate work impossible will invite bypasses.

No such execution is claimed in this article. These scenarios define an acceptance plan for an implementation, and the illustrative types establish vocabulary rather than a finished reference system.

## Version the behavior you depend on

Frameworks evolve, and tool invocation behavior can change with adapters, middleware or model providers. Record the framework package, tool schema, application policy and prompt versions for each release. Preserve a behavioral test suite across upgrades.

Microsoft Agent Framework reached version 1.0 before this article's context, and the official MCP C# SDK also had a stable 1.0 release. Those milestones support choosing stable integration points; they do not prove that a particular middleware configuration enforces the proposed invariants. [Microsoft Agent Framework version 1.0](https://devblogs.microsoft.com/agent-framework/microsoft-agent-framework-version-1-0/?ref=devinside.cloud), [MCP C# SDK version 1.0](https://devblogs.microsoft.com/dotnet/release-v10-of-the-official-mcp-csharp-sdk/?ref=devinside.cloud)

Keep the core action contract independent of the agent adapter. A model proposes a normalized action. The application validates and persists it. A controlled executor performs it. This separation makes an SDK upgrade a change at an inspectable boundary instead of a reason to redefine authorization.

The same principle applies to audit explanations. A generated summary can help a reviewer navigate the ledger, but the summary is not the ledger. Every important statement should resolve to a stored event or external reference. When the evidence is incomplete, the explanation should preserve that incompleteness.

## Build trust from inspectable transitions

An auditable agent system does not need to claim that the model is perfectly predictable. It needs to show that consequential effects pass through controls whose meaning is stable and whose outcomes can be checked.

The resulting architecture is more deliberate than directly wiring every available tool to a conversation. It also makes failure less mysterious. We can distinguish a poor proposal, a denied authorization, an expired approval, an execution failure and an uncertain external outcome.

That distinction is the foundation of operational trust. The model can remain useful for interpretation and planning while the application remains accountable for what actually happens.

## Execution appendix, 12 November 2026: the control now has a durable fixture

The earlier article describes an action contract and an acceptance plan. This appendix adds a real local implementation and executed checks dated 12 November 2026\. The implementation uses package versions from that date; it does not imply that later versions existed at the article's earlier context date.

The shared laboratory has an ASP.NET Core caller, a `Microsoft.Extensions.AI` function caller and an actual Microsoft Agent Framework `ChatClientAgent`. All three enter the same domain service and SQLite-backed reservation store. A separate SQLite database acts as the simulated receiver. Its rows are synthetic effects, not real payments or changes to customer systems.

The selected environment is SDK 10.0.400 and runtime 10.0.15, with `Microsoft.Extensions.AI` 11.0.0 and `Microsoft.Agents.AI` 1.28.0\. The database adapter is `Microsoft.Data.Sqlite` 10.0.0 with the native bundle pinned in the lockfile. Public package records establish availability; the local build and executed calls establish the tested combination. [Microsoft.Agents.AI 1.28.0](https://www.nuget.org/packages/Microsoft.Agents.AI/1.28.0?ref=devinside.cloud), [Microsoft.Data.Sqlite 10.0.0](https://www.nuget.org/packages/Microsoft.Data.Sqlite/10.0.0?ref=devinside.cloud).

The purpose is to make the word auditable concrete. A caller can inspect the proposal identity, approval consumption, reservation state and receiver effect. It is no longer necessary to infer the result only from a generated response or an illustrative state diagram.

## Keep the proposal fixed across callers

The stored quote identifies the task, resource, resource version, amount, synthetic unit code and expiry. Its digest is computed from a versioned binary representation of those fields. An approval binds its actor and identity to that exact quote digest.

The action-facing command does not carry a freely editable amount. It carries identifiers for the operation, quote and approval. The domain service loads the approved content from the store. This makes a changed-price or changed-target request a new proposal problem rather than an unnoticed change to arguments after a user approved something else.

The database rejects ordinary updates to the quote table. On read, the service also recalculates the digest. These mechanisms help preserve application-level immutability, but they do not make the file tamper-proof against an administrator who can replace the database or schema. The fixture's threat boundary remains explicit.

The HTTP and tool callers share the same immutable actor-and-tenant context shape. The HTTP test uses a clearly labelled synthetic authorization mapping; the tool closes over context supplied by the host. Additional identity-looking JSON arguments cannot override that context. This is a tested data-flow property, not a claim that the fixture implements production authentication.

The selected command and context reach one method:

```csharp
public Outcome Execute(Command command, RequestContext context)
{
    // The full source records trace events and maps defined denials.
    // Tenant checking precedes the durable reservation and dispatch.
}

```

The full implementation is in the shared `Domain.cs` and `Authority.cs` files. The important point is that no adapter receives its own easier version of the policy. A new caller cannot become privileged merely because it uses an agent framework.

## Reserve authority and consume approval together

The reservation transaction loads the quote, checks the trusted actor, validates expiry and resource version, and confirms that the approval is bound to the quote and has not been consumed. It then inserts the operation and records which operation used the approval.

Those changes commit together. An operation record without approval consumption would allow reuse; approval consumption without an operation record would lose the explanation of what was authorized. The transaction connects the two pieces of state.

An exact replay is handled separately. If the operation already exists with matching quote, approval and digest, the store returns its state rather than spending authority again. A different operation attempting to reuse the same approval is denied. This lets retries recover knowledge without converting a single-use approval into a ban on asking for the result again.

The reference also retains synthetic capacity reservations, following the accepted AI13 design. Reserved and Unknown amounts remain held; Succeeded amounts are committed. These units are application fixture data. There are no account balances, provider budgets, real charges or billing queries involved.

SQLite transactions provide local atomic changes under the selected storage contract. They do not make the independent receiver commit part of the same transaction. That separation is the reason the Unknown state exists. [Microsoft.Data.Sqlite transaction documentation](https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/transactions?ref=devinside.cloud).

The migrated callers do not alter these rules. The new acceptance test checks the same outcome and domain trace through actual HTTP, direct function middleware and Agent Framework, rather than merely unit-testing the policy method in isolation.

## Preserve uncertainty before crossing the effect boundary

01 / Watch the mechanism

### Persist uncertainty before crossing the boundary

![Persist uncertainty before crossing the boundary. The ledger stores Unknown before the receiver commits. Losing the response leaves the reservation held; reconciliation finds the same receiver record without another effect.](https://devinside.cloud/content/images/2026/11/devinside/M34-appendix-1.svg)

Persist uncertainty before crossing the boundaryThe ledger stores Unknown before the receiver commits. Losing the response leaves the reservation held; reconciliation finds the same receiver record without another effect.M34 / NOVEMBER 2026 EXECUTION APPENDIXPersist uncertainty before crossing the boundaryReservedUnknown persistedReceiver commitsResponse lostEffect remains 1Reopen + reconcileSucceededEffect remains 1Local synthetic fixture. No live-model or payment claim.

Play animation[Enlarge diagram](https://devinside.cloud/content/images/2026/11/devinside/M34-appendix-1.svg)

Static view. Play to see how the mechanism unfolds.

The ledger stores Unknown before the receiver commits. Losing the response leaves the reservation held; reconciliation finds the same receiver record without another effect.

Interpretation and evidence
- Record responsibility before dispatch.
- A missing response is not proof of failure.
- Reconcile using the stable operation identity.
conceptual sequence matching executed local fixture

After reservation, dispatch rechecks the conditions relevant at its claim boundary. A stale or expired proposal is released before contacting the receiver. Otherwise the store records Unknown before asking the receiver to apply the action.

That ordering is deliberately conservative. Once dispatch has been claimed, a process interruption can make the sender uncertain whether the receiver was contacted or committed. The ledger must retain responsibility for that interval instead of turning every missing response into a declared failure.

The receiver's own table uses the operation identity as its idempotency key and retains the digest, amount and unit code. A repeat with the same content does not insert another effect. A conflicting repeat is rejected. This is a separate local transaction in a separate file, preserving the distinction between the two authorities.

The lost-response fixture performs the receiver effect and then suppresses the local success update. Immediately afterward, the expected outcome is Unknown with one receiver effect, thirty held synthetic units and zero committed units. That state is checked before recovery.

The test then creates a new store object over the same database and reconciles against the receiver. The matching receiver record establishes success. Held units move to committed units, and the receiver-effect count remains one. The result is the same through all three entry paths.

Reopening an object and connection is not a machine-power-loss test. It does demonstrate that the operation's recovery information was stored in the database rather than surviving only in a local variable. Stronger storage-failure claims would need a different fault model and evidence.

## Read the negative paths as evidence, not reassuring labels

02 / See the idea

### Durable outcomes survive the caller change

![Durable outcomes survive the caller change. All three callers are checked against the same expected receiver outcomes. The unknown scenario includes an asserted intermediate Unknown state and final reconciliation to one successful effect.](https://devinside.cloud/content/images/2026/11/devinside/M34-appendix-2.svg)

[Enlarge diagram](https://devinside.cloud/content/images/2026/11/devinside/M34-appendix-2.svg)

All three callers are checked against the same expected receiver outcomes. The unknown scenario includes an asserted intermediate Unknown state and final reconciliation to one successful effect.

Interpretation and evidence
- Denial must prevent a new effect.
- Exact replay must not duplicate it.
- Unknown recovery must preserve its identity.
actual shared check or measurement report

The accepted run covers nine scenarios across three callers, completing 75 checks. Five rejection scenarios exercise wrong actor, wrong tenant, expired quote, stale resource version and changed quote. The test inspects the receiver state as well as the returned outcome, so an attractive denial message cannot hide a created effect.

Two replay scenarios need different expected counts. Repeating an exact operation succeeds as a replay and leaves one effect. Reusing the consumed approval for a different operation is denied but also leaves one effect, because the first authorized action already happened. Calling both situations “no effect” would make the test's statement false.

The valid scenario supplies the positive control: the policy must permit legitimate work. A system that denies every request could satisfy many negative checks while failing its purpose. The valid path creates exactly one effect under the declared fixture authority.

The final scenario exercises Unknown and reconciliation. Its intermediate and final states are checked, not merely the eventual Succeeded label. That makes the ownership of uncertain work visible to the test.

Each caller starts from its own equivalent scenario database. The comparison therefore does not rely on one adapter preparing a result for another. It checks that the adapters independently preserve the same policy and receiver behavior from the same initial conditions.

## The audit trace is not the authority store

The harness also records a short ordered trace: request received, tenant accepted, reservation result, dispatch result and reconciliation. These entries are compared across adapters to expose changed paths.

That trace is not the durable authority ledger. It is a test artifact held in memory and exported after execution. The SQLite operation and approval records establish local state; the receiver table establishes the simulated effect. Keeping these roles separate prevents a dropped trace from becoming equivalent to a missing business record.

A real audit design would need additional decisions about access, retention, corrections and privileged operators. This fixture does not establish tamper resistance, legal evidentiary value or indefinite retention. It establishes a concrete relationship among a proposal, its consumed approval, an operation state and a receiver record.

The same distinction applies to a generated explanation. A model can summarize the trace for a human, but it cannot make an absent receiver confirmation appear. The explanation should identify the relevant records and preserve an Unknown outcome while evidence is incomplete.

## Measure the cost of replay without confusing it with assurance

The timing fixture begins after the operation has already succeeded. It compares direct domain replay, `Microsoft.Extensions.AI` function replay and Agent Framework replay. No path is allowed to create a second effect.

This boundary includes reading and validating the existing SQLite state. The framework paths additionally create their local wrappers and perform the scripted function round trip. It excludes first-time commits, real HTTP transport, remote model latency and external payment processing.

Six samples of sixteen replays follow a warm-up for each path. Process-wide managed allocation is recorded because asynchronous continuations may not stay on one thread. Native SQLite memory and retained heap are not measured. The result is a local cost observation, not a score of security or audit quality.

The shared measurement completed on 12 November 2026 at 14:05 UTC on .NET 10.0.15, with exit code zero. It contains six samples for each path. The table reports milliseconds per successful replay and process-wide managed bytes allocated per replay; all three paths are retained.

| Local replay path | Median ms | Observed ms range | Allocated bytes range |
| ----------------- | --------- | ----------------- | --------------------- |
| direct-domain     | 1.298     | 1.267–1.374       | 37,203.5–37,222.5     |
| meai              | 1.338     | 1.318–1.406       | 42,435.5–42,498.5     |
| maf               | 1.435     | 1.351–1.583       | 49,907.5–49,978.5     |

The medians differ, but the observed timing ranges overlap. This small single-process run does not establish a statistically reliable overhead percentage or identify which internal layer caused a difference. Connection creation, SQLite reads, validation, wrapper construction and scripted function calls are all part of the declared boundaries. No empty-loop or storage baseline was subtracted.

The allocation counter covers the process because the calls use asynchronous APIs. It does not measure retained heap, native SQLite allocations or a live provider's memory. Each replay is checked for the expected Succeeded state and exactly one receiver effect. That correctness gate is more important than a lower time obtained by accidentally omitting policy or persistence work.

These are deliberately local measurements. The direct route does not include HTTP, and neither chat route includes a remote model request. Their labels identify the exercised code paths, not the latency a user should expect from an AI application. The same raw report is shared across the three article appendices and is counted as one experiment, not three independent repetitions.

## Carry the invariant into a real deployment carefully

The three-caller result supports reusing one policy service. It does not remove the need to examine how a deployed host obtains identity, how a real receiver defines idempotency or how quickly authorization changes become effective.

The reference checks resource version at dispatch claim. A change after that point does not recall an already in-flight action. If the business requires the receiver to enforce a version condition at commit time, that must be part of the receiver contract. A local check cannot manufacture a distributed atomicity guarantee.

Likewise, the internal reconciliation method is trusted fixture functionality. Exposing it publicly would require its own authenticated actor, tenant checks, rate controls and safe output contract. The fact that reconciliation often reads state does not make unrestricted access harmless.

These limits are useful precisely because the core now executes. A team can replace the fixture identity mapping, local receiver or storage configuration one boundary at a time, preserving the invariant tests while adding checks for each new responsibility.

The article's original distinction remains intact: the agent proposes an action, while the application authorizes an effect. The new appendix demonstrates that distinction through real adapter code and durable local state, without claiming more than the executed scenarios establish.

Historical versions and verification boundaries

These pins existed before the context date. Availability and static API checks do not establish a successful build or a production-safe patch level. Execution claims are limited to explicitly identified companion checks.

| Component                     | Version  | Available by | Source                                                                                                                   |
| ----------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| .NET SDK                      | 10.0.100 | 2025-11-11   | [Primary record](https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/10.0/releases.json?ref=devinside.cloud) |
| .NET runtime                  | 10.0.0   | 2025-11-11   | [Primary record](https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/10.0/releases.json?ref=devinside.cloud) |
| ASP.NET Core shared framework | 10.0.0   | 2025-11-11   | [Primary record](https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/10.0/releases.json?ref=devinside.cloud) |
| C#                            | 12.0     | 2024-12-03   | [Primary record](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-12?ref=devinside.cloud)                |
| Microsoft.Agents.AI           | 1.0.0    | 2026-04-03   | [Primary record](https://www.nuget.org/packages/Microsoft.Agents.AI/1.0.0?ref=devinside.cloud)                           |
| ModelContextProtocol          | 1.0.0    | 2026-03-05   | [Primary record](https://www.nuget.org/packages/ModelContextProtocol/1.0.0?ref=devinside.cloud)                          |
| OpenTelemetry                 | 1.9.0    | 2024-06-14   | [Primary record](https://www.nuget.org/packages/OpenTelemetry/1.9.0?ref=devinside.cloud)                                 |

[Download the complete laboratory and execution records](https://devinside.cloud/content/files/2026/11/M34-lab.zip).