Auditoría de arquitectura · Senior Architecture Audit

Agent Squad — Journey completo: del signup al Canva de línea de producción

Alcance: app.agentsquadai.com (web) · api-substrate.digitalhubassist.ai (substrato) · InsForge (BaaS) Fuente: código real del repo agent-squad-app + runbook server-topology (nada inferido sin evidencia) Fecha de corte: 2026-07-12 Navegación: entre pasos

HALLAZGO 0 El journey auditado NO atraviesa AWS en su hot path — pero SÍ hay cuenta AWS real con componentes desplegados

La columna vertebral del journey (signup → onboarding → discovery → charter) es SvelteKit en Vercel (frontend + funciones serverless), InsForge (BaaS cloud: auth, Postgres con RLS, perfiles) y un box Hetzner único (178.104.101.213, 8 CPU/16 GB) que corre el substrato (API Hono en Bun vía systemd, Inngest self-hosted, Postgres/Timescale, Langfuse). No hay Cognito, API Gateway ni DynamoDB en ese camino. PERO existe una cuenta AWS real del proyecto — 226585212364, IAM user remotion-lambda, región us-east-1 (credenciales en ~/.aws del box, credential chain estándar) — con 4 componentes desplegados en sesiones anteriores que hoy operan como failover y planos opt-in, no en el camino caliente:

Dato de auditoría clave: el apps/api/.env de producción tiene CERO variables AWS (ni AWS_*, ni TOOL_PLANE_ADAPTER, ni FORGE_SANDBOX_ADAPTER, ni MODEL_CLASS_*) → con la config vigente, ninguno de los 4 se ejecuta en tráfico de producción. Son capacidad instalada: código cableado en puntos precisos + credenciales listas + verificación en vivo hecha. El call-site exacto de cada uno:

Componente AWS realPunto de invocación EXACTO en el códigoQuién lo consumiríaCómo se enciende / estado hoy
Amazon Bedrock (Runtime)apps/api/src/inngest/llm.ts:192 — el switch de generateLLMText: if (target.provider === 'bedrock') → generateViaBedrock (model-plane/bedrock.ts, credential chain estándar, región AWS_REGION ?? us-east-1)TODA llamada LLM del API pasa por ese switch: Nova discovery (paso 06), charter (paso 09), compose, judges, FORGEEnv MODEL_CLASS_<CLASE>=bedrock:<model-id> o fila en model_routing_policy. Hoy: política = claude-cli · claude-sonnet-4-5 para todas las clases → la rama nunca se toma. Inference profile Haiku 4.5 verificado en vivo 2026-07-08. Runbook: llm-failover-max-to-api.md
Bedrock AgentCore · Gatewaytool-plane/resolve.ts (resolveToolPlaneAdapter) — consumido en DOS puntos: inngest/operations/runtime.ts:85 (runtime de operaciones de workflows) y forge/registry.ts:135 (registro de tools de FORGE). mcp-client con firma SigV4Los steps de workflows durables y FORGE al resolver herramientas remotas vía MCPTOOL_PLANE_ADAPTER=agentcore-gateway + AGENTCORE_GATEWAY_URL. Hoy: default self-hosted (la rama agentcore lanza error si falta la URL, nunca se alcanza)
Bedrock AgentCore · Code Interpreterforge/sandbox-port.ts:62-73 — selector del sandbox: FORGE_SANDBOX_ADAPTER === 'code-interpreter' → AgentCoreCodeInterpreterClient (forge/code-interpreter/client.ts: Start/Invoke/StopCodeInterpreterSession; fallo AWS → InfraError kind 'infra', nunca fallo de generación)La verificación/ejecución del código que genera FORGEFORGE_SANDBOX_ADAPTER=code-interpreter + AGENTCORE_CODE_INTERPRETER_ID. Hoy: 'local' (sandbox por-proceso en el box)
AWS Secrets Managertool-plane/agentcore/gateway-provisioner.ts:118getSecretString(secretId) dentro de provisionGateway (secrets/secrets-manager.ts; el valor jamás se loguea)SOLO el aprovisionamiento del Gateway — hoy únicamente lo dispara el script de operador apps/api/scripts/toolplane-e2e.ts (provisiona y desprovisiona en la prueba E2E)Se enciende junto con el Gateway; no está en ningún request path de prod. String-only (sin SecretBinary), fail-hard si vacío

Veredicto del auditor: los pasos del journey reportan lo que EJECUTA cada clic hoy; los componentes AWS aparecen donde tocan (ModelPlane, pasos 06 y 09) marcados como plan B/opt-in. Para el resto de conceptos pedidos, la equivalencia:

Tabla de equivalencias conceptuales (pedido AWS → realidad verificada)
Concepto pedido (AWS)Realidad en Agent SquadDetalle verificable
Amazon CognitoInsForge Authhttps://iec6r486.us-east.insforge.app/api/auth/* — users, sessions (client_type=server), refresh con rotación, verificación de email
API Gateway + LambdaVercel Serverless Functions (rutas +server.ts de SvelteKit, adapter-vercel)Cada ruta /api/* del web es una función; p.ej. discovery declara maxDuration: 90. Vercel las ejecuta sobre AWS Lambda como detalle de SU plataforma (no es un recurso administrado por el proyecto)
ECS/EKS (compute persistente)systemd agent-squad-api.service en HetznerHono + Bun en 0.0.0.0:4000, cwd ~/agent-squad-app/apps/api; deploy por cron auto-deploy-api.sh (poll de main + marker + restart con health-gate)
DynamoDB / RDSPostgres de InsForge (estado de la app) + Postgres/Timescale del substrato (:5433, grafo intents→plans→traces)InsForge: auth.users, public.user_access, profiles.app_state. Substrato: container substrate-postgres
Step FunctionsInngest self-hostedContainer substrate-inngest (:8288), steps durables, waitForEvent para gates humanos. NO participa en el journey auditado (hasta el charter no se ejecuta ningún workflow)
CloudFrontCDN de Vercel + nginx en el boxnginx enruta api-substrate.digitalhubassist.ai → 127.0.0.1:4000 con TLS
IAM (roles/policies)Capas de secretos y gates aplicativosCookie httpOnly insforge_session, anon key vs SERVICE_KEY (bypass RLS, solo server), RLS auth.uid() = user_id, Bearer SUBSTRATE_API_TOKEN (comparación constant-time), gate user_access.authorized fail-closed
RegiónVercel (edge/iad1 gestionado por Vercel) · InsForge us-east (subdominio lo declara) · Hetzner: box único europeo (región exacta no verificada en el repo → no se afirma)

FILTRAR CAPA TÉCNICA:
Experiencia del usuario (UX)
Verdad técnica cruda (backend / infra)