DEV Community

Toni Antunovic
Toni Antunovic

Posted on • Originally published at lucidshark.com

Constraint Decay: Why Your AI Coding Agent Passes Tests But Breaks Production

A paper published this week on arxiv has a name that should land with weight in any engineering meeting: Constraint Decay: The Fragility of LLM Agents in Backend Code Generation. The finding is precise and uncomfortable. LLM coding agents generate plausible backend code when requirements are loose. As structural constraints accumulate, performance collapses. Capable model configurations lose 30 points on average in assertion pass rates from a baseline unconstrained task to a fully specified production task. Weaker configurations approach zero.

            This is not a benchmark complaint. It is a description of what happens in your codebase every day. Your AI coding agent produces code that satisfies functional tests, makes the CI pipeline green, and ships. The structural violations, the ORM misuse, the architectural drift, the missing query composition constraints sit silently in the diff until they cause a production incident.


            > 
                **Paper reference:** "Constraint Decay: The Fragility of LLM Agents in Backend Code Generation" (arxiv 2605.06445, May 2026). The study evaluated 80 greenfield generation tasks and 20 feature-implementation tasks across eight web frameworks. Trending on Hacker News today with substantial developer discussion confirming the pattern in real codebases.


            ## What Constraint Decay Actually Looks Like

            The paper introduces a precise definition. Constraint decay is the measurable drop in an LLM agent's ability to satisfy structural requirements as the number of non-functional constraints grows. Functional correctness, meaning the code does what you described, stays relatively stable. Structural correctness, meaning the code follows your architectural patterns, ORM conventions, query composition rules, and framework idioms, degrades sharply.


            The researchers tested agents against eight backend frameworks. Flask, the most explicit and minimal framework, produced the best results. Django and FastAPI, both convention-heavy and relying on implicit structural contracts, produced the worst. The root cause analysis pointed to two specific failure categories that dominated the results:



                - **Incorrect query composition:** Agents writing raw queries or composing ORM queries in ways that violate the expected query patterns for the framework.
                - **ORM runtime violations:** Agents generating code that passes static analysis and unit tests but violates runtime ORM contracts, triggering errors only under real data conditions or at the database layer.


            These failure modes share one property: they are invisible to functional tests. A unit test that mocks the database layer will pass. An integration test that does not exercise the specific query path will pass. The violation surfaces in production, often under load or with production-shaped data.


            ## The Test Suite Cannot See What It Was Not Asked to See

            Here is the structural problem. When you ask an AI coding agent to implement a feature, you describe the functional requirement. The agent generates code that satisfies that description. Your test suite validates the functional behavior. Everyone signs off.


            But your test suite was also written by the same agent, or by developers who inherited the same mental model of what the code should do. It tests what was intended. It does not test whether the implementation respects the implicit structural contracts of your framework, your ORM configuration, or your team's architectural decisions documented somewhere in a CLAUDE.md or a markdown file that may not have been loaded into the agent's context window when it wrote the code.


            > 
                **The documentation accumulation problem:** Hacker News discussion on the constraint decay paper surfaced a pattern that every team running agentic workflows recognizes. Teams accumulate extensive markdown files documenting style guides, corner cases, and architectural patterns. This guidance "piles up" and is not fully reviewed. The agent receives it as context but its effectiveness degrades as the constraint count grows. The very documentation you created to constrain the agent becomes part of the decay problem.


            Consider a realistic Django example. Your team uses a repository pattern and has established conventions for queryset composition. The convention is documented in your CLAUDE.md. The agent generates a new view. The view works. The tests pass. But the implementation bypasses the repository layer and calls the ORM directly with a queryset chain that does not match the team's select_related and prefetch_related conventions. Under production load with 50,000 rows, this generates N+1 query patterns that the test suite never triggered because the test fixtures had three rows.
Enter fullscreen mode Exit fullscreen mode
# What the agent generated: passes all tests, violates structural constraints
class OrderListView(LoginRequiredMixin, ListView):
    def get_queryset(self):
        # Direct ORM call, bypasses repository pattern
        # Missing prefetch_related("items__product") convention
        return Order.objects.filter(
            user=self.request.user,
            status__in=["pending", "processing"]
        ).order_by("-created_at")

# What the team's architectural contract requires
class OrderListView(LoginRequiredMixin, ListView):
    def get_queryset(self):
        # Uses repository layer per team convention
        # Applies correct prefetch strategy documented in architecture.md
        return self.order_repository.get_active_for_user(
            user=self.request.user,
            prefetch_items=True
        )
