Skip to main content
Version: v1.1.0
This page explains common misuses and how to avoid them.

Anti-Patterns

Even with good intentions, teams can misuse TealTiger in ways that break determinism, hurt performance, or create maintenance nightmares. This page shows you what NOT to do.

Why Anti-Patterns Matter

These aren’t bugs in TealTiger - they’re misaligned usage patterns that:
  • Break deterministic behavior
  • Degrade performance
  • Make policies unmaintainable
  • Destroy trust in the system
Learn from others’ mistakes and avoid these patterns.

Common Anti-Patterns

1. Using TealTiger as a Business Logic Engine

Anti-pattern: Embedding core application logic inside policies.
// ❌ WRONG: Business logic in policies
const engine = new TealEngine({
  policies: {
    order_processing: {
      calculate_discount: {
        conditions: {
          user_tier: 'premium',
          order_total: { min: 100 },
          day_of_week: 'friday'
        },
        actions: {
          apply_discount: 0.15,
          send_email: true,
          update_loyalty_points: 50
        }
      }
    }
  }
});
Why it’s wrong:
  • Business logic changes frequently; policies should be stable
  • Increases coupling between governance and domain logic
  • Makes both harder to understand and maintain
Correct approach:
// ✅ CORRECT: Business logic in app, governance in policies
// Your application handles business logic
const discount = calculateDiscount(user, order);
const loyaltyPoints = calculateLoyaltyPoints(user, order);

// TealTiger only enforces constraints
const decision = engine.evaluate({
  action: 'order.process',
  context: {
    user_id: user.id,
    order_total: order.total,
    estimated_cost: 0.05  // LLM cost for order processing
  }
});

if (decision.action === 'allow') {
  processOrder(order, discount, loyaltyPoints);
}

2. Treating Policies as Frequently Mutating Rules

Anti-pattern: Updating policies on every deploy or runtime event.
// ❌ WRONG: Constantly changing policies
app.on('deploy', () => {
  engine.updatePolicies({
    cost: { budget_limit: getRandomBudget() }
  });
});

app.on('user_login', (user) => {
  engine.updatePolicies({
    tools: { allowed: user.preferences.tools }
  });
});
Why it’s wrong:
  • Breaks policy stability guarantees
  • Makes audit trails meaningless
  • Increases risk of unintended behavior
  • Destroys determinism
Correct approach:
// ✅ CORRECT: Stable policies, dynamic context
const engine = new TealEngine({
  policies: {
    cost: {
      budget_limit: {
        perUser: { daily: 10.00 }  // Stable policy
      }
    }
  }
});

// Pass dynamic data through context, not policy changes
const decision = engine.evaluate({
  action: 'llm.call',
  context: {
    user_id: user.id,           // Dynamic
    user_tier: user.tier,       // Dynamic
    environment: process.env.NODE_ENV  // Dynamic
  }
});

3. Using TealTiger for Real-Time Alerting

Anti-pattern: Expecting TealTiger to generate alerts and page your team.
// ❌ WRONG: TealTiger as alerting system
const engine = new TealEngine({
  policies: {
    security: {
      pii_detection: {
        enabled: true,
        on_violation: {
          page_security_team: true,  // This doesn't exist
          create_jira_ticket: true,  // This doesn't exist
          send_slack_message: true   // This doesn't exist
        }
      }
    }
  }
});
Why it’s wrong:
  • TealTiger emits events, it doesn’t manage alerts
  • Alert fatigue and correlation belong in observability tools
  • Mixing governance with incident response creates complexity
Correct approach:
// ✅ CORRECT: Forward events to your alerting system
const engine = new TealEngine({
  policies: {
    security: {
      pii_detection: { enabled: true, block_on_pii: true }
    }
  },
  audit: {
    outputs: [
      {
        type: 'custom',
        handler: async (event) => {
          // Your alerting logic
          if (event.decision.action === 'deny' && 
              event.decision.reason_code.startsWith('SECURITY')) {
            await pagerDuty.alert({
              severity: 'high',
              message: `Security violation: ${event.decision.reason_code}`,
              details: event
            });
          }
        }
      }
    ]
  }
});

4. Passing Secrets Through Policies

