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

- pages-must-not-contain-business-logic.good.al/.bad.al: the "good"
  codeunit still directly assigned real Sales Line."Line Amount" and
  called Modify(), bypassing the field's normal Validate cascade
  (discount, VAT, related-amount maintenance) - persisting inconsistent
  document lines regardless of which object the code lived in. Replaced
  the real Sales Line example with a self-contained "Sample Order Line"
  table and switched the codeunit to Validate()/Modify(true), so the
  fixture demonstrates the page-vs-codeunit separation without teaching
  unsafe direct field writes to a real BC document table.
- bcpt-scenarios-must-be-app-specific.good.al: Customer.FindFirst()
  assumed a pre-existing customer (fails against an empty environment),
  and a session-local NextNo counter for the header key collides across
  concurrent BCPT sessions and repeated runs. Creates its own customer
  when none exists, and generates keys from CreateGuid() instead of an
  in-memory counter.
- upgrade-tag-logic-must-not-nest-deeply: the rule conflated two
  different things - nesting one tag's existence check inside another
  (the real anti-pattern Microsoft's guidance warns against) with
  having business-data safety conditions inside a single tagged
  migration's own loop body (which Microsoft's own worked example does,
  and its own design guidance explicitly requires: "Implement extra
  safety checks to avoid data corruption, even though you're using
  upgrade tags"). Rewrote the Description/Best Practice/Anti Pattern to
  scope the rule to actual tag nesting and migrations blended under one
  tag, and rewrote both fixtures: good.al now shows two safety
  conditions correctly nested inside one migration's own loop plus a
  second, genuinely separate migration as its own flat tagged
  procedure; bad.al now shows the real anti-pattern, one tag's check
  nested inside another's guarded body.
- table-design-must-match-bc-table-type-conventions: the rule and its
  worklist cue fired on any new table with a keys block, forcing
  buffers, queues, logs, mapping tables, and staging tables into the
  nearest-looking one of nine business-record archetypes. Added an
  explicit scope note that these nine types aren't an exhaustive table
  catalogue, and narrowed the al-data-modeling-review.md cue to require
  positive evidence (a type-specific naming suffix, key shape, or
  usage) before worklisting, instead of a bare keys/primary-key
  declaration.
This commit is contained in:
Michael Dieringer 2026-09-22 14:41:49 +02:00
parent 67962727f6
commit 4a95985c8c
8 changed files with 154 additions and 37 deletions

View file

@ -72,6 +72,19 @@ table with a real business-field key and no page), say so explicitly
rather than forcing a classification; settling it requires checking actual
row cardinality or call sites, not just the object definition.
These nine types cover Business Central's *business-record* tables — they
are not an exhaustive catalogue of every legitimate table shape. A
temporary/buffer table, a work queue, a log or telemetry table, a
cross-reference/mapping table with no business meaning of its own, or a
staging/working table used only inside one process is not required to fit
any of the nine, and forcing one into the nearest-looking type (usually
Ledger, because it has an `Integer` key, or Subsidiary, because it has a
composite key) produces a harmful redesign recommendation for a table that
was never meant to carry that type's guarantees. Apply this rule only when
the table's name, fields, or usage genuinely establish it as one of the
nine business-record types; when nothing points that way, this rule simply
does not apply — that is not the same as an unresolved classification.
See sample: [`table-design-must-match-bc-table-type-conventions.good.al`](table-design-must-match-bc-table-type-conventions.good.al).
## Anti Pattern