Tirar o Render do AgentPack para uma app propria, e consertar os MCPs proxied que tem sessao. O que existe, o que falta e o que depende de voce.
O que foi medido, o que existe e o que nao existe. Os zeros sao a parte importante.
| Gate | Resultado | Observacao |
|---|---|---|
| backend:typecheck | verde | |
| frontend:typecheck | verde | |
| jest shard 1/8 | verde | |
| jest shard 2/8 | verde | |
| jest shard 3/8 | verde | |
| jest shard 4/8 | vermelho | 3 falhas PRE-EXISTENTES de shutdown.test.ts, iguais ao baseline. Nenhuma falha nova. |
| jest shard 5/8 | verde | |
| jest shard 6/8 | verde | |
| jest shard 7/8 | verde | |
| jest shard 8/8 | verde | |
| frontend:vitest mcps+render | verde | |
| eslint dos arquivos tocados | verde | |
| lint:ratchet | verde | 4831 avisos, numero identico ao baseline, 0 erros |
| docs:gen + docs:check | verde |
Leia antes de acreditar nos numeros. Gates verdes provam que os testes EXISTENTES nao regrediram. Nao provam que as revisoes adversariais aprovaram — e elas nao aprovaram: as 3 lentes voltaram com verdict 'fix'.
Fase A entrega o Render dentro do AgentPack; fase B tira de dentro e o AgentPack vira ponte.
| Medida | Valor |
|---|---|
| Entra no Render | 43% do backend · 41% do frontend |
| Rotas REST | 47 (o plano falava 54; o desenho corrigiu com criterio escrito) |
| Tools MCP | 59 — 20 render + 39 render-admin |
| Banco | 8 tabelas + 3 enums + espelhos + approvals |
| Nomes de wire | agentpack_render_* (iguais aos de hoje) |
| Fica no AgentPack | o core inteiro + projeto + decisao humana + chave |
A virada. No corte, o AgentPack cadastra o /mcp do Render como MCP proxied com toolPrefix agentpack_render, de modo que uma URL so e os mesmos nomes continuem valendo. Hoje o AgentPack publica agentpack_render_ como built-in e o catalogo proxied descarta nomes que colidem com built-in (mcp/catalog.ts:292) — por isso a ponte so funciona DEPOIS de remover RENDER_TOOLS do registro. E mecanismo de virada, nao de convivencia.
A sessao do destino e por (chave, projeto), nao por conversa: duas conversas da mesma chave dividem a MESMA janela do browser. O gateway e stateless por decisao (ADR-011), entao nao existe sessao de quem chama.
| MCP de destino | Impacto | Por que |
|---|---|---|
| MCP que so fala 2026-07-28 (o do MyPanel) | MCP inteiro: 0 tools, toda chamada falha | o cliente v1 1.30.1 so conhece ate 2025-11-25 |
| MCP com sessao (browsers) | funciona ate: 5 min parado, 1 chamada acima de 60 s, 1 erro HTTP, deploy — e mistura conversas | |
| MCP SSE legado (/sse) | MCP inteiro: nao conecta | o proxy marca 'not spoken' |
| MCP so de stdio (REA) via ponte | depende da ponte: hoje fora do ar (503) | as 4 falhas de producao tem a assinatura da ponte sem reescrita de id |
| Empresa A x empresa B | catalogo de MCP e global (seguranca, nao 'nao funciona') |
O que a correcao entrega — e o defeito que continua aberto
A proxima chamada da conversa refaz o handshake (GET /sse novo) em vez de repetir o mesmo erro por 30 min. Em LEITURA a chamada e repetida na sessao nova; em ESCRITA nao (o efeito pode ter ocorrido) — e nos dois casos o resultado leva o aviso pt-BR de sessao reiniciada, igual ao Streamable HTTP.
Prova: 2 testes novos contra upstream SSE legado REAL (v1 SSEServerTransport) com dropSessions(): reconexao (inits 1 -> 2) e http_status em vez de invalid_response.
McpUpstreamError com problem http_status e o codigo, mensagem citando HTTP 400/404/410, em vez de 'The MCP server sent an invalid JSON-RPC response'.
Prova: Red-check: desligando so o ssePostRefusalStatus, os 2 testes novos falham e os outros 6 do arquivo passam.
O cliente sobrevive a eles: uma credencial trocada no cadastro nao derruba a janela do MCP nem dispara handshake desnecessario. So 400/404/410 contam.
Prova: Faixa estreita, deliberada.
O GET /sse morre (idle timeout do LB, rede, deploy). O client.onerror recebe o SseError e so loga: a entrada do pool NUNCA sai. Toda chamada daquele escopo cai em EGRESS_TIMEOUT por 5 min, e o updateAgeOnGet do LeasePool RENOVA o TTL de 30 min a cada tentativa — entao so se cura para quem ficar quieto.
Consequencia: Tools de ESCRITA executam de verdade no destino enquanto o agente ve 'o destino nao respondeu', e a chamada seguinte executa de novo. Execucao duplicada com o agente mal informado.
Prova: r3-lab-streamdead.jsonl: pool=1 sem evict, 2 tools/call de verdade no destino.
Fix: Marcar a conexao quando o stream cai; tratar EgressTimeoutError/SseError como sessao morta SO quando transport e 'sse' (o Streamable HTTP mantem a regra atual e o teste que a trava continua verde); evict + retry so-em-leitura + onSessionRestarted. Cobrir tambem a chamada que estava em voo quando o stream caiu.
| Quando | Regra |
|---|---|
| antes | A sessao e por (chave, projeto). Duas conversas da mesma chave dividem a mesma janela do browser. Nao existe sessao de quem chama, porque o gateway e stateless. |
| depois | O Mcp-Session-Id entra como ENTRADA OPCIONAL e nunca e emitido. O gateway continua stateless (ADR-011) e sem o header o escopo e o de hoje. Com o header, o escopo do pool passa a ser a conversa — sem escalada, porque ator e projeto continuam vindo do token e do header. |
| prova | 2 testes em mcp-transport.test.ts: o header e so entrada (initialize nao o devolve, duas conversas chamam) e valor malformado e ignorado. |
| Regra | Por que |
|---|---|
| Retry de 404 so em chamada de leitura | o HTTP nao distingue chamada processada de nao processada; repetir uma escrita pode duplicar efeito. Em escrita so o aviso. |
| 401/403 nunca sao sessao morta | o cliente sobrevive a eles; repetir o handshake nao conserta credencial errada. |
| O Mcp-Session-Id so entra, nunca sai | ator e projeto continuam vindo do token e do header — o id nao concede nada novo. |
| Cache do catalogo com chave por organizacao | depois da migration por empresa, o '*' global faria duas empresas lerem o MESMO objeto cacheado. |
| Credencial so atravessa a origem ja autorizada | nextHop compara por origin, e origin ignora porta padrao — o B2 corrige isso. |
12 bloqueios abertos. 3 criticos. O status real do trabalho e BLOQUEADO, nao pronto: os gates verdes provam que os testes existentes nao regrediram, nao que as revisoes aprovaram.
O repo PedroPaduelo/render tem 1 commit e um unico README.md de 129 bytes. O proprio desenho diz: 'Isto e planta, nao execucao.' O dono pediu a aplicacao, nao a planta.
Proximo passo: Responder as 5 decisoes D1-D4 e D17 e despachar P-1..P14 em worktrees do sandbox render
Quando o stream GET /sse morre, a entrada do pool nunca sai. Toda chamada cai em EGRESS_TIMEOUT por 5 min ate o TTL de 30 min, que cada tentativa RENOVA. Tools de ESCRITA executam de verdade no destino enquanto o agente ve 'o destino nao respondeu', e a chamada seguinte executa de novo.
Proximo passo: Marcar a conexao quando o stream cai (hoje o client.onerror so loga), tratar EgressTimeoutError/SseError como sessao morta so quando transport e 'sse', evict + retry so-em-leitura + onSessionRestarted
orgVisible() devolve true para organizationId null (correto para leitura) e a regra foi propagada para as ESCRITAS. PATCH, DELETE e as DUAS rotas de credencial nao conferem posse. Qualquer usuario de qualquer empresa pode reescrever a URL de um MCP de plataforma ou de outra empresa, trocar/apagar a credencial cifrada e apagar a linha.
Proximo passo: Exigir posse (organizationId igual) em todo write e nas duas rotas de credencial; passar scope para setBearerToken/clearSecrets; teste fixando que empresa A nao escreve na linha da B. Fechar ANTES de qualquer deploy.
origin ignora porta padrao. Redirect de https://host/mcp para https://host:80/mcp mantem o Authorization com uma origem que a politica nao considera igual. O host continua revalidado (SSRF nao abre), mas a garantia de credencial esta furada.
Proximo passo: Comparar por host e porta efetiva, com teste de redirect para porta padrao e nao-padrao
O commit 1a67c15 corrigiu tools/call, mas quando o POST recusado e o da sonda/initialize o SDK embrulha o Error e a classificacao cai em 'invalid_response' ANTES do extrator de status HTTP. Voce ve 'resposta invalida' quando o destino recusou com um HTTP claro.
Proximo passo: Percorrer a cadeia cause (como egressCauseOf ja faz) e chamar o extrator antes do ramo SdkError; teste de recusa 400 no initialize
A branch fix/mcp-proxy-sessoes (9 commits, head 1a67c15) NAO existe no GitHub — a API devolve 404 para a ref. Existe so no worktree local do sandbox, que expira em 2026-10-16. As branches feat/prompts-agente e feat/roadmap-gantt tambem so estao locais.
Proximo passo: Com o seu aval: push da branch e merge na main, e so entao o deployments_trigger. Hoje NAO ha nada para deployar.
O bundle do agentpack-frontend-ws embute o sandbox morto https://sb-conta-nommand-app.mp.serendiped.com. A Conta de producao e https://conta.mp.serendiped.com. Quebra Minha Conta, Gerenciar na Conta, o aviso de laco de SSO e o fallback da barra. A decisao D16 e 'sim, e uma env e um rebuild' e nada foi feito.
Proximo passo: Sua env AGENTPACK_CONTA_URL=https://conta.mp.serendiped.com + rebuild do agentpack-frontend-ws. Escrita em producao, proibida para os agentes.
toolError mora em tools/render/common.ts e e usado por mcp/tool-call.ts e mcp/proxy-call.ts para TODA tool; appBaseUrl mora em lib/render-view-url.ts e e usado por task-decision.service.ts; as 3 tools project_* moram no registro do Render; e as 2 chaves de rate-limit.ts:87-88 derrubam o boot se as rotas sumirem.
Proximo passo: Executar P-1 e P-2 (que sao no AgentPack e nao dependem de nada) antes de qualquer remocao
impl.json marcava status 'done' e falhas_novas [], enquanto as 3 revisoes da rodada 3 estao com verdict 'fix' e 5 bloqueios abertos no mesmo head. 'Pronto' ali significava apenas que os testes existentes continuavam verdes.
Proximo passo: Este relatorio abre pelos bloqueios, nao pelos gates verdes. O status real e BLOQUEADO.
Voce disse: 'nao existe a sandbox para o Renner, voce vai ter que criar... nao existe um repository Git para ele, voce vai ter que criar. Privado, publico nao, privado.' Se 'Renner' e o Render: sandbox e repo privado JA FORAM criados (sb-render, PedroPaduelo/render privado) — o que falta e o codigo. Se 'Renner' e uma pessoa, nada foi criado para ela.
Proximo passo: Confirmar se Renner = Render ou uma pessoa. Se for pessoa, criar sandbox + repo privado e atualizar o escopo.
B6 (orgId no actor do token de preview + NOT NULL em agent_keys.organization_id) ficou 'de proposito' de fora, sem dono. As 3 falhas pre-existentes de shutdown.test.ts tambem estao sem dono. Sem teste dedicado tambem para 500 no SSE (que nao e sessao morta).
Proximo passo: Nomear dono e prazo, ou registrar aceite formal do risco
O runbook que existe e o da app Render. Falta o de deploy/rollback da correcao de MCP no agentpack-backend-ws, e o efeito da migration 20261013090000 no banco de producao.
Proximo passo: Escrever: deployments_trigger, conferencia por hash de bundle, rollback = deployments_rollback, e o passo da migration
Renner = Render. Entao ja esta feito: sandbox 'render' criada em 2026-10-13 (20 GB) e repo PedroPaduelo/render PRIVADO. O que falta e o codigo, nao a sandbox nem o repo.
Preciso da sua palavra: Preciso da sua palavra: Renner e o Render ou uma pessoa?
5 delas travam um pacote: sem a resposta, nenhum agente pode comecar. Todas as 17 tem recomendacao do desenho.
Por que: As 4 tabelas do Render tem FK project_id e toda operacao passa por requireProject: sem esta decisao nenhuma tela, mapa, biblioteca de projeto ou porte abre. Espelhar preserva os ids que os URLs, a key da decisao de upgrade e os designSystemId ja carregam. Ler por API a cada chamada transforma uma transacao SERIALIZABLE em duas e quebra agente sem rede.
O que custa: A cascata e o portao de lixeira passam a ser espelho: o purge precisa virar evento (webhook + reconciliador) e o AgentPack precisa de um contrato de purga.
Por que: Consultar o AgentPack por API e exatamente o acoplamento que a extracao quer eliminar, e a alternativa de so pessoa logada enfraquece a garantia de que um agente nunca se aprova. O caminho humano (REST) ja existe e nao precisa de tabela.
O que custa: A pergunta nova e se voce aceita a TELA de decisao nova dentro da app Render. Se nao, o caminho do agente volta ao AgentPack, ou a tool exige approvedByHuman e responde APPROVAL_REQUIRED.
Por que: A regra sua e que cada app guarda so os proprios recursos, e hoje qualquer usuario de qualquer empresa escreve no catalogo global (alcance platform). Manter global leva um vazamento multiempresa para a app nova. Some e demais: as bibliotecas globais sao o espelho de onde os projetos herdam.
O que custa: Mudanca de dado, indice, consulta e politica: 3 indices parciais reescritos, visibleProjectsWhere/activeOwnerWhere por organizacao, GlobalWriteReach passando de platform para org, e a assinatura de readLibrary/writeLibrary recebendo a organizacao ativa (35 chamadores).
Por que: E a unica forma de implementar a sua regra — contrato encerrado suspende as chaves da empresa, recontrato reativa as MESMAS chaves, saida de membro revoga so as pessoais — num app que controle as chaves. A suspensao ja esta implementada e testada no LB (LB-ORG-SUSP-01) e pode ser copiada de la.
O que custa: Cliente OIDC proprio 'render', claim apps[render], e um CONTA_PROVISIONING_SECRET novo por app (e o que identifica o app.contract.cancelled desta app). Acao sua fora do painel.
Por que: No AgentPack, AgentKey.createdBy tem onDelete SetNull e authenticateAgentKey nao consulta o estado do criador: desativar o criador nao derruba a chave admin. E a semantica correta para uma chave que e da empresa e nao da pessoa.
O que custa: Se preferir que desativar o criador DERRUBE a chave admin, e checagem nova — authenticateAgentKey passa a consultar o estado do criador — e muda o contrato da D4.
Por que: Renomear quebra 7 skills built-in, a skill agentpack-task-execution, docs geradas, prompts e configs de agente ja gravados. O prefixo e de wire: o codigo dos handlers nao o ve (defineTool grava render_screen_list e o registro prefixa com BUILTIN_TOOL_PREFIX). A app Render mantem o prefixo no gateway proprio.
Custo/ressalva: Nenhum. A diferenca e so de rotulo de API.
Por que: loadProxiedCatalog descarta nome que colide com built-in: enquanto o registro do AgentPack ainda tiver RENDER_TOOLS, a ponte nao publica nada. E mecanismo de virada, nao de convivencia. Com o prefixo, as tools chegam ao agente com exatamente os nomes de hoje.
Custo/ressalva: Tres ressalvas aceitas: tool proxied recebe escopo write e nao render:write; a identidade do agente nao atravessa (o Render ve a chave da configuracao do MCP, nao a do agente); toda chamada proxied vira linha de auditoria como escrita. Antes de cadastrar, o McpServer precisa de organizationId (achado C4).
Por que: Skills sao recurso do AgentPack e o gate npm run check:skills valida as tools citadas contra o catalogo — que, com a ponte ativa, continua publicando agentpack_render_*. A app nova publica os seus docs/mcp/tools.md e llms-full.txt.
Custo/ressalva: Se a ponte for desativada e o registro do Render sair do AgentPack, as 7 skills passam a citar tools inexistentes e o check:skills quebra: nesse momento precisam ser reescritas ou aposentadas.
Por que: Segue o padrao dos vizinhos (agentpack-backend-ws / agentpack-frontend-ws / agentpack-v0 / agentpack-v0-api), os nomes de container sao globais no painel e nao colidem com o sandbox sb-render, e o sufixo v0 deixa o dominio curto para quando a versao estavel sair.
Custo/ressalva: Fora do workspace_nommand nao ha ganho e quebra o pregao dos bancos de producao.
Por que: Hoje nao existe em producao e a captura esta provavelmente quebrada desde 2026-09-29 (o shot grava sessionStorage agentpack:auth-token, que o frontend nao le mais desde 7ac8e39, e /render/preview/** esta atras do RequireAuth: o Chromium cai no SSO). Ligar entrega as duas tools de screenshot que hoje devolvem so a URL.
Custo/ressalva: 1 GB e um servico a mais. Deixar desligado e aceitavel e mais barato.
Por que: Mesmo preset de eslint e tsconfig do AgentPack — tres arquivos do Render estao no teto do lint, mudar o preset estoura o gate — e mesmo check-lock no prebuild.
Custo/ressalva: A v1.13.7 difere num componente de teclado; subir depois e bump de uma linha. A main do nomad-ui tem 1 arquivo e qualquer spec sem tag instala nada.
Por que: Banco separado e o que torna possivel matar o Render no AgentPack com uma migration de drop sem tocar em mais nada. O padrao do Postgres e max_connections 100 e o pool do Prisma vence o que vier na URL.
Custo/ressalva: Redis opcional: o Render so usa os contadores do rate limit e sem REDIS_URL o plugin conta por instancia.
Por que: Os 9 servicos do workspace_nommand estao com autoDeploy true, mas o historico mostra deploy manual (o backend do AgentPack teve 1 deploy entre 10-03 e 10-11 com 18 commits na main). Merge na main nao deve publicar nada sem um trigger explicito seu — que e exatamente o que voce pediu.
Custo/ressalva: Nenhum. E o comportamento que voce pediu.
Por que: As escritas do Render sao transacoes SERIALIZABLE de REST e MCP e um agente escreve a qualquer hora; sem congelar, quem escrever as 3h da manha perde a tela. Congelar e curto e declarado.
Custo/ressalva: O script e so-insert contra banco novo: o rollback e descartar o banco novo (e o volume) e reabrir a escrita no AgentPack.
Por que: As rotas legadas sao o que o frontend atual usa (3 modais, o guarda de rota) e sao o caminho de heranca global -> projeto; deixar de fora quebra a autoria. O que nao pode e continuar como catalogo de plataforma de todas as empresas.
Custo/ressalva: Depende da D3 ser respondida.
Por que: E correcao de credencial e de superficie de ataque, nao feature: sem ela as duas tools de screenshot nao funcionam em lugar nenhum, porque o frontend nao le mais a chave que o shot grava. E a pagina de preview executa o motor do Render: com sessionStorage, qualquer XSS le o token.
Custo/ressalva: Um gancho no cliente HTTP (getToken), a chave de storage certa no shot, e o RequireAuth do preview redesenhado. Vem no pacote P12.
Por que: O bug ja esta em PRODUCAO para todo usuario do AgentPack: Minha Conta, Gerenciar na Conta, o aviso de laco de SSO e o fallback da barra apontam para um sandbox morto. A app nova ja nasce com o build arg certo (RENDER_CONTA_URL) desde o primeiro deploy.
Custo/ressalva: Escrita em producao, que os agentes tem proibida. Precisa do seu go.
Cada pacote e do tamanho de um agente. Os dois primeiros sao no AgentPack (preparo) e nao dependem de nada — sao o que evita derrubar o /mcp no dia da remocao.
| # | Pacote | Onde | Depende de | Estado |
|---|---|---|---|---|
| P-1 | Preparo do AgentPack: mover toolError | AgentPack | — | nao feito derruba o /mcp inteiro se a pasta Render for apagada antes disso |
| P-2 | organizationId em McpServer + normalizacao do prefixo upstream | AgentPack | — | nao feito sem isso a ponte publica agentpack_render_agentpack_render_* |
| P0 | Nucleo do backend da app Render | Render | — | nao feito esqueleto Fastify, config, Prisma, erros, plugins, health, Dockerfiles, gates |
| P1 | Banco do Render: schema, migration e espelhos da Conta | Render | P0 | nao feito TRAVA D1 |
| P2 | Contratos do Render (zod, JSON Schema, typegen, seguranca) | Render | P0, P1 | nao feito |
| P3 | Identidade: OIDC render, suspensao por contrato, chaves apk_*, token de preview | Render | P0, P1 | nao feito TRAVA D4 + D17 |
| P4 | Dominio do Render no backend (services e lib) | Render | P2, P3 | nao feito |
| P4b | Escopo de empresa do catalogo | Render | P3, P4 | nao feito TRAVA D3 |
| P5 | Rotas REST, schemas zod e serializers do Render | Render | P4b | nao feito 47 rotas |
| P6 | Tools MCP do Render e gateway /mcp proprio | Render | P5 | nao feito 59 tools |
| P7 | Portao de upgrade, aprovacoes e sincronia de projetos | Render | P6 | nao feito TRAVA D2 |
| P8 | Casca do frontend: Vite, Tailwind, @nomad/ui, TopBar Nomad, shell, nginx | Render | P0, P6 | nao feito aqui o @nomad/ui v1.13.5 entra fixado |
| P9 | Motor do Render no frontend (engine, primitivas, canvas, contrato gerado) | Render | P8, P2 | nao feito |
| P10 | Camada de dados e editor de tela do Render no frontend | Render | P6, P8 | nao feito |
| P11 | Telas do Render: raiz, Studio, compartilhados, telas de projeto, previews e rotas | Render | P9, P10 | nao feito |
| P12 | shot/ como servico da app + caminho de credencial do preview | Render | P11, P3 | nao feito cookie httpOnly, nao sessionStorage |
| P13 | Testes do Render migrados, cobertura, docs e gates | Render | P5, P6, P9, P10, P11 | nao feito |
| P14 | Script de migracao dos dados de producao e runbook de corte | Render | P13, P7 | nao feito so depois das travas |
O que fazer em cada etapa, quem faz e por que nessa ordem. O passo 3 e o unico que so voce pode executar.
Voce responde as 5 travas (D1, D2, D3, D4, D17) e os agentes comecam a escrever codigo no sandbox 'render' (20 GB), em worktrees, commitando no PedroPaduelo/render.
Por que nesta ordem: E o pedido principal e o que nao existe. Hoje ha desenho, nao aplicacao. O repo ja e privado e o sandbox ja foi criado — falta o codigo.
Quem faz: agentes em worktrees
A branch fix/mcp-proxy-sessoes (9 commits, head 1a67c15) esta so no worktree local. Antes do push, os 5 bloqueios da rodada 3 precisam cair.
Por que nesta ordem: Ha um defeito provado de ciclo de vida (stream do SSE que morre) e uma regressao de seguranca multiempresa introduzida pelo proprio trabalho (B1). Mergir agora publicaria pior do que o que existe.
Quem faz: agentes, com o seu aval para push e merge
Nenhum passo publica nada sozinho: autoDeploy desligado nos servicos novos. A publicacao e deployments_trigger, uma decisao sua.
Por que nesta ordem: Voce pediu: deixa pronto, mergia para a main, e quando tiver tudo pronto me fala para a gente dar ou nao o trigger no deploy. Esta e a parte que so voce faz.
Quem faz: voce, com o runbook do desenho em maos
As envs vao com segredo via env_vars_create com isSecret. Nenhum valor de segredo aparece neste relatorio.
| Servico | Porta | Memoria | Volume | Dominio |
|---|---|---|---|---|
| render-backend-ws | 4000 | 1024 MB | render-prod-data -> /data | render-v0-api.mp.serendiped.com |
| render-frontend-ws | 8080 | 256 MB | - | render-v0.mp.serendiped.com |
| render-shot-ws | 4500 | 1024 MB | - | nenhum (opcional, por ultimo) |
Postgres proprio em databases_prod, max_connections acima de 1000, DB_CONNECTION_LIMIT 1000. Nenhum banco foi criado.
O corte. Remover RENDER_TOOLS do registro do AgentPack, cadastrar o MCP https://render-v0-api.mp.serendiped.com/mcp com toolPrefix agentpack_render, e conferir os 59 nomes agentpack_render_* em tools/list.