Technology Aug 24, 2026 · 5 min read

How I turned 200+ BCQuality knowledge files into 26 AL rules (and rejected most of the rest)

I just shipped AL Griller, a static analyzer for Dynamics 365 Business Central AL code that roasts you when it finds a real problem. Before I talk about the jokes, I want to talk about the boring part, because the boring part is the reason the jokes are trustworthy: how the 26 rules actually got cho...

DE
DEV Community
by Yahya Touil
How I turned 200+ BCQuality knowledge files into 26 AL rules (and rejected most of the rest)

I just shipped AL Griller, a static analyzer for Dynamics 365 Business Central AL code that roasts you when it finds a real problem. Before I talk about the jokes, I want to talk about the boring part, because the boring part is the reason the jokes are trustworthy: how the 26 rules actually got chosen.

Disclosure up front: AL Griller's rule research was built by working through Microsoft's BCQuality repository - a curated knowledge base and skills library for Business Central quality. Full credit to the BCQuality team and community for that research. AL Griller is an independent, community-run open-source project. It is not a Microsoft product and there's no official partnership.

The starting point

BCQuality is big - north of 200 knowledge files across 14 domains (performance, query, data modeling, error handling, events, security, and more). Not every one of those files can become a static analysis rule. A lot of them describe judgment calls: "reorder this switch by frequency, but only if profiling shows it's hot," or "pick the right key based on read/write ratio." Real advice, completely useless as a line-matching rule, because it needs information a single-file text scanner will never have.

So the research pass wasn't "convert every file to a rule." It was a filter, applied file by file:

  1. Is this a meaningful practice?
  2. Is it deterministic?
  3. Is it detectable from AL source without AI?
  4. Are false positives controllable?
  5. Is it explainable?
  6. Is it testable?
  7. Is it already covered by a Microsoft analyzer (CodeCop / AppSourceCop / PerTenantExtensionCop / UICop)?

Full reads went into Performance (54 files), Query, Data Modeling, Error Handling, the community layer, and the Events files specific to loop/database behavior. Security got a representative sample (8 of ~20 files, chosen for deterministic detectability). Domains like Privacy, Telemetry, Testing, and Interfaces got only a file-listing pass - flagged as future research, not "nothing there."

What survived

Everything that passed the filter got classified STRONG / GOOD / EXPERIMENTAL, and every rule that actually shipped got a priority: P0 or P1.

  • P0 (12 rules) - purely syntactic or local to a single procedure/trigger, with short, reliable false-positive carve-outs.
  • P1 (14 rules) - still deterministic, but needs cross-statement ordering within a procedure, a light heuristic, or one extra piece of context.

That's the entire shipped set: 26 rules, ALGRILL001ALGRILL026. No P2 or P3 rules made it into rules.json. That was a deliberate call - the project's own research doc calls it "trust over rule count." A rule that's right 80% of the time and annoying the other 20% erodes trust in every other rule it ships next to.

What got rejected outright

A handful of well-documented BCQuality patterns were investigated and explicitly rejected - not deferred, rejected - because they fail on a fundamental axis rather than just confidence:

  • Error message tone (internal vs. client-facing) - requires judging the tone of English prose. Not a syntactic pattern.
  • Hand-rolled validation error accumulation - the anti-pattern has too many unrelated shapes (a List, a TextBuilder, a temp table, plain concatenation) to match reliably.
  • Case-branch reordering by frequency - the source article itself says this is only justified when profiling shows a hot path. Not statically detectable, and explicitly called out as "not a default review finding."
  • SetCurrentKey alignment with filters - picking the "right" key requires understanding business-relevant filter/sort intent that isn't recoverable from source. The original task brief flagged this one specifically as a trap: don't manufacture "SetCurrentKey after FindSet = bad" out of it.

What's deferred, not rejected

A separate bucket - real, well-evidenced findings that didn't clear the bar this pass, usually because reliable detection needs cross-object context a single-file scanner can't resolve:

  • N+1 Get()/FindFirst() in a loop, refined by "and a query/dictionary would have collapsed it" - needs join-feasibility awareness across tables.
  • Missing SetLoadFields() - the source article lists four separate suppression conditions (field count, field-read percentage, loop iteration bound, temp/singleton exemption). Shipping without all four would produce exactly the false-positive fatigue the project was trying to avoid.
  • Setup-table singleton detection - currently only a naming heuristic (*Setup, blank Code[10] key), with real false-positive risk on legitimately multi-row tables that happen to end in "Setup."

These are recorded in the research doc specifically so a future contributor doesn't have to re-derive them from scratch.

Why this matters for the roasts

Every AL Griller finding carries a joke, but the joke only exists because the pattern underneath it survived that filter. ALGRILL003 doesn't say "consider CalcSums." It says CalcFields() "got summoned once per row like a tiny genie who can only grant one wish before vanishing back into the lamp, forever, on repeat" - and then, one click away under "Technical details," the actual mechanism: one SQL round trip per row vs. one aggregate query. The joke is decoration. The finding underneath has to survive the same bar CodeCop's own rules would.

Where this goes next

BCQuality is an active, growing project, and AL Griller's rule set is meant to track it over time rather than freeze at v1.0.0. If you work in AL and know a pattern that should be a rule - or have a better roast for an existing one - PRs are genuinely welcome. New rules need the same false-positive discipline described above; new roasts just need to be specific to the pattern, not generic.

Repo: https://github.com/yahyatouil-dev/al-griller
BCQuality (the research this is built on): https://github.com/microsoft/BCQuality
My Blog: https://yahyatouil.com

DE
Source

This article was originally published by DEV Community and written by Yahya Touil.

Read original article on DEV Community
Back to Discover

Reading List