Architecture: How should the SandboxPlacementRouter be architected to supp...
Documentation for Sessions
🏗️ Architecture: How should the SandboxPlacementRouter be architected to supp...
Date: 2026-03-23
Time: 15:39:09 UTC
Session: gspace1-260.3
Agent: backend
Confidence: 94%
Status: ✅ Documented
📋 Decision Context
Question:
How should the SandboxPlacementRouter be architected to support concurrent multi-server VM routing with role-based workload placement?
Task: S260: Multi-server sandbox infrastructure with concurrent workload routing
🎯 Decision Made
Chosen:
Placement Router pattern (inspired by K8s scheduler + Nomad affinity model): SandboxPlacementRouter implements SandboxProvider interface (zero consumer changes). Config-driven server registry via SANDBOX_SERVERS_JSON with per-server id, url, apiKey, roles[], priority, maxContainers. Filter→Score placement: filter by health+capacity+role, score by priority. Placement map (vmId→serverId) for sticky routing. Per-server health monitor with circuit breaker (healthy→degraded→down). Server IDs: {hardware-class}-{sequence} (ax102-01, ax42-01) — roles as metadata. Git operations moved to ax102-01 (more powerful). ax42-01 kept as sandbox.gograb.space (legacy DNS preserved).
Options Considered:
- Modify SelfHostedProvider to accept multiple URLs (breaks single-responsibility)
- Two separate SelfHostedProviders in factory (doesn't scale, hacky)
- HAProxy/NGINX load balancer in front of both servers (no workload-type routing)
- SandboxPlacementRouter with filter-score-place pattern (chosen — clean, extensible, zero consumer changes)
💭 Reasoning
Research across 3 dimensions: (1) Codebase — SelfHostedProvider is single-URL, SandboxProviderFactory selects ONE provider at startup, SandboxHandle has no server affinity. (2) External — K8s filter→score is the gold standard but overkill at 2-3 servers; simplified to priority+capacity. Nomad's constraint+affinity model maps directly (hard: role match, soft: priority preference). Registry-based stickiness beats hash-based for stateful VMs. (3) MCP history — S178.13 documented the missing fallback as known gap. S244 IDS spec identified executive/customer VM mixing as dangerous. S240 snapshot model is current correct approach. The Placement Router wraps multiple SelfHostedProvider-like HTTP clients behind the same SandboxProvider interface, achieving multi-server without touching any consumer code.
📁 Files Involved
APIs/backend-ai-api/src/app/infrastructure/services/sandbox/sandbox-provider.interface.tsAPIs/backend-ai-api/src/app/infrastructure/services/sandbox/sandbox-provider.factory.tsAPIs/backend-ai-api/src/app/infrastructure/services/sandbox/self-hosted.provider.tsAPIs/backend-ai-api/src/app/infrastructure/services/computer-use-loop.service.tsAPIs/backend-ai-api/src/app/infrastructure/infrastructure.module.tsdocs/superpowers/specs/2026-03-23-hetzner-dual-server-infrastructure-design.md
🔗 Related
- Decision ID:
dev_1774280349838_q915b9u - Session: 260
- Workspace: gspace1
Auto-generated by MCP Smart Consolidation