Retry Logic with Heuristics
Trinity's build pipeline with optional self-healing
Trinity uses a layered pipeline that combines deterministic template rendering with optional LLM content generation and CSS self-healing.
Architecture Overview
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ SKELETON │ │ BRAIN │ │ PREDICTOR │
│ │ │ │ │ (optional) │
│ Jinja2 + │───▶│ Local LLM │───▶│ Random Forest│
│ Tailwind │ │ (optional) │ │ (Multiclass) │
│ │ │ │ │ │
│ Deterministic│ │ Creative │ │ Predictive │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
│ ▼ ▼
│ ┌──────────────┐ ┌──────────────┐
│ │ CACHE │ │ HEALER │
│ │ │ │ │
│ │ Memory/ │ │ LSTM Neural │
│ │ Redis/ │ │ + Heuristic │
│ │ Filesystem │ │ │
│ └──────────────┘ └──────────────┘
│ │
│ ▼
│ ┌──────────────┐
│ │ GUARDIAN │
│ │ (optional) │
└────────────────────────────────▶│ Playwright │
│ DOM inspect │
└──────────────┘Key Principles:
- Separation of Concerns: Each layer has a single responsibility
- Fail-Safe Defaults: Graceful degradation at every layer
- Observable: Structured logging throughout
- Testable: Each component can be tested in isolation
- Optional Components: Guardian, Predictor, and Neural Healer are all opt-in
Layer 1: Brain (Content Generation)
Responsibility: Generate content from structured input or via LLM
LLM Client
The LLM client provides content generation with:
- Exponential backoff retry logic (max 3 attempts)
- Circuit breaker integration (fail-fast after repeated errors)
- Multi-tier cache support (memory/filesystem/Redis)
- Structured logging
Supported LLM Providers
| Provider | Local/Cloud | Notes |
|---|---|---|
| LM Studio | Local | Default endpoint (http://localhost:1234/v1) |
| Ollama | Local | Alternative local option |
| OpenAI | Cloud | Requires TRINITY_OPENAI_API_KEY |
Content Generation Flow
# 1. Load input data
with open("data/input_content.json") as f:
content = json.load(f)
# Or generate with LLM (--llm flag)
brain = ContentEngine(base_url=config.lm_studio_url)
content = brain.generate_content_with_fallback(
raw_text_path="data/raw_portfolio.txt",
theme="brutalist",
fallback_path="data/input_content.json",
)
# 2. Validate against schema
self.validator.validate_content_schema(content)Layer 2: Skeleton (Theme Application)
Responsibility: Apply themes to content and render HTML
Theme System
Trinity uses YAML-based theme configuration (config/themes.yaml):
brutalist:
metadata:
description: "Raw, bold, unapologetically direct aesthetic"
category: creative
classes:
hero_title: "text-7xl font-black uppercase tracking-tight"
card_bg: "bg-black border-4 border-white p-6"
# ... more Tailwind class mappingsBuilt-in Themes (14 total)
artistic_01, artistic_02, brutalist, chaotic_01, chaotic_02, editorial, enterprise, historical_01, historical_02, professional_01, professional_02, retro_arcade, tech_01, tech_02
The available_themes config lists enterprise, brutalist, and editorial by default; all themes in config/themes.yaml are available for use.
Rendering Pipeline
# 1. Load theme from YAML
builder = SiteBuilder(template_dir=str(config.templates_path))
# 2. Build page with content and theme
output_path = builder.build_page(
content=content,
theme=theme,
output_filename=output_filename,
style_overrides=style_overrides,
)Layer 3: Predictor (ML Strategy Recommendation, optional)
Responsibility: Predict which CSS fix strategy to apply before rendering
Why a Predictor?
Without a predictor, the self-healing loop must run Guardian validation after each build attempt to determine if a fix worked. The predictor can suggest a strategy upfront, reducing the number of Guardian rounds.
Setup
The predictor requires training data and a trained model:
# Step 1: collect training data
trinity mine-generate --count 1000 --guardian
# Step 2: train the model
trinity trainModel
Random Forest Classifier (Multiclass):
- 100 estimators, max depth 10
- Features: content character count, word count, CSS density metrics, pathological score, theme ID, current strategy
- Output: Strategy ID (0 = NONE, 1-4 = healing strategies)
- Confidence threshold: 0.6
The predictor is enabled by default (predictive_enabled=true) but has no effect if no trained model exists.
Layer 4: Healer (CSS Auto-Repair)
Responsibility: Fix layout issues after Guardian detection
SmartHealer (default)
Rule-based CSS fixes applied progressively:
| Attempt | Strategy | What it does |
|---|---|---|
| 1 | CSS_BREAK_WORD | Add word-break and overflow-wrap |
| 2 | FONT_SHRINK | Reduce font size |
| 3 | CSS_TRUNCATE | Apply text truncation |
| 4 | CONTENT_CUT | Truncate content string |
Neural Healer (optional, --neural)
An LSTM Seq2Seq model that generates CSS class fixes based on error context. Falls back to SmartHealer if confidence < 0.6 or model unavailable.
Layer 5: Guardian (Visual Validation, optional)
Responsibility: Verify layout integrity using browser automation
Requirements
Playwright and browser binaries must be installed separately:
pip install playwright
playwright install chromiumDetection
Guardian loads the rendered HTML in a headless browser and checks all text elements for overflow:
async def detect_overflows(page: Page) -> List[OverflowError]:
elements = await page.query_selector_all("h1, h2, p, span")
overflows = []
for el in elements:
box = await el.bounding_box()
scroll_width = await el.evaluate("el => el.scrollWidth")
if scroll_width > box["width"] + 5: # 5px tolerance
overflows.append({
"element": await el.evaluate("el => el.className"),
"overflow": scroll_width - box["width"],
"text": await el.text_content()
})
return overflowsUsage
# Enable Guardian
trinity build --input data/content.json --guardian --theme brutalist
# Disable (default)
trinity build --input data/content.json --theme brutalistInfrastructure Components
Multi-Tier Caching
3-tier cache architecture:
- Memory Cache: In-process LRU, cleared on restart, <1ms access
- Redis Cache: Distributed, optional, requires running Redis server
- Filesystem Cache: Persistent,
.cache/directory
Cache keys are generated from the prompt content, model name, and provider. Caching is applied automatically to LLM requests when enabled.
Structured Logging
Trinity uses structured logging with two formats:
- Development (default): Human-readable colored output
- Production (
TRINITY_ENV=Production): JSON format suitable for log aggregation
logger.info("Build started", extra={
"theme": "brutalist",
"guardian": True,
"correlation_id": "build-123"
})Circuit Breaker
Fail-fast protection on LLM errors:
class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60):
self.failure_count = 0
self.state = "CLOSED" # CLOSED, OPEN, HALF_OPENStates:
- CLOSED: Normal operation
- OPEN: Failing fast (timeout period)
- HALF_OPEN: Testing if service recovered
Complete Build Flow
1. Input
↓
data/input_content.json (structured) or raw text
2. Brain (optional LLM content generation)
↓
ContentEngine → LLM API → JSON response
↓
Pydantic validation → structured content
↓
Cache store
3. Skeleton (Theme Application)
↓
Load YAML theme → Jinja2 rendering
↓
HTML + Tailwind CSS → output file
4. Predictor (optional, if model trained)
↓
FeatureExtractor → feature vector
↓
Random Forest → strategy recommendation
↓
Pre-emptive CSS fix applied
5a. Guardian disabled (default)
↓
Return output file (done)
5b. Guardian enabled (--guardian)
↓
Playwright → DOM inspection
↓
If overflow: Healer → apply CSS fix → rebuild → revalidate
↓
Return output file (or BROKEN_ file if max retries exceeded)Next Steps
See Async & MLOps for caching and async client details.
See Development → Setup for installation and usage.
See Features for self-healing and Centuria Factory guides.