Anti-pattern: Storing API keys or credentials in policy metadata.
// ❌ WRONG: Secrets in policies
const engine = new TealEngine({
  policies: {
    llm: {
      openai: {
        api_key: 'sk-proj-abc123...',  // NEVER DO THIS
        org_id: 'org-xyz789'
      }
    }
  }
});
Why it’s wrong:
  • Violates separation of concerns
  • Increases blast radius if policies are leaked
  • Creates audit and compliance risks
  • Secrets end up in version control
Correct approach:
// ✅ CORRECT: Secrets from environment, identity from context
const engine = new TealEngine({
  policies: {
    cost: { budget_limit: { perUser: { daily: 10.00 } } }
  }
});

// Secrets from environment
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

// Identity from context
const decision = engine.evaluate({
  action: 'llm.call',
  context: {
    user_id: user.id,      // Identity reference, not credentials
    user_role: user.role   // Authorization context
  }
});

5. Using Policies to Fix Poor Agent Design

Anti-pattern: Compensating for unbounded agents with increasingly complex policies.
// ❌ WRONG: Policies as band-aids for bad design
const engine = new TealEngine({
  policies: {
    // Trying to fix an agent that has no built-in limits
    tools: {
      web_search: {
        max_calls_per_minute: 100,
        max_results_per_call: 50,
        blocked_domains: ['...100 domains...'],
        required_keywords: ['...50 keywords...'],
        forbidden_patterns: ['...200 patterns...']
      }
    }
  }
});
Why it’s wrong:
  • Governance can’t replace good design
  • Leads to brittle, unmaintainable policies
  • Masks root causes
  • Performance degrades
Correct approach:
// ✅ CORRECT: Design agents responsibly, use policies for guardrails
// 1. Design your agent with built-in limits
class WebSearchAgent {
  constructor() {
    this.maxResultsPerCall = 10;  // Built-in limit
    this.rateLimiter = new RateLimiter({ rpm: 60 });
  }
  
  async search(query: string) {
    await this.rateLimiter.check();
    return await webSearch(query, { limit: this.maxResultsPerCall });
  }
}

// 2. Use TealTiger for high-level governance
const engine = new TealEngine({
  policies: {
    tools: {
      web_search: {
        allowed: true,
        requires_approval: false
      }
    },
    cost: {
      budget_limit: { perUser: { daily: 10.00 } }
    }
  }
});

6. Encoding Vendor-Specific Logic in Policies

Anti-pattern: Hard-coding provider details into policies.
// ❌ WRONG: Vendor-specific policies
const engine = new TealEngine({
  policies: {
    openai: {
      models: {
        'gpt-4': { max_tokens: 8000 },
        'gpt-3.5-turbo': { max_tokens: 4000 }
      },
      endpoints: {
        'https://api.openai.com/v1/chat/completions': { allowed: true }
      }
    },
    anthropic: {
      models: {
        'claude-3-opus': { max_tokens: 4000 }
      }
    }
  }
});
Why it’s wrong:
  • Reduces portability
  • Locks policies to infrastructure decisions
  • Makes provider migrations painful
  • Policies break when providers change
Correct approach:
// ✅ CORRECT: Vendor-agnostic policies
const engine = new TealEngine({
  policies: {
    cost: {
      budget_limit: {
        perUser: { daily: 10.00 }  // Works with any provider
      },
      token_limit: {
        max_input_tokens: 4000,    // Behavior-based, not vendor-specific
        max_output_tokens: 2000
      }
    },
    security: {
      pii_detection: {
        enabled: true,             // Works with any provider
        block_on_pii: true
      }
    }
  }
});

// Provider selection happens in your app, not policies
const provider = selectProvider(user.preferences);
const response = await provider.call(prompt);

7. Expecting Policies to Learn or Adapt

Anti-pattern: Assuming policies will automatically adjust based on behavior.
// ❌ WRONG: Expecting magic
const engine = new TealEngine({
  policies: {
    cost: {
      budget_limit: {
        perUser: { daily: 10.00 }
      }
    }
  }
});

// Waiting for policies to "learn" that user-123 needs more budget
// (This will never happen - policies are deterministic)
Why it’s wrong:
  • TealTiger is deterministic by design
  • Policies don’t learn or adapt automatically
  • Creates false expectations
Correct approach:
// ✅ CORRECT: Explicit policy updates when needed
const engine = new TealEngine({
  policies: {
    cost: {
      budget_limit: {
        perUser: {
          daily: 10.00,  // Default
          overrides: {
            'user-123': 50.00,  // Explicit override for power user
            'user-456': 5.00    // Explicit override for trial user
          }
        }
      }
    }
  }
});

