Skip to content

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:

  1. Separation of Concerns: Each layer has a single responsibility
  2. Fail-Safe Defaults: Graceful degradation at every layer
  3. Observable: Structured logging throughout
  4. Testable: Each component can be tested in isolation
  5. 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

ProviderLocal/CloudNotes
LM StudioLocalDefault endpoint (http://localhost:1234/v1)
OllamaLocalAlternative local option
OpenAICloudRequires TRINITY_OPENAI_API_KEY

Content Generation Flow

python
# 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):

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 mappings

Built-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

python
# 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:

bash
# Step 1: collect training data
trinity mine-generate --count 1000 --guardian

# Step 2: train the model
trinity train

Model

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:

AttemptStrategyWhat it does
1CSS_BREAK_WORDAdd word-break and overflow-wrap
2FONT_SHRINKReduce font size
3CSS_TRUNCATEApply text truncation
4CONTENT_CUTTruncate 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:

bash
pip install playwright
playwright install chromium

Detection

Guardian loads the rendered HTML in a headless browser and checks all text elements for overflow:

python
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 overflows

Usage

bash
# Enable Guardian
trinity build --input data/content.json --guardian --theme brutalist

# Disable (default)
trinity build --input data/content.json --theme brutalist

Infrastructure 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
python
logger.info("Build started", extra={
    "theme": "brutalist",
    "guardian": True,
    "correlation_id": "build-123"
})

Circuit Breaker

Fail-fast protection on LLM errors:

python
class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_count = 0
        self.state = "CLOSED"  # CLOSED, OPEN, HALF_OPEN

States:

  • 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.

Released under the MIT License.