Skip to content

Knowledge: report layouts and dataset contract, query join and grouping defaults - #230

Merged
Jesper Schulz-Wedde (JesperSchulz) merged 2 commits into
microsoft:mainfrom
demiliani:knowledge/reporting-and-query
Oct 20, 2026
Merged

Jesper Schulz-Wedde (JesperSchulz) merged 2 commits into
microsoft:mainfrom
demiliani:knowledge/reporting-and-query

Conversation

@demiliani

@demiliani Stefano Demiliani (demiliani) commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Why

The reporting (9) and query (4) domains are among the thinnest in the corpus. Report layout declaration and the report dataset/layout contract had only incidental mentions. Two query defaults that differ from what SQL-trained models assume (the implicit join type and the implicit GROUP BY) had no coverage. These mistakes compile cleanly and analyzers do not catch them.

What

Five Microsoft-layer articles with good/bad samples and Microsoft Learn references.

Domain Article Mistake prevented
reporting declare-report-layouts-in-the-rendering-section New reports use DefaultLayout/RDLCLayout/WordLayout/ExcelLayout. Learn says these are to be avoided and will be deprecated, and reading them loads the full layout. [20..]
reporting reportextension-layouts-are-not-selected-automatically A layout added in a reportextension is assumed to replace the base layout. DefaultRenderingLayout cannot be set on a report extension, and the layout must be selected. [20..]
reporting do-not-rename-or-remove-shipped-report-dataset-columns Column names are the contract for Excel Data sheets, Word XML parts, and user-defined layouts outside the repo. Renames and removals break those layouts.
query query-dataitems-default-to-left-outer-join Omitting SqlJoinType gives LeftOuterJoin, so unmatched upper rows (with blank lower columns) end up in "X with Y" queries.
query every-non-aggregated-query-column-is-a-group-key Adding a display column to a totals query silently changes its grouping. Integer Average uses integer division.

Each article lists false-positive carve-outs: unchanged legacy declarations, optional layouts, changed source expressions with the same column name, explicit or intended left joins.

Wiring

  • al-reporting-review and al-query-review: tokens plus one targeted cue per article. The column-rename cue requires comparison evidence, because a folder snapshot cannot show a rename.
  • evaluation/review-fixtures.json: the three code-detectable articles are added to the query/reporting overrides. Two narrow coverageWaivers cover the reporting articles whose defect depends on release history (column rename) or intent (layout expected to become default). Once comments are removed, those samples cannot show the defect.

Points to confirm

  • declare-report-layouts-in-the-rendering-section: I know of no compiler or analyzer diagnostic for the legacy layout properties, only the "Convert to 'Rendering'" code action. If a deterministic rule exists, this article should be dropped under the admission test.

Validation

  • tools/Test-ReviewFixtures.ps1 (including -ChangedPathsFile and -PrepareDirectory): PASSED
  • tools/Test-ReviewContract.ps1, .github/scripts/Test-SkillIndex.ps1, .github/scripts/Test-KnowledgeIndex.ps1: PASSED
  • validate_frontmatter.py was not run locally (no Python on this machine); CI will confirm.
  • AL samples are demonstrations, not compiled.

Independent of #228 and #229.

…ng defaults

Reporting (Microsoft layer, al-reporting-review):
- declare report layouts in the rendering section, not with the legacy
  DefaultLayout/RDLCLayout/WordLayout/ExcelLayout properties
- a layout added in a report extension is not used until it is selected
- do not rename or remove columns of a released report dataset

Query (Microsoft layer, al-query-review):
- a lower data item without SqlJoinType is a LeftOuterJoin
- every non-aggregated column of a totals query is a group key

