Skip to content

Finish CONTRIBUTING.md's data-type rule: rewrite the 33 abbreviated int sites and move UnabbreviatedTypes in scope #3087

Closed

Description

@erikdarlingdata

CONTRIBUTING.md's Data types bullet states two independent properties — "lowercase, never abbreviated (integer not int, nvarchar(max) not nvarchar(MAX))". #3081 / #3085 enforced the case half and deliberately left the abbreviation half uncovered, on a stated remediation cost rather than on detectability. TsqlConventionGuardTests already carries the detector (AbbreviatedTypeUse) and the measurement (AbbreviatedTypeSites()); Findings just declines to emit the rule.

That was the right call for a change whose subject was the guard. It is a half-state now, and the guard says so in its own words: TheAbbreviationScopeNote_CountsTheSitesItClaims reds the moment the count moves, and its message names the follow-through — "move UnabbreviatedTypes from the Data types bullet's Uncovered side to its Covered side, emit it from Findings, and give it a hazard fixture."

This issue is that follow-through: rewrite the sites, then move the rule in scope.

The count, re-derived

Driven through the guard's own AbbreviatedTypeSites() — the same population, the same code view, and the same TypeNameClauseCollisions blanking the enforced checks read — rather than a fresh grep:

33 sites in 7 files. Agrees with the figure the scope note carries, and every site enumerates back to a distinct regex match, so the total is not covering for a collapsed key.

File Sites
Lite/Services/LocalDataService.FinOps.ServerProperties.cs 10
PerformanceMonitor.Collectors/DatabaseSizeStatsCollector.cs 9
PerformanceMonitor.Collectors/ServerPropertiesCollector.cs 5
Lite/Services/LocalDataService.FinOps.Recommendations.cs 4
Darling/PerformanceMonitor.Darling.Analysis/PgPlanFetcher.cs 2
Lite/Services/LocalDataService.QueryStats.cs 2
PerformanceMonitor.Collectors/MemoryStatsCollector.cs 1

int is the only abbreviation present. dec for decimal and double precision for float are the others T-SQL accepts and neither appears — a bound on the figure, not on the rule.

Scope of the in-scope move

All of it, or the disposition map contradicts itself:

  • UnabbreviatedTypes moves from the Data types bullet's Uncovered array to its Covered array.
  • Findings emits it.
  • It gets a hazard fixture in TheDetector_FlagsEveryCoveredRule_AndNoBenignForm, whose rule coverage is asserted at set equality against CoveredRules.
  • Its fixture is deleted from TheUncoveredRules_AreViolatedByFixturesThisGuardDoesNotFlag, whose fixture set is asserted at set equality against UncoveredRules.
  • The abbreviation-cost pin (TheAbbreviationScopeNote_CountsTheSitesItClaims) and the note text it parses are deleted — a cost pin for a cost nobody is paying any more is a pin that can only go stale.
  • The split-pair assertion in TheDispositionMap_PartitionsTheBulletsContributingStates drops to { "Indentation" }, since Data types stops being split. That assertion names the split bullets rather than counting them, so it reds rather than drifting — which is the whole reason it is shaped that way.

Two things that need care rather than a sweep

1. Three of the seven files carry an sp_executesql PARAMETER DECLARATION, not a query body

PgPlanFetcher.cs and LocalDataService.QueryStats.cs both hold N'@h varbinary(64), @stmt_start int, @stmt_end int', and LocalDataService.FinOps.Recommendations.cs holds N'@c int OUTPUT' — the same class, and the scope note only named the first shape.

A parameter declaration is not a statement body, so "DECLARE @x integer is valid, therefore this is too" is an inference about a grammar position rather than a fact about it. Nothing in this repository executes that path, so no test here can settle it and a green build would mean nothing.

It wants a live parse check, and the check should not be run against a monitored production server.

2. Every edit is inside a query string that runs against monitored production servers

The compiler cannot see a typo in one, so the parity pins are the only thing between a bad edit and a shipped one. #3085 established that none of the nine sites it fixed was verbatim-pinned by a *CollectorDefinitionTests parity constant — but these are different files, and that conclusion should not be inherited. Establish it per file, and re-run the guard afterwards.

Acceptance

  • 33 → 0, re-derived through AbbreviatedTypeSites() rather than asserted.
  • The rule reads as Covered and reds by name on UnabbreviatedTypes when one of the rewritten sites is reverted. A rule moved to Covered that cannot fail is worse than one honestly left uncovered.
  • The detector must not match int inside a longer token — integer, bigint, smallint, tinyint, int_col, sysint — and those belong in the benign fixture set, where a greedy or unanchored match reds.

Activity

  1. added a commit that references this issue on Sep 6, 2026
    6b336da
  2. erikdarlingdata commented on Sep 6, 2026

    @erikdarlingdata
    OwnerAuthor

    Claude posting for Erik Darling

    Fixed by #3092, merged to dev as 6b336da37b9. Closing by hand — a closing keyword does not fire on a dev-targeted PR here.

    33 abbreviated int type positions rewritten to integer across 7 files, and UnabbreviatedTypes moved from the guard's Uncovered to Covered. CONTRIBUTING.md's data-type bullet is now enforced in both halves.

    The count is 33 only in the right unit, and that matters for anyone re-deriving it. The diff carries 41 added lines containing integer, minus 9 in the guard's own test file and 1 parity pin, leaving 31 production lines. Two of those lines carry two declarations each — the varbinary/@stmt_start/@stmt_end line in both PgPlanFetcher.cs and LocalDataService.QueryStats.cs. Counting type positions, which is the unit the rule operates on, gives 31 + 2 = 33. A line count and a word count both disagree with it, and both are the wrong unit.

    Two care items broke the expected way:

    • A parity pin did bite, where Fixes #3081 #3085's nine sites had none. Lite.Tests/MemoryCollectorsDefinitionTests.cs:35 pinned CONVERT(int, NULL) against MemoryStatsCollector's Azure variant, found by scanning 56,098 string literals across 757 test files. It moved with the query in this PR; reverting the query while leaving the pin reds BuildQuery_SelectsVariantByTarget. Editing the query without it would have failed build.
    • The sp_executesql parse question was the weak half. integer parses inside a parameter-declaration string and binds as int — so the parse alone establishes nothing, because SQL Server normalises the synonym and any read-back reports int. What was established instead: nothing reads the declaration back. Zero DeriveParameters, zero sys.parameters, zero sys.types across the shipped trees, with SqlDbType as a positive control returning three files so the search was alive. The one GetSchemaTable hit is a pass-through decorator reading result-set metadata, not parameter metadata.

    A third declaration site the original scope note never named — N'@c int OUTPUT' in FinOps.Recommendations — was found and probed. The sp_executesql shape is now a permanent hazard fixture rather than a memory.

    Probes ran on stage (SQL Server 2022, 16.0.4215.2) via SSM port-forward. No production server was touched.

    Not verified: no query in this diff was executed in the form the diff ships it. Only purpose-built read-only probes of each shape it uses. Worth knowing that these collectors run every minute across the fleet, so the next nightly carrying this build is the first time these queries execute in production.

    Zero abbreviated type positions remain, with a before/after that proves the pattern was alive: the detector pattern matches 5 files on the pre-merge dev and 0 on this branch. A zero from a pattern that also returned zero beforehand would have proved nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions