DEV Community

Cover image for AI Is Changing What 'Correct Software' Means
Majdi Zlitni
Majdi Zlitni

Posted on

AI Is Changing What 'Correct Software' Means

Software engineers used to define a "Correct software" via a simple deterministic binary an Expected Output.
All Test are passed, but this is collapsing, a green CI pipeline no longer guarantees correct software, with AI-generated code that's look syntactically perfect and test-compliant yet they are semantically wrong in a ways that appears in productions.
The bottleneck in software engineering is no longer writing code, it is verifying it execution intent


Table of Contents

  1. The Determinism Illusion
  2. Why Unit Tests Fail to Catch AI Era Bugs
  3. The Architecture Shift: From Test Suites to Verification Engines
  4. Practical Implementation Invariant Verification in Dot NET and Azure
  5. Tradeoffs and Structural Limitations
  6. Conclusion

The Determinism Illusion

Traditional software used to relies on deterministic assertions. We write code with known paths, control inputs, and verify exact results:

[Fact]
public void CalculateDiscount_StandardUser_ReturnsTenPercent()
{
    var calculator = new DiscountCalculator();
    var result = calculator.GetDiscount(UserType.Standard, orderTotal: 100);
    Assert.Equal(10, result);
}

Enter fullscreen mode Exit fullscreen mode

This works well because we write the logics and most bugs comes from missed edge cases or small mistakes.
But with AI-generated codes, it follows a patterns based on trained context and user prompt. An agent will write code that pass 100% of our unit tests but silently violation non-functional, implicit system boundaries:

  • It Adds hidden performance costs.
  • It breaks state machine idempotency under concurrent execution.
  • It bypasses domain entity validation rules by instantiating raw records directly.

So we got a syntactically valid and test passing code but architecturally incorrect.


Why Unit Tests Fail to Catch AI Era Bugs

AI agents are exceptionally good at writing tests for the very code they just generated. If an agent writes a flawed implementation, it generates an equally flawed, matching assertion suite.

AI Generation Loop

When tests mirror the assumptions of the generation engine, unit tests become a confirmation bias machine.

To govern AI-generated code, we must shift our definition of correctness from Output Equality (Assert.Equal) to System Invariants (Constraint Validation at Execution Runtime).


The Architecture Shift: From Test Suites to Verification Engines

In an AI-native engineering workflow, correctness is defined by bounded runtime guardrails and architectural fitness functions.
Instead of testing whether a function returned 10, a verification engine continuously enforces structural constraints across the entire codebase execution model.
Using this we are not just checking test results we are enforcing rules at runtime and checking that the system design stays valid.


Practical Implementation Invariant Verification in Dot NET and Azure

Let's build a practical implementation of an architectural verification pipeline.

Step 1: Enforce System Invariants in the Architecture Pipeline

Instead of trusting AI-generated tests we will enforce rules that our system must always follow:

  • Before merge (CI) → check code structure
  • At runtime → check what the AI is trying to do
using NetArchTest.Rules;
using Xunit;

public class ArchitectureVerificationTests
{
    [Fact]
    public void DomainEntities_MustBeImmutable_AndNeverBypassedByAgents()
    {
        // Enforce that AI-generated code cannot introduce mutable state into the Core Domain
        var result = Types.InCurrentDomain()
            .That()
            .ResideInNamespace("OrderSystem.Domain")
            .Should()
            .BeImmutable()
            .GetResult();

        Assert.True(result.IsSuccessful, "AI generated mutable entities in the domain layer!");
    }

    [Fact]
    public void Handlers_MustEnforceIdempotencyDecorator()
    {
        // Ensure every generated Command Handler implements IIdempotentCommand
        var result = Types.InCurrentDomain()
            .That()
            .HaveNameEndingWith("CommandHandler")
            .Should()
            .ImplementInterface(typeof(IIdempotentCommand))
            .GetResult();

        Assert.True(result.IsSuccessful, "AI generated a command handler lacking explicit idempotency execution!");
    }
}

Enter fullscreen mode Exit fullscreen mode

Step 2: Runtime Semantic Guardrail Verification Engine

For AI agent workflows running in production or ambient background tasks when it tries to change code or data, we validate its intent before allowing it so we ensure:

  • No direct DB access outside repositories
  • No performance-heavy allocations
  • Every external change must trigger an event
using Microsoft.SemanticKernel;
using Microsoft.Extensions.Logging;

public record ExecutionIntent(string TaskDescription, string TargetNamespace, string ProposedDiff);
public record VerificationResult(bool IsValid, string StructuralDivergenceReason);

public class AgentVerificationEngine
{
    private readonly Kernel _kernel;
    private readonly ILogger<AgentVerificationEngine> _logger;

    public AgentVerificationEngine(Kernel kernel, ILogger<AgentVerificationEngine> logger)
    {
        _kernel = kernel;
        _logger = logger;
    }

    public async Task<VerificationResult> VerifyAgentActionAsync(ExecutionIntent intent)
    {
        // Define hard system invariants that the LLM engine cannot negotiate
        var verificationPrompt = """
            You are an Architectural Verification Engine. Evaluate the proposed code change against the system invariants:

            SYSTEM INVARIANTS:
            1. No direct database access outside Infrastructure/Repositories.
            2. Memory allocations on critical paths must avoid heap overhead (no boxing, use ReadOnlySpan<T> where applicable).
            3. All external state modifications MUST emit an IntegrationEvent.

            PROPOSED CHANGE:
            Target: {{$target}}
            Diff: {{$diff}}

            Respond ONLY in JSON format:
            {"is_valid": true|false, "reason": "Detailed failure justification"}
            """;

        var arguments = new KernelArguments
        {
            ["target"] = intent.TargetNamespace,
            ["diff"] = intent.ProposedDiff
        };

        var result = await _kernel.InvokePromptAsync(verificationPrompt, arguments);
        var responseJson = result.GetValue<string>();

        // System parses verification evaluation deterministically
        return System.Text.Json.JsonSerializer.Deserialize<VerificationResult>(responseJson)!;
    }
}

Enter fullscreen mode Exit fullscreen mode

Azure Deployment Architecture

Deploy this verification process directly inside your Azure DevOps Pipeline or GitHub Actions Engine alongside Azure Container Apps for isolation:

Azure DevOps Pipeline


Tradeoffs and Structural Limitations

Moving to an invariant-driven verification architecture introduces real engineering trade-offs:

  1. Increased CI Execution Latency: Evaluating structural ASTs and executing dynamic LLM-driven verification gates adds 30–90 seconds per pull request compared to simple syntax compilation.
  2. High Upfront Modeling Cost: Defining system invariants requires deep domain expertise. You cannot ask an AI to write your system invariants — doing so reintroduces the confirmation bias loop.
  3. Over-Constrained Evolution: Overly strict architectural fitness functions can cause false positives, blocking valid edge-case refactoring tasks generated by agents or human engineers.

Conclusion

AI is not removing the need for software engineering — it is raising the level of abstraction.

When writing code becomes frictionless, the primary value of a senior engineer shifts from syntax authoring to system boundary definition. Stop relying solely on traditional unit tests to validate AI-generated code. Build verification engines that enforce immutable architecture invariants, audit non-deterministic outputs, and protect runtime stability.

Software correctness is no longer about passing unit tests. It is about proving your system cannot violate its core invariants.


How are you adapting your CI/CD pipelines to handle AI-generated code? Are you relying on static unit testing, or building verification boundaries? Drop your thoughts in the comments below!

Top comments (0)