Quality skills and knowledge for Business Central development. The shared bar for humans and agents alike.
Find a file
Michael Dieringer 830eaff68f
3 AL/BC testing patterns from an external BC testing expert's blog (Luc van Vugt, fluxxus.nl) (#159)
* Add 4 more AL/BC testing patterns from Luc van Vugt's fluxxus.nl blog

Fourth batch from CURABIS ApS, mined from an external BC/NAV testing expert's blog archive (fluxxus.nl). Confirm+StrSubstNo interaction with ConfirmHandler, Table Relation Test's OnAfterRemoveTableRelation exclusion hook (verified against BCApps source, codeunit 134926), committing shared lazy-Initialize fixture data, and Assert.IsFalse vs asserterror for boolean checks.

* Address Jesper Schulz-Wedde's review on PR #159

- transactionmodel-attribute-governs-test-transactions.md: the "Commit
  causes an error" behavior is specific to an explicitly declared
  AutoRollback attribute. A test method with no TransactionModel
  attribute at all is a distinct, valid shape — BCApps' own
  codeunit 134915 "ERM Online Mapping Setup" commits inside a lazy
  Initialize() with no attribute declared, cleaning up via a manual
  asserterror at the end. Evidence for commit-shared-test-fixture-
  inside-lazy-initialize.md (this PR), which is correct as submitted.
