Surface KQL language rules to the query-writing agent plugins - #2234
Conversation
…them The KQL rules from the coding guidelines (#2223) live in docs-wiki and AGENTS.md, which contributors and repo coding agents read but shipped plugin agents never load. The ftk-database-query agent and the finops-toolkit skill generate ad-hoc KQL at runtime and would reproduce the exact pitfalls fixed repo-wide in #2189/#2220/#2225 (bare joins defaulting to innerunique, tolower() comparisons, contains vs has, fullouter without key coalescing). Distill the runtime-relevant rules into the KQL language rules section of finops-hub-database-guide.md, which the skill task routing loads before any query is written, and reference it from the agent's operational guidelines. Both agent-skill structures (agent-skills today, agent-plugin after #2167) link to src/queries, so the rules survive the plugin restructuring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the FinOps hubs query guidance so shipped query-writing agents (not just contributors/coding agents) load a distilled set of KQL correctness rules alongside the hub schema, reducing the likelihood of known KQL pitfalls in newly generated ad-hoc queries.
Changes:
- Added a concise “KQL language rules” subsection to the hub database query guide under “Query best practices”.
- Updated the
ftk-database-queryagent operational guidelines to point to (and inline-highlight) the highest-impact KQL rules.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/templates/claude-plugin/agents/ftk-database-query.md | Adds an operational guideline directing the agent to apply the KQL rules from the query guide when generating queries. |
| src/queries/finops-hub-database-guide.md | Introduces a “KQL language rules” section and records the change in the guide’s changelog. |
…cy example note, markdownlint - Reword the case-insensitivity rule so it no longer claims every plain operator is case-insensitive (== and in are not); scope the claim to matching operators with the _cs/equality forms as the opt-in. - Add an explicit note that the legacy 'join ... on 1 == 1' example further down is replaced by toscalar() in #2225 and must not be copied. - Fix MD036 (bold-as-heading) and align the new change log row's table pipes with the header (MD060). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rule itself already states the pattern is invalid; the note would go stale the moment #2225 replaces the example it points at. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'on 1 == 1 is invalid KQL' clause was trivia about an edge case, not a widespread bad practice; the actionable part is computing totals once with toscalar() instead of joining an aggregate subquery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Michael Flanakin (flanakin)
left a comment
There was a problem hiding this comment.
🤖 [AI][claude] PR Review
Summary: Good idea and mostly solid, technically accurate rules (verified against Microsoft's KQL docs — join/lookup semantics, case sensitivity, and dedup guidance all check out). One example in the new content contradicts how has actually works and should be fixed before this ships into agent context; one small formatting issue and one imprecise ARG claim are worth a look too.
🚫 Blockers (1)
- The
hasexample in "String matching" uses a multi-segment path as the needle, buthasonly matches whole terms (alphanumeric runs) — this example won't work as described.
⚠️ Should fix (1)
- Missing blank line before the "Azure Resource Graph is different" paragraph causes it to merge into the preceding bullet list on GitHub's renderer.
💡 Suggestions (1)
- The ARG "at most 3 joins per query" claim is a bit imprecise per Microsoft docs.
…ng blank line Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8f79334
into
dev
|
All Contributors (@all-contributors) please add Roland Krummenacher (@RolandKrummenacher) for code |
|
@microsoft-github-policy-service[bot] Roland Krummenacher (@RolandKrummenacher) already contributed before to code |
🛠️ Description
Follow-up to #2220 / #2223 / #2225. The KQL rules added to the coding guidelines in #2223 live in
docs-wiki/Coding-guidelines.mdandAGENTS.md— contributors and repo coding agents read those, but the shipped plugin agents never load them. Theftk-database-queryagent generates ad-hoc KQL againstCosts()/Prices()/etc. at runtime and would reproduce exactly the pitfall classes fixed repo-wide (barejoindefaulting toinneruniqueand silently dropping rows,tolower()in comparisons,containswherehasis meant,fullouterwithout key coalescing). #2225 fixes the example queries in the skill references, but examples don't immunize newly generated queries — the rules themselves need to be in the context the agent loads.This PR puts a distilled, runtime-relevant subset of the rules where query-writing agents already look:
src/queries/finops-hub-database-guide.md— new KQL language rules subsection under Query best practices: case-insensitive operators (nevertolower()in comparison position),hasvscontainsby matching intent, explicitjoin kind=always,lookupfor small-dimension enrichment with atake_any-deduped right side,leftantifor exclusions, key coalescing afterfullouter,toscalar()for grand totals, plus a short Azure Resource Graph caveat (nolookup, no semi/anti flavors, 3-join limit). This file is what thefinops-toolkitskill's task routing loads before writing any KQL, so the rules ride along with the schema.src/templates/claude-plugin/agents/ftk-database-query.md— new operational guideline pointing at that section, with the three highest-impact rules inlined.Placement rationale
src/queriesvia links from both the currentagent-skillsstructure and the restructuredagent-pluginlayout in feat(plugins): add FinOps Toolkit agent plugins #2167, so the rules survive the plugin move without duplication. cc Brett Wilson (@MSBrett) — when feat(plugins): add FinOps Toolkit agent plugins #2167 lands, the same one-line pointer belongs inftk-database-query.agent.md.join on 1 == 1pattern ondev; Fix KQL join pitfalls and adopt lookup for dimension enrichment #2225 replaces it withtoscalar(). Until then the new rules section and that example briefly disagree — intentional, to avoid editing the same lines in two open PRs.📷 Screenshots
N/A — documentation only.
🙋♀️ Ask for the community
Review whether the distilled rule set is the right size — it's loaded into agent context on every query-writing task, so it's deliberately terse compared to the full guidelines in #2223.
🤖 Generated with Claude Code