// Or pass dynamic limits through context
const decision = engine.evaluate({
  action: 'llm.call',
  context: {
    user_id: user.id,
    budget_limit: getUserBudgetLimit(user)  // From your database
  }
});

8. Using Audit Logs as Debug Logs

Anti-pattern: Logging verbose debugging information to audit events.
// ❌ WRONG: Audit logs as debug logs
const engine = new TealEngine({
  audit: {
    outputs: [
      {
        type: 'file',
        path: './audit/events.jsonl',
        include_debug_info: true,  // This doesn't exist
        log_every_variable: true,  // This doesn't exist
        verbose_mode: true         // This doesn't exist
      }
    ]
  }
});
Why it’s wrong:
  • Audit logs must remain structured and stable
  • Excessive noise reduces forensic value
  • Increases storage and processing costs
  • Makes compliance harder
Correct approach:
// ✅ CORRECT: Separate audit logs from debug logs
// Application debug logs
import { logger } from './logger';
logger.debug('Evaluating policy', { context, policy });

// TealTiger audit logs (structured, stable)
const engine = new TealEngine({
  audit: {
    enabled: true,
    outputs: [
      {
        type: 'file',
        path: './audit/events.jsonl'  // Structured governance events only
      }
    ]
  },
  logging: {
    level: 'INFO'  // TealTiger's own logs (separate from audit)
  }
});

9. Creating Monolithic Policies

Anti-pattern: One massive policy covering everything.
// ❌ WRONG: Monolithic policy
const engine = new TealEngine({
  policies: {
    everything: {
      cost_and_security_and_reliability_and_compliance: {
        conditions: {
          // 500 lines of conditions
        },
        actions: {
          // 200 lines of actions
        }
      }
    }
  }
});
Why it’s wrong:
  • Hard to review
  • Hard to test
  • Hard to evolve
  • Impossible to understand
Correct approach:
// ✅ CORRECT: Compose policies by concern
const engine = new TealEngine({
  policies: {
    // Cost policies
    cost: {
      budget_limit: { perUser: { daily: 10.00 } },
      token_limit: { max_input_tokens: 4000 }
    },
    // Security policies
    security: {
      pii_detection: { enabled: true, block_on_pii: true },
      prompt_injection: { enabled: true, block_on_injection: true }
    },
    // Reliability policies
    reliability: {
      rate_limit: { requests_per_minute: 60 },
      circuit_breaker: { failure_threshold: 5 }
    },
    // Tool policies
    tools: {
      file_delete: { allowed: false },
      web_search: { allowed: true }
    }
  }
});

10. Set and Forget

Anti-pattern: Deploying TealTiger once and never reviewing policies.
// ❌ WRONG: Deploy and forget
const engine = new TealEngine({
  policies: { /* ... */ }
});

// 6 months later...
// - AI usage patterns have changed
// - New tools have been added
// - Cost structure has evolved
// - Policies are outdated
Why it’s wrong:
  • AI systems evolve
  • Usage patterns change
  • Risk profiles shift
  • Policies become stale
Correct approach:
// ✅ CORRECT: Treat policies as living governance artifacts
// 1. Version policies in git
// policies/v1.0.0.ts
export const policies = { /* ... */ };

// 2. Review periodically (monthly or quarterly)
// - Check audit logs for patterns
// - Adjust thresholds based on data
// - Add new policies for new risks

// 3. Test policy changes
import { testPolicy } from '@tealtiger/testing';
testPolicy(policies, goldenCorpus);

// 4. Deploy with monitoring
const engine = new TealEngine({
  policies: policies_v1_1_0,  // Versioned
  mode: PolicyMode.MONITOR    // Test before enforcing
});

Summary: The Pattern

Most anti-patterns follow a common theme:
Anti-PatternRoot Cause
Business logic in policiesMixing concerns
Frequently mutating policiesTreating policies as config
TealTiger as alertingWrong tool for the job
Secrets in policiesSecurity anti-pattern
Policies fix bad designBand-aid over root cause
Vendor-specific policiesTight coupling
Expecting learningWrong mental model
Audit as debug logsMixing log types
Monolithic policiesLack of composition
Set and forgetLack of maintenance
The fix: Use TealTiger for what it’s designed for - deterministic, policy-based governance.