> ## 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.

# Permission Changed Mid-Answer: Identity, Evidence and Telemetry Boundaries
- URL: https://devinside.cloud/permission-changed-mid-answer-identity-evidence-and-telemetry-boundaries/
- Published: 2026-07-30T11:00:00.000Z
- Updated: 2026-11-12T17:08:31.000Z
- Description: Controlled HTTP streaming tests show what happens when access or resource version changes after retrieval but before protected content is emitted.
- Author: Marcin Borecki
- Tags: Engineering, Performance & Runtime, #plat10, #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

## Permission Changed Mid-Answer: Identity, Evidence and Telemetry Boundaries

Editorial context: 30 July 2026 · Prepared and updated: 12 November 2026

Dates and technology context

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

Signed fixture-token experiment, retrieve/emit gate, borrowed-evidence observations and32 shared checks were executed12Nov2026\. Preserve non-Entra/non-live-model scope.

*An executed local HTTP streaming experiment with signed fixture tokens. It does not test Microsoft Entra revocation or a live language model.*

An assistant retrieves a protected passage while the user has access. Before the answer is released, that access changes. Is the application allowed to continue because the first authorization check passed, or must it reconsider the evidence already held in memory?

There is no universally correct answer without an application contract. A snapshot-based workflow may deliberately preserve a permission decision for a bounded operation. Another product may require access to remain valid until each protected result is emitted. The mistake is to let implementation convenience choose the policy silently.

This article implements the second, conservative policy in a small local fixture. It uses actual JWT validation and an actual streamed HTTP response. Controlled gates pause the request after evidence retrieval but before protected content is written. The test then revokes access, changes the resource version, allows normal completion or disconnects the client.

The protected content is a synthetic marker, not a customer document. The effect is a local counter, not an external write. A separate operator endpoint exposes selected diagnostic categories, and the suite verifies that its output does not contain the marker. The value of the experiment is the precise timing boundary it makes visible.

The process runs on SDK 10.0.400 and runtime 10.0.15\. It shares its code with the role-separation and minimal-platform articles. The three publications therefore describe different questions asked of one local reference system, not three independent deployments.

## Name the points where information changes audience

01 / See the idea

### Evidence moves through several audiences

