Skip to content

fix(PC0030): stop suggesting SetLoadFields on setup and reference tables - #543

Merged
Arthurvdv merged 4 commits into
mainfrom
fix/pc0030-setup-reference-table-reads
Sep 12, 2026
Merged

Arthurvdv merged 4 commits into
mainfrom
fix/pc0030-setup-reference-table-reads

Conversation

@Arthurvdv

@Arthurvdv Arthurvdv commented Sep 12, 2026

Copy link
Copy Markdown
Member

Fixes #531.

Why

Partial records bypass the NST record cache. A full-record read that repeats identically is served from memory with one SQL statement; the same read with SetLoadFields re-queries SQL every time (Duilio Tacconi measured ~10,000 identical statements where the cached read produced one - Partial record vs NST caching; the same effect surfaced in #297). On tables whose few rows are always cached - setup singletons, posting groups and other lookup data - PC0030 was recommending something that makes code slower.

Whether a read repeats is a data property the analyzer cannot see, so the fix does not try to predict performance. It recognizes the table class where the cache is essentially always hot and stays silent there; master data, documents and ledgers are unchanged.

What

  • TableHelper.IsSetupOrReferenceTable (Common): the existing setup-table heuristic, or a namespace ending in .Setup, or a single Code-type primary key named Code or Name; vetoed when the primary key is AutoIncrement (growing tables that live in a Setup namespace). Structural signals only - no table-name matching, no field counts - so it behaves the same for Microsoft, partner and localized apps. IsSetupTable keeps its narrow meaning for AC0013.
  • PC0030 no longer reports any read on such a table. Until now only a parameterless Get() on a setup table was excluded; Get('CODE'), FindFirst and FindSet still fired.
  • Fixtures: 31 existing fixtures used a "Primary Key" PK by habit and would have flipped silently; they are re-keyed to "No." so each keeps testing the suppression it is named after. SetupTableGetWithArgs and SetupTableFindFirst move to NoDiagnostic; nine new fixtures cover each signal and each veto (.Setup namespace with compound PK, .Setup as a non-final segment, AutoIncrement PK, Integer PK named Code, PK Code/Name).
  • Rule doc updated with the recognizer, the Base App evidence and the accepted limitations.

Evidence (Base App w1-28.4, 1,527 tables)

Signal Tables Precision
single Code PK named Code 185 ~90% lookup tables (all posting groups, Payment Terms, Currency, Location, ...)
single Code PK named Name 29 journal templates, schedule names
PK Primary Key / GetRecordOnce 95 / 10 100% singletons (existing heuristic)
namespace ends with .Setup 72 ~90%; adds the compound-PK posting setups. The AutoIncrement veto removes two of its false positives (Payment Reporting Argument, Adv. Bonus Depreciation Setup); Close Income Statement Buffer, Inventory Period Entry and Warehouse Employee remain accepted misses
single Code PK named No. 78 100% master data / document headers - deliberately not matched

Field count was rejected as a signal (General Ledger Setup has 114 fields and one row). Known misses: compound-PK reference tables outside .Setup (Inventory Posting Setup, Dimension Value) still report.

Companion docs PR: ALCops/alcops.dev#183

Verification

  • dotnet test ALCops.sln: 1,191 passed, 0 failed (PC0030 87/87, PC0031 31/31, AC0013 8/8); the new NoDiagnostic fixtures failed before the analyzer change.
  • dotnet format --verify-no-changes clean; Common and PlatformCop built for netstandard2.1;net8.0;net10.0 with ContinuousIntegrationBuild=true; Validate-Rules.ps1 OK.

🤖 Generated with Claude Code

Arthurvdv and others added 2 commits September 12, 2026 14:58
Partial records bypass the NST record cache: a full-record read that repeats
identically is served from memory, while the same read with SetLoadFields
goes back to SQL every time. On tables whose few rows are always cached -
setup singletons, posting groups and other lookup data - the suggestion
therefore makes code slower, not faster.

TableHelper.IsSetupOrReferenceTable recognizes that class structurally: the
existing setup-table heuristic, a namespace ending in ".Setup", or a single
Code-type primary key named "Code" or "Name", vetoed when the primary key
is AutoIncrement. PC0030 no longer reports any read on such a table; until
now only a parameterless Get() on a setup table was excluded. IsSetupTable
keeps its narrow meaning for AC0013.

Fixtures that used a "Primary Key" PK by habit are re-keyed to "No." so
they keep testing the suppression they are named after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Arthurvdv and others added 2 commits September 12, 2026 19:35
…efs and any AutoIncrement key field

A RecordRef linked to a setup or reference record via SetTable now inherits
that record's suppression, so the same read is judged the same way through
either receiver. The AutoIncrement veto inspects every primary-key field, not
only the first, so a compound "Code, Entry No." key on a growing table in a
Setup namespace no longer slips through.

TableHelper shares one single-Code-PK predicate between IsSetupTable and
IsSetupOrReferenceTable, evaluates the cheap primary-key check before the
namespace and member lookups, and describes the shapes it matches without
rule-specific rationale.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…0 recognizer

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Arthurvdv
Arthurvdv merged commit aa58208 into main Sep 12, 2026
38 checks passed
@Arthurvdv
Arthurvdv deleted the fix/pc0030-setup-reference-table-reads branch September 12, 2026 18:08
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.

[Bug]: PC0030 - SetLoadFields should be used with caution

1 participant