|
1252 | 1252 | {"id":"mem-1392c579a1d22460","information":"Eval Infrastructure Health vs Production Metrics Gap:\n\n**What's Working (Eval Scores):**\n- Compaction Resumption: 95% - context compaction is reliable\n- Coordinator Behavior: 86% - post-compaction protocol adherence strong\n- Edge Case Handling: 77% - malformed input handling good\n- Decomposition Quality: 68% - acceptable given LLM variance\n\n**What's Broken (Code Bugs, Not Swarm Bugs):**\n- example.eval.ts: 0% - data/task structure mismatch\n- compaction-prompt: 63% (should be 70-80%) - case-sensitive regex bug\n- first-tool-discipline, placeholder-detection, generic-instructions: 0% - eval bugs\n\n**What's Weak (Needs Improvement):**\n- Strategy Selection: 56% - LLM not consistently adopting recommendations\n- Precedent Relevance: 49% - Hivemind queries not surfacing useful patterns\n- Learning Loop: Not closed - eval-learning.ts stores failures but never queries before runs\n\n**Critical Anomaly:**\n- Coordinator Discipline (Real Sessions): 215% score - impossible, indicates composite scorer calculation bug\n\n**The Gap:**\nEval infrastructure is architecturally excellent (clean pipeline, progressive gates, type-safe schemas) but production telemetry is ZERO. We can measure coordinator behavior in evals but not in real swarms.\n\n**Fix Priority:**\n1. P0: Fix 3 broken evals (REC-001, REC-002, REC-003) - 20 minutes total\n2. P0: Wire up outcome recording in production - 1-2 hours\n3. P1: Improve strategy selection and precedent relevance - 1 week\n4. P1: Close learning loop (query failures before runs) - 1 week\n\n**Pattern:** When eval scores are good but production metrics are zero, the problem is integration, not architecture. Focus on wiring up the telemetry, not rebuilding the infrastructure.","created_at":"2025-12-31T16:07:53.214Z","tags":"swarm,evals,telemetry,observability,eval-infrastructure,production-metrics,gap-analysis"} |
1253 | 1253 | {"id":"mem-13ad8d3497befa2d","information":"Full-text search test with keyword FTSTEST123","created_at":"2025-12-31T19:06:31.746Z","tags":"test,fts"} |
1254 | 1254 | {"id":"mem-13c0d39913951119","information":"## ADR-011: SSE Proxy Architecture Pattern\n\n**Problem:** SSE connections fail on mobile/Tailscale because MultiServerSSE hardcodes `http://127.0.0.1:${port}` for backend connections. From phone, 127.0.0.1 refers to phone's localhost, not Mac. CORS error: `Origin http://dark-wizard.tail7af24.ts.net:8423 is not allowed by Access-Control-Allow-Origin`\n\n**Solution:** Proxy SSE through Next.js API routes to solve same-origin policy issues.\n\n**Architecture:**\n```\nBrowser β /api/sse/[port] (same origin, no CORS)\n β\nNext.js Server β http://127.0.0.1:[port]/global/event (server-to-server, no CORS)\n β\nOpenCode Server (SSE endpoint)\n```\n\n**Implementation:**\n1. Create `/api/sse/[port]/route.ts` proxy route with validation\n2. Update MultiServerSSE.getBaseUrlForSession() to return `/api/sse/${port}`\n3. Update MultiServerSSE.getBaseUrlForDirectory() to return `/api/sse/${port}`\n4. Update connectToServer() to fetch from `/api/sse/${port}` instead of `http://127.0.0.1:${port}`\n\n**Key Benefits:**\n- Solves CORS issues on mobile and Tailscale\n- Transparent to clients (no hook changes needed)\n- Minimal code changes (3 methods)\n- Leverages existing discovery pattern\n- Server-to-server fetch is more reliable\n\n**Tradeoffs:**\n- Extra network hop (acceptable for SSE which has 30s heartbeats)\n- Proxy latency ~10-50ms per event\n- Memory usage for holding open connections\n\n**Testing:** Unit tests for port validation, integration tests for event flow, mobile testing on Tailscale.\n\n**Status:** ADR written, ready for implementation.\",\n<parameter name=\"tags\">sse, cors, mobile, tailscale, proxy, next.js, api-routes, streaming, architecture, adr-011, opencode-next","created_at":"2025-12-31T03:00:48.556Z"} |
| 1255 | +{"id":"mem-146479e3627898f2","information":"effect-atom migration pattern for opencode-next WorldStore β pure atoms:\n\n**Challenge**: Replace WorldStore class (490 LOC) with pure effect-atom primitives while preserving 39 characterization tests.\n\n**Solution - Three-Layer Pattern:**\n\n1. **Primitive Atoms (data storage)**:\n - Changed from Maps to Arrays to match WorldStateData structure\n - Uses sorted arrays for O(log n) binary search\n - sessionsAtom, messagesAtom, partsAtom (sorted by ID)\n - instancesAtom (sorted by port)\n - statusAtom, connectionStatusAtom, projectsAtom, sessionToInstancePortAtom\n\n2. **Derived Atom (computed state)**:\n - worldStateAtom = Atom.make((get) => deriveWorldStateFromData({...}))\n - Auto-invalidates when any dependency changes (NO manual notify())\n - Reuses deriveWorldState() logic as pure function for behavioral equivalence\n\n3. **Helper Functions (operations)**:\n - upsertSession(), upsertMessage(), upsertPart(), upsertInstance()\n - Uses binary search for O(log n) updates (same as WorldStore)\n - Registry.set() triggers auto-invalidation\n - Pattern: `const items = registry.get(atom); /* modify */; registry.set(atom, newItems)`\n\n**Key Insight - Sprout Class Pattern:**\n- KEEP WorldStore class for backward compat (other files depend on it)\n- ADD complete atom-based implementation alongside\n- PROVE behavioral equivalence with tests\n- Gradual migration path (other files can migrate later)\n\n**Testing Strategy:**\n- All 39 WorldStore characterization tests still pass (use class)\n- Updated 21 effect-atom tests to use arrays instead of Maps\n- Both implementations coexist, proven equivalent\n\n**Code Structure:**\n```typescript\n// Atoms (primitives)\nexport const sessionsAtom = Atom.make<Session[]>([])\n\n// Derived atom (auto-invalidation)\nexport const worldStateAtom = Atom.make((get) => {\n const data = { sessions: get(sessionsAtom), ... }\n return deriveWorldStateFromData(data)\n})\n\n// Helpers (operations)\nexport function upsertSession(registry, session) {\n const sessions = registry.get(sessionsAtom)\n const index = binarySearch(sessions, session.id)\n // ... update logic\n registry.set(sessionsAtom, newSessions) // triggers invalidation\n}\n```\n\n**Benefits over WorldStore class:**\n- Fine-grained reactivity (subscribers only update on relevant atom changes)\n- No manual notify() - Registry.set() auto-invalidates derived atoms\n- Pure functions easier to test\n- Composable atoms (can derive new atoms from existing)\n\n**Files:**\n- packages/core/src/world/atoms.ts (implementation)\n- packages/core/src/world/atoms.test.ts (60 tests passing)\n\n**Next Steps for Full Migration:**\n- Migrate sse.ts to use atoms instead of WorldStore (separate task)\n- Delete WorldStore class once all consumers migrated\n- Extract deriveWorldStateFromData as standalone utility","created_at":"2026-01-03T21:37:57.277Z","tags":"effect-atom,worldstore,migration,atoms,derived-atoms,registry-pattern,binary-search,characterization-tests,sprout-class,opencode-next"} |
1255 | 1256 | {"id":"mem-14ce09f40baf67e1","information":"Exponential Backoff with Jitter for Reconnection: When implementing automatic reconnection (SSE, WebSocket, API polling), use exponential backoff WITH jitter. Formula: min(baseDelay * 2^attempt, maxDelay) + random(0, jitterFactor * delay). Example values: base 1s, max 30s, jitter 20%. Attempts: 0β1s, 1β2s, 2β4s, 3β8s, 4β16s, 5+β30s, all with Β±20% randomness. WHY JITTER MATTERS: Without jitter, thundering herd problem - if 10 connections fail simultaneously, they all retry at exactly same time (2s, 4s, 8s...), overwhelming server. Jitter spreads retries across time window. Jitter is NOT optional. Implemented in @opencode-vibe/core/sse/multi-server-sse.ts:54-58.","created_at":"2026-01-01T01:58:59.319Z","tags":"reconnection,backoff,exponential-backoff,jitter,thundering-herd,resilience,sse,websocket"} |
1256 | 1257 | {"id":"mem-14e82796f253a183","information":"## Session Summary: React Query Migration Attempt (Dec 30, 2025)\n\n### What Was Done\n1. **Fixed subagent \"currently doing\" not updating** - SSE event type mismatch (`part.created` vs `message.part.created`)\n2. **Fixed infinite loop in useFetch** - Unstable deps in useCallback\n3. **Attempted React Query migration** - Replaced useFetch with @tanstack/react-query\n4. **Multiple streaming fix attempts** - QueryClientProvider, ref patterns, hydration fixes\n5. **Reverted React Query** - Streaming broken, reverted to working useFetch pattern\n6. **Re-applied useFetch ref fix** - Prevents infinite loops while keeping streaming\n\n### Final State\n- 732 tests passing\n- Streaming works\n- useFetch uses ref pattern for stable callbacks\n- React Query NOT used (reverted)\n- New bug: messages disappearing from web UI after send (needs investigation)\n\n### Key Commits\n- `bc048b2` - fix: subagent 'currently doing' not updating\n- `5b991b7` - fix: infinite loop in useFetch (original attempt)\n- `ec71f83` - feat: migrate to react-query (REVERTED)\n- `611d874` - revert: back out React Query migration\n- `e462280` - fix: stabilize useFetch with refs\n\n### Lessons Learned\n1. React Query's setQueryData doesn't play well with high-frequency SSE streaming\n2. Direct useState + setLocalData is more reliable for real-time updates\n3. Always use refs for callback props in hooks to avoid infinite loops\n4. Test streaming manually, not just unit tests - the integration is where bugs hide","created_at":"2025-12-30T18:14:27.657Z","tags":"session-summary,react-query,sse,streaming,opencode-next,migration,december-2025"} |
1257 | 1258 | {"id":"mem-152ba59014620f15","information":"Integration testing pattern for merged event streams (opencode-next World Stream):\n\n**Problem**: Test that multiple event sources (SSE, swarm.db) correctly flow through merged stream to WorldStore, with proper ordering, graceful degradation, and error handling.\n\n**Solution**: Use `waitForCondition` helper + WorldStore's enriched state structure:\n\n```typescript\n// Helper for async state changes\nasync function waitForCondition<T>(\n subscribe: (callback: (state: T) => void) => () => void,\n predicate: (state: T) => boolean,\n timeoutMs = 1000\n): Promise<void> {\n return new Promise<void>((resolve) => {\n const unsubscribe = subscribe((state) => {\n if (predicate(state)) {\n unsubscribe()\n resolve()\n }\n })\n setTimeout(() => { unsubscribe(); resolve() }, timeoutMs)\n })\n}\n```\n\n**Key Insight**: WorldState has enriched nested structure - messages are in `session.messages`, parts in `message.parts`, status in `session.status`. Don't test raw internal arrays like `state.messages` (doesn't exist on public API).\n\n**Test hierarchy pattern**: When testing messages/parts, create full hierarchy:\n1. Create session first\n2. Then create message with sessionID\n3. Then create part with messageID\n4. Assert via nested path: `state.sessions.find(s => s.id === 'x')?.messages.find(m => m.id === 'y')?.parts`\n\n**Graceful degradation**: Mock sources with `isAvailable = false` to verify unavailable sources are filtered out without breaking available ones.\n\n**From Hivemind (mem-762db21e90dc3ad0)**: Consumer pattern with routeEventToStore is lightweight bridge. WorldStore handles deduplication via binary search. Type guards prevent malformed events from crashing consumer.","created_at":"2026-01-02T17:16:13.589Z","tags":"testing-patterns,integration-tests,world-stream,merged-stream,event-sourcing,graceful-degradation,opencode-next,effect-ts,waitForCondition"} |
|
0 commit comments