The Problem
You compressed your 20K token codebase down to 5K using aggressive filtering. The AI's response? Generic, wrong, or hallucinates code that doesn't match your architecture. You re-run with full context and suddenly it works perfectly.
Compression saved tokens but destroyed understanding.
The hard truth: compression is optimization. And premature optimization kills more AI sessions than it helps. You need to know when compression makes things worse.
The Core Insight
AI models need context to understand relationships. Over-compression breaks the mental model.
Think of it like reading a novel where every third page is missing. You can follow the plot, but you miss character motivations, foreshadowing, and subtle connections. The AI has the same problem with over-compressed code.
The key: some context types are compression-hostile. Recognize them and back off.
Anti-Pattern Catalog
Anti-Pattern 1: The Signature Massacre
What happens: Compression removes type hints, parameter names, or docstrings from function signatures.
# Original (clear contract)
def process_payment(
user_id: str,
amount: Decimal,
payment_method: PaymentMethod,
idempotency_key: Optional[str] = None
) -> PaymentResult:
"""
Process a payment for a user.
Args:
user_id: UUID of the user
amount: Payment amount (must be positive)
payment_method: Validated payment method
idempotency_key: Optional key for duplicate prevention
Returns:
PaymentResult with transaction ID or error
"""
pass
# After aggressive compression (broken contract)
def process_payment(user_id, amount, payment_method, idempotency_key=None):
pass
Why it breaks: AI loses critical information about what types are expected, what the function does, and what constraints exist.
The fix: Never compress function signatures in your public API or the files being modified.
def protect_signatures(code):
"""Extract and preserve function signatures."""
signatures = extract_function_defs_with_docstrings(code)
body = extract_function_bodies(code)
# Compress bodies aggressively, keep signatures intact
compressed_bodies = compressor.compress_prompt(body, rate=0.3)
return merge(signatures, compressed_bodies)
Anti-Pattern 2: The Context Collapse
What happens: Compression removes the "glue" that connects pieces of code, leaving isolated fragments.
# Original (shows flow)
def checkout_flow(cart):
# Validate inventory first
if not inventory.check_availability(cart.items):
raise OutOfStockError()
# Then validate payment
payment_valid = validate_payment_method(cart.payment)
if not payment_valid:
raise PaymentError()
# Finally process
return process_order(cart)
# After compression (lost flow)
def checkout_flow(cart):
inventory.check_availability(cart.items)
validate_payment_method(cart.payment)
process_order(cart)
Why it breaks: Comments explaining the "why" are gone. Error handling is gone. The AI doesn't understand the order matters or why.
The fix: Preserve comments that explain control flow, especially for the main file being debugged.
Anti-Pattern 3: The Type System Blindness
What happens: TypeScript interfaces, Python type aliases, or schema definitions get compressed away.
# Original (clear types)
from typing import TypedDict, Literal
class UserProfile(TypedDict):
user_id: str
email: str
role: Literal["admin", "user", "guest"]
credits: Decimal
subscription_tier: Literal["free", "pro", "enterprise"]
# After compression (type info lost)
# [Types removed, only runtime code remains]
Why it breaks: AI loses understanding of valid values, field constraints, and relationships between types.
The fix: Extract and preserve type definitions before compression.
def preserve_type_system(code):
"""Keep type definitions intact."""
types = extract_type_definitions(code) # TypedDict, interfaces, etc
schemas = extract_validation_schemas(code) # Pydantic, Zod, etc
runtime = extract_runtime_code(code)
compressed_runtime = compressor.compress_prompt(runtime, rate=0.4)
return merge(types, schemas, compressed_runtime)
Anti-Pattern 4: The Error Message Purge
What happens: Compression treats error messages as "low value" and removes them.
# Original (helpful errors)
if not user.has_permission("checkout"):
raise PermissionError(
f"User {user.id} lacks 'checkout' permission. "
f"Current role: {user.role}. Required: admin or premium"
)
# After compression (useless error)
if not user.has_permission("checkout"):
raise PermissionError()
Why it breaks: When debugging, error messages are often the most valuable context. They explain what went wrong.
The fix: Boost importance of error messages and exception handling.
def protect_error_context(code):
"""Preserve error messages and raise statements."""
import ast
tree = ast.parse(code)
protected_lines = set()
for node in ast.walk(tree):
# Protect raise statements
if isinstance(node, ast.Raise):
protected_lines.add(node.lineno)
# Protect exception handlers
if isinstance(node, ast.ExceptHandler):
protected_lines.update(range(
node.lineno,
node.end_lineno + 1
))
return selective_compress(code, protected_lines)
Anti-Pattern 5: The Test Apocalypse
What happens: Tests are "less important than prod code" so they get compressed to nothing.
# Original test (documents behavior)
def test_checkout_with_insufficient_credits():
"""
When user has $5 credits but cart is $10,
checkout should fail with InsufficientFundsError
and preserve the cart state.
"""
user = User(credits=Decimal("5.00"))
cart = Cart(items=[Item(price=Decimal("10.00"))])
with pytest.raises(InsufficientFundsError) as exc:
checkout(user, cart)
assert "insufficient funds" in str(exc.value).lower()
assert cart.is_active # Cart should not be cleared
# After compression (lost behavior spec)
def test_checkout_with_insufficient_credits():
user = User(credits=Decimal("5.00"))
cart = Cart(items=[Item(price=Decimal("10.00"))])
pytest.raises(InsufficientFundsError, checkout, user, cart)
Why it breaks: Tests are documentation of expected behavior. Compressing them loses the spec.
The fix: For feature changes, include full test context. For debugging, include only failing tests at full fidelity.
Anti-Pattern 6: The Dependency Black Box
What happens: External library usage gets compressed, AI loses understanding of how to use APIs.
# Original (shows library usage)
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
# Stripe requires amount in cents, not dollars
amount_cents = int(payment.amount * 100)
charge = stripe.Charge.create(
amount=amount_cents,
currency="usd",
source=payment.token,
idempotency_key=payment.idempotency_key # Critical for retries
)
# After compression (lost API details)
import stripe
charge = stripe.Charge.create(
amount=amount_cents,
currency="usd",
source=payment.token
)
Why it breaks: Comments explaining library quirks (cents vs dollars, idempotency) are lost. AI might suggest incorrect API usage.
The fix: Don't compress code that interfaces with external APIs. Include relevant docs instead.
Anti-Pattern 7: The Configuration Vaporization
What happens: Configuration files and constants get filtered out as "not code."
# config.py (excluded from context)
MAX_RETRY_ATTEMPTS = 3
PAYMENT_TIMEOUT_SECONDS = 30
ALLOWED_CURRENCIES = ["USD", "EUR", "GBP"]
FEATURE_FLAGS = {
"enable_store_credit": True,
"enable_crypto_payments": False
}
# checkout.py (AI sees this without config)
if currency not in ALLOWED_CURRENCIES: # AI doesn't know what's allowed!
raise ValueError(f"Unsupported currency: {currency}")
Why it breaks: AI can't suggest valid changes without knowing configuration constraints.
The fix: Always include configuration files that define constraints for the code being modified.
Detection Strategies
How to Know Compression Broke Your Prompt
| Symptom | Root Cause | Fix |
|---|---|---|
| AI suggests generic solutions | Lost domain-specific context | Reduce compression rate |
| AI hallucinates function signatures | Signature compression | Preserve signatures intact |
| AI violates type constraints | Type definitions removed | Include full type system |
| AI suggests already-tried solutions | Error messages compressed | Protect error handling code |
| Generated code doesn't compile | Syntax-breaking compression | Use AST-aware compression |
When to Skip Compression Entirely
Do NOT Compress For:
- Code generation: AI needs full examples to match your style
- Security audits: One missing line could hide a vulnerability
- Refactoring: Needs full context to avoid breaking changes
- Small contexts: Under 10K tokens? Just send it all
- First debugging attempt: You don't know what's relevant yet
- Type-heavy codebases: TypeScript, Haskell, Rust - types ARE the context
- API contract changes: Full signatures required
Safe Compression Checklist
Before compressing, verify:
class CompressionSafetyCheck:
def is_safe_to_compress(self, code, task):
"""Run safety checks before compression."""
checks = {
'has_sufficient_tokens': self.token_count(code) > 10000,
'not_security_audit': 'security' not in task.lower(),
'not_first_attempt': self.attempt_count > 1,
'has_fallback_context': self.can_retrieve_full_context(),
'preserves_signatures': self.will_keep_signatures(),
'preserves_types': self.will_keep_type_defs(),
'preserves_errors': self.will_keep_error_handling()
}
if not all(checks.values()):
failed = [k for k, v in checks.items() if not v]
self.warn(f"Compression safety failed: {failed}")
return False
return True
Quick Reference
Never Compress:
- Function signatures being modified
- Type definitions and interfaces
- Error messages and exception handlers
- Configuration constants
- API integration code
- Files under 500 tokens
Warning Signs:
# If you see these, compression failed:
- AI suggests wrong types
- AI hallucinates non-existent functions
- Generated code doesn't compile
- Solutions ignore constraints
- Responses are too generic
Recovery Pattern:
if ai_response_quality == "poor":
# Step 1: Try again with less compression
compression_rate *= 1.5 # 0.4 → 0.6
if still_poor:
# Step 2: Include full context for main file
include_full_file(target_file)
if still_poor:
# Step 3: Skip compression entirely
send_full_context()
Safe Defaults:
- Start with 0% compression on first attempt
- Only compress if over 80% of token budget
- Never compress below 50% retention (rate=0.5)
- Always preserve the file being modified at 100%