![Evidence moves through several audiences. Retrieval, client emission, tool execution and diagnostics are separate boundaries. A successful check at the first boundary does not establish authority at every later one.](https://devinside.cloud/content/images/2026/11/devinside/PLAT10-v1.svg)

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

Retrieval, client emission, tool execution and diagnostics are separate boundaries. A successful check at the first boundary does not establish authority at every later one.

Interpretation and evidence
- Name each recipient.
- Keep tool authority distinct from read access.
- Treat telemetry as another audience.
conceptual mapping of local fixture or compiled-only Azure template

The request crosses several boundaries. A bearer token is validated. The application checks whether this principal may retrieve the selected evidence. The retrieved content enters request-local memory. A later step emits content to the client, and another may invoke a tool. Diagnostic events can reach an operator through a separate channel.

Each boundary has a different consequence. Retrieving evidence into the server's memory is not the same as releasing it to a client. A tool effect can outlive the response. A diagnostic record can expose material to an operator who lacks direct access to the source. Treating all these movements as one authorization event hides the decisions that matter.

The fixture's policy checks validated role and scope, tenant, a live access flag and, where relevant, an expected resource version. The role and scope come from the token. The access flag and resource version come from host-controlled application state. Model arguments cannot supply them.

The policy's purpose is not to determine whether a generated sentence is factually correct. It decides whether the application may cross a particular boundary with the information or action. A perfectly accurate answer can still be an unauthorized disclosure.

This is why the test begins with a conspicuous synthetic marker. It gives the independent HTTP observer an exact value to detect. Natural language about a confidential document would be harder to classify and could tempt the evaluator into judging whether a paraphrase “seems safe.” The first experiment should have a clear oracle.

## Validate identity once, then recheck application authority

The API uses ASP.NET Core JWT bearer middleware with issuer, audience, signing-key, lifetime and algorithm validation enabled. Invalid issuer, audience, expiry and signature cases fail before the protected operation begins. A valid token for another tenant fails the application authorization rule.

That proves a necessary first boundary. It does not mean the application can ignore later changes. A valid principal is a statement about an authenticated identity and its token; current access to a mutable resource is another input to the operation.

The local issuer exists only inside the test process. Its RSA key is generated in memory and is never written into the repository or report. There is no OIDC discovery endpoint, live identity-provider session or remote token-revocation request. Microsoft's guidance supports using the real bearer handler to validate tokens, while warning against treating self-created test tokens as a substitute for a production identity system. [JWT bearer authentication](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/configure-jwt-bearer-authentication?view=aspnetcore-10.0&ref=devinside.cloud).

The fixture deliberately changes a local policy flag rather than waiting for an external directory update. That isolates the application's response to a known change. It cannot establish how quickly Microsoft Entra, Azure RBAC or a provider-side cache would communicate a revocation.

For a real integration, those propagation semantics belong in the contract. The application needs to know whether it relies on a live policy lookup, a cached grant, a token's expiry or another signal. A test of immediate local state change should not be presented as evidence of immediate global revocation.

## Hold the request at a meaningful boundary

02 / Watch the mechanism

### A controlled gate exposes the authorization change

![A controlled gate exposes the authorization change. The actual request pauses after retrieval and before the protected marker is written. The test changes access or resource version, then releases the gate and checks response bytes.](https://devinside.cloud/content/images/2026/11/devinside/PLAT10-v2.svg)

A controlled gate exposes the authorization changeThe actual request pauses after retrieval and before the protected marker is written. The test changes access or resource version, then releases the gate and checks response bytes.PLAT10 / LOCAL IDENTITY REFERENCEA controlled gate exposes the authorization changeRetrieve markerPause at gateRecheck beforeemissionHost changes access or versionLocal checks executed. Azure template compiled, not deployed.

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

Static view. Play to see how the mechanism unfolds.

The actual request pauses after retrieval and before the protected marker is written. The test changes access or resource version, then releases the gate and checks response bytes.

Interpretation and evidence
- Do not rely on arbitrary sleeps.
- The marker stays withheld before the gate.
- A later denial cannot recall earlier bytes.
conceptual mapping of local fixture or compiled-only Azure template

The streaming endpoint first checks access and captures the current resource version. It writes a generic started event and flushes the response. It then checks access before obtaining the protected marker, records a safe retrieval event and signals a test gate.

At that point the parent test knows that the request has reached the interesting state: evidence is available to the server, but the protected content has not been written to the client. The test can now change policy or version deterministically.

The core sequence is visible in the application code:

```csharp
string borrowedEvidence = PolicyState.Marker;
state.SafeTrace.Add("retrieved:v" + version);
gate.Retrieved.TrySetResult();

await gate.Release.Task.WaitAsync(http.RequestAborted);

if (!Allow(http.User, "runtime", "evidence.read", version))
{
    state.SafeTrace.Add("stopped:authorization-change");
    await http.Response.WriteAsync(
        "{\"stage\":\"access-changed\"}\n", http.RequestAborted);
    return;
}

```

The gate is test instrumentation, not a production scheduling API. It creates a repeatable ordering without sleeping and hoping that a permission update happens at the right moment. A five-second watchdog prevents a broken test from waiting forever, but the watchdog is not the evidence that the authorization change was handled correctly.

The expected result is checked outside the server. The client reads the actual response and searches for the marker. The suite also inspects the effect count and active-request count after the endpoint has finished. A server log saying “access changed” would be insufficient if the response had already contained the protected value.

The started event is deliberately non-sensitive. Once response bytes have been sent, the server cannot retract them by changing a later status or writing a denial message. The fixture therefore chooses the protected emission point carefully rather than claiming that rechecking access can erase earlier disclosure.

## Revoke access after retrieval and before emission

In the revoke scenario, the test waits for the retrieval gate, changes the live access flag to false and releases the request. The second policy check fails. The response contains a generic stopped event, not the protected marker, and the tool effect does not occur.

This is the precise accepted claim: the tested marker was not emitted after the controlled revocation, and no subsequent synthetic effect was applied. It is not a claim that the marker never existed in server memory. The endpoint had deliberately retrieved it before the gate.

The implementation holds evidence only in a local request variable. It does not place it in a shared cache. That reduces the number of locations the first experiment must govern, but it does not prove a general cache-invalidation design. Adding a shared evidence cache would require identity, tenant, resource-version and retention rules of its own.

The same distinction matters for model calls. If protected content had already been sent to an external model before revocation, withholding the final answer would not undo that earlier transfer. This fixture has no remote model call, so it makes no claim about recall or deletion from an external provider.

For a production RAG system, list every audience that can receive the evidence: retrieval service, application process, model provider, tool, client and telemetry backend. Authorization needs to be evaluated at the relevant movement, not merely at the last visible screen.

## Treat resource replacement as different evidence

The version-change scenario keeps access enabled but changes the current resource version after retrieval. The request's captured version no longer matches. The endpoint stops before emitting the marker or applying the tool effect.

This case tests freshness and identity, not a denial of the user's general role. A person can remain authorized to read a document collection while a particular answer becomes stale because the document it relied on was replaced. The product may choose to retrieve again, ask the user to retry or finish under a declared snapshot. This fixture chooses to stop.

The stop is intentionally conservative. It avoids silently combining evidence from one version with a decision made under another. It also avoids pretending that every version change is harmful: a production policy might allow certain nonmaterial changes, but that requires a meaningful compatibility definition.

A version token is only useful if it names the state that matters. A counter incremented by the wrong component can create the appearance of freshness checking while missing the actual source change. The fixture uses a host-controlled integer to make the mechanism explicit; a real system must bind it to the authoritative document or policy representation.

The test does not inject a change during an already-running external effect. It controls the order before the protected step. To enforce a version condition atomically with a remote write, the receiver must participate through a conditional operation or another suitable protocol. A local check immediately before a call narrows the window but does not create distributed atomicity.

## Recheck the tool boundary independently

After an allowed evidence write, the endpoint checks the tool scope and version again before incrementing its synthetic effect count. The tool step does not inherit unconditional permission merely because evidence was previously readable.

The shared `/tool` endpoint also exercises actual `Microsoft.Extensions.AI` function invocation. A scripted `IChatClient` asks for the `execute` function with a resource argument and identity-looking extra fields. The registered local function uses the validated server principal and checks the resource. The model-facing arguments do not determine the actor or tenant.

That test is useful because a function wrapper can accidentally become a second, weaker policy path. The HTTP route might reject an operator while the function closure reconstructs authority from untrusted arguments. Exercising the generated function through the SDK detects a real binding path rather than merely asserting that a policy helper exists.

The provider is deterministic and local. It does not generate a natural-language answer from the protected marker. Its role is to verify the integration seam, not to provide evidence of model robustness, prompt-injection resistance or reasoning quality. The selected package and runtime are recorded with the executed artifact.

Keeping these two checks separate also helps interpretation. Evidence-read authority and tool-execution authority can legitimately differ. A user might be permitted to inspect a document but not publish a change derived from it. The application should preserve that distinction even if the model proposes both steps in one conversational turn.

## Cancellation closes the request, not an imagined effect

The disconnect scenario starts the real HTTP stream, waits until the server reaches the retrieval gate and then cancels the client request and disposes its response. The endpoint's wait observes `RequestAborted`, enters its cancellation path and runs its cleanup.

The test waits for the endpoint's finished signal and confirms zero active requests and zero effects. This establishes that the controlled waiting operation did not remain alive after the client disconnected. It does not establish that cancellation could undo an effect already committed elsewhere.

The distinction is particularly important for streamed responses. A client can leave after receiving some output. The server needs a policy for whether its underlying work continues, becomes a durable background job or is cancelled. That choice must match the product's responsibility rather than be inferred from whether an HTTP connection remains open.

Here the request owns its short-lived work, so cancellation stops the gate wait and releases request-local state. There is no detached model task, background timer or external write left behind. The fixture remains deliberately small enough that resource closure can be inspected.

The positive stream scenario is also required. With unchanged access and version, the response includes the marker and the effect count becomes one. Without that positive control, a service that never emits anything could pass all the negative non-disclosure checks while failing its purpose.

## Keep diagnostics from becoming another evidence channel

04 / A concrete example

### Safe diagnostics omit the protected payload

![Safe diagnostics omit the protected payload. The operator endpoint returns stage categories and counters. Its response was scanned for the same marker that appeared in the allowed client response, and the marker was absent.](https://devinside.cloud/content/images/2026/11/devinside/PLAT10-v4.svg)

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

The operator endpoint returns stage categories and counters. Its response was scanned for the same marker that appeared in the allowed client response, and the marker was absent.

Interpretation and evidence
- Record stage and version when sufficient.
- Do not log source content by default.
- A monitoring role cannot repair overcollection.
conceptual mapping of local fixture or compiled-only Azure template

The application records categories such as retrieved version, stopped authorization, cancelled stream and applied tool. It does not record the protected marker in that diagnostic list. The operator endpoint exposes this limited projection together with counters.

After all stream scenarios, the suite calls the operator endpoint with a valid operator token and searches the returned body for the marker. Its absence is an actual observation about this projection. The operator role is also denied direct access to the evidence endpoint in the role matrix.

This does not prove that a large telemetry system contains no sensitive data. Exception messages, automatic instrumentation, request logging and third-party adapters can introduce additional copies. The reference disables ordinary logging providers for its finite test host and does not claim to audit a production collector pipeline.

The useful lesson is to treat telemetry as another recipient with its own purpose. An operator often needs the stage, policy version and failure category, not the document passage itself. A carefully chosen correlation identifier can connect authorized investigation paths without embedding the source content in every event.

Azure monitoring roles do not correct overcollection. A read-only operator can still read sensitive material if the application emits it into an accessible log. Role separation and data minimization therefore reinforce each other; neither substitutes for the other.

The Bicep candidate shared with the companion articles reflects a separate monitoring role, but it is not deployed and does not prove the application's actual Azure diagnostic path. The local operator endpoint is the tested boundary here.

## Read the executed outcomes at their exact scope

03 / See the idea

### The four stream outcomes are not interchangeable

![The four stream outcomes are not interchangeable. Revocation and version change withheld the protected marker. The positive case released it once; disconnect left no active request or tool effect.](https://devinside.cloud/content/images/2026/11/devinside/PLAT10-v3.svg)

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

Revocation and version change withheld the protected marker. The positive case released it once; disconnect left no active request or tool effect.

Interpretation and evidence
- Check actual response content.
- Keep a positive control.
- Wait for cleanup completion.
actual check-results.json

The accepted shared run passed 32 checks on .NET 10.0.15\. The nine role-route combinations produced 200 only for the intended role and 403 for the other roles. Tokens with wrong issuer, audience, expiry or signature produced 401\. A valid runtime token for the other tenant produced 403\. A privileged-looking request body did not elevate the operator, while the runtime tool request exercised the real Microsoft function path and produced one effect.

| Stream scenario                          | Protected marker in response  | Tool effects | Active requests after completion |
| ---------------------------------------- | ----------------------------- | ------------ | -------------------------------- |
| Access revoked after retrieval           | No                            | 0            | 0                                |
| Resource version changed after retrieval | No                            | 0            | 0                                |
| Access and version unchanged             | Yes                           | 1            | 0                                |
| Client disconnected before release       | No protected content released | 0            | 0                                |

The operator diagnostic response did not contain the protected marker. The job fixture separately verified capacity one, success on the third scripted attempt, Unresolved after three unsuccessful attempts, stored success after reopening a connection, and Stopped with zero active work after graceful cancellation. These are functional outcomes; no latency, model quality or cloud availability claim is inferred from them.

The negative stream scenarios inspect actual response bytes rather than only the server's return value. Revocation and resource-version change both stop before the marker. Disconnect closes the active request. The allowed scenario provides the positive control, emitting the marker and applying one synthetic effect.

The experiment uses controlled ordering, not probabilistic load. It demonstrates what happens when the change is known before the next guarded step. It does not measure the probability of a race in production or guarantee that a remote identity system communicates revocation instantaneously.

No timing benchmark was needed to establish those properties. A shorter response time would not compensate for releasing protected content after a failed check. Conversely, a small amount of repeated policy work is a design cost to evaluate only after the required boundary is correct.

The actual code and results are shared across three articles. The role matrix belongs primarily to the identity discussion, the stream cases to this article, and the bounded job lifecycle to the platform article. They are one reference implementation with distinct consumers, not multiple independent replications.

## Decide the policy before adding streaming polish

05 / See the idea

### Stop at the boundary that changed

![Stop at the boundary that changed. The fixture stops when a known local policy or version change invalidates the next step. It does not test global token revocation or an atomic remote write.](https://devinside.cloud/content/images/2026/11/devinside/PLAT10-v5.svg)

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

The fixture stops when a known local policy or version change invalidates the next step. It does not test global token revocation or an atomic remote write.

Interpretation and evidence
- Define snapshot versus live-check policy.
- State the remaining race explicitly.
- Do not equate a local flag with Entra revocation.
conceptual mapping of local fixture or compiled-only Azure template

A product team should decide what an answer means when its source or permission changes mid-operation. It can preserve a declared snapshot, restart retrieval, stop with an explanation or transfer the decision to a human. What it should not do is let the user interface imply that the original authority remains valid without an explicit rule.

That decision also determines which state must travel with the operation. A resource identifier alone may be insufficient; a version, policy revision and authorized scope may matter. The application needs enough information to explain why it continued or stopped without storing more protected content than necessary.

The local reference takes one conservative path and tests it. It captures the version, rechecks before emission and effect, stops on a changed condition and records only a safe diagnostic category. Its simplicity makes the boundary visible and provides a starting point for a more nuanced policy.

A later system may require stronger guarantees. If a permission must remain valid atomically with a database update, the update boundary needs to enforce it. If a message has already reached an external service, local cancellation cannot recall it. If an answer is streamed token by token, the system must decide which partial content is permitted to be released before final validation.

Those are not reasons to abandon rechecking. They are reasons to say exactly which transition each check governs. The most useful result of this experiment is not the slogan “authorize continuously.” It is a concrete, reproducible statement: after this controlled change and before this protected emission, the server stopped, the marker did not appear, and the synthetic tool effect did not occur.

## A passed recheck cannot recall bytes already sent

There is an unavoidable time boundary around streaming. Once a protected byte has reached the client, a later denial cannot make the client forget it. The reference therefore sends only a generic started event before the test gate. Its protected marker appears only after the post-gate check succeeds.

That design supports a precise non-disclosure claim for the tested ordering. It does not support the stronger statement that no byte can ever be released concurrently with a policy change. The check and the socket write are separate operations. A production system requiring a stronger atomic relationship must define how the policy authority and release mechanism coordinate, or choose a different response model.

The same issue arises in token-by-token generation. Validating the final answer after streaming it cannot prevent earlier disclosure. A product may need to buffer sensitive output, validate each permitted fragment under a stable snapshot, or restrict what the streaming phase is allowed to contain. The choice should follow the consequence of a mistake rather than a preference for a smooth animation.

This fixture avoids pretending to solve that broader problem. It has one protected emission and deterministic changes before that emission. The resulting test is useful because it proves an actual boundary and makes the remaining race visible, rather than hiding both behind the phrase continuous authorization.

## Test the positive path with the same observer

A non-disclosure test can be accidentally weak if the observer never receives any content. The allowed stream is therefore checked through the same HTTP client and response reader as the denied paths. It must contain the marker and produce one effect while releasing its active request count.

This positive control helps distinguish a functioning guard from a broken stream, an unread response or a provider that never returns data. It does not prove every legitimate application workflow, but it prevents the most obvious false confidence from a service that only stops.

The operator projection is checked after both positive and negative scenarios. The protected marker has genuinely existed in a successful response, yet it must remain absent from the operator's diagnostic body. That gives the diagnostic check a concrete adversarial value instead of asking whether a log looks harmless in a run that never handled protected content.

The tests remain synthetic and finite. Their strength comes from the controlled contrast and independent observation, not from using real confidential documents. A clear marker and a known expected effect are enough to reveal this class of boundary error without introducing private data into the experiment.

## Reproduce locally and carry the remaining questions forward

The runner starts a temporary loopback API, creates its signing keys in memory and disposes them at the end. It closes the HTTP listener, observes cancellation completion and removes its local job journal. It does not write private keys, bearer tokens or account configuration into the repository.

```powershell
dotnet restore --locked-mode
dotnet run -c Release -- ../check-results.json <owned-work-directory>

```

The command performs functional checks. It does not contact Microsoft Entra, create Azure resources, read account limits or invoke a hosted model. The resulting report should remain labelled accordingly when used in a presentation or deployment review.

Before replacing the fixture with a real provider, identify the new boundary being introduced. A real identity source adds token issuance, key discovery and propagation behavior. A shared cache adds reuse and invalidation. A remote model adds another recipient for evidence. A durable tool adds an external effect that may remain uncertain after response loss.

Add evidence for those boundaries without discarding the local invariant. The user should be able to distinguish what the application knows, what it is still allowed to reveal and which action it has actually performed. That distinction becomes more important, not less, when an answer arrives one fragment at a time.

## Source code and execution evidence

[Download the complete lab, source record and raw execution results](https://devinside.cloud/content/files/2026/11/PLAT10-lab.zip). This package supports the specific execution claims in this article. It is not a production certification.