Copied to Clipboard
# 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
)
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.
#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.
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.
# lucidshark.config.yml - encoding structural constraints as rules
rules:
# Repository pattern enforcement
- id: ARCH-ORM-001
name: "NodirectORMinviewlayer"
pattern: "*.objects.filter|get|create|update|delete"
files: ["views/**/*.py", "api/**/*.py"]
message: "DirectORMaccessinviewlayerviolatesrepositorypattern"
severity: error
# Query composition conventions
- id: PERF-ORM-003
name: "Orderquerysetmustprefetchitems"
pattern: "Order.objects"
require_pattern: "prefetch_related"
message: "Orderquerysetsrequireprefetch_related('items')perqueryconventions"
severity: warning
# Transaction boundary enforcement
- id: ARCH-TXN-001
name: "Multi-stepwritesrequiretransactiondecorator"
pattern: "def(create|update|delete)_.*\(self"
context_check: "@transaction.atomic"
files: ["services/**/*.py"]
message: "Servicemethodswithwriteoperationsrequire@transaction.atomic"
severity: error
# Framework-specific structural checks
sast:
semgrep_rules:
- "p/django"
- "p/python"
custom_rules: ".lucidshark/rules/"
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.
# 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
## 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.
```
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>.