- confirm-needs-strsubstno-before-confirmhandler-sees-substituted-text.md:
  reframe as a known, unconfirmed-fix platform defect
  (microsoft/ALAppExtensions#23935) rather than designed behavior; add
  the Message/MessageHandler asymmetry as supporting evidence.
- table-relation-test-exclude-known-invalid-relations-via-event.md:
  note the test-app-only consumer dependency; correct "walks every
  TableRelation field property in the app" to the actual tenant-wide
  Table Relations Metadata scope across installed apps.
- Wire confirm-needs-strsubstno, commit-shared-test-fixture-inside-
  lazy-initialize, and table-relation-test-exclude-known-invalid-
  relations-via-event into al-testing-review.md's candidate-selection
  cues.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Address second round of Jesper Schulz-Wedde's review on PR #159

- commit-shared-test-fixture-inside-lazy-initialize.md: fundamentally
  rewritten. AutoCommit is the documented default TransactionModel, not
  AutoRollback. Explains the real mechanism (Commit() protects a fixture
  from the test method's own later deliberate rollback, per Codeunit.Run/
  TransactionModel-property semantics) and the TestIsolation dependency
  (Disabled/Codeunit survive across methods, Function does not). Fixtures
  rewritten to demonstrate the actual failure/success shape.
- transactionmodel-attribute-governs-test-transactions.md: now states the
  AutoCommit default explicitly and agrees with the article above, closing
  the contradiction Jesper flagged between the two testing articles.
- Deleted confirm-needs-strsubstno-before-confirmhandler-sees-substituted-text
  (.md/.good.al/.bad.al): the underlying platform bug (microsoft/
  ALAppExtensions#23935) was closed as completed in Feb 2024; cannot be
  reproduced or bc-version-pinned on any currently supported version.
- table-relation-test-exclude-known-invalid-relations-via-event.md: added
  the [Scope('OnPrem')] boundary verified against BCApps' Table Relation
  Test codeunit.
- use-assert-isfalse-not-asserterror-for-boolean-checks.md: added a Scope
  section resolving the overlap with asserterror-needs-expectederror-and-code.
- al-testing-review.md: fixed the shared-fixture cue to catch the actual
  anti-pattern instead of the compliant shape, added the missing cue for
  use-assert-isfalse-not-asserterror-for-boolean-checks, wired precedence
  between it and the generic asserterror rule, and removed the cue for the
  deleted article.
- Added in-file Source provenance (specific fluxxus.nl post per article,
  with what was independently verified vs. taken from the post) to the
  three surviving externally-inspired articles, per Jesper's request that
  provenance live in the knowledge file itself, not only the PR description.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix remaining correctness issues from Jesper's 2026-09-15 re-review

- commit-shared-test-fixture-inside-lazy-initialize: three sub-issues.
  Recommended TestIsolation = Codeunit instead of listing Disabled as an
  equal option - Disabled never rolls back at all ("tests are not
  isolated from each other" per the property's own docs), so a fixture
  this pattern commits under Disabled is permanent database
  contamination unless something else tears it down; Disabled is now
  only mentioned alongside that explicit teardown requirement. Added
  precedence in al-testing-review.md so the deliberate end-of-test
  asserterror Error(...) rollback sentinel isn't also flagged by the
  generic asserterror-needs-expectederror-and-code rule. Rewrote both
  fixtures to actually demonstrate the pattern: persisted fixture data
  (an Item record) instead of an empty comment, a second [Test] method
  that depends on the fixture surviving into it, and an explicit
  Subtype = TestRunner / TestIsolation = Codeunit runner codeunit.

- table-relation-test-exclude-known-invalid-relations-via-event:
  the length/type rule was stated as one global requirement. Verified
  ValidateFieldRelation in codeunit 134926 directly (BCApps reference
  clone) and split it into the two branches the source actually has:
  a field with any unconditional relation needs exact length and exact
  resolved type; a field whose relations are all conditional only fails
  on being shorter (longer is fine) than the largest related field, and
  when the required type is specifically Code, a Text source passes too
  - a tolerance that does not apply on the unconditional side and does
  not extend to a required Text.

Rebased onto upstream/main (one conflict in
transactionmodel-attribute-governs-test-transactions.md - upstream had
already linked its sample references via the READ convention, ours
added a Source section; merged both). Also converted the 3 remaining
plain-backtick sample references in this PR to the READ-convention
markdown-link form, same fix as #156/#157/#158.

* Fix four merge-critical issues from Jesper's 2026-09-22 review

- al-testing-review.md: the generic ExpectedError cue's asserterror
  Assert.IsTrue/IsFalse exclusion was unconditional, but the
  specialized rule it deferred to only claims the pure-inversion
  shape. A test expecting the guarded Boolean-returning call itself to
  raise fell through both routes. Narrowed the exclusion to the same
  inversion-only condition the specialized cue already uses.
- asserterror-needs-expectederror-and-code.md: the rollback-sentinel
  exception (a trailing asserterror Error(...) used purely to force a
  fixture rollback, not to verify a specific failure) previously lived
  only in skill routing prose. Encoded it directly in the article's
  Anti Pattern section so every consumer of the knowledge base sees it,
  not just this one skill.
- commit-shared-test-fixture-inside-lazy-initialize.good.al/.bad.al:
  replaced hand-rolled Item.Init()/Insert(true) with
  LibraryInventory.CreateItem, so the canonical fixture doesn't itself
  trigger use-library-codeunits-for-test-fixtures.
- table-relation-test-exclude-known-invalid-relations-via-event.good.al/
  .bad.al: declared minimal "Sample Setup"/"Sample Header" tables
  inline instead of referencing undefined symbols, matching this
  repo's own convention that every fixture is self-contained.

* Give the table-relation-test fixtures a real relation to exclude and one to protect

The "Category Code" field had no TableRelation at all, so the good
subscriber's RemoveTableRelation call targeted metadata that never
existed - a no-op. Added a real TableRelation to "Sample Setup" on
that field (the one known exception to exclude) and a second,
ordinary self-referencing relation ("Parent No." -> "Sample
Header"."No.") with no exception. The good fixture now removes only
the first; the bad fixture's table-wide removal (field/related
table/field all 0) now demonstrably also strips the second, showing
the actual anti-pattern instead of removing nothing meaningful.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-29 17:13:06 +02:00
.claude-plugin Simplify standalone AL code review skill (#150) 2026-09-03 10:25:44 +02:00
.github Strengthen review contracts and add AL reliability guidance (#196) 2026-09-29 13:03:39 +02:00
community Add AL-focused AppSource validation guidance (#142) 2026-09-14 12:42:45 +02:00
custom Improve partner onboarding and documentation navigation (#174) 2026-09-09 17:31:03 +02:00
docs Strengthen review contracts and add AL reliability guidance (#196) 2026-09-29 13:03:39 +02:00
evaluation Strengthen review contracts and add AL reliability guidance (#196) 2026-09-29 13:03:39 +02:00
microsoft 3 AL/BC testing patterns from an external BC testing expert's blog (Luc van Vugt, fluxxus.nl) (#159) 2026-09-29 17:13:06 +02:00
schemas Add machine-readable review contracts (#182) 2026-09-15 10:27:40 +02:00
skills Strengthen review contracts and add AL reliability guidance (#196) 2026-09-29 13:03:39 +02:00
tools Strengthen review contracts and add AL reliability guidance (#196) 2026-09-29 13:03:39 +02:00
.gitignore Own the knowledge-index generator + index-aware review skills (#25) 2026-06-04 15:02:12 +02:00
CODEOWNERS Fix CODEOWNERS: correct @jeschulz -> @jesperschulz on base rules (#53) 2026-06-25 14:28:48 +02:00
LICENSE Add initial project structure with .gitignore, LICENSE, README, and CODEOWNERS 2026-04-17 05:56:10 +02:00
plugin.json Simplify standalone AL code review skill (#150) 2026-09-03 10:25:44 +02:00
README.md Add SCM functional knowledge domain (#192) 2026-09-21 10:16:44 +02:00
SECURITY.md Microsoft mandatory file 2026-04-17 03:58:13 +00:00

BC Quality - Don’t teach one agent. Teach the ecosystem. 🤝

Quality skills and knowledge that help AI tools make better Business Central development decisions: catch BC-specific defects, avoid misleading advice, and explain findings with references you can read.

BCQuality contains knowledge and reusable skills, not agents or a Business Central extension. Your host supplies the agent. You can install the content as a plugin, use it from another integration, or browse the knowledge directly.

Quick start

The walkthrough below uses GitHub Copilot CLI in a terminal, not the Copilot Chat panel in VS Code. First install Copilot CLI and sign in. Your account and organization policy must allow its use. You do not need to clone BCQuality, build a runner, or deploy an app to Business Central for this source-review example.

Standalone plugin installation

Run these commands in your terminal:

copilot plugin install microsoft/BCQuality
copilot plugin list

The list should include bcquality. The plugin currently exposes the al-code-review skill. Installation and skill discovery are the general pattern; reviewing an app is one example of using it.

Example: Review a complete app folder

Start a new CLI session in your own app folder, replacing the example path:

cd "C:\Repos\MyBusinessCentralApp"
copilot

Approve access only to a project you trust, then ask:

Use the installed al-code-review skill to review the complete Business Central app in this folder without changing my source files. Return the complete BCQuality findings report.

The folder should contain app.json and your AL source; it does not need to be a Git repository. On macOS or Linux, use your app's local path instead.

Expect a report for each selected review, with findings, source locations, severity, confidence, and references to the relevant guidance. Some hosts show the structured JSON directly. completed with no findings means nothing was flagged in that review's scope; partial or failed is not a clean result. See reading your results.

PowerShell 7 (pwsh) is recommended for fast knowledge discovery. If it is unavailable, the review can still discover knowledge by reading the folders.

Documentation

I want to... Start here
Choose direct reading, a supplied skill, or my own agent Ways to use BCQuality
Review a file, changes, a branch, or a particular concern Using BCQuality
Resolve setup problems, incomplete reviews, or incorrect findings Troubleshooting and support
Browse the available guidance Knowledge by domain
Configure the plugin or use my organization's rules Customizing BCQuality
Contribute knowledge or improve a rule Your first contribution
Connect a host, agent, or CI integration Minimal integration example

All documentation and technical references.

Scope

Today's curated content covers technical AL code review and a focused Supply Chain Management (SCM) functional domain. It augments the agent's judgment; it is not an exhaustive BC manual or a substitute for compilation, analyzers, tests, or human review. See coverage and limits for the available domains and the difference between a folder review and a comparison. Mechanical issues already enforced by the AL compiler or standard analyzers are intentionally left to those deterministic tools rather than duplicated here.

The SCM domain covers selected inventory, costing, reservation, tracking, and warehouse/posting workflows, not exhaustive supply chain validation. Broader functional coverage such as Finance, Manufacturing, Jobs, and Service, and technologies such as PowerShell, pipelines, and Power Platform, remain valid future scope, not current coverage claims.

What's in this repo

Knowledge articles cover one concern each. Skills tell an agent how to find and apply the relevant knowledge. Both live in three layers:

Layer Purpose
Microsoft Microsoft-endorsed skills and their knowledge.
Community Community-owned skills and their knowledge.
Custom Organization-specific additions and overrides in your own fork.

All three are enabled by default; Custom is empty upstream. You do not need to configure layers to get started.

Versioning

Update the installed plugin from your terminal, then start a new session:

copilot plugin update bcquality

Plugin versions and content-release tags are different. For reproducible runs and organization forks, see updates and versions.

What belongs here

Knowledge belongs here when it prevents a BC-specific mistake an otherwise capable agent would make, including false-positive findings. BC facts belong in knowledge articles, not skill instructions. See the admission test and examples.

Contributing

Partners are welcome to contribute to the layer that owns the domain, regardless of affiliation. Start with the contribution guide. To report a problem without authoring a rule, see support.

License

MIT