**MANDATORY POST-WRITE CHECKLIST — runs after every file is created or modified.** This skill simulates a professional CI/CD quality gate combining VS Code diagnostics, SonarQube static analysis, vulnerability scanning, security auditing, and performance optimization. It applies to all languages in the stack: T-SQL, C#/.NET, TypeScript/React, HTML/CSS, JSON/config files. ---
Scanned 9/12/2026
Install to Claude Code
npx -y skills add aibot88/sec_skill_store --skill reachtokarthikr-agent_skills-. --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Reachtokarthikr Agent Skills .?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-reachtokarthikr-agent-skills)More formats (shields.io, HTML) on the badges page.
# Code Quality Gate Skill
**MANDATORY POST-WRITE CHECKLIST — runs after every file is created or modified.**
This skill simulates a professional CI/CD quality gate combining VS Code diagnostics, SonarQube static analysis, vulnerability scanning, security auditing, and performance optimization. It applies to all languages in the stack: T-SQL, C#/.NET, TypeScript/React, HTML/CSS, JSON/config files.
---
## When This Skill Activates
This skill activates **automatically after every code change**. It is not optional.
| Trigger | Example |
|---------|---------|
| New file created | `create_file` for any `.cs`, `.ts`, `.tsx`, `.sql`, `.json`, `.html`, `.css`, `.csproj` |
| File edited | `str_replace` on any code file |
| Bug fix applied | After fixing a reported issue |
| Refactor completed | After restructuring code |
| User says "review" / "check" / "audit" | Explicit quality review request |
| Before delivery to `/mnt/user-data/outputs/` | Final gate before presenting files |
**RULE: Never copy files to `/mnt/user-data/outputs/` until all 6 layers pass with zero Critical/High issues.**
---
## The 6-Layer Quality Gate
Every file change must pass through ALL 6 layers in order. If any layer produces Critical or High severity findings, fix them before proceeding to the next layer. Medium/Low findings should be noted and fixed where practical.
```
Layer 1: VS Code Problems Tab → Syntax, type errors, warnings
Layer 2: Lint Check (ALL langs) → ESLint, Roslyn, SQL Lint, Prettier, Stylelint, HTMLHint, JSONLint
Layer 3: SonarQube-Lite Analysis → Code smells, complexity, duplication, maintainability
Layer 4: Vulnerability Scan → Dependencies, injection, secrets, data exposure
Layer 5: Security Hardening → OWASP Top 10, auth/authz, input validation
Layer 6: Optimization & Standards → Performance, best practices, team conventions
```
---
## ARCHITECTURAL MANDATE — Stored Procedures ONLY (No Inline SQL, No EF)
**🔴 CRITICAL RULE — NO EXCEPTIONS. This overrides all other patterns. Violations block delivery.**
All database access MUST go through stored procedures called via **Dapper + SpHelper**. The following are **permanently BANNED** in this codebase:
### ⌠BANNED — Inline SQL / Raw Queries
```
🔴 BANNED: conn.QueryAsync<T>("SELECT * FROM Users WHERE Id = @Id", ...)
🔴 BANNED: conn.ExecuteAsync("INSERT INTO Users (...) VALUES (...)", ...)
🔴 BANNED: conn.QueryAsync<T>($"SELECT * FROM Users WHERE Email = '{email}'")
🔴 BANNED: new SqlCommand("SELECT ...", conn)
🔴 BANNED: SqlCommand.CommandType = CommandType.Text
🔴 BANNED: FromSqlRaw("SELECT ...")
🔴 BANNED: FromSqlInterpolated($"SELECT ...")
🔴 BANNED: Database.ExecuteSqlRaw(...)
🔴 BANNED: Database.ExecuteSqlInterpolated(...)
🔴 BANNED: Any string containing SELECT/INSERT/UPDATE/DELETE in C# code
🔴 BANNED: Dapper calls without CommandType.StoredProcedure — must go through SpHelper
```
### ⌠BANNED — Entity Framework Core (ALL of it — zero tolerance)
```
🔴 BANNED: DbContext / DbSet<T>
🔴 BANNED: IEntityTypeConfiguration<T> / Fluent API
🔴 BANNED: modelBuilder.ApplyConfigurationsFromAssembly(...)
🔴 BANNED: dbContext.Users.Where(...).ToListAsync()
🔴 BANNED: dbContext.SaveChangesAsync() / SaveChanges()
🔴 BANNED: dbContext.Add() / Update() / Remove() / AddRange() / RemoveRange()
🔴 BANNED: AsNoTracking() (implies EF query)
🔴 BANNED: Include() / ThenInclude() (EF eager loading)
🔴 BANNED: EF migrations: dotnet ef migrations add ...
🔴 BANNED: Microsoft.EntityFrameworkCore NuGet package in any .csproj
🔴 BANNED: LINQ-to-SQL / LINQ-to-Entities (dbContext.Users.Select(...))
🔴 BANNED: ExecuteUpdateAsync / ExecuteDeleteAsync (EF 7+ bulk ops)
🔴 BANNED: HasKey() / HasIndex() / HasOne() / HasMany() / WithOne() / WithMany()
🔴 BANNED: OnModelCreating() override
🔴 BANNED: any file named *DbContext.cs, *Context.cs (EF context files)
🔴 BANNED: Data/Migrations/ folder
```
### ✅ REQUIRED — The ONLY Allowed Data Access Pattern
```
✅ REQUIRED: Dapper + SpHelper → calls stored procedures ONLY
✅ REQUIRED: CommandType.StoredProcedure on every database call
✅ REQUIRED: SpHelper.ManageAsync<T>(spName, params) → INSERT/UPDATE/DELETE via SP
✅ REQUIRED: SpHelper.GetByIdAsync<T>(spName, id) → Single record via SP
✅ REQUIRED: SpHelper.GetListAsync<T>(spName, params) → Paged list via SP
✅ REQUIRED: SpHelper.GetWithChildrenAsync<P,C>(spName, id)→ Parent+Children via SP
✅ REQUIRED: DynamicParameters for all SP parameters
✅ REQUIRED: @CorrelationId + @RequestId injected via SpHelper.WithTracking()
✅ REQUIRED: Every SP defined in .sql files following _Manage / _Get pattern
✅ REQUIRED: Repository classes use SpHelper, never direct Dapper or ADO.NET
```
### ✅ Required NuGet Packages (Data Access ONLY these)
```xml
<!-- ALLOWED — the ONLY data access packages -->
<PackageReference Include="Dapper" Version="2.*" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.*" />
<!-- ⌠BANNED — if any of these appear in .csproj, it is a CRITICAL violation -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore" /> -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" /> -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore.Design" /> -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" /> -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" /> -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" /> -->
```
### Detection Commands (MUST run on every C# / .csproj file change)
```bash
echo "â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•"
echo " SP-ONLY MANDATE CHECK — ZERO TOLERANCE"
echo "â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•"
VIOLATIONS=0
# ── Inline SQL detection (🔴 CRITICAL) ──
echo "--- Checking for inline SQL ---"
if grep -rn "CommandType\.Text" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: CommandType.Text found — must use CommandType.StoredProcedure"
((VIOLATIONS++))
fi
if grep -rn "FromSqlRaw\|FromSqlInterpolated\|ExecuteSqlRaw\|ExecuteSqlInterpolated" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: Raw SQL via EF methods found"
((VIOLATIONS++))
fi
if grep -rn '"SELECT \|"INSERT \|"UPDATE \|"DELETE \|"EXEC ' --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: Inline SQL string found in C# code"
((VIOLATIONS++))
fi
if grep -rn '\$"SELECT\|\$"INSERT\|\$"UPDATE\|\$"DELETE' --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: Interpolated SQL string found — SQL injection risk"
((VIOLATIONS++))
fi
if grep -rn "new SqlCommand" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: Raw SqlCommand found — must use SpHelper"
((VIOLATIONS++))
fi
# Direct Dapper without SP type (allowed only inside SpHelper itself)
if grep -rn "\.QueryAsync<\|\.QueryFirstOrDefaultAsync<\|\.ExecuteAsync(" --include="*.cs" 2>/dev/null | grep -v "SpHelper.cs" | grep -v "CommandType.StoredProcedure"; then
echo "🔴 CRITICAL: Direct Dapper call outside SpHelper — must go through SpHelper"
((VIOLATIONS++))
fi
# ── Entity Framework detection (🔴 CRITICAL) ──
echo "--- Checking for Entity Framework ---"
if grep -rn "DbContext\|DbSet<" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: Entity Framework DbContext/DbSet found"
((VIOLATIONS++))
fi
if grep -rn "using Microsoft.EntityFrameworkCore" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: EF Core using directive found"
((VIOLATIONS++))
fi
if grep -rn "EntityFrameworkCore" --include="*.csproj" 2>/dev/null; then
echo "🔴 CRITICAL: EF Core NuGet package referenced in .csproj"
((VIOLATIONS++))
fi
if grep -rn "\.Include(\|\.ThenInclude(" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: EF eager loading (Include/ThenInclude) found"
((VIOLATIONS++))
fi
if grep -rn "AsNoTracking\|SaveChangesAsync\|SaveChanges()" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: EF persistence method found"
((VIOLATIONS++))
fi
if grep -rn "modelBuilder\|OnModelCreating\|IEntityTypeConfiguration\|HasKey(\|HasIndex(\|HasOne(\|HasMany(" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: EF model configuration / Fluent API found"
((VIOLATIONS++))
fi
if grep -rn "ExecuteUpdateAsync\|ExecuteDeleteAsync" --include="*.cs" 2>/dev/null; then
echo "🔴 CRITICAL: EF bulk operation found"
((VIOLATIONS++))
fi
if find . -name "*DbContext.cs" -o -name "*Context.cs" 2>/dev/null | grep -v "TrackingContext\|HttpContext\|LogContext"; then
echo "🔴 CRITICAL: EF Context file found"
((VIOLATIONS++))
fi
if [ -d "Data/Migrations" ] || [ -d "Migrations" ]; then
echo "🔴 CRITICAL: EF Migrations folder found"
((VIOLATIONS++))
fi
# ── Verify correct pattern exists ──
echo "--- Verifying SP-only pattern ---"
grep -rn "CommandType.StoredProcedure" --include="*.cs" 2>/dev/null && echo "✅ StoredProcedure CommandType found" || echo "âš ï¸ No StoredProcedure calls found"
grep -rn "class SpHelper" --include="*.cs" 2>/dev/null && echo "✅ SpHelper class found" || echo "âš ï¸ SpHelper not found — required"
grep -rn "DynamicParameters" --include="*.cs" 2>/dev/null && echo "✅ DynamicParameters usage found" || echo "âš ï¸ No DynamicParameters found"
grep -rn "WithTracking" --include="*.cs" 2>/dev/null && echo "✅ WithTracking (CorrelationId/RequestId injection) found" || echo "âš ï¸ WithTracking not found — tracking IDs may be missing"
echo "â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•"
if [ $VIOLATIONS -gt 0 ]; then
echo "⌠SP-ONLY MANDATE: $VIOLATIONS CRITICAL VIOLATIONS — DELIVERY BLOCKED"
else
echo "✅ SP-ONLY MANDATE: PASSED — all data access through stored procedures"
fi
echo "â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•"
```
### Why This Mandate Exists
| Concern | Stored Procedures (✅ our way) | Inline SQL / EF (⌠banned) |
|---------|-------------------------------|----------------------------|
| **SQL Injection** | Parameterized by design | Risky string interpolation |
| **Performance** | Cached execution plans, DBA-tunable | Plan recompilation, N+1 queries, lazy loading traps |
| **Request Tracking** | @CorrelationId/@RequestId in every SP call | No tracking — invisible to log.RequestLog |
| **Audit Trail** | SP logs START/SUCCESS/ERROR automatically | Changes happen silently, no audit |
| **DBA Control** | DBAs tune queries without code deploys | Locked in compiled C# code |
| **Soft Delete** | Enforced in SP (IsActive = 0, always) | Dev might forget, hard-delete data permanently |
| **Business Logic** | Centralized in SP + service layer | Scattered across EF configs, LINQ, migrations |
| **Schema Changes** | Idempotent .sql scripts, version-controlled | EF migration conflicts, snapshot drift |
| **Consistency** | Same _Manage/_Get pattern everywhere | Mixed patterns, every dev does it differently |
| **Debugging** | grep log.RequestLog by RequestId | No centralized logging, hunt through app logs |
### Correct Architecture Flow
```
React (UI) → API Controller → Service (optional) → Repository → SpHelper → Dapper → Stored Procedure → SQL Server
↑
Uses DynamicParameters
Injects @CorrelationId + @RequestId
CommandType.StoredProcedure ALWAYS
```
**Every data operation follows this chain. No shortcuts. No "just a quick EF query". No "inline SQL is faster for this one case".**
---
## Layer 1 — VS Code Problems Tab Simulation
Simulate what VS Code's Problems tab would show: Errors, Warnings, and Information diagnostics. Check every changed file.
### For ALL Languages
| Check | Severity | What to Look For |
|-------|----------|------------------|
| Syntax errors | 🔴 Error | Missing brackets, semicolons, unclosed strings, invalid tokens |
| Undefined references | 🔴 Error | Variables, functions, types, tables used but never declared |
| Type mismatches | 🔴 Error | Assigning string to int, wrong function argument types |
| Unused imports/usings | 🟡 Warning | `using System.Linq;` when no LINQ is used |
| Unused variables | 🟡 Warning | Declared but never read |
| Unreachable code | 🟡 Warning | Code after `return`, `throw`, `RETURN` |
| Deprecated API usage | 🟡 Warning | `DateTime` instead of `DateTime2`, `TEXT` instead of `NVARCHAR(MAX)` |
| Missing null checks | 🟡 Warning | Nullable types accessed without `?.` or null guard |
| Implicit `any` (TypeScript) | 🟡 Warning | Untyped parameters, missing return types |
| Missing `await` | 🔴 Error | Async call without `await` — fire-and-forget bug |
### Language-Specific Checks
#### T-SQL
```
✅ All identifiers resolved (tables, columns, SPs exist or are in context)
✅ Matching BEGIN/END blocks
✅ SET NOCOUNT ON present in every SP
✅ SET XACT_ABORT ON present in _Manage SPs
✅ GO batch separators between CREATE/ALTER statements
✅ No SELECT * in production code (list columns explicitly)
✅ All CASE expressions have matching END
✅ String literals use N'' prefix for NVARCHAR columns
✅ No orphaned temp tables (created but never dropped or used)
✅ THROW has correct 3-param syntax (number, message, state)
```
#### C# / .NET
```
✅ Namespace matches folder structure
✅ All interfaces implemented fully
✅ All abstract methods overridden
✅ async methods return Task/Task<T>, not void (except event handlers)
✅ IDisposable types wrapped in using/await using
✅ No raw Task.Result or .Wait() (deadlock risk)
✅ CancellationToken accepted and forwarded in async chains
✅ Nullable reference types handled (no CS8600, CS8601, CS8602 warnings)
✅ Constructor parameters match DI registrations
✅ No ambiguous method overloads
🔴 NO inline SQL strings (SELECT/INSERT/UPDATE/DELETE in C# code)
🔴 NO Entity Framework (DbContext, DbSet, SaveChanges, Include, migrations)
🔴 NO raw SqlCommand or CommandType.Text
🔴 ALL data access through SpHelper → Stored Procedures → Dapper
🔴 NO EF NuGet packages in .csproj (EntityFrameworkCore.*)
```
#### TypeScript / React
```
✅ No TypeScript strict mode violations (noImplicitAny, strictNullChecks)
✅ All imports resolve to existing modules
✅ JSX elements have matching closing tags
✅ React hooks follow Rules of Hooks (no conditional hooks, correct deps)
✅ useEffect cleanup functions present where needed (subscriptions, timers, AbortController)
✅ Key prop present on mapped elements
✅ No direct DOM manipulation (use refs instead)
✅ Event handlers typed correctly (React.ChangeEvent<HTMLInputElement>, etc.)
✅ Generic type parameters specified (no implicit any on useState<>, useRef<>)
✅ Exported types match their usage in consuming modules
```
### Validation Commands (run where applicable)
```bash
# TypeScript — compile check
npx tsc --noEmit 2>&1 | head -50
# ESLint
npx eslint . --ext .ts,.tsx --format compact 2>&1 | head -50
# .NET build
dotnet build --no-restore 2>&1 | grep -E "(error|warning) [A-Z]{2}[0-9]+" | head -50
# SQL syntax (basic)
# Use sqlcmd dry-run or grep for common syntax errors
grep -n "SELECT \*" *.sql # No SELECT * in production
grep -n "GETDATE()" *.sql # Should use SYSUTCDATETIME()
grep -n "= NULL" *.sql # Should use IS NULL
grep -n "EXEC(" *.sql # Check for SQL injection in dynamic SQL
```
### Output Format
```
## Layer 1 — VS Code Problems Tab
| # | File | Line | Severity | Code | Message |
|---|------|------|----------|------|---------|
| 1 | Users_Manage.sql | 45 | 🔴 Error | SQL001 | Missing SET NOCOUNT ON |
| 2 | UserService.cs | 12 | 🟡 Warning | CS8602 | Possible null reference |
| 3 | api.ts | 8 | 🟡 Warning | TS6133 | 'response' declared but never used |
**Result: ⌠1 Error, 2 Warnings — fix errors before proceeding**
```
---
## Layer 2 — Lint Check (ALL Languages)
**MANDATORY for every file.** Run the appropriate linter for each file type. Fix all errors; warnings should be fixed unless explicitly justified. This layer catches style violations, anti-patterns, and code quality issues that compilers don't flag.
### Installation Commands (run once per session if needed)
```bash
# ── TypeScript / React / JavaScript ──
npm install -D eslint @eslint/js typescript-eslint eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y 2>/dev/null
npm install -D prettier eslint-config-prettier eslint-plugin-prettier 2>/dev/null
# ── CSS / SCSS ──
npm install -D stylelint stylelint-config-standard stylelint-config-tailwindcss 2>/dev/null
# ── HTML ──
npm install -D htmlhint 2>/dev/null
# ── JSON ──
npm install -D jsonlint-mod 2>/dev/null
# ── Markdown ──
npm install -D markdownlint-cli 2>/dev/null
# ── SQL (T-SQL) ──
npm install -D sql-lint 2>/dev/null
pip install sqlfluff --break-system-packages 2>/dev/null
# ── C# / .NET (Roslyn analyzers — included in SDK 8+) ──
# These are built into dotnet build with <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
# Additional: dotnet format for auto-fix
```
---
### 2.1 TypeScript / React — ESLint + Prettier
#### Rules (Error = 🔴, Warning = 🟡)
| Rule ID | Severity | What It Catches |
|---------|----------|-----------------|
| `@typescript-eslint/no-explicit-any` | 🔴 Error | Using `any` type — use `unknown` and narrow |
| `@typescript-eslint/no-unused-vars` | 🔴 Error | Variables/imports declared but never used |
| `@typescript-eslint/no-non-null-assertion` | 🟡 Warning | Using `!` non-null assertion — prefer optional chaining `?.` |
| `@typescript-eslint/explicit-function-return-type` | 🟡 Warning | Public functions missing return type annotation |
| `@typescript-eslint/no-floating-promises` | 🔴 Error | Async call without `await` or `.catch()` — fire-and-forget bug |
| `@typescript-eslint/no-misused-promises` | 🔴 Error | Passing async function where sync callback expected |
| `@typescript-eslint/strict-boolean-expressions` | 🟡 Warning | Truthy check on non-boolean: `if (str)` instead of `if (str !== '')` |
| `@typescript-eslint/consistent-type-imports` | 🟡 Warning | `import type { X }` for type-only imports |
| `@typescript-eslint/no-unnecessary-condition` | 🟡 Warning | Condition is always true/false — dead code |
| `@typescript-eslint/prefer-nullish-coalescing` | 🟡 Warning | Use `??` instead of `\|\|` for null/undefined checks |
| `@typescript-eslint/no-unsafe-assignment` | 🔴 Error | Assigning `any` typed value to typed variable |
| `@typescript-eslint/no-unsafe-member-access` | 🔴 Error | Accessing properties on `any` typed value |
| `@typescript-eslint/no-unsafe-call` | 🔴 Error | Calling `any` typed value as function |
| `@typescript-eslint/no-unsafe-return` | 🔴 Error | Returning `any` from typed function |
| `react/jsx-no-target-blank` | 🔴 Error | `<a target="_blank">` without `rel="noopener noreferrer"` |
| `react/no-array-index-key` | 🟡 Warning | Using array index as `key` prop — unstable on reorder |
| `react-hooks/rules-of-hooks` | 🔴 Error | Hooks called conditionally or inside loops |
| `react-hooks/exhaustive-deps` | 🟡 Warning | Missing dependencies in useEffect/useMemo/useCallback |
| `react/no-danger` | 🔴 Error | Using `dangerouslySetInnerHTML` — XSS risk |
| `react/jsx-no-constructed-context-values` | 🟡 Warning | Object literal in Context.Provider value — re-renders children |
| `react/no-unstable-nested-components` | 🟡 Warning | Component defined inside render — unmounts/remounts every render |
| `jsx-a11y/alt-text` | 🔴 Error | `<img>` without `alt` attribute |
| `jsx-a11y/click-events-have-key-events` | 🟡 Warning | `onClick` without `onKeyDown`/`onKeyUp` |
| `jsx-a11y/no-autofocus` | 🟡 Warning | `autoFocus` disrupts screen reader flow |
| `jsx-a11y/anchor-is-valid` | 🟡 Warning | `<a>` without valid `href` — use `<button>` instead |
| `no-console` | 🟡 Warning | `console.log` left in production code |
| `no-debugger` | 🔴 Error | `debugger` statement in production code |
| `no-var` | 🔴 Error | Using `var` — use `const` or `let` |
| `prefer-const` | 🟡 Warning | `let` when variable is never reassigned |
| `eqeqeq` | 🔴 Error | `==` / `!=` instead of `===` / `!==` |
| `no-eval` | 🔴 Error | `eval()` — code injection risk |
| `no-implied-eval` | 🔴 Error | `setTimeout("code")` — hidden eval |
| `curly` | 🟡 Warning | If/else/for/while without braces |
#### ESLint Config (eslint.config.mjs — flat config)
```javascript
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import prettier from 'eslint-config-prettier';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
plugins: { react, 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y },
rules: {
// ── TypeScript ──
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/consistent-type-imports': 'warn',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
'@typescript-eslint/strict-boolean-expressions': 'warn',
'@typescript-eslint/no-non-null-assertion': 'warn',
'@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }],
'@typescript-eslint/no-unnecessary-condition': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
// ── React ──
'react/jsx-no-target-blank': 'error',
'react/no-array-index-key': 'warn',
'react/no-danger': 'error',
'react/jsx-no-constructed-context-values': 'warn',
'react/no-unstable-nested-components': 'warn',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
// ── Accessibility ──
'jsx-a11y/alt-text': 'error',
'jsx-a11y/click-events-have-key-events': 'warn',
'jsx-a11y/no-autofocus': 'warn',
'jsx-a11y/anchor-is-valid': 'warn',
// ── General JS ──
'no-console': 'warn',
'no-debugger': 'error',
'no-var': 'error',
'prefer-const': 'warn',
'eqeqeq': ['error', 'always'],
'no-eval': 'error',
'no-implied-eval': 'error',
'curly': ['warn', 'all'],
},
languageOptions: {
parserOptions: {
project: true,
ecmaFeatures: { jsx: true },
},
},
settings: { react: { version: 'detect' } },
},
prettier, // Must be last — disables formatting rules that conflict with Prettier
);
```
#### Prettier Config (.prettierrc)
```json
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"jsxSingleQuote": false,
"arrowParens": "always",
"endOfLine": "lf"
}
```
#### Run Commands
```bash
# Lint check (report only)
npx eslint . --ext .ts,.tsx,.js,.jsx --format stylish 2>&1
# Lint auto-fix
npx eslint . --ext .ts,.tsx,.js,.jsx --fix 2>&1
# Prettier check
npx prettier --check "src/**/*.{ts,tsx,js,jsx,json,css,md}" 2>&1
# Prettier auto-fix
npx prettier --write "src/**/*.{ts,tsx,js,jsx,json,css,md}" 2>&1
# Combined: lint + format check
npx eslint . --ext .ts,.tsx && npx prettier --check "src/**/*.{ts,tsx}"
```
---
### 2.2 C# / .NET — Roslyn Analyzers + dotnet-format + EditorConfig
#### Rules (Error = 🔴, Warning = 🟡)
| Rule ID | Severity | What It Catches |
|---------|----------|-----------------|
| `CA1001` | 🔴 Error | Type owns disposable field but doesn't implement IDisposable |
| `CA1031` | 🟡 Warning | Catching general `Exception` — catch specific types |
| `CA1032` | 🟡 Warning | Custom exception missing standard constructors |
| `CA1054` | 🟡 Warning | URI parameter should be `System.Uri`, not `string` |
| `CA1062` | 🔴 Error | Validate public method arguments for null |
| `CA1063` | 🔴 Error | Implement IDisposable correctly (Dispose pattern) |
| `CA1303` | 🟡 Warning | String literal in exception/UI — consider resource file for i18n |
| `CA1304` | 🟡 Warning | Missing `CultureInfo` or `StringComparison` on string operations |
| `CA1305` | 🟡 Warning | Missing `IFormatProvider` — use `CultureInfo.InvariantCulture` |
| `CA1707` | 🟡 Warning | Identifier contains underscore (non-standard naming) |
| `CA1716` | 🟡 Warning | Identifier matches reserved language keyword |
| `CA1812` | 🟡 Warning | Internal class never instantiated — dead code? |
| `CA1822` | 🟡 Warning | Method doesn't access instance data — make `static` |
| `CA1848` | 🟡 Warning | Use `LoggerMessage.Define` for high-perf logging |
| `CA1860` | 🟡 Warning | Prefer `Length > 0` over `Any()` for collections |
| `CA2000` | 🔴 Error | Dispose objects before losing scope |
| `CA2007` | 🟡 Warning | Missing `ConfigureAwait(false)` in library code |
| `CA2016` | 🔴 Error | Forward `CancellationToken` to methods that accept it |
| `CA2100` | 🔴 Error | SQL command text from variable — SQL injection risk |
| `CA2213` | 🔴 Error | Disposable fields should be disposed |
| `CA2227` | 🟡 Warning | Collection property has setter — remove setter, use init or readonly |
| `CA2241` | 🔴 Error | Format string argument count mismatch |
| `CA2254` | 🟡 Warning | Log message template should not vary between calls |
| `IDE0003` | 🟡 Warning | `this.` qualification unnecessary — remove |
| `IDE0005` | 🟡 Warning | Unnecessary `using` directive — remove |
| `IDE0011` | 🟡 Warning | Add braces to `if`/`else`/`for`/`while` |
| `IDE0044` | 🟡 Warning | Private field can be `readonly` |
| `IDE0055` | 🟡 Warning | Formatting rule violation (indentation, spacing) |
| `IDE0058` | â„¹ï¸ Info | Expression value is never used |
| `IDE0060` | 🟡 Warning | Unused parameter — remove or prefix with `_` |
| `IDE0063` | 🟡 Warning | Use simple `using` declaration instead of `using` block |
| `IDE0066` | 🟡 Warning | Use switch expression instead of switch statement |
| `IDE0090` | 🟡 Warning | Use `new()` target-typed expression |
| `CS8600` | 🔴 Error | Converting null literal to non-nullable type |
| `CS8601` | 🔴 Error | Possible null reference assignment |
| `CS8602` | 🔴 Error | Dereference of possibly null reference |
| `CS8604` | 🔴 Error | Possible null reference argument for parameter |
| `CS8618` | 🔴 Error | Non-nullable property must contain non-null when exiting constructor |
| `CS8625` | 🔴 Error | Cannot convert null literal to non-nullable reference type |
| `ASP0014` | 🟡 Warning | Suggest using top-level route registrations |
| `ASP0019` | 🟡 Warning | Suggest using IHeaderDictionary.Append |
| **SP-ONLY MANDATE RULES** | | |
| `SP001` | 🔴 Error | **Inline SQL detected** — any SELECT/INSERT/UPDATE/DELETE string in C# code |
| `SP002` | 🔴 Error | **Entity Framework detected** — DbContext, DbSet, using EF namespace, EF NuGet package |
| `SP003` | 🔴 Error | **Raw SqlCommand** — new SqlCommand() or CommandType.Text found |
| `SP004` | 🔴 Error | **Direct Dapper outside SpHelper** — Dapper calls must go through SpHelper only |
| `SP005` | 🔴 Error | **EF NuGet reference** — EntityFrameworkCore in .csproj |
| `SP006` | 🔴 Error | **EF migration** — Migrations folder, dotnet ef command, Add-Migration |
| `SP007` | 🔴 Error | **EF Fluent API** — modelBuilder, HasKey, HasOne, OnModelCreating |
| `SP008` | 🔴 Error | **EF persistence** — SaveChanges, SaveChangesAsync, Add(), Update(), Remove() on context |
| `SP009` | 🔴 Error | **EF query operators** — Include(), ThenInclude(), AsNoTracking() on context |
| `SP010` | 🔴 Error | **FromSqlRaw / ExecuteSqlRaw** — raw SQL through EF methods |
| `SP011` | 🟡 Warning | **Missing SpHelper** — Repository class has no SpHelper dependency |
| `SP012` | 🟡 Warning | **Missing WithTracking** — SP call without CorrelationId/RequestId injection |
| `ASP0019` | 🟡 Warning | Suggest using IHeaderDictionary.Append |
#### .editorconfig (place in solution root)
```ini
root = true
# ── All files ──
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
# ── C# files ──
[*.cs]
# Formatting
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_space_after_cast = false
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
# Naming: private fields _camelCase
dotnet_naming_rule.private_fields_should_be_camel_case.symbols = private_fields
dotnet_naming_rule.private_fields_should_be_camel_case.style = camel_case_underscore
dotnet_naming_rule.private_fields_should_be_camel_case.severity = warning
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.camel_case_underscore.required_prefix = _
dotnet_naming_style.camel_case_underscore.capitalization = camel_case
# Naming: interfaces I prefix
dotnet_naming_rule.interfaces_begin_with_i.symbols = interfaces
dotnet_naming_rule.interfaces_begin_with_i.style = begins_with_i
dotnet_naming_rule.interfaces_begin_with_i.severity = error
dotnet_naming_symbols.interfaces.applicable_kinds = interface
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.capitalization = pascal_case
# Naming: async methods end with Async
dotnet_naming_rule.async_methods_end_with_async.symbols = async_methods
dotnet_naming_rule.async_methods_end_with_async.style = ends_with_async
dotnet_naming_rule.async_methods_end_with_async.severity = warning
dotnet_naming_symbols.async_methods.applicable_kinds = method
dotnet_naming_symbols.async_methods.required_modifiers = async
dotnet_naming_style.ends_with_async.required_suffix = Async
dotnet_naming_style.ends_with_async.capitalization = pascal_case
# Code quality
dotnet_diagnostic.CA1001.severity = error
dotnet_diagnostic.CA1062.severity = error
dotnet_diagnostic.CA1063.severity = error
dotnet_diagnostic.CA2000.severity = error
dotnet_diagnostic.CA2016.severity = error
dotnet_diagnostic.CA2100.severity = error
dotnet_diagnostic.CA2213.severity = error
dotnet_diagnostic.CA1031.severity = warning
dotnet_diagnostic.CA1822.severity = warning
dotnet_diagnostic.IDE0005.severity = warning
dotnet_diagnostic.IDE0044.severity = warning
dotnet_diagnostic.IDE0060.severity = warning
# Nullable reference types
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8601.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8604.severity = error
dotnet_diagnostic.CS8618.severity = error
# ── SQL files ──
[*.sql]
indent_size = 4
indent_style = space
# ── TypeScript / JavaScript ──
[*.{ts,tsx,js,jsx}]
indent_size = 2
# ── JSON ──
[*.json]
indent_size = 2
# ── YAML ──
[*.{yml,yaml}]
indent_size = 2
# ── Markdown ──
[*.md]
trim_trailing_whitespace = false
```
#### .csproj Analyzer Configuration
```xml
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
```
#### Run Commands
```bash
# Full build with analyzers (catches Roslyn + nullable + style)
dotnet build --no-restore -warnaserror 2>&1 | head -80
# Format check (dry run — reports violations)
dotnet format --verify-no-changes --verbosity diagnostic 2>&1 | head -50
# Format auto-fix
dotnet format 2>&1
# Specific analyzer check
dotnet build /p:EnforceCodeStyleInBuild=true /p:AnalysisLevel=latest-all 2>&1 | grep -E "(error|warning) (CA|CS|IDE|ASP)" | head -50
```
---
### 2.3 T-SQL — SQL Lint Rules
#### Rules (Error = 🔴, Warning = 🟡)
| Rule ID | Severity | What It Catches |
|---------|----------|-----------------|
| `SQL001` | 🔴 Error | Missing `SET NOCOUNT ON` in stored procedure |
| `SQL002` | 🔴 Error | Missing `SET XACT_ABORT ON` in write procedures (_Manage) |
| `SQL003` | 🔴 Error | `SELECT *` used in production query — list columns explicitly |
| `SQL004` | 🔴 Error | `= NULL` comparison — must use `IS NULL` / `IS NOT NULL` |
| `SQL005` | 🔴 Error | `GETDATE()` used — must use `SYSUTCDATETIME()` for UTC |
| `SQL006` | 🔴 Error | `DATETIME` data type used — must use `DATETIME2` |
| `SQL007` | 🔴 Error | Dynamic SQL with string concatenation — SQL injection risk |
| `SQL008` | 🟡 Warning | Missing `N''` prefix for NVARCHAR string literals |
| `SQL009` | 🟡 Warning | Missing explicit constraint names (PK_, FK_, UQ_, DF_, CK_) |
| `SQL010` | 🟡 Warning | Missing `GO` batch separator between DDL statements |
| `SQL011` | 🟡 Warning | Missing `IF NOT EXISTS` guard on CREATE TABLE/INDEX |
| `SQL012` | 🟡 Warning | Missing index on foreign key column |
| `SQL013` | 🟡 Warning | `NOLOCK` hint used — prefer RCSI at database level |
| `SQL014` | 🟡 Warning | Unqualified column names in multi-table query (missing table alias) |
| `SQL015` | 🟡 Warning | `TOP` without `ORDER BY` — non-deterministic results |
| `SQL016` | 🟡 Warning | `IN` subquery — prefer `EXISTS` for correlated subqueries |
| `SQL017` | 🟡 Warning | `MONEY` / `FLOAT` for currency — use `DECIMAL(19,4)` |
| `SQL018` | 🟡 Warning | `TEXT` / `IMAGE` deprecated types — use `NVARCHAR(MAX)` / `VARBINARY(MAX)` |
| `SQL019` | 🔴 Error | Missing `@CorrelationId` / `@RequestId` as first two SP parameters |
| `SQL020` | 🔴 Error | Missing `log.RequestLog` START/SUCCESS/ERROR logging in SP |
| `SQL021` | 🟡 Warning | Missing audit columns (`CreatedBy`, `CreatedAt`, `ModifiedBy`, `ModifiedAt`) |
| `SQL022` | 🟡 Warning | Missing `IsActive BIT` soft-delete column |
| `SQL023` | 🟡 Warning | Missing semicolon statement terminator |
| `SQL024` | 🟡 Warning | Non-SARGable WHERE clause (function on indexed column) |
| `SQL025` | 🟡 Warning | Implicit conversion risk (VARCHAR compared to NVARCHAR column) |
| `SQL026` | 🟡 Warning | Missing TRY/CATCH in stored procedure |
| `SQL027` | 🟡 Warning | Cursor used — prefer set-based operations |
| `SQL028` | 🟡 Warning | `WHILE` loop — consider set-based alternative |
| `SQL029` | 🟡 Warning | `VARCHAR(MAX)` used without justification — prefer sized `VARCHAR(n)` |
| `SQL030` | 🟡 Warning | Table/column name is a reserved keyword |
#### Run Commands (bash-based SQL linting)
```bash
# ── Critical checks (🔴 Errors) ──
echo "=== SQL LINT — CRITICAL ==="
# SQL003: SELECT *
grep -rn "SELECT \*" --include="*.sql" | grep -v "EXISTS\s*(SELECT" | grep -v "\-\-" && echo "🔴 SQL003: SELECT * found"
# SQL004: = NULL
grep -rn "[^!<>]= NULL" --include="*.sql" | grep -v "\-\-" && echo "🔴 SQL004: = NULL found (use IS NULL)"
# SQL005: GETDATE
grep -rn "GETDATE()" --include="*.sql" | grep -v "\-\-" && echo "🔴 SQL005: GETDATE() found (use SYSUTCDATETIME())"
# SQL006: DATETIME without 2
grep -rn "DATETIME[^2]" --include="*.sql" | grep -v "DATETIME2" | grep -v "\-\-" && echo "🔴 SQL006: DATETIME found (use DATETIME2)"
# SQL007: Dynamic SQL concatenation
grep -rn "EXEC\s*(" --include="*.sql" | grep "+" | grep -v "\-\-" && echo "🔴 SQL007: Dynamic SQL with concatenation"
# SQL019: Missing tracking params
for f in $(grep -rl "CREATE.*PROCEDURE\|ALTER.*PROCEDURE" --include="*.sql"); do
if ! grep -q "@CorrelationId.*UNIQUEIDENTIFIER" "$f"; then
echo "🔴 SQL019: $f — Missing @CorrelationId parameter"
fi
if ! grep -q "@RequestId.*UNIQUEIDENTIFIER" "$f"; then
echo "🔴 SQL019: $f — Missing @RequestId parameter"
fi
done
# SQL001: Missing SET NOCOUNT ON
for f in $(grep -rl "CREATE.*PROCEDURE\|ALTER.*PROCEDURE" --include="*.sql"); do
if ! grep -q "SET NOCOUNT ON" "$f"; then
echo "🔴 SQL001: $f — Missing SET NOCOUNT ON"
fi
done
# ── Warning checks (🟡) ──
echo "=== SQL LINT — WARNINGS ==="
# SQL009: Unnamed constraints
grep -rn "PRIMARY KEY\|FOREIGN KEY\|UNIQUE\|DEFAULT\|CHECK" --include="*.sql" | grep -v "CONSTRAINT [A-Z][A-Z]_" | grep -v "\-\-" | head -20
# SQL013: NOLOCK hints
grep -rn "NOLOCK\|WITH\s*(NOLOCK)" --include="*.sql" | grep -v "\-\-" && echo "🟡 SQL013: NOLOCK hint found"
# SQL015: TOP without ORDER BY
grep -rn "SELECT TOP" --include="*.sql" | while read -r line; do
linenum=$(echo "$line" | cut -d: -f2)
file=$(echo "$line" | cut -d: -f1)
if ! sed -n "$((linenum)),\$p" "$file" | head -10 | grep -q "ORDER BY"; then
echo "🟡 SQL015: $line — TOP without ORDER BY"
fi
done
# SQL023: Missing semicolons
grep -rn "^[[:space:]]*\(SELECT\|INSERT\|UPDATE\|DELETE\|EXEC\)" --include="*.sql" | head -20
echo "=== SQL LINT COMPLETE ==="
```
#### SQLFluff Config (.sqlfluff — when using sqlfluff)
```ini
[sqlfluff]
dialect = tsql
templater = raw
max_line_length = 120
[sqlfluff:rules:capitalisation.keywords]
capitalisation_policy = upper
[sqlfluff:rules:capitalisation.identifiers]
capitalisation_policy = pascal
[sqlfluff:rules:aliasing.table]
aliasing = explicit
[sqlfluff:rules:aliasing.column]
aliasing = explicit
[sqlfluff:rules:convention.terminator]
require_final_semicolon = true
```
```bash
# SQLFluff lint
sqlfluff lint --dialect tsql *.sql 2>&1 | head -50
# SQLFluff auto-fix
sqlfluff fix --dialect tsql *.sql 2>&1
```
---
### 2.4 HTML — HTMLHint
#### Rules
| Rule | Severity | What It Catches |
|------|----------|-----------------|
| `tagname-lowercase` | 🟡 Warning | Tag names should be lowercase |
| `attr-lowercase` | 🟡 Warning | Attribute names should be lowercase |
| `attr-value-double-quotes` | 🟡 Warning | Attribute values should use double quotes |
| `doctype-first` | 🔴 Error | DOCTYPE must be first line in HTML files |
| `tag-pair` | 🔴 Error | Tags must be paired (no unclosed tags) |
| `spec-char-escape` | 🟡 Warning | Special characters must be escaped (`&`, `<`) |
| `id-unique` | 🔴 Error | Duplicate `id` attributes on same page |
| `src-not-empty` | 🔴 Error | `src` / `href` attributes must not be empty |
| `alt-require` | 🔴 Error | `<img>` must have `alt` attribute |
| `title-require` | 🟡 Warning | `<html>` should have `<title>` in `<head>` |
| `style-disabled` | 🟡 Warning | Inline `style` attribute — use CSS classes |
| `inline-script-disabled` | 🟡 Warning | Inline `onclick` etc. — use event listeners |
| `head-script-disabled` | 🟡 Warning | Prefer scripts at bottom of `<body>` or `defer` |
| `input-requires-label` | 🔴 Error | `<input>` must have associated `<label>` |
#### HTMLHint Config (.htmlhintrc)
```json
{
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"doctype-first": true,
"tag-pair": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"alt-require": true,
"title-require": true,
"style-disabled": true,
"inline-script-disabled": true,
"input-requires-label": true
}
```
```bash
npx htmlhint "**/*.html" 2>&1 | head -30
```
---
### 2.5 CSS / SCSS — Stylelint
#### Rules
| Rule | Severity | What It Catches |
|------|----------|-----------------|
| `color-no-invalid-hex` | 🔴 Error | Invalid hex color value |
| `font-family-no-duplicate-names` | 🟡 Warning | Same font listed twice |
| `declaration-no-important` | 🟡 Warning | `!important` — usually a specificity issue |
| `no-duplicate-selectors` | 🟡 Warning | Same selector appears twice in file |
| `no-descending-specificity` | 🟡 Warning | Lower specificity rule overrides higher one |
| `selector-no-qualifying-type` | 🟡 Warning | `div.class` — unnecessary type qualifier |
| `shorthand-property-no-redundant-values` | 🟡 Warning | `margin: 10px 10px 10px 10px` → `margin: 10px` |
| `property-no-unknown` | 🔴 Error | Unknown CSS property (typo) |
| `unit-no-unknown` | 🔴 Error | Unknown CSS unit (e.g., `10xp`) |
| `selector-max-id` | 🟡 Warning | Avoid ID selectors in stylesheets (specificity) |
| `max-nesting-depth` | 🟡 Warning | SCSS nesting > 3 levels deep |
| `no-empty-source` | 🟡 Warning | Empty CSS file |
#### Stylelint Config (.stylelintrc.json)
```json
{
"extends": ["stylelint-config-standard"],
"rules": {
"color-no-invalid-hex": true,
"font-family-no-duplicate-names": true,
"declaration-no-important": true,
"no-duplicate-selectors": true,
"no-descending-specificity": true,
"property-no-unknown": true,
"unit-no-unknown": true,
"selector-max-id": 0,
"max-nesting-depth": 3,
"no-empty-source": true
}
}
```
```bash
npx stylelint "**/*.css" "**/*.scss" 2>&1 | head -30
```
---
### 2.6 JSON — JSONLint + Schema Validation
#### Rules
| Rule | Severity | What It Catches |
|------|----------|-----------------|
| Syntax error | 🔴 Error | Invalid JSON (trailing comma, single quotes, comments) |
| Duplicate keys | 🔴 Error | Same key appears twice in same object |
| Schema mismatch | 🟡 Warning | `appsettings.json` missing required fields, wrong types |
| Trailing comma | 🔴 Error | `{ "a": 1, }` — invalid in standard JSON |
| Single quotes | 🔴 Error | `{'key': 'value'}` — JSON requires double quotes |
#### Run Commands
```bash
# Validate all JSON files
for f in $(find . -name "*.json" -not -path "*/node_modules/*"); do
python3 -c "import json; json.load(open('$f'))" 2>&1 && echo "✅ $f" || echo "🔴 $f — INVALID JSON"
done
# OR use jsonlint
npx jsonlint-mod --quiet *.json 2>&1
```
---
### 2.7 Markdown — markdownlint
#### Rules
| Rule | Severity | What It Catches |
|------|----------|-----------------|
| `MD001` | 🟡 Warning | Heading increment by more than one level (h1 → h3 skips h2) |
| `MD003` | 🟡 Warning | Inconsistent heading style (ATX vs setext) |
| `MD009` | 🟡 Warning | Trailing whitespace |
| `MD012` | 🟡 Warning | Multiple consecutive blank lines |
| `MD013` | â„¹ï¸ Info | Line length exceeds 120 chars |
| `MD022` | 🟡 Warning | Headings should be surrounded by blank lines |
| `MD032` | 🟡 Warning | Lists should be surrounded by blank lines |
| `MD033` | 🟡 Warning | Inline HTML in markdown (prefer markdown syntax) |
| `MD034` | 🟡 Warning | Bare URL (wrap in `<>` or `[text](url)`) |
| `MD041` | 🟡 Warning | First line should be a top-level heading |
```bash
npx markdownlint "**/*.md" --ignore node_modules 2>&1 | head -30
```
---
### 2.8 YAML — yamllint
```bash
pip install yamllint --break-system-packages 2>/dev/null
yamllint -s . 2>&1 | head -30
```
---
### 2.9 Dockerfile — hadolint
```bash
# If Docker files exist
if ls Dockerfile* 2>/dev/null; then
docker run --rm -i hadolint/hadolint < Dockerfile 2>&1 | head -20
fi
```
---
### Layer 2 Output Format
```
## Layer 2 — Lint Check
### TypeScript / React (ESLint + Prettier)
| # | File | Line | Rule | Severity | Message | Auto-Fix? |
|---|------|------|------|----------|---------|-----------|
| 1 | UserCard.tsx | 12 | @typescript-eslint/no-explicit-any | 🔴 Error | Unexpected `any`. Specify a type. | No |
| 2 | api.ts | 34 | @typescript-eslint/no-floating-promises | 🔴 Error | Promise returned but not awaited | No |
| 3 | App.tsx | 5 | prefer-const | 🟡 Warning | 'theme' is never reassigned. Use `const`. | ✅ Yes |
| 4 | index.tsx | 1 | @typescript-eslint/consistent-type-imports | 🟡 Warning | Use `import type` for type-only imports | ✅ Yes |
Prettier: 2 files need formatting (auto-fixable ✅)
### C# / .NET (Roslyn + dotnet-format)
| # | File | Line | Rule | Severity | Message | Auto-Fix? |
|---|------|------|------|----------|---------|-----------|
| 1 | UserService.cs | 45 | CA2016 | 🔴 Error | Forward CancellationToken to 'GetAsync' | No |
| 2 | SpHelper.cs | 12 | CS8602 | 🔴 Error | Dereference of possibly null reference | No |
| 3 | Program.cs | 8 | IDE0005 | 🟡 Warning | Remove unnecessary using | ✅ Yes |
dotnet-format: 3 files need formatting (auto-fixable ✅)
### T-SQL (SQL Lint)
| # | File | Line | Rule | Severity | Message | Auto-Fix? |
|---|------|------|------|----------|---------|-----------|
| 1 | Reports_Get.sql | 15 | SQL003 | 🔴 Error | SELECT * — list columns explicitly | No |
| 2 | Users_Manage.sql | 88 | SQL023 | 🟡 Warning | Missing semicolon terminator | ✅ Yes |
### JSON
All JSON files valid ✅
### Summary
| Language | 🔴 Errors | 🟡 Warnings | Auto-Fixable |
|----------|-----------|-------------|--------------|
| TypeScript/React | 2 | 2 | 2 |
| C# / .NET | 2 | 1 | 1 |
| T-SQL | 1 | 1 | 1 |
| JSON | 0 | 0 | 0 |
| **Total** | **5** | **4** | **4** |
**Result: ⌠5 Errors found — fix all errors before proceeding to Layer 3**
```
---
## Layer 3 — SonarQube-Lite Static Analysis
Simulate SonarQube's key rules for reliability, maintainability, and code smells.
### 3.1 Code Smells
| Smell | Severity | Detection |
|-------|----------|-----------|
| **Cognitive Complexity** > 15 | 🟠High | Nested ifs/loops/switches exceeding 3 levels; long CASE chains |
| **Method too long** > 40 lines | 🟡 Medium | Functions/methods/SP blocks exceeding 40 executable lines |
| **Too many parameters** > 7 | 🟡 Medium | Functions or SPs with more than 7 business parameters (tracking IDs excluded) |
| **Duplicate code blocks** | 🟡 Medium | 6+ lines duplicated across files; copy-pasted WHERE clauses |
| **Dead code** | 🟡 Medium | Commented-out code blocks, unreachable branches, unused functions |
| **Magic numbers/strings** | 🟡 Medium | Hardcoded values instead of constants: `if (status == 3)`, `"admin"` |
| **Long parameter list** | 🟡 Medium | Favor parameter objects over 5+ primitive parameters |
| **Deep nesting** > 3 levels | 🟡 Medium | Early return/guard clauses preferred over nested ifs |
| **Empty catch blocks** | 🟠High | `catch { }` or `catch (Exception) { }` with no logging/re-throw |
| **God class/file** > 300 lines | 🟡 Medium | Split into focused, single-responsibility modules |
### 3.2 Reliability
| Rule | Severity | Detection |
|------|----------|-----------|
| Null pointer dereference | 🔴 Critical | Accessing `.Property` on potentially null object |
| Resource leak | 🟠High | SqlConnection, HttpClient, Stream not disposed |
| Unchecked return value | 🟡 Medium | Ignoring return from async calls, .TryParse, etc. |
| Off-by-one errors | 🟠High | Array bounds, pagination OFFSET calculations |
| Race conditions | 🟠High | Shared mutable state without synchronization |
| Missing error handling | 🟠High | No try-catch around I/O operations |
| Infinite loop risk | 🔴 Critical | Loops with no guaranteed exit condition |
### 3.3 Maintainability Rating
Score each file A-E:
| Rating | Criteria |
|--------|----------|
| **A** | ≤ 5% of code needs refactoring; no smells above Medium |
| **B** | 6–10% needs refactoring; no more than 2 Medium smells |
| **C** | 11–20% needs refactoring; has High smells but no Critical |
| **D** | 21–50% needs refactoring; has Critical smells |
| **E** | > 50% needs refactoring; fundamental design issues |
### 3.4 Duplication Detection
Flag these patterns:
- **Exact duplicates**: 6+ identical lines across files
- **Structural duplicates**: Same logic with different variable names
- **SQL duplicates**: Repeated WHERE/JOIN patterns that should be a view or CTE
- **Config duplicates**: Same connection strings, URLs in multiple places
### Output Format
```
## Layer 3 — SonarQube-Lite Analysis
### Code Smells: 3 found
| # | File | Line | Rule | Severity | Message |
|---|------|------|------|----------|---------|
| 1 | OrderService.cs | 45-120 | S3776 | 🟠High | Cognitive complexity is 22 (max 15) |
| 2 | Users_Get.sql | 30 | S109 | 🟡 Medium | Magic number 200 — extract to named constant or parameter |
| 3 | UserList.tsx | 15-89 | S138 | 🟡 Medium | Function too long (74 lines, max 40) |
### Duplication: 1 block
| Files | Lines | Duplicate Lines |
|-------|-------|----------------|
| Orders_Get.sql ↔ Products_Get.sql | 20-35 ↔ 18-33 | 15 lines (pagination pattern) |
### Maintainability: B (92/100)
**Result: âš ï¸ 1 High, 2 Medium — fix High before proceeding**
```
---
## Layer 4 — Vulnerability Scan
Check for known vulnerability patterns in code and dependencies.
### 4.1 Injection Vulnerabilities
| Type | Language | What to Check |
|------|----------|---------------|
| **SQL Injection** | T-SQL | Dynamic SQL built with string concatenation: `EXEC('SELECT * FROM ' + @TableName)` |
| **SQL Injection** | C# | Raw string interpolation in queries: `$"SELECT * FROM Users WHERE Id = {id}"` |
| **XSS** | React/TS | `dangerouslySetInnerHTML`, unescaped user input in DOM |
| **Command Injection** | C# | `Process.Start()` with user-supplied arguments |
| **Path Traversal** | C#/Node | File operations with unsanitized user input: `File.ReadAllText(userPath)` |
| **LDAP Injection** | C# | Unsanitized input in LDAP queries |
| **NoSQL Injection** | TS/Node | Unvalidated objects passed to MongoDB queries |
| **Header Injection** | C# | User input in HTTP response headers |
### 4.2 Secrets & Credentials Exposure
```
🔴 CRITICAL — scan every file for:
✅ Hardcoded connection strings with passwords
✅ API keys in source code (regex: [A-Za-z0-9]{20,} near 'key', 'secret', 'token', 'password')
✅ Private keys or certificates in code
✅ Credentials in config files committed to source (appsettings.json with real passwords)
✅ JWT secrets hardcoded
✅ Cloud provider access keys (AWS, Azure, GCP patterns)
✅ Database passwords in plain text
```
**Detection regex patterns:**
```bash
# Secrets detection
grep -rn "password\s*[:=]\s*['\"]" --include="*.cs" --include="*.ts" --include="*.json" --include="*.sql"
grep -rn "connectionstring.*password" --include="*.json" --include="*.config" -i
grep -rn "Bearer [A-Za-z0-9\-._~+/]+" --include="*.cs" --include="*.ts"
grep -rn "sk-[A-Za-z0-9]{20,}" --include="*.cs" --include="*.ts" --include="*.json"
grep -rn "AKIA[A-Z0-9]{16}" --include="*.cs" --include="*.ts" --include="*.json"
```
### 4.3 Dependency Vulnerabilities
```bash
# .NET
dotnet list package --vulnerable 2>&1
# Node/React
npm audit 2>&1 | head -30
# Check for known vulnerable package versions
grep -n "System.Text.Json.*[0-7]\." *.csproj # Example: < v8 has known issues
```
### 4.4 Data Exposure
| Check | Severity | Details |
|-------|----------|---------|
| Stack traces in API responses | 🔴 Critical | GlobalExceptionMiddleware must catch ALL exceptions |
| Verbose error messages | 🟠High | Never expose column names, SP names, SQL errors to client |
| Sensitive data in logs | 🟠High | Don't log passwords, tokens, PII, full credit card numbers |
| Missing HTTPS enforcement | 🟠High | `app.UseHttpsRedirection()` must be present |
| PII in URL query parameters | 🟠High | Email, SSN, phone should be in POST body, not GET params |
| Sensitive data in localStorage | 🟠High | Tokens and PII should use httpOnly cookies or sessionStorage |
| Over-fetching from DB | 🟡 Medium | SELECT * returning columns with PII when not needed |
### Output Format
```
## Layer 4 — Vulnerability Scan
| # | File | Line | Type | Severity | Finding |
|---|------|------|------|----------|---------|
| 1 | appsettings.json | 5 | Secret | 🔴 Critical | Hardcoded DB password in connection string |
| 2 | SearchController.cs | 22 | SQLi | 🔴 Critical | String interpolation in raw SQL query |
| 3 | UserCard.tsx | 15 | XSS | 🟠High | dangerouslySetInnerHTML with user-supplied bio |
**Result: ⌠2 Critical, 1 High — MUST fix all before proceeding**
```
---
## Layer 5 — Security Hardening (OWASP Top 10)
Map every finding to OWASP 2021 Top 10 categories.
### OWASP Checklist per Language
#### A01: Broken Access Control
```
✅ Every API endpoint has [Authorize] or explicit [AllowAnonymous]
✅ Resource-level authorization (user can only access their own data)
✅ CORS configured for specific origins, never wildcard in production
✅ SQL SPs accept @UserId for audit — verify caller has permission
✅ No IDOR: user cannot pass another user's ID to access their data
✅ Anti-CSRF tokens on state-changing operations
✅ Directory listing disabled on web server
```
#### A02: Cryptographic Failures
```
✅ Passwords hashed with bcrypt/Argon2, never MD5/SHA1/plain
✅ Sensitive data encrypted at rest (column encryption, TDE)
✅ TLS 1.2+ enforced; no HTTP fallback
✅ Secrets in vault/environment variables, not in source
✅ No custom cryptography implementations
```
#### A03: Injection
```
✅ Parameterized queries / stored procedures — never string concatenation
✅ Input validated on both client AND server side
✅ HTML output encoded to prevent XSS
✅ File uploads validated (type, size, name sanitization)
✅ LIKE patterns escaped: user input with %, _, [ chars handled
```
#### A04: Insecure Design
```
✅ Rate limiting on authentication endpoints
✅ Account lockout after failed attempts
✅ Business logic validation server-side (not just UI)
✅ Proper error handling that doesn't reveal system internals
✅ Principle of least privilege in DB permissions
```
#### A05: Security Misconfiguration
```
✅ Debug/development mode disabled in production config
✅ Default credentials changed
✅ Unnecessary HTTP methods disabled
✅ Security headers set: X-Content-Type-Options, X-Frame-Options, CSP
✅ Stack traces never exposed in production responses
✅ Swagger/API docs disabled in production
```
#### A06: Vulnerable and Outdated Components
```
✅ No packages with known CVEs
✅ Frameworks at supported LTS versions
✅ No deprecated APIs used (TEXT, IMAGE, DATETIME in SQL Server)
```
#### A07: Identification and Authentication Failures
```
✅ JWT tokens have reasonable expiry
✅ Refresh token rotation implemented
✅ Password complexity enforced
✅ Session invalidation on logout
✅ Multi-factor authentication available for admin
```
#### A08: Software and Data Integrity Failures
```
✅ Input deserialization is validated (no insecure deserialization)
✅ Package integrity verified (lock files committed)
✅ No eval() or dynamic code execution with user input
```
#### A09: Security Logging and Monitoring Failures
```
✅ CorrelationId + RequestId logged on every operation
✅ Authentication failures logged
✅ Authorization failures logged
✅ Input validation failures logged (potential attack detection)
✅ Sensitive data masked in logs
✅ Log injection prevented (user input sanitized before logging)
```
#### A10: Server-Side Request Forgery (SSRF)
```
✅ URL validation on any server-side HTTP requests
✅ Allowlist for external API calls
✅ No user-controlled URLs passed to HttpClient without validation
```
### Output Format
```
## Layer 5 — Security Hardening (OWASP)
| # | OWASP | File | Line | Severity | Finding | Fix |
|---|-------|------|------|----------|---------|-----|
| 1 | A01 | UsersController.cs | 34 | 🔴 Critical | Missing [Authorize] on DELETE endpoint | Add [Authorize(Roles = "Admin")] |
| 2 | A03 | Reports_Get.sql | 22 | 🟠High | LIKE pattern not escaping user wildcards | Add ESCAPE clause or sanitize @SearchText |
| 3 | A05 | Program.cs | 48 | 🟡 Medium | Swagger enabled in all environments | Wrap in if (app.Environment.IsDevelopment()) |
**Result: ⌠1 Critical, 1 High, 1 Medium — fix Critical and High before proceeding**
```
---
## Layer 6 — Optimization & Standards Compliance
### 6.1 Performance Optimization
#### T-SQL Performance
```
✅ SARGable WHERE clauses — no functions on indexed columns
✅ Appropriate indexes exist for JOIN/WHERE/ORDER BY columns
✅ Foreign key columns indexed
✅ OFFSET/FETCH used for pagination (not TOP with subquery)
✅ ISNULL/COALESCE used correctly (ISNULL is faster for simple cases)
✅ Temp tables for large sets, table variables for < 100 rows
✅ No unnecessary DISTINCT (indicates a JOIN issue)
✅ EXISTS preferred over IN for correlated subqueries
✅ No implicit conversions in WHERE/JOIN (VARCHAR vs NVARCHAR)
✅ NOLOCK used sparingly; RCSI preferred
✅ No cursors — use set-based operations
✅ Computed columns considered for frequently derived values
✅ Statistics up to date on key columns
```
#### C# / .NET Performance
```
✅ async/await used throughout I/O paths — no sync-over-async
✅ CancellationToken forwarded through entire call chain
✅ IAsyncEnumerable for streaming large datasets from SPs
✅ StringBuilder for string concatenation in loops (> 3 concatenations)
✅ Span<T> / ReadOnlySpan<T> for parsing and slicing
✅ No Task.Result / .Wait() (deadlock risk in ASP.NET)
✅ HttpClient registered via IHttpClientFactory (not new HttpClient())
✅ SpHelper connection opened/closed per call (Dapper handles pooling)
✅ SP result sets return only needed columns — no SELECT * in SPs
✅ SP pagination uses OFFSET/FETCH with max PageSize cap (200)
✅ Dapper QueryMultipleAsync for SPs returning multiple result sets
✅ DynamicParameters reused efficiently — no unnecessary allocations
✅ Value types (struct/record struct) for small, immutable DTOs
🔴 NO EF Core — no AsNoTracking, no Select() projection, no compiled queries
🔴 NO inline SQL — all data access through SpHelper → Stored Procedures
```
#### React / TypeScript Performance
```
✅ Components don't re-render unnecessarily (check with React DevTools)
✅ useMemo/useCallback only where profiling shows benefit — not everywhere
✅ Large lists virtualized (@tanstack/react-virtual)
✅ Route-based code splitting with lazy() and Suspense
✅ Images optimized (WebP, lazy loading, appropriate dimensions)
✅ Bundle size checked — no unnecessary large dependencies
✅ Debounced search input (300ms minimum)
✅ AbortController used for cancellable fetch requests
✅ No inline object/array creation in JSX props (causes re-renders)
✅ TanStack Query caching configured (staleTime, gcTime)
```
### 6.2 Standards Compliance
#### Naming Conventions
| Element | T-SQL | C# | TypeScript/React |
|---------|-------|-----|-----------------|
| Tables | PascalCase plural (`app.Users`) | N/A | N/A |
| Columns | PascalCase (`FirstName`) | PascalCase properties | camelCase (`firstName`) |
| SPs | `{Table}_Manage` / `{Table}_Get` | N/A | N/A |
| Variables | `@CamelCase` | `_camelCase` (private) | `camelCase` |
| Constants | N/A | `PascalCase` | `SCREAMING_SNAKE` or `PascalCase` |
| Interfaces | N/A | `IUserRepository` | `UserCardProps` (no I prefix) |
| Files | `SP_{Name}.sql` | `UserService.cs` | `UserCard.tsx` |
| CSS classes | N/A | N/A | `kebab-case` or Tailwind utilities |
#### Team Convention Checks
```
✅ Consistent quote style (single quotes in TS, single in SQL strings)
✅ Consistent indentation (4 spaces for C#/SQL, 2 spaces for TS/React)
✅ Consistent import ordering (React → third-party → local → types)
✅ Consistent file organization (feature-based folders)
✅ Consistent error handling patterns (Result<T> or exception-based — pick one)
✅ No mixed patterns (don't use both Dapper and raw ADO.NET in same project)
✅ Comment quality — complex logic has WHY comments, not WHAT comments
✅ TODO/FIXME/HACK markers documented with ticket numbers
```
### 6.3 Documentation & Readability
```
✅ Public APIs have XML doc comments (C#) or JSDoc (TypeScript)
✅ Complex SQL has inline comments explaining business logic
✅ README updated when new features/tables/endpoints added
✅ Breaking changes documented
✅ API endpoint documentation (Swagger annotations) accurate
```
### Output Format
```
## Layer 6 — Optimization & Standards
| # | File | Line | Category | Severity | Finding | Recommendation |
|---|------|------|----------|----------|---------|----------------|
| 1 | Orders_Get.sql | 44 | Perf | 🟡 Medium | Non-SARGable: WHERE YEAR(OrderDate) = 2024 | Use date range: >= '2024-01-01' AND < '2025-01-01' |
| 2 | UserService.cs | 28 | Perf | 🟡 Medium | Missing CancellationToken forwarding | Add CancellationToken ct parameter |
| 3 | UserList.tsx | 12 | Perf | â„¹ï¸ Info | Search input not debounced | Add useDebounce(300ms) hook |
| 4 | api.ts | 5 | Standards | â„¹ï¸ Info | Inconsistent import ordering | Group: react → third-party → @/ local → types |
**Result: ✅ 0 Critical/High — 2 Medium, 2 Info (recommended fixes)**
```
---
## Final Gate Summary Template
After all 6 layers run, produce this summary:
```
â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
CODE QUALITY GATE — FINAL REPORT
â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
Files Checked: 5
Languages: T-SQL, C#, TypeScript/React
┌──────────────────────────────┬────────┬────────────â”
│ Check │ Status │ Issues │
├──────────────────────────────┼────────┼────────────┤
│ ðŸ›ï¸ SP-Only Mandate │ ✅ Pass │ No EF/Inline│
│ 1. VS Code Problems Tab │ ✅ Pass │ 0E 2W 0I │
│ 2. Lint Check (ALL langs) │ ✅ Pass │ 0E 3W 1I │
│ 3. SonarQube-Lite Analysis │ ✅ Pass │ 0C 1H 2M │
│ 4. Vulnerability Scan │ ✅ Pass │ 0C 0H 1M │
│ 5. Security (OWASP) │ ✅ Pass │ 0C 0H 2M │
│ 6. Optimization & Standards │ ✅ Pass │ 0C 0H 3M │
├──────────────────────────────┼────────┼────────────┤
│ OVERALL │ ✅ PASS │ 0C 1H 11M │
└──────────────────────────────┴────────┴────────────┘
Legend: C=Critical, H=High, M=Medium, E=Error, W=Warning, I=Info
SP-Only Mandate:
✅ No Entity Framework detected (no DbContext, DbSet, EF NuGet packages)
✅ No inline SQL detected (no raw SELECT/INSERT/UPDATE/DELETE in C#)
✅ All data access via SpHelper → Stored Procedures → Dapper
✅ @CorrelationId + @RequestId injected via WithTracking()
Gate Criteria:
✅ SP-Only Mandate passed
✅ Zero Critical findings across all layers
✅ Zero Errors in Layer 1 + Layer 2
âš ï¸ 1 High in Layer 3 — accepted (tracked in findings below)
Remaining Findings (Medium/Low — fix when practical):
1. [L2] App.tsx:5 — prefer-const: 'theme' never reassigned → use const
2. [L3] OrderService.cs:45 — Cognitive complexity 18 → refactor to extract methods
3. [L4] package.json — lodash 4.17.20 has prototype pollution fix in 4.17.21
4. ...
✅ GATE PASSED — files cleared for delivery to /mnt/user-data/outputs/
```
---
## Gate Decision Rules
| Findings | Decision |
|----------|----------|
| ðŸ›ï¸ SP-Only Mandate violated (EF or inline SQL found) | ⌠**BLOCKED** — rewrite to use SpHelper + SPs, no exceptions |
| 🔴 Any Critical (any layer) | ⌠**BLOCKED** — fix immediately, re-run gate |
| 🔴 Any Error in Layer 1 or Layer 2 | ⌠**BLOCKED** — code won't compile/run or fails lint |
| 🟠High findings only | âš ï¸ **CONDITIONAL** — fix if straightforward; document if accepted |
| 🟡 Medium and below only | ✅ **PASS** — deliver, note findings for future improvement |
| No findings | ✅ **CLEAN PASS** — deliver immediately |
---
## Integration with Existing Skills
This quality gate works alongside the existing tech-stack skills:
| After This Skill Runs... | This Gate Checks... |
|--------------------------|---------------------|
| **mssql** (T-SQL skill) | SP has @CorrelationId/@RequestId, SET NOCOUNT ON, idempotent DDL, proper indexing, no SELECT *, UTC dates, audit columns, soft delete |
| **dotnet** (.NET skill) | **ðŸ›ï¸ SP-Only Mandate** (no EF, no inline SQL, all access via SpHelper), TrackingContext injected, GlobalExceptionMiddleware present, no leaked stack traces, Serilog configured, CancellationToken forwarded, ApiResponse<T> wrapper used, Dapper + Microsoft.Data.SqlClient ONLY |
| **react** (React skill) | X-Correlation-Id sent, X-Request-Id read, ErrorBoundary wrapping routes, ErrorFallback shows requestId not stack trace, hooks follow rules, proper TypeScript strict mode |
### Cross-Stack Consistency Checks
```
✅ T-SQL SP parameter names match C# DynamicParameters.Add() names
✅ SP result set column names match C# DTO property names (case-insensitive via Dapper)
✅ API response shape matches TypeScript interface definitions
✅ API route naming matches React api.ts URL constants
✅ Error codes thrown in SP (50001, 50002...) handled in C# service layer
✅ Filter parameters (PageNumber, PageSize, SortColumn) consistent across all 3 layers
✅ CorrelationId + RequestId present in: SP params → C# SpHelper → API headers → React apiClient → ErrorFallback
✅ NO EF Core anywhere — no DbContext, no migrations, no EF NuGet packages
✅ ALL .cs repository files inject SpHelper, not DbContext
✅ ALL data operations: Repository → SpHelper.ManageAsync/GetByIdAsync/GetListAsync → SP
✅ NO inline SQL in any .cs file — zero tolerance
```
---
## Execution Workflow
When running this gate, follow this exact workflow:
```
1. IDENTIFY changed files
→ List all files created or modified in this session
2. RUN SP-ONLY MANDATE CHECK (before all layers — instant blocker)
→ For .cs files: scan for inline SQL, EF Core, raw SqlCommand
→ For .csproj files: scan for EntityFrameworkCore NuGet packages
→ If ANY violation found: ⌠BLOCKED — rewrite to use SpHelper + SPs
→ This check is NON-NEGOTIABLE — no exceptions, no workarounds
3. RUN Layer 1 (VS Code Problems)
→ For each file: syntax check, type check, reference check
→ Use bash tools where possible (tsc --noEmit, dotnet build)
→ If ANY 🔴 Error: STOP, fix, re-check
4. RUN Layer 2 (Lint Check — ALL languages)
→ TypeScript/React: npx eslint + npx prettier --check
→ C#/.NET: dotnet build (Roslyn analyzers) + dotnet format --verify-no-changes
→ C#/.NET: SP001-SP012 rules (inline SQL, EF detection, SpHelper verification)
→ T-SQL: bash grep checks for SQL001-SQL030 rules + sqlfluff lint
→ HTML: npx htmlhint
→ CSS: npx stylelint
→ JSON: python3 json.load validation / npx jsonlint-mod
→ Markdown: npx markdownlint
→ Auto-fix where possible (eslint --fix, prettier --write, dotnet format)
→ If ANY 🔴 Error after auto-fix: STOP, manual fix, re-check
5. RUN Layer 3 (SonarQube-Lite)
→ For each file: complexity, smells, duplication, maintainability rating
→ If ANY 🔴 Critical: STOP, fix, re-check
6. RUN Layer 4 (Vulnerability Scan)
→ For each file: injection patterns, secrets scan, dependency audit
→ If ANY 🔴 Critical: STOP, fix, re-check
7. RUN Layer 5 (Security / OWASP)
→ For each file: auth, input validation, data exposure, headers
→ If ANY 🔴 Critical: STOP, fix, re-check
8. RUN Layer 6 (Optimization & Standards)
→ For each file: performance, naming, conventions, documentation
→ Note findings but don't block on Medium/Low
9. PRODUCE Final Gate Summary
→ Table with all 6 layers + SP-only mandate status
→ List remaining Medium/Low findings
→ ✅ PASS / ⌠BLOCKED decision
9. IF PASSED: copy to /mnt/user-data/outputs/
IF BLOCKED: fix issues and re-run from the failed layer
```
---
## Quick-Reference Severity Guide
| Severity | Icon | Action | Examples |
|----------|------|--------|----------|
| 🔴 Critical | 🔴 | **Must fix now** — blocks delivery | SQL injection, hardcoded secrets, missing auth, syntax errors, null pointer crash |
| 🟠High | 🟠| **Should fix** — significant risk or smell | Empty catch blocks, resource leaks, cognitive complexity > 20, missing HTTPS |
| 🟡 Medium | 🟡 | **Fix when practical** — quality improvement | Unused variables, long methods, missing comments, non-optimal indexes |
| â„¹ï¸ Info | â„¹ï¸ | **Note for awareness** — nice-to-have | Import ordering, minor naming inconsistencies, potential micro-optimizations |
---
## Output Delivery
1. **This gate runs AFTER code is written** — it is the last step before delivery
2. **Run ALL 6 layers** — no skipping, no shortcuts
3. **Layer 2 (Lint) must auto-fix first** — run `eslint --fix`, `prettier --write`, `dotnet format` before reporting remaining issues
4. **Produce the Final Gate Summary** in every response where files are delivered
5. **Block delivery on Critical/Error findings** — fix first, then re-run
6. **Document accepted findings** — Medium/Low issues noted for future improvement
7. **Cross-reference with tech-stack skills** — ensure mssql/dotnet/react conventions followed
8. **Include lint config files** — when creating new projects, generate `.eslintrc`/`eslint.config.mjs`, `.prettierrc`, `.editorconfig`, `.stylelintrc.json`, `.htmlhintrc`, `.sqlfluff` alongside source code
9. **The gate report is shown inline in the chat** — not as a separate file (unless user requests it)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!