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.