Skip to content

test(analyzer): add PX1121 MissingSchemaMutationGuard test coverage#671

Open
kbibelhausen wants to merge 2 commits into
Acumatica:devfrom
studio-b-ai:feature/px1121-missing-schema-mutation-guard
Open

test(analyzer): add PX1121 MissingSchemaMutationGuard test coverage#671
kbibelhausen wants to merge 2 commits into
Acumatica:devfrom
studio-b-ai:feature/px1121-missing-schema-mutation-guard

Conversation

@kbibelhausen
Copy link
Copy Markdown

Summary

Adds test coverage for the PX1121 MissingSchemaMutationGuard analyzer introduced alongside the production code. No production code was modified.

Positive cases (diagnostic expected at line 9, col 4)

Test Scenario
Diagnostic_BareAlterTableAdd ALTER TABLE … ADD with no guard
Diagnostic_MultipleUnguardedMutations Two bare ALTER TABLE … ADD statements
Diagnostic_UnrelatedGuardDoesNotSatisfyMutation An IF EXISTS … PRINT guard that does not cover the ALTER TABLE
Diagnostic_ConstantStringConcatenation String-concat form: "ALTER TABLE SOOrder " + "ADD …"
Diagnostic_InterpolatedIdentifiers Interpolated form: $"ALTER TABLE {tableName} ADD {columnName} …" (line 11, col 4)
Diagnostic_BareCreateTable CREATE TABLE with no OBJECT_ID/IF NOT EXISTS guard
Diagnostic_BareCreateIndex CREATE INDEX with no INDEXPROPERTY guard

Negative cases (no diagnostic expected)

Test Guard pattern exercised
NoDiagnostic_ColLengthGuard IF COL_LENGTH(…) IS NULL before ALTER TABLE … ADD
NoDiagnostic_IfNotExistsSysColumns IF NOT EXISTS (SELECT 1 FROM sys.columns …)
NoDiagnostic_ObjectIdGuardCreateTable IF OBJECT_ID(…, 'U') IS NULL before CREATE TABLE
NoDiagnostic_IndexPropertyGuardCreateIndex IF INDEXPROPERTY(OBJECT_ID(…), …, 'IndexID') IS NULL before CREATE INDEX
NoDiagnostic_BeginEndBlockUnderGuard IF COL_LENGTH … BEGIN … END block
NoDiagnostic_NonSchemaMutationPlugin INSERT only — not a schema mutation
NoDiagnostic_AlterInCommentIsIgnored ALTER appears only inside -- line comment, /* */ block comment, and a string literal

Notes

  • All Sources files use using PX.Data; only; no PX.Web.Customization reference required because the analyzer fires on any PXDatabase.Execute call regardless of enclosing class.
  • Build verification deferred to upstream Windows CI (ExternalDependency.csproj targets net48, unavailable on macOS).
  • Codex review: CLEAR TO SHIP — no actionable issues found.

New Roslyn analyzer detecting unguarded schema mutations in
PXDatabase.Execute calls. Catches the bug pattern that breaks
CustomizationPlugin re-publish:

  PXDatabase.Execute("ALTER TABLE SOOrder ADD UsrFoo int NULL")
  // Error PX1121: this ALTER will fail on the second publish

Recognized guard patterns:
  - IF NOT EXISTS (SELECT ... FROM sys.columns/tables/indexes ...)
  - IF EXISTS (...)
  - IF COL_LENGTH('<table>', '<column>') IS NULL
  - IF OBJECT_ID('<object>', '<type>') IS NULL
  - IF INDEXPROPERTY(OBJECT_ID('<table>'), '<index>', 'IndexID') IS NULL

Implementation:
  - Per-mutation guard detection (action-keyword tracking)
  - Comment + string literal stripping before regex match
  - Constant string concatenation via SemanticModel.GetConstantValue
  - Interpolated string analysis with hole placeholders
  - Severity: Warning, Category: Acuminator

Documented limitations (heuristic-based, not full T-SQL parse):
  - Dynamic SQL silently skipped
  - Interpolation holes standing in for DDL keywords not modeled
  - SELECT-as-then before mutation = rare false negative
  - ELSE-branch mutations after a then-branch action = false positive

Codifies Studio B's CLAUDE.md Rule Acumatica#24 (Acumatica <Sql> scripts and
PXDatabase.Execute do NOT re-execute idempotently across publishes
unless guarded explicitly).

Codex review gate: PASS (3 iterations).

Files:
  - src/Acuminator/Acuminator.Analyzers/StaticAnalysis/MissingSchemaMutationGuard/MissingSchemaMutationGuardAnalyzer.cs (310 LOC)
  - docs/diagnostics/PX1121.md (159 LOC)
  - Resource + descriptor wiring across 5 support files
- 7 positive cases: BareAlterTableAdd, MultipleUnguardedMutations,
  UnrelatedGuardDoesNotSatisfyMutation, ConstantStringConcatenation,
  InterpolatedIdentifiers, BareCreateTable, BareCreateIndex
- 7 negative cases: ColLengthGuard, IfNotExistsSysColumns,
  ObjectIdGuardCreateTable, IndexPropertyGuardCreateIndex,
  BeginEndBlockUnderGuard, NonSchemaMutationPlugin, AlterInCommentIsIgnored

All source files use `using PX.Data;` only (no CustomizationPlugin
reference) so they compile cleanly in the test harness.
Build verification deferred to upstream Windows CI (macOS lacks net48).
Codex review: CLEAR TO SHIP (no actionable issues found).
@kbibelhausen kbibelhausen force-pushed the feature/px1121-missing-schema-mutation-guard branch from c6faf6a to c0ad119 Compare May 20, 2026 18:48
kbibelhausen added a commit to studio-b-ai/acuops-website that referenced this pull request May 20, 2026
Adds a horizontal data ribbon between section 03 Ticker and section 05
How it works, per the canonical site-update spec at
~/Documents/brain/library/2026-05-17-acuops-site-update-spec.md §
'NEW SECTION — Open Source data strip'.

3 cells, Day-1 qualitative state per Pass 2 (Option A):
  acumatica-lint · just shipped · v0.1.0 on pypi
    → https://pypi.org/project/acumatica-lint/
  acuminator/pxsb · 1 pr open at acumatica · 2 queued
    → Acumatica/Acuminator#671 (PX1121)
  field · 25 validators · 60+ failure modes encoded
    → https://github.com/studio-b-ai/acumatica-lint#what-it-catches

Mission Control register (Pass 5): --surface bg, --signal-dim border,
JetBrains Mono labels, --text color, tabular-nums, hard corners,
hover shifts to --signal (terminal green).

Anti-patterns avoided per spec:
  - No 3-column card grid (Mission Control AI slop blacklist #1)
  - No icons in colored circles
  - No emoji as status indicators
  - No border-left colored accents on cells

Section eyebrows renumbered 01/08 → 01/09 across all 8 existing
sections (anchor IDs preserved per Pass 7 lock — #pricing, #ticker
etc still work). New section gets id='open-source'.

Mobile (<768px) stacks vertically with 48px touch targets per Pass 6
a11y locks; prefers-reduced-motion disables hover transition.

Co-authored-by: Kevin Bibelhausen <kevin@bibelhausen.com>
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.

1 participant