Enter fullscreen mode Exit fullscreen mode
            A functional test that checks "does the view return the right orders for this user" passes in both cases. The structural violation only surfaces when someone reads the code during review, or when the database query count alarm fires at 2am.


            ## Why Constraint Decay Gets Worse With Your Codebase Over Time

            The paper's findings have a compounding property that matters for teams with mature codebases. As a codebase grows, the number of structural constraints accumulates. You add a caching layer. You establish a specific serializer pattern. You document which database operations are allowed in view code versus service code. You adopt a specific approach to transaction boundaries.


            Each new constraint is another item in the context that the agent must simultaneously satisfy. The decay curve the paper documents is not linear: it is a cliff. At some constraint count, agent performance does not gracefully degrade. It collapses. Teams that have been successfully using AI coding agents for six months start experiencing a different failure mode profile than they saw in month one, not because the model got worse, but because the codebase accumulated structural constraints that now exceed the agent's effective constraint satisfaction capacity.


            The Hacker News discussion confirmed this with practitioner data. One developer noted they generate 80% of their code with LLMs and observe the complexity tradeoff directly: constraints that used to live in formal language constructs now live in informal natural language, and the enforcement is gone. Another noted that agents tend to over-apply patterns they encounter, making it difficult to break established conventions even when beneficial, and easy to introduce violations of conventions that were not included in the specific prompt context.


            ## What Static Analysis Catches That Tests Miss

            This is where local-first SAST tooling earns its place in the agentic workflow. The constraint decay failure modes, incorrect query composition, ORM violations, architectural drift, are exactly the categories that static analysis can detect before the code reaches the test suite, before it reaches CI, and before it reaches production.


            Static analysis does not care whether code is functionally correct. It checks structure. It checks patterns. It checks whether the code you committed matches the rules you have encoded. For AI-generated code with constraint decay characteristics, this is the enforcement layer that the test suite cannot provide.
Enter fullscreen mode Exit fullscreen mode
# LucidShark pre-commit hook catching ORM structural violations
# in a Django project with repository pattern enforcement

$ git commit -m "feat: add order list view"

Running LucidShark quality gates...

[SAST] Analyzing changed files...
  src/views/orders.py

[WARNING] Direct ORM query in view layer (line 12)
  Rule: ARCH-ORM-001 - Repository pattern required for database access in views
  Pattern: Order.objects.filter() called directly in View class
  Expected: Use self.order_repository or OrderRepository()

[WARNING] Missing prefetch annotation (line 14)
  Rule: PERF-ORM-003 - Active queryset on Order must include items prefetch
  Pattern: Order.objects.filter() without .prefetch_related("items")
  Doc reference: docs/architecture.md#query-conventions

2 structural violations found.
Commit blocked. Fix violations before committing.

Tip: Run `lucidshark check --explain ARCH-ORM-001` for remediation guidance.
Enter fullscreen mode Exit fullscreen mode
            This output is generated locally, before the code leaves your machine. No API call to an external review service. No waiting for CI. No production incident. The structural violation that constraint decay produced is caught at the commit boundary by rules that encode your team's actual architectural contracts.


            ## Encoding Your Structural Constraints as Enforceable Rules

            The practical implication of the constraint decay paper is that natural language documentation is not a reliable constraint mechanism for LLM agents. Your CLAUDE.md is not a contract. Your architecture.md is not enforcement. They are context that degrades in effectiveness as constraint count grows.


            The solution is not to write better documentation. The solution is to encode your structural constraints as machine-checkable rules that run at commit time, regardless of how many constraints the agent was supposed to hold in context.
Enter fullscreen mode Exit fullscreen mode
# lucidshark.config.yml - encoding structural constraints as rules

rules:
  # Repository pattern enforcement
  - id: ARCH-ORM-001
    name: "No direct ORM in view layer"
    pattern: "*.objects.filter|get|create|update|delete"
    files: ["views/**/*.py", "api/**/*.py"]
    message: "Direct ORM access in view layer violates repository pattern"
    severity: error

  # Query composition conventions
  - id: PERF-ORM-003
    name: "Order queryset must prefetch items"
    pattern: "Order.objects"
    require_pattern: "prefetch_related"
    message: "Order querysets require prefetch_related('items') per query conventions"
    severity: warning

  # Transaction boundary enforcement
  - id: ARCH-TXN-001
    name: "Multi-step writes require transaction decorator"
    pattern: "def (create|update|delete)_.*\(self"
    context_check: "@transaction.atomic"
    files: ["services/**/*.py"]
    message: "Service methods with write operations require @transaction.atomic"
    severity: error

  # Framework-specific structural checks
  sast:
    semgrep_rules:
      - "p/django"
      - "p/python"
    custom_rules: ".lucidshark/rules/"
Enter fullscreen mode Exit fullscreen mode
            These rules are the machine-readable version of your structural constraints. They do not decay. They do not depend on whether the agent loaded the right documentation in its context window. They run at commit time on every diff, AI-generated or human-written, and they fail the commit if the structure does not match the contract.


            ## The Framework-Specific Dimension

            The paper's finding that Flask outperforms Django and FastAPI is instructive beyond the benchmark. It explains a pattern that experienced agentic developers have observed: AI coding agents produce more reliable code in minimal, explicit frameworks and more problematic code in convention-heavy frameworks.


            The implication for teams is that the risk profile of AI-generated code is not uniform across your stack. A Python service using Flask with explicit dependency injection and minimal framework magic is a lower constraint-decay risk than a Django application with signals, middleware conventions, custom managers, and a repository layer. Your quality gate strategy should reflect this: heavier structural enforcement where constraint decay risk is highest.
