{% extends "base.html" %} {% block title_suffix %} — Patterns{% endblock %} {% block content %}

Session Patterns

{# ── Judge / LLM status strip ─────────────────────────────────────────────── #}
LLM status: {% if ollama_available %} Ollama running — local inference, no egress {% else %} Ollama not detected {% endif %} {% if api_key_available %} ANTHROPIC_API_KEY set — consent required before use {% endif %} CLI: tes patterns · tes ask "…"
{% if not cache.get('valid') %} {# ── Below-floor / not enough sessions ────────────────────────────────────── #}
Not enough sessions for pattern analysis yet.
{{ cache.get('status', 'Pattern analysis requires at least 30 content sessions.') }}

Current: {{ cache.get('n_sessions', 0) }} content sessions — need {{ cache.get('n_content_sessions_needed', 30) }} to activate clustering.
{% else %} {# ── Validity header ───────────────────────────────────────────────────────── #}
k={{ cache.k }} archetypes over {{ cache.n_sessions }} content sessions  ·  silhouette = {{ "%.3f"|format(cache.silhouette) }} {% if cache.silhouette >= 0.20 %} (meaningful structure) {% else %} (weak structure — treat archetypes as coarse summaries) {% endif %}  ·  {{ cache.anomaly_count }} anomalies ({{ "%.1f"|format(cache.anomaly_pct) }}% of corpus)
Computed {{ cache.get('computed_at', '')[:19] }} · tracegauge {{ cache.get('tracegauge_version', '') }} · session store count {{ cache.get('session_count', '?') }}
Descriptive only — not predictive, not quality labels. {{ cache.get('domain_of_validity', '') }} Archetypes reflect measured differences in session size, context-building stage, and waste presence — they do not rate whether sessions were efficient or "good."
{# ── Archetypes ────────────────────────────────────────────────────────────── #}

Archetypes

{% for a in cache.archetypes %} {% set c = a.centroid %}
{{ a.name }}
{{ a.size }} sessions ({{ "%.1f"|format(a.fraction * 100) }}% of corpus)  ·  {% set task_items = a.task_type_counts.items() | list | sort(attribute='1', reverse=True) %} {{ task_items | map(attribute=0) | join(', ') }}
{# Context re-send bar #}
Context re-send {{ "%.0f"|format(c.get('context_resend_pct', 0) * 100) }}%
{# Context growth bar #}
Context growth {{ "%.0f"|format(c.get('context_growth_pct', 0) * 100) }}%
{# Output bar #}
Output {{ "%.0f"|format(c.get('output_pct', 0) * 100) }}%
{# Waste indicator #}
Has waste {% if c.get('has_waste', 0) >= 0.5 %}YES{% else %}NO{% endif %}
{# Dominant features #} {% if a.dominant_features %}
Standout: {% for df in a.dominant_features[:2] %} {{ df.label }}{% if not loop.last %}, {% endif %} {% endfor %}
{% endif %}
{% endfor %}
{# ── Anomalies ─────────────────────────────────────────────────────────────── #}

Anomalies

{{ cache.anomaly_count }} of {{ cache.n_sessions }} sessions ({{ "%.1f"|format(cache.anomaly_pct) }}%) are statistical outliers for their cluster (Tukey outer fence on centroid distance). Anomalies are sessions unusually far from their archetype centroid — not failures, just statistically atypical. Run tes patterns in the CLI for per-session details.
{% endif %}{# end valid #} {# ── Ask panel (shown in both valid and invalid states; floor enforced in backend) ── #}

Ask about your sessions

Answers are grounded in your measured metrics only. {% if not cache.get('valid') %} Pattern analysis not available yet (below 30-session floor) — corpus stats are still provided. {% endif %} {% if ollama_available %} Using local Ollama — no data leaves your machine. {% elif api_key_available %} Ollama not detected. API path available below (sends metrics only — no session content). {% else %} No LLM detected. Start Ollama or set ANTHROPIC_API_KEY. {% endif %}
{# API consent — only shown when Ollama is absent and an API key is available #} {% if not ollama_available and api_key_available %} {% endif %}
{% endblock %}