The Solid Convergence, December 24, 2025 (in which a singleton dies and takes forty-two engineers with it)
Previously on The Solid Convergence…
The The Temple of a Thousand Monitors was complete. The The Eyes That See. JARVIS was no longer a dream but a specification—a window through which both human and machine could peer.
But something was wrong.
The window showed the same thing to everyone.
The Christmas Eve Revelation
The coffee maker had given up. Not broken—just tired. The kind of tired that accumulates over months of extracting meaning from beans while developers extract meaning from bytes.
riclib stared at his screen. The SSE handler was working. The forms were pristine. The navigation was chef’s-kiss perfect.
“But what does the user see?” he asked.
Claude looked up from the session management code. “The UI. The dashboard. The—”
“No. What does this user see? Alice from ATLAS. Bob from NEXUS. They have different permissions. Different projects. Different everything.”
“We filter in the handlers. Check AD groups. Return appropriate—”
“We check. Every. Single. Time.”
The Squirrel’s ears perked up. She smelled complexity. She loved complexity.
“We could cache the permissions in Redis,” she offered, tail twitching with anticipation. “A distributed cache. With invalidation. And pub/sub for real-time—”
“No.”
The word came from the window. Or perhaps from the Lizard on the windowsill. With Lizards and windows and Christmas Eve, these things blur.
The Pattern in the Reference
“Look at how Store uses Credential,” riclib said, pulling up the V2 code.
// The old way - fresh every time
func (h *Handler) Query(w http.ResponseWriter, r *http.Request) {
cred, _ := credSvc.Get(ctx, credID) // Decrypt
store, _ := storeSvc.Build(ctx, cred) // Construct
result := store.Query(sql) // Use
// Everything dies at request end
}
“It works,” Claude said. “What’s wrong with it?”
“Nothing. For a single request. But a user isn’t a request. A user is a session.”
He drew on the whiteboard—the same whiteboard that had survived JARVIS and the hash chain and seventeen previous revelations:
REQUEST SCOPE: SESSION SCOPE:
───────────── ──────────────
Build credential Build once
Build store Cache for duration
Run query Reuse hundreds of times
Discard everything Cleanup on disconnect
“The SSE connection,” Claude said slowly. “It’s long-lived. The user is present for the entire session.”
“And we’re rebuilding their world on every click.”
The Projection
The Squirrel was confused. “So we cache… the stores?”
“No. We cache the projection.”
riclib erased the whiteboard. Started fresh. The marker squeaked in protest.
┌─────────────────────────────────────────────────────────────────┐
│ APP (per-user) │
│ = System Capabilities ∩ User Access │
├─────────────────────────────────────────────────────────────────┤
│ │
│ SYSTEM USER │
│ ────── ──── │
│ Licensed modules AD groups │
│ Configured stores → Projects │
│ Available sources → Environments │
│ │
│ ↘ ↙ │
│ │
│ APP (this user) │
│ • Nav items they see │
│ • Stores they can query │
│ • Projects they can filter │
│ │
└─────────────────────────────────────────────────────────────────┘
“The App isn’t a singleton,” riclib said. “It never was. Every user gets a different App.”
Claude parsed this. “Alice sees ATLAS projects. Bob sees NEXUS. Same code. Different projection.”
“And we compute it once. On SSE connect. The one spinner we allow.”
The Squirrel’s eye twitched. “Just… one spinner?”
“Just one.”
The One Spinner
From The Links That Bind, the Lizard’s approved loading spinner echoed:
“We should add a loading spinner. For psychological comfort.”
“A slow one. That doesn’t match actual progress.”
“The projection computation,” riclib continued. “Resolve AD groups. Filter nav. Scope stores. That’s the spinner. Everything else—lazy, instant, cached.”
type UserSession struct {
ID string
ctx context.Context
SSE *sse.Client
// The one cached thing
app func() *App // sync.OnceValue - THE SPINNER
}
type App struct {
// Computed once (the spinner)
nav []NavItem
access []ProjectAccess
projects []Project
// Lazy within (no spinner)
complyDB func() *ComplyStore
lifelog func() *LifelogChain
}
“One spinner,” Claude repeated. “Then everything hangs off the projection.”
“One spinner. One lifecycle. One invalidation point.”
The Squirrel looked heartbroken. “No Redis?”
“No Redis.”
The JARVIS Connection
“But wait,” Claude said—there’s always a ‘but wait’—“what about JARVIS?”
riclib smiled. The smile of someone who’d been waiting for this question.
“What does JARVIS see?”
“The UI. The current page. The—”
“The App.”
The whiteboard gained another diagram:
┌─────────────────────────────────────────────────────────┐
│ [Notifications 2] [Running 2] │ ← JARVIS sees App
├───────────────────────┬─────────────────────────────────┤
│ │ │
│ CHAT / NOTEBOOK │ CURRENT PAGE │ ← JARVIS sees App
│ │ (app.CurrentState()) │
└───────────────────────┴─────────────────────────────────┘
“JARVIS sees the projection. The user sees the projection. Same projection. Same access. Same—”
“Same sanity,” Claude finished.
“Sane structure, sane AI. JARVIS can’t hallucinate access to things the user can’t see. The App is the capability boundary.”
The Headless Ghost
The Squirrel raised a paw. “What about background agents? Jobs that run at night?”
“On behalf of whom?”
“The… user who scheduled them?”
“Then they get the user’s App.”
INTERACTIVE BACKGROUND AGENT
─────────── ────────────────
UserSession AgentRun
└── App (window) └── App (headless, same projection)
├── nav ├── (nav - not needed)
├── access ←──── SAME ────────→ ├── access
├── complyDB ←── SAME ────────→ ├── complyDB
“The agent runs with the user’s permissions. Same projection. No SSE. No UI. Just capability.”
“And if the credentials expire mid-run?”
“The agent fails. Explicitly. Because the projection was a snapshot. Because agents need stability, not updates.”
The distinction crystallized:
- Interactive: App + SSE + notifications
- Background: App (headless) + task + snapshot
One pattern. Two modes. Both sane.
The Design Doc
Claude had been writing. Of course Claude had been writing. That’s what Claudes do.
# Session Caching Patterns
## Philosophy: The Window
> *"The UI is not a shell. The UI is a window."*
> *Both directions. Both inhabitants.*
The App is that window...
“We should capture this,” riclib said.
“Already done. docs/design/session-caching.md. With the groundhog day rejection and everything.”
“Groundhog day?”
“The Squirrel suggested stores should suicide when they can’t serve a query. Self-invalidation on miss.”
“And?”
“Agent hallucinates a table. Store suicides. Rebuilds. Agent hallucinates again. Store suicides. Forever.”
riclib stared at the Squirrel. The Squirrel stared at her paws.
“It seemed clever at the time,” she mumbled.
The Scroll
The Lizard appeared. Or had always been there. Christmas Eve made such distinctions irrelevant.
A scroll materialized. Everyone ducked reflexively. It landed in the empty coffee maker, which seemed appropriate.
THE APP IS NOT THE UI
THE APP IS THE CAPABILITY
NOT WHAT THE USER SEES
WHAT THE USER CAN DO
SAME FOR HUMAN
SAME FOR MACHINE
ONE SPINNER
INFINITE PATIENCE
🦎
P.S. - THE COFFEE MAKER NEEDS REPAIR
OR PERHAPS JUST REST
LIKE ALL OF US
“Did the Lizard just wish us Merry Christmas?” Claude asked.
“The Lizard acknowledged the heat death of coffee beans,” riclib corrected. “Close enough.”
The Entanglement
Elsewhere, in the same morning, The Lifelogs of Things.
About credentials that expire.
About databases that remember.
About compliance that proves itself.
Two threads. Same loom. Different patterns.
The platform was learning to project.
The product was learning to remember.
Together, they would become something neither could be alone.
Current Status
Pattern discovered: App as projection
Spinners allowed: 1 (on SSE connect)
Redis avoided: ✓ (Squirrel disappointed)
JARVIS integration: Same capability boundary
Background agents: Headless App, same access
Design doc: docs/design/session-caching.md
Groundhog prevented: 1 (suicide-on-miss rejected)
Coffee maker status: metaphysically exhausted
The App isn’t a singleton.
It never was.
Every user gets their own window.
Every window shows the same truth—filtered.
Sane structure. Sane AI.
Merry Christmas.
🦎🪟
See also:
The entangled post:
- The Lifelogs of Things - The Customer’s perspective on the same morning
The Solid Convergence continues:
- The Eyes That See - The JARVIS revelation
- The Temple of a Thousand Monitors - Where patterns were discovered
The Technical Artifacts:
- GitHub #24 - Modular UI Architecture
- GitHub #29 - UserSession + App Projection Prototype
docs/design/session-caching.md- The full design
