Complete AL review knowledge readiness (#108)
Some checks failed
Validate knowledge index / validate-index (push) Has been cancelled
Validate AL review fixtures / validate-review-fixtures (push) Has been cancelled
Validate frontmatter and structure / validate (push) Has been cancelled

* Complete AL review knowledge readiness

Fill telemetry and Query coverage, strengthen thin review domains, correct audited content defects, and add deterministic cheap-model evaluation and reference-integrity safeguards.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Generalize review fixture discovery

Derive smoke cases from the leaf, domain, and paired-sample conventions so new leaves require no scoring-contract changes. Keep only exceptional selection/context overrides and fail when retrieval metadata cannot rank the selected article.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Preserve published field IDs in sample

Keep the existing Email and Contact Email field IDs unchanged, clarify that the sample represents an independent baseline, and use a local breaking-change rule for the generic smoke evaluation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Clarify published field identity rules

State explicitly that a published field keeps its ID, name, and type while a replacement is added as a separate field under an unused ID.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Align field obsoletion sample baselines

Use Email field ID 3 as the shared baseline so the bad example demonstrates a same-ID rename while the good example retains the original field and adds a separate replacement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

---------

Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com>
This commit is contained in:
Jesper Schulz-Wedde 2026-07-15 10:55:25 +02:00 committed by GitHub
parent ae04938c03
commit 186d8a1314
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 2229 additions and 212 deletions

View file

@ -0,0 +1,28 @@
query 50426 "Query Reuse Bad"
{
QueryType = Normal;
elements
{
dataitem(Customer; Customer)
{
column(CustomerNo; "No.") { }
}
}
}
codeunit 50427 "Query Reuse Bad"
{
procedure ReadAgain(CustomerNoFilter: Code[20])
var
CustomerQuery: Query "Query Reuse Bad";
begin
CustomerQuery.SetRange(CustomerNo, CustomerNoFilter);
CustomerQuery.Open();
if CustomerQuery.Read() then;
// Reopening resets to the first row and retains CustomerNo.
CustomerQuery.Open();
if CustomerQuery.Read() then;
end;
}

View file

@ -0,0 +1,39 @@
query 50424 "Query Reuse Good"
{
QueryType = Normal;
elements
{
dataitem(Customer; Customer)
{
column(CustomerNo; "No.") { }
}
}
}
codeunit 50425 "Query Reuse Good"
{
procedure ReadTwoIndependentSets(FirstNo: Code[20]; SecondNo: Code[20])
var
CustomerQuery: Query "Query Reuse Good";
begin
CustomerQuery.SetRange(CustomerNo, FirstNo);
ReadAll(CustomerQuery);
Clear(CustomerQuery);
CustomerQuery.SetRange(CustomerNo, SecondNo);
ReadAll(CustomerQuery);
end;
local procedure ReadAll(var CustomerQuery: Query "Query Reuse Good")
begin
CustomerQuery.Open();
while CustomerQuery.Read() do
ProcessCustomer(CustomerQuery.CustomerNo);
CustomerQuery.Close();
end;
local procedure ProcessCustomer(CustomerNo: Code[20])
begin
end;
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: query
keywords: [query, open, close, clear, cursor, filters, reuse]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Reopening a Query resets its cursor but keeps its filters
## Description
Calling `Open()` on an already open query first closes the current dataset and opens it again. The next `Read()` starts at the first row; it does not continue from the previous cursor. Reopening also retains filters previously applied to the query variable. Only `Clear(QueryVariable)` resets those filters, so reuse can unexpectedly reread the first row or carry an old filter into a logically separate operation.
## Best Practice
Open once for one read pass. Close after the pass, and call `Clear(QueryVariable)` before reusing the variable for a logically independent query whose filters must start empty. Set the next pass's filters explicitly before reopening.
See sample: `reopening-query-resets-cursor-but-keeps-filters.good.al`.
## Anti Pattern
Calling `Open()` inside or between reads to "advance" or "start fresh", or reusing the same query variable for a new operation while assuming `Open()` cleared old filters. The code compiles but can repeatedly process the first row or silently omit rows behind a retained filter.
See sample: `reopening-query-resets-cursor-but-keeps-filters.bad.al`.

View file

@ -0,0 +1,30 @@
query 50422 "Query Customer Sales Bad"
{
QueryType = Normal;
elements
{
dataitem(Customer; Customer)
{
column(CustomerNo; "No.") { }
column(CustomerName; Name) { }
}
}
}
codeunit 50423 "Query Filter Order Bad"
{
procedure ReadCustomer(CustomerNoFilter: Code[20])
var
CustomerSales: Query "Query Customer Sales Bad";
begin
CustomerSales.Open();
CustomerSales.SetRange(CustomerNo, CustomerNoFilter);
while CustomerSales.Read() do
ProcessCustomer(CustomerSales.CustomerNo);
end;
local procedure ProcessCustomer(CustomerNo: Code[20])
begin
end;
}

View file

@ -0,0 +1,31 @@
query 50420 "Query Customer Sales Good"
{
QueryType = Normal;
elements
{
dataitem(Customer; Customer)
{
column(CustomerNo; "No.") { }
column(CustomerName; Name) { }
}
}
}
codeunit 50421 "Query Filter Order Good"
{
procedure ReadCustomer(CustomerNoFilter: Code[20])
var
CustomerSales: Query "Query Customer Sales Good";
begin
CustomerSales.SetRange(CustomerNo, CustomerNoFilter);
CustomerSales.Open();
while CustomerSales.Read() do
ProcessCustomer(CustomerSales.CustomerNo);
CustomerSales.Close();
end;
local procedure ProcessCustomer(CustomerNo: Code[20])
begin
end;
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: query
keywords: [query, setfilter, setrange, open, read, dataset, filter-order]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Set Query filters before Open
## Description
`Query.SetFilter` and `Query.SetRange` automatically close an open query dataset. A call placed after `Open()` therefore does not refine the rows already being read; it ends that dataset. The next `Read()` has no open dataset unless the code explicitly calls `Open()` again, so a plausible filter change can turn a working loop into an empty or failing read sequence without a compiler diagnostic.
## Best Practice
Apply every filter before `Open()`, then read the dataset to completion and call `Close()`. When a later branch needs different filters, close or clear the query, set the new filters, and open a new dataset deliberately.
See sample: `set-query-filters-before-open.good.al`.
## Anti Pattern
`Query.Open()` followed by `SetFilter` or `SetRange` and then `Read()` under the assumption that the filter updates the open cursor. Refiltering after `Open()` is valid only when the code intentionally opens a fresh dataset afterward.
See sample: `set-query-filters-before-open.bad.al`.