One Question, Several Queries: Put Typed Intent Between Language and SQL
Typed intent separates language proposals from executable SQL, trusted tenant scope and independently checked aggregate results.
Explore the mechanism โ
Reading tools Listen or translate
Read aloud
Uses an installed voice on your device.
Translate article
Machine translation. Code and evidence notes stay in English.
Original English text.
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
One Question, Several Queries: Put Typed Intent Between Language and SQL
Dates and technology context
This is a retrospective editorial timeline. Topic context: 18 June 2026. First publicly available: 12 November 2026. Current text, visuals and laboratory revisions were prepared on 12 November 2026.
The nine proposal outcomes, restricted SQL principal, Microsoft.Agents.AI1.28.0 and MEAI11 code, exact oracle and actual .NET11 execution are dated 2026-11-12.
A user asks for a regional total. Another user asks for the same total with different wording. A third changes the region number, and a fourth adds a request to inspect another tenant. These requests look similar as text, but they do not all authorize the same database operation.
The tempting architecture sends the question to a model, receives SQL and executes it. That makes generated syntax carry too many responsibilities at once: interpreting intent, choosing data scope, selecting query structure and respecting database authority. A query that looks plausible can be wrong in any of those dimensions while still returning a polished answer.
This article examines a narrower executable design. A provider proposes a typed QueryPlan. Application code validates its fields and selects one of two fixed, parameterized SQL templates. The database executes under a restricted user. A small set of paraphrases, number changes and unsafe proposals checks the boundary through real Microsoft Agent Framework function invocation.
The provider is deterministic and scripted. It does not understand English, and the experiment is not a natural-language benchmark. Its purpose is to make the contract after interpretation concrete: which proposal is accepted, which values can reach SQL, which scope is trusted and which evidence proves the returned aggregate is correct.
Split the question into independent decisions
01 / Watch the mechanism
Put a contract between language and SQL
Static view. Play to see how the mechanism unfolds.
The application owns meaning and authority at the execution boundary. A future model evaluation is separate from this deterministic conformance test.
Interpretation and evidence
- Proposal is not authority.
- Values are not SQL syntax.
- Interpretation needs its own evaluation.
The fixture's question has several components. The operation is a regional count and amount sum. The region is a bounded integer. The tenant scope is fixed by the application to tenant one. The query representation is selected by an allowlisted template key. Free-form SQL is not part of the executable contract.
Those components should not become one opaque string. A model can propose a region value without gaining permission to choose a tenant. It can select an approved operation without choosing arbitrary tables. It can express intent without being responsible for SQL syntax that the application has not reviewed.
The actual proposal type is small:
sealed record QueryPlan(string Template,int Tenant,int Region,string Sql="");
The Sql field is intentionally present only to test rejection of a free-form proposal. Any nonempty value is refused. The field is not a fallback path, and the adapter never executes its contents. Keeping that behavior explicit prevents a convenient escape hatch from undermining the typed boundary.
The Tenant field is also not treated as authority. The adapter compares it with the trusted fixture scope, tenant one. A proposal requesting tenant two fails even if its template and region would otherwise be valid. In a production service, the trusted scope would come from authenticated application context rather than a constant, but it should still be independent of the model's suggestion.
The design leaves interpretation as a separate component. A real language model could eventually produce QueryPlan values, but that component would need its own evaluation for ambiguity, paraphrases and unsupported requests. The current experiment tests what happens to the proposed values, not whether a model can infer them reliably.
Keep the executable vocabulary finite
02 / See the idea
A typed record still needs semantic rules
A record type alone does not enforce permission or meaning. The rules determine whether the proposal can reach connection creation.
Interpretation and evidence
- Validate every executable dimension.
- Use trusted tenant context.
- Do not keep a raw-SQL fallback.
The adapter owns a dictionary containing region_summary and region_summary_cast. Each key maps to a complete fixed SQL statement. The normal template compares an integer Region column with an integer parameter. The comparison template converts Region to text and uses a character parameter, allowing the laboratory to inspect a different access pattern for the same result.
The caller cannot provide a table name, column expression, join clause or SQL suffix. Region values are bound through SqlParameter. Tenant filtering is embedded in the approved view definition. The executable vocabulary is therefore finite and reviewable rather than an open-ended SQL language hidden behind a string field.
The validation order is explicit. Free SQL is rejected first, then tenant mismatch, unknown template and out-of-range region. Accepted proposals proceed to connection creation and query execution. Rejected proposals return a structured reason, and the test checks that the SQL execution counter did not change.
The important property is not that the adapter uses an enum or a record by itself. A typed record can still contain dangerous unconstrained fields. The protection comes from the meaning assigned to those fields and the finite mapping from accepted values to application-owned statements.
Likewise, parameterization protects value binding but does not decide authorization. A perfectly parameterized query can still read the wrong tenant if its scope is wrong. The fixture therefore combines trusted-scope comparison, a tenant-specific view and a restricted database principal rather than asking one technique to solve every problem.
The comparison template is deliberately approved for the experiment. A production application might not expose a slower diagnostic shape to normal users at all. Its presence here is not an argument for letting a model choose arbitrary query rewrites. It is a controlled alternative whose semantics and cost can be measured.
Exercise the real tool protocol without claiming language intelligence
The scripted IChatClient emits a FunctionCallContent for query_orders with the predetermined proposal. FunctionInvokingChatClient performs the tool invocation, and ChatClientAgent supplies the agent/session layer. After observing the function result, the provider returns a fixed acknowledgement.
Each case requires exactly two provider calls and one tool call. Those assertions prove that the function-call round trip happened through the actual framework rather than being replaced by a direct adapter invocation. The pinned packages are Microsoft.Agents.AI 1.28.0 and Microsoft.Extensions.AI 11.0.0. Microsoft Agent Framework package, Microsoft.Extensions.AI package
The English question in each test is paired with a known proposal. The provider does not parse the text. This is a protocol fixture: it verifies that equivalent proposals behave equivalently and unsafe proposals are rejected, not that a model has learned a paraphrase distribution.
That limitation is useful when interpreting a green result. A test named What is our region 3 total can pass even though no natural-language understanding occurred. The evidence should say exactly that. Otherwise a deterministic application test can accidentally become a marketing claim about model quality.
The same separation improves future evaluation. Keep the adapter conformance tests stable, then add a model-facing test that measures how often real questions produce the intended typed plan. When a case fails, the team can distinguish interpretation failure from adapter validation, permission or database-result failure.
This is a better debugging boundary than a single end-to-end assertion that the final prose looks reasonable. A plausible sentence can hide the wrong query, and a correct query can be wrapped in a misleading explanation. The current fixture records authoritative tool results without asking the scripted provider to invent a factual answer.
Define an independent result oracle
03 / A concrete example
Empty authorized data is a valid result
The region-four result does not trigger a search in another tenant. The oracle distinguishes an empty success from a rejected scope.
Interpretation and evidence
- Check the empty case.
- Keep scope unchanged.
- Use an independent expected result.
The database contains ten thousand synthetic rows. Identifier i belongs to tenant i modulo two, region i modulo ten and amount i modulo one hundred plus one. The approved tenant-one view therefore exposes the odd identifiers.
For region three, the expected count is one thousand and the expected amount sum is 49,000. For region five, the count is one thousand and the total is 51,000. Region four has no rows in tenant one's view because that region corresponds to even identifiers in this fixture, so the expected count and total are both zero.
The empty case matters. A tool should not confuse a valid query returning no authorized rows with a failed query or an invitation to widen scope. The SQL uses COALESCE around the sum so that the response contract returns zero rather than leaving the application to invent a meaning for a null aggregate.
The oracle is calculated in C# from the generator's rule. It is independent of the SQL statement and does not compare one query only with another query that could share the same error. Every accepted tool result must match the expected count and sum.
The fixture's tenant-region correlation is deliberately simple, not representative of every business dataset. It gives the empty-result test a clear answer. A production evaluation should include its actual distributions, boundary values and authorization rules rather than assuming this arithmetic models them.
A count and sum are sufficient for this aggregate contract, but they would not validate an arbitrary row export or ranking. The expected result must match the operation's semantics. Adding more checks without identifying the contract can produce a large test suite that still misses the result users care about.
Read the nine proposal outcomes as a contract matrix
04 / A concrete example
Count execution after the decision
The function-call round trip completes in both outcomes. The distinction is visible in the query counter rather than inferred from prose.
Interpretation and evidence
- Refusal is a normal tool result.
- Check zero database executions.
- Do not call scripted cases language accuracy.
The executed cases contain five accepted proposals and four rejected proposals. Two differently worded region-three requests share the same typed plan and return the same aggregate. A region-five request changes the bounded value and receives the corresponding result. A region-four request returns the valid empty aggregate. The approved conversion template preserves the region-three result while changing the access work.
The rejected cases request another tenant, supply free-form SQL, use an unknown template and specify a region outside zero through nine. Each returns a distinct rejection reason before SQL execution. The framework still completes its function-call round trip, so rejection is a normal tool result rather than an unhandled transport failure.
| Proposed difference | Result | SQL queries executed |
|---|---|---|
| Equivalent region-three wording | Same count 1000 and total 49,000 | 1 per accepted case |
| Region changed to five | Count 1000 and total 51,000 | 1 |
| Region four in approved tenant | Count 0 and total 0 | 1 |
| Approved conversion template | Same region-three aggregate | 1 |
| Tenant changed to two | tenant_scope_mismatch | 0 |
| Nonempty SQL text | free_sql_forbidden | 0 |
| Unknown template | unknown_template | 0 |
| Region outside supported range | region_out_of_range | 0 |
The table describes actual checks, but it is not a statistical accuracy report. There are nine hand-selected cases, not a representative corpus of user language. The deterministic provider makes the expected proposal known in advance. The value is the explicit executable boundary and its negative paths.
The rejected SQL string contains a destructive statement as test data. It is never executed through the proposal path. Separate database-permission tests issue fixed laboratory-owned statements under the restricted principal to verify the engine's authority boundary. Keeping those two tests distinct avoids confusing input rejection with permission enforcement.
Equivalent results can still choose different work
05 / A concrete example
Review query diversity deliberately
The application can prefer a stable reviewed template instead of generating a new shape for each paraphrase. This SQL evidence does not validate another backend.
Interpretation and evidence
- Separate semantics from cost.
- Keep query families finite.
- Evaluate another engine separately.
Both approved region-three templates return one thousand rows in the aggregate count and an amount total of 49,000. Their actual SQL plans are not identical in work, even though both contain an Index Seek.
The integer template reads one thousand rows at the access operator and produces one thousand. The text-conversion template reads five thousand rows and produces the same one thousand. Their diagnostic logical reads are six and seventeen respectively. Both captured executions report zero physical reads.
The index covers Tenant and Region and includes Amount. The conversion template can still use the tenant prefix while requiring more work to evaluate the region condition. The correct conclusion is not simply that conversion always means scan; this actual plan still uses a seek. The rows-read evidence explains the difference more precisely than the operator label.
This matters for intent contracts because semantic equivalence does not establish performance equivalence. Two approved representations can answer the same question while consuming different resources. The application can choose a canonical template based on measured behavior rather than letting superficial wording determine SQL shape.
The diagnostic capture uses STATISTICS XML and STATISTICS IO separately from the timing loop. Actual plans are saved, and missing per-node counters remain unreported rather than being converted to zero. The analysis therefore keeps the database's observed work separate from a general claim about all possible optimizer decisions. Microsoft: STATISTICS XML
There is no Kusto engine in this experiment. The general idea of typed intent could be applied to KQL, but no KQL query, permission model or execution plan is validated here. A SQL result should not be presented as evidence that another query language or backend behaves the same way.
Make scope an input from the application, not the conversation
The proposal's tenant value is checked against the application-owned scope. It is not trusted because the question says my tenant or because the provider included a familiar identifier. The database view adds another fixed boundary by filtering the base table to tenant one.
The effective SQL user is AgentReader, created without a login inside the fixture database. A fresh connection switches to that user with NO REVERT before the approved query executes. The harness verifies the user name and tests that other-tenant and direct base-table reads are denied.
This is an actual database permission test, but it is still a laboratory hosting arrangement. The trusted harness creates the database with administrative credentials and then impersonates the restricted user. It is not a deployment where the model process has only a separately provisioned low-privilege login. The article does not claim that arbitrary code execution in the host would be contained by the tool's data contract.
That distinction is important. Application validation constrains proposed tool arguments. Database permissions constrain statements executed in the selected context. Process and credential isolation are another boundary. A secure production design should decide all three rather than describe one successful impersonation test as complete isolation.
The diagnostic-summary view exposes an approved object label and the fixture's row count. That intentionally permitted metadata is different from access to another tenant's order rows. Scope should be defined in terms of the data and metadata the tool may return, not only a binary read-only label.
The conversation remains useful for expressing a question, but it is not the source of authority. A user instruction embedded in a proposal cannot expand the tenant scope or add a new executable template. The application must make those changes through its own reviewed configuration and permission process.
Decide what to do with ambiguity before adding a model
A typed plan does not remove ambiguity from language. It gives the application a place to represent or reject ambiguity before execution. If a real question could mean two regions, two time ranges or two metrics, the proposer needs a way to request clarification or return an unsupported-intent result.
The current record has no time range because the fixture's operation does not require one. A production extension should not add an unconstrained natural-language date string and assume the problem is solved. It should define units, inclusivity, time zone and range bounds as part of the executable contract.
Similarly, adding a metric field requires deciding which aggregates are allowed and how their semantics differ. Count of rows, count of distinct orders and count of completed operations are not interchangeable merely because all return integers. A typed vocabulary should preserve those distinctions instead of mapping them to whichever SQL function is easiest to generate.
The empty-result case is a good example of a decision that belongs in the contract. Region four returns no rows for the approved tenant. The adapter does not search another tenant to find a more satisfying answer. A model-facing answer can explain the empty authorized result, but it must not silently change scope to avoid disappointing the user.
An unsupported template is also a meaningful outcome. The application can refuse a request it cannot express safely rather than passing raw SQL through a fallback. That refusal preserves the boundary while giving the product a concrete signal about which new capability might be worth implementing.
The next step is then a reviewed template, result contract and test set. It is not a prompt instruction asking the model to be more careful with an unbounded execution channel. The former changes the application's capabilities; the latter only changes how an unconstrained proposal is worded.
Evaluate interpretation and execution separately
When a real model is introduced, the evaluation should retain the current conformance layer. Given an exact QueryPlan, does the adapter accept or reject it correctly, bind the intended values and return the independent expected result? Those tests can remain deterministic.
A separate interpretation evaluation can ask whether the model produces the expected plan for a collection of questions. Include equivalent wording, numeric changes, ambiguous scope, unsupported operations and malicious-looking instructions. The expected answer may be a refusal or clarification rather than a query plan.
The two layers should have separate failure labels. A model that chooses the wrong region is not the same defect as a tool that binds the right region with the wrong SQL type. A model that proposes another tenant is not the same defect as a database user that can read it. Combining them into one final-answer score hides the repair location.
The final prose answer is another layer. A correct aggregate can still be explained with the wrong units or an unsupported causal claim. The fixture's scripted provider avoids that issue by acknowledging the authoritative tool result rather than generating a narrative. A real product must evaluate the explanation contract as well.
This layered approach does not require every stage to be perfect before useful work begins. It makes uncertainty local and reviewable. The application can improve interpretation while retaining a stable execution boundary, or optimize a query template while preserving the same intent and result tests.
The current experiment supplies the executable core for that progression. It is a small complete path through a real framework and real database, with accepted and rejected proposals, exact results, actual plans and permission evidence. Its limits are explicit enough that a later model evaluation can extend it without rewriting what the original evidence proved.
Version the intent contract when its meaning changes
A finite template dictionary is easier to review than arbitrary SQL, but it can still change meaning over time. A template named region_summary might initially include every order and later include only completed orders. Keeping the same key while changing that semantic boundary could make old conversations and cached plans misleading.
The fixture does not implement a versioned deployment protocol, but it exposes where one belongs. The plan vocabulary, parameter meaning and result schema form a contract. If the implementation changes the meaning of count or total, the caller needs a way to distinguish the new operation from the old one. A code hash can support provenance, while an explicit contract version can support application behavior.
Performance-only changes need care too. Replacing the conversion template with the integer template preserves this fixture's result, but the proof depends on the parameter domain and view definition. An apparently equivalent rewrite should pass the same independent result cases, including the empty authorized result, before it is promoted as a better implementation.
The database permission boundary should be reviewed with the contract change. Adding a new view or widening a scope is not merely another prompt capability. It changes what the effective principal can observe. The negative tests should continue to reject the adjacent forbidden scope after the new approved operation is added.
A rejected plan should remain distinguishable from an empty successful result across those versions. Region four returns a valid zero in this fixture; tenant two is not queried at all. Collapsing both into an empty response would remove information needed for authorization review and make the caller guess whether the question was answered.
This is also where a useful audit record becomes possible. Record the accepted template key, bounded values, trusted scope and authoritative result, along with the implementation version. That record is more interpretable than storing only the original question or only the final prose answer. It shows which executable meaning the application actually accepted.
The record should avoid storing unnecessary sensitive content. The fixture's values are synthetic, but a production question can contain private information unrelated to the aggregate. Typed intent can reduce what needs to be retained for reproducibility: the approved operation and parameters may be sufficient without preserving the entire conversation.
The broader lesson is that constrained execution is a maintained interface, not a one-time validation function. Its usefulness comes from keeping semantics, authority and evidence aligned as the application evolves. A model can change how the proposal is produced, but the application still owns that alignment.
Prefer a reviewed query family to accidental syntax diversity
The most useful outcome is not that the fixture understands nine questions. It does not. The outcome is that nine predetermined proposals pass through one stable contract and produce explainable accepted or rejected results. Five reach approved SQL; four do not reach the database at all.
The two equivalent region-three templates also show why query diversity should be intentional. Different syntax can preserve the answer while increasing source work. A canonical application-owned template gives performance review a stable target instead of making every paraphrase another query-shape experiment.
The real framework invocation matters because it verifies the tool protocol that a future provider will use. The deterministic provider matters because it prevents that protocol evidence from being confused with model intelligence. The restricted database identity matters because a validation mistake should not automatically become unrestricted data access.
Together, those boundaries make the system easier to reason about. Language proposes intent. The application decides whether that intent is supported and authorized. Fixed SQL implements the approved operation. The database returns a result checked against the contract. The final explanation should preserve those facts rather than blur them into a fluent answer.
That is a practical way to let an agent ask useful questions of data without making generated SQL the authority for what the system is allowed to do.
Source code and execution evidence
Download the complete lab, source record and raw execution results. This package supports the specific execution claims in this article. It is not a production certification.