* 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> |
||
|---|---|---|
| .claude-plugin | ||
| .github | ||
| community | ||
| custom | ||
| docs | ||
| evaluation | ||
| microsoft | ||
| schemas | ||
| skills | ||
| tools | ||
| .gitignore | ||
| CODEOWNERS | ||
| LICENSE | ||
| plugin.json | ||
| README.md | ||
| SECURITY.md | ||
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.