Enter fullscreen mode Exit fullscreen mode
# High constraint-decay risk: Django with multiple implicit contracts
# The agent must simultaneously satisfy: ORM conventions, signal hooks,
# custom manager methods, serializer patterns, permission classes,
# and transaction boundaries

class OrderService:
    def create_order(self, user, cart_data):
        # Agent may violate any of: transaction boundary, signal firing order,
        # custom manager usage, select_for_update requirement on inventory
        with transaction.atomic():
            order = Order.objects.create_from_cart(
                user=user,
                cart_data=cart_data
            )
            # post_save signal expected by analytics service
            # Agent frequently omits or duplicates signal triggers
            order_created.send(sender=Order, instance=order, user=user)
            return order

# Lower constraint-decay risk: Flask with explicit contracts
# Fewer implicit conventions for the agent to violate

def create_order(user_id: int, cart_data: CartData, db: Session) -> Order:
    # Explicit: no signals, no custom manager magic, transaction is explicit
    with db.begin():
        order = Order(user_id=user_id, status="pending")
        db.add(order)
        for item in cart_data.items:
            line = OrderLine(product_id=item.product_id, quantity=item.quantity)
            order.lines.append(line)
    return order
Enter fullscreen mode Exit fullscreen mode
            ## Practical Quality Gate Strategy for Constraint Decay

            The constraint decay paper gives teams a concrete framework for thinking about AI-generated code risk. Here is how to translate that into a gate strategy:


            ### 1. Audit your structural constraint count
            List every implicit structural contract in your codebase: ORM patterns, transaction conventions, serializer patterns, permission patterns, caching conventions, query composition rules. The higher this count, the higher your constraint decay risk for AI-generated code. Prioritize encoding the highest-impact constraints as rules first.


            ### 2. Separate functional and structural review
            Your test suite handles functional validation. Your pre-commit quality gate handles structural validation. These are different concerns and should not be conflated. A green test suite does not indicate structural correctness for AI-generated code.


            ### 3. Apply differential scrutiny by framework
            AI-generated code in convention-heavy frameworks like Django, Rails, or Spring carries higher constraint-decay risk. Apply heavier static analysis rule sets to these areas. AI-generated code in minimal, explicit frameworks carries lower risk.


            ### 4. Encode constraints at the boundary, not in the prompt
            Natural language constraints in CLAUDE.md are context, not enforcement. Machine-checkable rules at the commit boundary are enforcement. Use both, but rely on the rules for structural compliance.


            > 
                **On the documentation accumulation problem:** The Hacker News discussion surfaced the pattern where teams accumulate guidance documents that "pile up" without full review. LucidShark's approach is to treat your quality rule configuration as the authoritative structural specification, not your markdown documentation. The rules config is version-controlled, reviewed, and enforced. The markdown is explanatory.


            ## The Bigger Picture: Agentic Development Needs Structural Gates

            The constraint decay paper lands at a moment when the industry is accelerating agentic code generation. Microsoft just canceled thousands of internal Claude Code licenses after costs spiraled, pushing developers back to GitHub Copilot CLI. DeepSeek Reasonix launched today as a terminal coding agent built around prefix caching for cost reduction. The tooling ecosystem is expanding rapidly, each tool promising faster code generation at lower cost.


            What none of these tools address is the structural correctness problem. Faster generation of structurally violated code is not a win. The constraint decay paper provides the academic framing for something practitioners have been experiencing: AI coding agents are reliable for functional requirements and unreliable for structural requirements, and this gap widens as codebases mature.


            Local-first quality gates are the structural enforcement layer that the AI coding tool ecosystem does not provide. They run on your machine, with your rules, encoding your team's actual architectural contracts. They are not dependent on which AI coding tool your employer happens to be licensing this quarter. They work with Claude Code, Copilot CLI, Reasonix, or any agent that produces code and commits it.


            The paper's conclusion is worth quoting directly: "jointly satisfying functional and structural requirements remains a key open challenge." That challenge does not disappear by waiting for model improvements. It is addressed by building structural enforcement into the development workflow today.



                **Add structural constraint enforcement to your AI coding workflow today.**
                LucidShark runs locally with no API calls, no data leaving your machine, and no per-review fees. It integrates with Claude Code via MCP and installs as a pre-commit hook in under two minutes. Encode your team's structural constraints as rules and catch constraint decay violations before they reach CI or production.
Enter fullscreen mode Exit fullscreen mode
                ```
Enter fullscreen mode Exit fullscreen mode

npx lucidshark@latest init



                    Open source under Apache 2.0. <a href="https://github.com/toniantunovic/lucidshark">View on GitHub</a> or <a href="https://lucidshark.com/docs">read the docs</a>.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)