Wire each article into its leaf review skill. Register the code-detectable
paired articles in the review-fixtures overrides; add narrow coverage
waivers for the two reporting articles whose defect depends on release
history or intent and cannot be shown by a neutralized sample.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 85932898420da11b0c6992fe21371948818b2d1a. Two merge-critical fixture issues remain:

  1. query-dataitems-default-to-left-outer-join.bad.al:18 places DataItemTableFilter Document Type = Order on Sales Header. The documented SQL WHERE restriction rejects unmatched/null child rows, so the implicit LeftOuterJoin already excludes customers without matching orders. Adding InnerJoin produces the same rows in the supplied scenario; it does not fix the claimed defect. An independent relational reproduction with no documents, quotes, released orders and open orders returned identical rows. Make the positive fixture demonstrate surviving unmatched rows, and recognize null-rejecting child filters as a valid alternative in article/routing and a clean control. This was checked against documented filter semantics, not claimed as a live BC runtime test.
  2. The good object names Customers With Open Orders Good and Open Orders By Salesperson Good are each 31 characters, exceeding AL's 30-character limit (AL0305). Neutralization also grows their corresponding Bad names to 31 characters, so all four prepared inputs remain invalid. Shorten both pairs and update query references, checking the names after neutralization too.

Exact-head frontmatter, index/retrieval, skill/schema and contract checks passed in the isolated review harness; the actual 18-path gate prepared 258 cases, with the declared reporting waivers retained. Those checks are structural and do not compile AL or prove the positive case's semantic defect.

Make the positive join fixture retain and miscount unmatched rows. Recognize null-rejecting child filters as a valid alternative in guidance, routing and the clean control. Shorten query/report names and update query references, including neutralized names.

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

Copy link
Copy Markdown
Contributor Author

Addressed both blockers from Jesper Schulz-Wedde (@JesperSchulz)'s review in commit 9a76407.

  • Changed the positive join fixture to count sales documents without a null-rejecting child filter. The implicit LeftOuterJoin now genuinely retains customers with no documents and incorrectly counts their unmatched rows. The corresponding InnerJoin clean scenario removes those rows.
  • Added a second clean query using the implicit outer join with Sales Header Document Type = Order / Status = Open filters, plus a consumer that counts the matching open orders. Updated the article and leaf routing to recognize null-rejecting child filters as valid and require an actual wrong-result scenario rather than a missing property or suggestive name alone.
  • Shortened both query and report name pairs, updated query references, and verified all affected object names remain within 30 characters after Good/Bad -> Eval neutralization.

Validation passed:

  • Independent relational reproduction with customers having no documents, quotes, released orders, and two open orders: unfiltered outer join returns 5 rows including one unmatched row; inner join returns the 4 actual documents; both filtered joins return the same 2 open orders.
  • 258 neutral fixtures across 20 leaf domains, including the actual PR-path coverage gate and existing reporting waivers; explicit prepared-input checks preserve the positive scenario and both clean alternatives.
  • Knowledge-index determinism/coverage and retrieval round-trip (419 articles, 725 samples).
  • Skill-index/schema and executable review-contract checks.
  • Object-name/query-reference checks and git diff --check.

The relational reproduction is not a live BC runtime test. No AL compilation/runtime execution or model-score result is claimed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 9a7640744c252b18b9b30b2f8de8a2c30854eb3f. Both prior blockers are resolved. The positive query now actually preserves unmatched customers and its consumer incorrectly counts those rows as sales documents; the good pair uses InnerJoin and separately preserves the null-rejecting filtered outer join as a clean control. Article/routing require a wrong effective result rather than flagging the omitted property or a name alone. The renamed query/report objects and updated references remain within AL's 30-character limit before and after neutralization. Exact-head actual-changed-path fixture preparation, contract, skill/schema, index/retrieval and frontmatter checks pass; the relational boundary probe agrees with the intended positive/clean distinction. No remaining merge-critical issue found. The substantive GitHub workflows still await permission to run before merge.

@JesperSchulz
Jesper Schulz-Wedde (JesperSchulz) merged commit 01715ec into microsoft:main Oct 20, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants