2026.02.25 - Bastion
Release Notes - 2026.02.25
Release Date: February 25, 2026
Code Name: "Bastion"
🏰 Overview
"Bastion" is a security and performance release that locks down the onboarding flow, hardens A2A mesh authentication, and introduces a two-tier prompt cache with full conversation-aware key hashing. Named after a fortified stronghold—Bastion ensures that Lucia's APIs are protected from unauthorized access while dramatically reducing redundant LLM calls through intelligent caching of agent planning decisions.
🚀 Highlights
- Setup Endpoint Security — Three-phase security model ensures onboarding APIs are only accessible when appropriate: anonymous key generation, authenticated configuration, then permanent lockdown after setup completes.
- Agent Prompt Caching — New
PromptCachingChatClientdecorator caches LLM planning decisions (tool selection + arguments) across all agents, with conversation-aware cache keys that include function call content and tool results to prevent stale responses. - A2A Mesh Auth Fix — Helm chart now auto-generates
InternalAuth__Tokenfor agent-to-registry communication in mesh deployments. - Cache Management Dashboard — Rewritten Prompt Cache page with Router/Agent tab switcher, per-namespace stats, and eviction controls. Activity page shows Router, Agent, and Combined cache hit rates.
✨ What's New
🔐 Setup Endpoint Security
- Three-phase security model — Phase 1 (pre-key): only
GET /api/setup/statusandPOST /api/setup/generate-dashboard-keyare anonymous. Phase 2 (post-key): all remaining setup endpoints require API key authentication. Phase 3 (post-complete):OnboardingMiddlewarereturns 403 for all/api/setup/*permanently. - Race-window elimination — Direct MongoDB check via
ConfigStoreWriter+ volatile one-way latch closes the 5-second window between setup completion andMongoConfigurationProviderpolling. - Health check exemption — Health endpoints remain anonymous for container orchestrator probes.
⚡ Agent Prompt Caching
- Two-tier cache architecture — Routing cache (
lucia:prompt-cache:) stores router decisions; agent cache (lucia:chat-cache:) stores LLM planning responses with 4-hour TTL. Same user prompt hitting different agents produces separate entries (system instructions hash differentiates). - Full conversation key hashing — Cache keys include
FunctionCallContent(tool name + arguments) andFunctionResultContent(result text), not justmessage.Text. Different tool results automatically produce different cache keys, preventing stale response replay. - Volatile field stripping — Regex strips
timestamp,day_of_week, andidfields from HA context before SHA256 hashing so identical intents produce the same key regardless of when they're sent. - Clean display prompts —
ExtractLastUserText()stores the human-readable user message asNormalizedPromptinstead of the raw cache key for dashboard display.
📊 Cache Management UI
- Tabbed Prompt Cache page — Router and Agent cache entries displayed in separate tabs with dedicated StatsBar (entries, hits, misses, hit rate) and per-entry eviction.
- Bulk eviction — "Clear All" button per cache namespace for cache invalidation.
- Activity dashboard integration — Summary cards show Router, Agent, and Combined cache hit rates in a 6-column grid layout.
- Chat cache REST API — New
/api/chat-cache/*endpoint group:GET /(list entries),GET /stats(hit/miss/rate),DELETE /{key}(evict single),DELETE /(evict all).
🔗 A2A Mesh Authentication
- Helm chart
InternalAuth__Token— NewinternalAuthTokenfield invalues.yamlwith auto-generation viarandAlphaNum 32insecret.yaml, injected as environment variable into all agent pods. - Registry auth fix — A2A agents no longer receive 401 when registering with the agent registry in mesh deployments.
🎭 Playwright E2E Tests
- Prompt cache validation — 5 serial test cases verifying cache hit/miss behavior, eviction, and stats accuracy through the dashboard UI.
- Environment-driven auth — Tests read
DASHBOARD_API_KEYfrom.envfile for login;.env.templateprovides placeholder for CI setup.
🐛 Bug Fixes
- Stale cache responses —
message.Textonly returnsTextContent, missingFunctionCallContentandFunctionResultContent. All round-2+ conversations hashed to the same key regardless of tool results, causing the LLM's cached response from a previous run to be replayed with wrong state (e.g., "lights are off" when they're on). Fixed by iteratingmessage.Contentsand including all content types in the key. - 0% cache hit rate — HA context injection of
timestamp,day_of_week, andidmade every prompt unique. Stripped via regex before hashing. - NormalizedPrompt display — Cache entries showed raw key format (
instructions:sha...\nuser:...\nassistant:\ntool:) instead of the clean user message. - TS interface mismatch —
ChatCacheEntry.functionCallsusedargumentsfield name but JSON serializes asargumentsJson; fixed TypeScript interface. - A2A 401 in mesh mode —
InternalAuth__Tokenwas auto-generated by Aspire AppHost but never injected in Helm chart for Kubernetes deployments. - Setup race window — 5-second gap between
POST /api/setup/completeandMongoConfigurationProviderconfig poll allowed anonymous access to setup endpoints.