Policy AOC Linting Rules

Document ID: DESIGN-POLICY-AOC-LINTING-001 Version: 1.0 Status: Published Last Updated: 2025-12-06

Overview

This document defines the linting and static analysis rules for Policy Engine and related library projects. These rules enforce determinism, nullability, async consistency, and JSON property ordering to ensure reproducible policy evaluation.

Target Projects

ProjectPathNotes
StellaOps.Policy.Enginesrc/Policy/StellaOps.Policy.Engine/Primary target
StellaOps.Policysrc/Policy/__Libraries/StellaOps.Policy/Core library
StellaOps.PolicyDslsrc/Policy/StellaOps.PolicyDsl/DSL compiler
StellaOps.Policy.RiskProfilesrc/Policy/StellaOps.Policy.RiskProfile/Risk scoring
StellaOps.Policy.Storage.Postgressrc/Policy/__Libraries/StellaOps.Policy.Storage.Postgres/Storage layer

Excluded

Rule Categories

1. Determinism Rules (Error Severity)

Enforced by ProhibitedPatternAnalyzer at src/Policy/StellaOps.Policy.Engine/DeterminismGuard/.

Rule IDPatternSeverityRemediation
DET-001DateTime.NowErrorUse TimeProvider.GetUtcNow()
DET-002DateTime.UtcNowErrorUse TimeProvider.GetUtcNow()
DET-003DateTimeOffset.NowErrorUse TimeProvider.GetUtcNow()
DET-004DateTimeOffset.UtcNowErrorUse TimeProvider.GetUtcNow()
DET-005Guid.NewGuid()ErrorUse StableIdGenerator or content hash
DET-006new Random()ErrorUse seeded random or remove
DET-007RandomNumberGeneratorErrorRemove from evaluation path
DET-008HttpClient in evalCriticalRemove network from eval path
DET-009File.Read* in evalCriticalRemove filesystem from eval path
DET-010Dictionary iterationWarningUse OrderBy or SortedDictionary
DET-011HashSet iterationWarningUse OrderBy or SortedSet

2. Nullability Rules (Error Severity)

Rule IDDescriptionEditorConfig
NUL-001Enable nullable reference typesnullable = enable
NUL-002Nullable warnings as errorsdotnet_diagnostic.CS8600-CS8609.severity = error
NUL-003Null parameter checksArgumentNullException.ThrowIfNull()

3. Async/Sync Consistency Rules (Warning Severity)

Rule IDDescriptionEditorConfig
ASY-001Async void methodsdotnet_diagnostic.CA2012.severity = error
ASY-002Missing ConfigureAwaitdotnet_diagnostic.CA2007.severity = warning
ASY-003Sync over asyncdotnet_diagnostic.MA0045.severity = warning
ASY-004Task.Result in asyncdotnet_diagnostic.MA0042.severity = error

4. JSON Property Ordering Rules

For deterministic JSON output, all DTOs must use explicit [JsonPropertyOrder] attributes.

Rule IDDescriptionEnforcement
JSN-001Explicit property orderCode review + analyzer
JSN-002Stable serializationJsonSerializerOptions.WriteIndented = false
JSN-003Key orderingJsonSerializerOptions.PropertyNamingPolicy with stable order

5. Code Style Rules

Rule IDDescriptionEditorConfig
STY-001File-scoped namespacescsharp_style_namespace_declarations = file_scoped
STY-002Primary constructorscsharp_style_prefer_primary_constructors = true
STY-003Collection expressionscsharp_style_prefer_collection_expression = true
STY-004Implicit usingsImplicitUsings = enable

Severity Levels

LevelBehaviorCI Impact
ErrorBuild failsBlocks merge
WarningBuild succeeds, loggedReview required
InfoLogged onlyNo action required

CI Integration

Build-time Enforcement

Policy projects use TreatWarningsAsErrors=true in .csproj:

<PropertyGroup>
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  <Nullable>enable</Nullable>
</PropertyGroup>

Static Analysis Pipeline

The .gitea/workflows/policy-lint.yml workflow runs:

  1. dotnet build with analyzer packages
  2. DeterminismGuard analysis via CLI
  3. Format check via dotnet format --verify-no-changes

Required Analyzer Packages

<ItemGroup>
  <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.0-*" />
  <PackageReference Include="Meziantou.Analyzer" Version="2.0.*" />
</ItemGroup>

Baseline Suppressions

Create .globalconfig for legacy code that cannot be immediately fixed:

# Legacy suppressions - track issue for remediation
[src/Policy/**/LegacyCode.cs]
dotnet_diagnostic.DET-010.severity = suggestion

Runtime Enforcement

The DeterminismGuardService provides runtime monitoring:

using var scope = _determinismGuard.CreateScope(scopeId, timestamp);
var result = await evaluation(scope);
var analysis = scope.Complete();
if (!analysis.Passed) { /* log/reject */ }

Acceptance Criteria

  1. All Policy projects build with zero errors
  2. dotnet format reports no changes needed
  3. DeterminismGuard analysis passes
  4. New code has no nullable warnings
  5. Async methods use ConfigureAwait(false)