← Aceite MVP V1 — evidências em vídeo

M5 — Caderno de medições do Spark 02 (2026-09)

Caderno de evidências do M5 (M5-model-fabric.md). A decisão A/B/C foi reaberta com dados: este arquivo registra, cru e antes de qualquer análise, todo output de medição (comando + saída + data + host). A análise/matriz de decisão vive na Fase 3; a formalização, no task-pack e no architecture-target.

Protocolo: (1) nenhuma medição entra aqui sem o comando exato que a produziu; (2) nada é resumido antes de o output bruto estar registrado; (3) cada medição lista runner — agente-ssh (read-only, sem privilégio) ou runbook-humano (exige doas interativa no NeoTek, o agente nunca automatiza senha).

Contexto da decisão (2026-09-03)

A política de fato no catálogo (~/dev/small-router/.ai-factory/models/*.yaml) já escolheu B (segundo modelo local: deepseek-v4-flash-vllm warm no spark-02) e mantém gpt-oss-120b/gpt-oss-20b como experimental no mesmo nó. O M5 reabre A/B/C com números:

multi-node, conforme decisão do dono).

Contra os 6 critérios do task-pack: latência, confiabilidade, custo, privacidade, utilidade para agentic coding, facilidade operacional.

Riscos pré-registrados

sbatch sem contato com o controller. A Fase 1 existe para detectar isso antes de medir.

coordenado falhavam com CUDA error: unspecified launch failure. Se T1.1 mostrar isso, registrar e parar (bloqueio explícito do plano).

Do NeoTek ao enverge, a identidade zero é alcançada via doas -u zero (runbook) — exceto o que passa pelo router :8080 (loopback, pcms lê direto).

(fallback=true) e queima custo sem erro — conferir logs do router ao interpretar qualquer latência "local".

Comandos aprovados

Fase 1 — Diagnóstico (read-only)

#RunnerComandoO que estabelece
F1.1agente-sshssh -J neotek.wg user@enverge.dev "hostname && uptime"workstation → spark01 alcançável
F1.2agente-sshssh -J neotek.wg user@enverge.dev sinfo && squeueSlurm vivo; estado dos nós
F1.3agente-sshssh -J neotek.wg user@enverge.dev "ssh spark02 hostname && ssh spark02 squeue" (quando aplicável)spark02 alcançável do spark01
F1.4agente-sshssh neotek.wg "curl -s http://127.0.0.1:8080/v1/models"catálogo real do router NeoTek; deepseek-v4-flash-vllm presente?
F1.5agente-sshssh neotek.wg "curl -s -X POST http://127.0.0.1:8080/v1/chat/completions -H 'Content-Type: application/json' -H 'Authorization: Bearer <key do router se exigido>' -d '{\"model\":\"deepseek-v4-flash-vllm\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}],\"max_tokens\":8}'"warm spark02 responde? (pré-condição do M5)
F1.6agente-sshssh -J neotek.wg user@enverge.dev "nvidia-smi --query-gpu=name,memory.total,memory.used,temperature.gpu,power.draw --format=csv" e o mesmo em ssh spark02VRAM total/livre por nó (T1.2)
F1.7runbook-humanoscripts/operator/enverge-gpu-diagnose.sh (repo dev-machine)só se F1.6 mostrar anomalia; doas no NeoTek

Fase 2 — Medições núcleo

#RunnerComandoProduz
F2.1 (T2.A)agente-sshssh neotek.wg "BENCH_STREAMS='1 4 8 16 32' sh -s" < scripts/operator/enverge-model-bench.sh deepseek-v4-flash-vllm (repo dev-machine)TTFT + tok/s × concorrência do warm spark02 (128 tokens, ignore_eos, comparável ao histórico vllm-dgx-spark-mxfp4.md)
F2.2 (T2.A)agente-sshdurante F2.1: ssh -J neotek.wg user@enverge.dev "nvidia-smi --query-gpu=memory.used --format=csv -l 5" (spark02)VRAM sob carga (antes/durante/depois)
F2.3 (T2.B)agente-sshssh neotek.wg "BENCH_STREAMS='1 4 8 16 32' sh -s" < scripts/operator/enverge-model-bench.sh qwen3-coder-30b-a3b-instructbaseline spark01, comparável linha a linha com F2.1
F2.4 (T2.C-custo)agente-localpricing dos YAMLs (~/dev/small-router/.ai-factory/models/) + ssh neotek.wg "curl -s http://127.0.0.1:8081/v1/sessions" (e /admin/metrics do small-pine)USD/Mtok real por modelo serverless + custo por sessão
F2.5 (T2.C-interconnect)agente-sshssh -J neotek.wg user@enverge.dev "ping -c 20 192.168.100.11"; iperf3 spark01↔spark02 se instalado (sem instalar nada)latência/bandwidth do rail RoCE
F2.6 (T2.C-interconnect, fallback)runbook-humanoscripts/operator/enverge-fabric-smoke.shNCCL 2-rank coordenado spark01+spark02 — prova de viabilidade do C (doas)
F2.7 (opcional)runbook-humanoscripts/operator/enverge-node-concurrency-smoke.sh both2 modelos simultâneos (um por nó) — discrimina envelope A vs B (doas)

Regras da Fase 2: T2.A e T2.B em paralelo só se ambas passarem pelo NeoTek sem contenção de GPU (cada nó tem 1 GPU; jobs do bench são por nó) — caso contrário sequencial, T2.A primeiro (é a decisão em teste). T2.C não toca GPU: sempre paralela.

RESULTADOS — F2.1/F2.3 executados (2026-09-05 05:59Z e 06:13Z) — Fase 2 completa

Bench executado sequencial (T2.A → T2.B) via router NeoTek :8080, 128 tokens ignore_eos, formato comparável ao histórico vllm-dgx-spark-mxfp4.md. Logs completos: /tmp/t2a-bench-spark02.log, /tmp/t2b-bench-spark01.log. Jobs Slurm 30 (tp=2, spark01+02) e 31 (tp=1, spark01). Cold start: deepseek ~370 s, qwen ~390 s (ambos ≤8 min, F1.5 folgado). F2.2 (VRAM sob carga) e F2.4+ (custo/interconnect) não executados — o dono pediu o bench direto; restam como complemento opcional.

streamsdeepseek-v4-flash tp=2 (spark01+02) aggtok/s/streamqwen3-coder-30b tp=1 (spark01) aggtok/s/stream
115.4015.4021.9621.96
429.6710.8883.9821.03
827.147.53170.1221.66
1631.235.15320.1920.41
3230.103.12426.4313.60

TTFT: 0.44 s cravado em todas as linhas, nos dois modelos (prefill não degrada com concorrência nesta faixa). 32/32 requisições ok no pior caso, zero perdas.

Catálogo do dashboard (throughput.tsv) — 2026-09-05: o --record do qwen está gravado e confirmado ao vivo (5 linhas, grade 1/4/8/16/32: 25.09 → 507.26 tok/s agg, TTFT 0.42 s). O do deepseek foi medido às 18:53Z (2ª rodada do dia, job Slurm 39, tp=2) — mesmíssimos números da madrugada, e o único dado novo do dia:

streamsdeepseek tp=2 agg (18:53Z)madrugadaTTFTok
115.0215.400.431/1
430.2629.670.434/4
829.9727.140.438/8
1631.1731.230.4316/16
3229.0330.100.4325/32

Reprodutibilidade total (ceiling ~30 tok/s agg em ambas as rodadas, TTFT 0.43–0.44 s). Diferença: 7 requisições perdidas em 32 streams nesta rodada (25/32; a madrugada teve 32/32) — variação sob concorrência máxima, não muda a leitura. Tempo de subida (dono pediu registrar): o próprio bench mediu "ready after ~380s" (pedido do router → primeiro 200), consistente com o cold de ~370 s da madrugada; contado da submissão do job Slurm (SubmitTime → ready) são ~492 s, sendo ~25 s de fila de alocação. Linhas prontas para append no /var/db/small-pine/throughput.tsv (comando doas no checklist do dev-machine, operador-e10-record-deepseek-e-senhas-stale.md) — é o último passo do FINDING-4/E10.

Leituras:

  1. O gargalo do tp=2 é o all-reduce por camada, não o rail RoCE — o transporte medido

(44.5 Gb/s, 0.935 ms, F2.5 histórico) é saudável, mas o decode do tp=2 trava em ~30 tok/s agregados; o tp=1 escala linear (21 tok/s/stream cravados até 16 streams).

  1. Para serving, um nó inteiro (tp=1) serve 14× mais que o mesmo hardware dividido em

tensor-parallel — o par de nós só compensa para modelos que não cabem num nó.

  1. Uso interativo (1 dev): qwen tp=1 (22 tok/s) > deepseek tp=2 (15 tok/s), e libera a

spark02 para o segundo modelo.

  1. Job 30 provou que o perfil :distributed submete e serve (resposta V7.2 da matriz

de validação do upgrade 0.28: SIM) — a inviabilidade do C é de desempenho/operacional, não de funcionalidade.

  1. Impacto na política de promoção: a leitura "warm teoricamente = spark01" confirma-se

e o critério de latência agora tem número: warm single-node vence serverless em TTFT (0.44 s vs. cold start de minutos) e não tem custo GPU. O TBD de custo mensal (serverless vs nó ocioso a $0) permanece — F2.4 não executado.

Fase 3 — Análise (sem cluster)

Matriz A/B/C pontuada nos 6 critérios + recomendação → gate humano (dono aprova).

Log de evidências

Fase 1 — Diagnóstico

F1.1 — rota workstation → spark01 (2026-09-03 20:50 UTC)

$ ssh -J neotek.wg user@enverge.dev "hostname && uptime"
spark01
 20:50:03 up 24 days,  9:39, 27 users,  load average: 0.43, 0.32, 0.77

OK: jump via neotek.wg autentica, spark01 up 24 dias, carga baixa.

Revalidação (2026-09-03 21:08 UTC): máquina ON (up 24d 9:57, load 0.46), spark02 alcançável do spark01 — o que está failed desde 2026-08-21 é o daemon slurmctld (exit 1, unit disabled), não a máquina. Distinção explícita para o relatório.

F1.4 — catálogo do router NeoTek :8080 (2026-09-03 20:50 UTC)

$ ssh neotek.wg "curl -s -m 10 http://127.0.0.1:8080/v1/models"
{"object":"list","data":[
  {"id":"deepseek-v4-flash-vllm","object":"model","owned_by":"small-infer"},
  {"id":"gpt-oss-120b",...},{"id":"gpt-oss-20b",...},
  {"id":"multilingual-e5-small",...},{"id":"nemotron-3-super-120b-a12b-nvfp4",...},
  {"id":"qwen3-14b-fp4",...},{"id":"qwen3-235b-a22b-fp4",...},{"id":"qwen3-8b-fp4",...},
  {"id":"qwen3-coder-30b-a3b-instruct",...},{"id":"qwen3-coder-30b-a3b-instruct-b",...},
  {"id":"qwen3-coder-next",...},{"id":"qwen3.5-122b-a10b-gptq-int4",...},
  {"id":"qwen3.6-35b-a3b-nvfp4",...},{"id":"qwen3.8-27b-fp8",...}]}

OK: 14 ids; deepseek-v4-flash-vllm presente (listado ≠ servindo — ver F1.5).

F1.5 — chat probe deepseek-v4-flash-vllm (2026-09-03 20:51 UTC) — STATUS: WARMING

$ ssh neotek.wg "curl -s -m 60 -X POST http://127.0.0.1:8080/v1/chat/completions \
    -d '{\"model\":\"deepseek-v4-flash-vllm\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}],\"max_tokens\":8}'"
{"error":{"type":"router_error","message":"deepseek-v4-flash-vllm is still starting (0s elapsed).
 The Slurm job is submitted and loading; a cold start takes roughly 8 minutes on two nodes.
 Retry then, or watch it with: enverge-model-cli.sh jobs",
 "data":{"status":503,"small-pine.service.warm-host/warming-up":true,
         "model":"deepseek-v4-flash-vllm","elapsed-ms":0}}}

Leitura: o warm-host submeteu o job e está carregando (cold start ~8 min em dois nós — o serving do deepseek-v4-flash-vllm aparenta ser multi-node; confirmar depois do warm). Contraste com 2026-08-21 (404/sem contato): hoje o ciclo de vida responde com 503+warming.

F1.2 — Slurm do login node (2026-09-03 20:51 UTC) — DEGRADADO (parcial)

$ ssh -J neotek.wg user@enverge.dev "sinfo; echo ---; squeue"
slurm_load_partitions: Unable to contact slurm controller (connect failure)
---
slurm_load_jobs error: Unable to contact slurm controller (connect failure)

Leitura: o cliente Slurm do login node não alcança o controller — mesmo sintoma de 2026-08-21 — mas o warm-host submeteu job (F1.5), ou seja, o caminho sbatch do router (por ssh, ADR-0003) funciona. Medir sinfo/squeue de outro ponto se necessário.

F1.6 — VRAM estático (2026-09-03 20:52 UTC)

$ nvidia-smi --query-gpu=name,memory.total,memory.used,temperature.gpu,power.draw --format=csv
spark01: NVIDIA GB10, [N/A], [N/A], 45, 11.98 W
spark02: NVIDIA GB10, [N/A], [N/A], 44, 12.23 W   (via ssh spark02)

Leitura: GPUs ociosas (~12 W, ~45 °C). memory.total N/A é particularidade do GB10 (memória unificada) — total/livre a coletar via nvidia-smi -q | grep -A2 Memory (F1.6b).

F1.6b — VRAM GB10 via nvidia-smi -q (2026-09-03 20:56 UTC) — N/A também no -q

FB Memory Usage: Total/Reserved/Used/Free = N/A em ambos os nós — o driver do GB10 não expõe VRAM via nvidia-smi. Substituto: free -g (memória unificada, F1.6c).

F1.6c — memória unificada GB10 (2026-09-03 20:56 UTC)

$ free -g | head -2   (spark01 e spark02 via ssh)
spark01: Mem: 116 total, 3 used, 108 free, 4 buff/cache, 112 available
spark02: Mem: 116 total, 3 used, 111 free, 1 buff/cache, 112 available

Leitura: 116 GB de memória unificada por nó, ~112 livres nos dois, GPU ociosa. Checkpoint 120B em NVFP4 (~60-70 GB) cabe em 1 nó; 2×120B warm simultâneos (A ou B) também cabem — a restrição real é compute/throughput, não capacidade.

Fase 2 — Medições (linhas não-GPU executadas em paralelo ao warm)

F2.4 — custo serverless (2026-09-03 20:57 UTC)

credencial — custo por sessão real fica para leitura com key (não bloqueia: pricing declarado cobre o eixo custo).

modeloinputcachedoutput
deepseek-v4-flash0.220.0070.66
deepseek-v4-pro1.320.0443.96
qwen3.8-max2.000.256.00
glm-5p2 / glm-5p31.400.14/0.264.40
glm-5p3-flash0.150.030.50
kimi-k2p7-code0.950.194.00
kimi-k33.000.3015.00
minimax-m30.300.061.20
muse-glimmer-30b0.350.041.50
nemotron-3-ultra-nvfp40.600.122.40
nemotron-lightning-3p5-30b0.050.010.20
own-fleet (warm/experimental)000

F2.5 — interconnect rail spark01→spark02 (ping; 2026-09-03 20:56 UTC)

$ ping -c 20 192.168.100.11   (de spark01)
20 transmitted, 20 received, 0% loss
rtt min/avg/max/mdev = 0.172/0.935/1.457/0.383 ms

iperf3 presente em ambos os nós → bandwidth test na sequência (F2.5b).

F2.5b — bandwidth rail spark01→spark02 (iperf3; 2026-09-03 21:00 UTC)

$ iperf3 -c 192.168.100.11 -t 5   (server no spark02)
[  5] 0.00-5.00 sec  25.9 GBytes  44.5 Gbits/sec  0  sender
[  5] 0.00-5.00 sec  25.9 GBytes  44.5 Gbits/sec     receiver

Leitura: 44.5 Gbits/sec, 0 retransmissões — rail RoCE saudável. Dado para qualificar C (serving distribuído): o transporte inter-nó existe e é rápido; o gargalo de C não é rede.

BLOQUEIO — Fase 2 (GPU) suspensa: slurmctld morto desde 2026-08-21

Descoberta da Fase 1 (2026-09-03 21:02 UTC) que ativa o bloqueio explícito do plano ("não medir sobre infra quebrada"):

$ ssh -J neotek.wg user@enverge.dev "systemctl status slurmctld"
× slurmctld.service - Slurm controller daemon
   Loaded: loaded (/usr/lib/systemd/system/slurmctld.service; disabled; preset: enabled)
   Active: failed (Result: exit-code) since Fri 2026-08-21 21:02:40 UTC; 1 week 5 days ago
   Duration: 18h 52min 28.427s

$ ps aux | grep -E 'slurmctld|slurmd'    (spark01)
user 3978408 bash /var/db/slurm/slurmd/job00062/slurm_script   (03:09 de hoje)
root 4133614 /usr/sbin/slurmd                                   (Sep02)

Estado observado:

  1. slurmctld failed + disabled no head (spark01) desde 2026-08-21 21:02:40 UTC — a

mesma data do incidente de serving degradado registrado na memória do projeto.

  1. Processos vLLM órfãos presos nos dois nós, sem pesos carregados (EngineCore ~2.2-2.4 GB

RSS, GPU a 12 W = ociosa, nenhuma porta de inferência respondendo): - spark01: gpt-oss-120b (srun, job00062, desde 03:09 UTC de hoje); - spark02: qwen3-coder-30b-a3b-instruct (srun, desde 03:47 UTC de hoje).

  1. O router :8080 responde chat para deepseek-v4-flash-vllm com 503 warming-up e

elapsed-ms: 0 em todo poll (nunca progride): o ciclo warm-host acredita que um job está carregando, mas sem controller não há como o job viver — o estado está wedgeado.

  1. Endpoints /prewarm e /backends retornam "not found" no :8080 — a superfície do

small-pine consolidado difere da do small-infer que o enverge-model-bench.sh documenta (risco para a Fase 2 quando ela for executada: adaptar o script ou medir por outro caminho).

  1. Hardware 100% saudável (2×116 GB livres, rail 44.5 Gb/s, GPUs frias) — o problema é

puramente o daemon do Slurm + processo órfãos.

Runbook humano (execução privilegiada no head — o agente não roda):

# 1. Por que o controller morreu em 2026-08-21?
ssh -J neotek.wg user@enverge.dev \
  "journalctl -u slurmctld --since '2026-08-21 20:00' -n 50 --no-pager"
# 2. Reativar e subir o controller
ssh -J neotek.wg user@enverge.dev "sudo systemctl enable --now slurmctld"
# 3. Fila e nós saudáveis?
ssh -J neotek.wg user@enverge.dev "squeue; sinfo"
# 4. Cancelar os jobs presos (00062 e afins) — se sobrar processo órfão nos nós:
ssh -J neotek.wg user@enverge.dev \
  "ssh spark02 'pkill -f vllm.entrypoints.openai.api_server'"
# (o mesmo pkill no spark01, se necessário)
# 5. Revalidar o warm: um chat request no :8080 dispara o ciclo warm-host.

Regra de retomada: com squeue respondendo e GPUs limpas, reexecutar F1.5 (chat probe deve passar de 503→200 em ≤8 min) e então liberar a Fase 2 (T2.A/T2.B). T2.C já está completa (custo F2.4 + interconnect F2.5/F2.5b).

Adendo ao bloqueio (2026-09-03 21:20 UTC) — wedge é geral e atinge serverless

Fireworks) no :8080mesmo 503 warming elapsed-ms:0. O wedge intercepta todo o chat do router own-fleet, inclusive modelos que não deveriam tocar Slurm. Reiniciar apenas o slurmctld pode não limpar o estado do router — se após o fix o 503 persistir, reiniciar o serviço do small-pine no NeoTek.

/backends timeout (HTTP 000); /queue 404; POST /prewarm/:model existe no código (gateada admin-token/:schedule-model) mas responde "not found" no deploy atual — o build no NeoTek é mais velho que o core.clj do small-pine (que monta /queue e prewarm-routes).

era allow_anonymous acabou (conforme auditoria MR-020B do small-router).

respondendo no host loopback é a jail small-pine (vnet=new, 17 jails persist no NeoTek; o Uberjar roda dentro dela, invisível ao ps do host). O rc small_infer do host é o serviço legado do small-infer (de fato não roda). Reiniciar o router wedged = doas jexec small-pine service <svc> restart dentro da jail (runbook). Jails kafka/qdrant estão no jail_list do rc.conf mas não estão rodando.

Adendo ao bloqueio (2026-09-05) — bloqueio ENCERRADO: controller sempre viveu em host dedicado; diagnóstico de 09-03 errou o host

A validação completa de infra de 2026-09-05 (dev-machine/docs/patches/2026-09-05-infra-verification.md, commit bc89e8be) observa um estado incompatível com este bloqueio:

  1. Inferência own-fleet ponta a ponta OK: POST /prewarm/qwen3-8b-fp4 submeteu job

Slurm real, backend ready em <1 min, completion HTTP 200 (usage {14,16,30}, vllm-0.26.0) — exatamente a Fase de revalidação (F1.5) que este runbook exigia para liberar a Fase 2.

  1. sinfo: nós inference idle, sem fila (squeue vazio) — sem jobs presos nem

processos órfãos relatados.

  1. POST /prewarm/:model respondeu no :8080 — o ponto 4 do estado observado

("not found", build mais velho que o core.clj) está superado: o deploy do NeoTek foi atualizado entre 09-03 e 09-05.

Interpretação (CORRIGIDA em 2026-09-05, confirmação formal): o diagnóstico de 09-03 errou o host do controller. Verificado ao vivo (2026-09-05 ~04:30 UTC):

é artefato (controller nunca precisou rodar num nó de computação; só o slurmd, que está ativo desde Sep 02).

controller primário vive num host dedicado (SlurmctldHost[0] = slurm-trusted-controller(172.31.110.6)), não é acessível por SSH direto do spark01 (DNS/IP sem rota), e o RPC dele responde.

do ps; BootTime do trusted-controller = 2026-09-03 12:11 UTC — o reboot do controller dedicado explica a recuperação entre 09-03 e 09-05.

Consequências:

  1. Este BLOQUEIO está ENCERRADO — control plane UP + nós idle + completion real 200

(validação 09-05). Fase 2 (T2.A/T2.B) liberada, respeitando a regra de contenção de GPU (sequencial se necessário).

  1. O runbook original ("sudo systemctl enable --now slurmctld" no spark01) estava errado

— subiria um controller duplicado no nó errado. Nunca executado (por sorte).

  1. O wedge real de 09-03 (503 warming-up elapsed-ms:0 na jail small-pine) era estado do

router + possivelmente o reboot pendente do controller dedicado — não o unit do spark01.

  1. HASH_VAL divergente (Ours=0xf0ba47fa Slurmctld=0x790f590 no scontrol show config)

é esperado entre nó de computação e controller (configs distintos por papel).

Pendência separada da mesma validação: senhas salvas na estação estão stale (rotação 09-03/04); não afeta as medições GPU (autenticação do bench não passa pelo OWUI/Keycloak).

Reprodutibilidade

Re-run de F2.1 com BENCH_STREAMS='1': tolerância a declarar após a primeira medição (preencher: valor observado vs re-run, desvio %).

RESULTADOS — Upgrade vLLM 0.26→0.28 executado (2026-09-05 23:24Z/23:29Z): TTFT -95%, throughput igual

O upgrade planejado em docs/vllm/vllm-0.28-upgrade-plan.md foi executado até o fim (jobs Slurm 44–51, stack final no side-by-side ~/venvs/vllm-028). Bench comparável (128 tokens ignore_eos, streams 1/4/8/16/32, job 51 tp=2 spark01+02, job ainda no ar), 2 rodadas completas, log /tmp/bench-v028.log:

streams0.26 agg (baseline 09-05)0.28 agg r1 / r2TTFT 0.26TTFT 0.28 r1 / r2ok
115.02–15.4016.13 / 15.610.43–0.440.02 / 0.001/1
430.2630.16 / 29.740.43–0.440.02 / 0.004/4
829.9729.14 / 28.540.43–0.440.02 / 0.008/8
1631.1726.73 / 29.180.43–0.440.02 / 0.0016/16
3229.0329.45 / 30.960.43–0.440.02 / 0.0032/32

Leituras:

  1. TTFT caiu ~95% (0.43–0.44 s → 0.00–0.02 s) — o ganho real do 0.28 neste hardware

(scheduler novo + --enable-prefix-caching + flashinfer autotune). Todas as 77 requisições ok (zero perdas, incluindo 32/32 que no 0.26 chegou a 25/32).

  1. Throughput agregado equivalente (ceiling ~30 tok/s agg mantido) — confirma a leitura

de que o gargalo do tp=2 é o all-reduce por camada, não a versão do vLLM.

  1. Cadeia de compatibilidade GB10 (aarch64+cu130) resolvida em 3 elos — registrado para

futuros upgrades de pilha neste hardware: a. torch 2.13 crasha o import (malloc(): corrupted top size) — bug do malloc glibc no GB10; LD_PRELOAD=libjemalloc.so.2 resolve (jemalloc 5.3 via .deb arm64 extraído userland). b. torch 2.12.1 (pin alternativo) é ABI-incompatível com o shim vendored vllm/third_party/deep_gemm do 0.28 (Unsupported TypeMeta in ATen) — bridge de símbolos resolve o load, mas o drift de TypeMeta quebra em runtime. 0.27.1 tem o mesmo pin 2.13 (porta fechada). Conclusão: usar o pin nativo. c. DSv4 (config index_topk) exige DeepGEMM no 0.28 (Sparse Attention Indexer, caminhos fp8_fp4_* sem escape por env); o ramo SM100 exige ue8m0_cast (não desligar VLLM_USE_DEEP_GEMM_E8M0) e as scales do checkpoint DS4 já são F8_E8M0 — o caminho nativo passa limpo. Stack final validada: vllm 0.28.0 + torch 2.13.0+cu130 + LD_PRELOAD jemalloc + E8M0 default, idêntica nos 2 nós (~/venvs/vllm-028, $HOME é node-local).

  1. KV cache 0.28: 179.827 tokens (job 51), max_model_len 131072 mantido.
  2. Rollout para produção (router :8080): trocar PYTHON_BIN/RAY_BIN do venv no

sbatch do catálogo — rollback = reverter a var (side-by-side preservado). O warm deepseek-v4-flash-vllm da política B continua no 0.26 até o dono aprovar a troca.

DRAFT — política explícita + matriz A/B/C parcial (2026-09-03, pré-análise GPU)

Rascunho para revisão do dono. Células com TBD dependem de T2.A/T2.B (medições GPU, suspensas pelo slurmctld). A formalização na Fase 4 promove este draft a decisão.

Matriz A/B/C contra os 6 critérios do task-pack

CritérioA — réplica Qwen (spark02)B — segundo modelo local (deepseek warm, atual)C — serving distribuído
LatênciaT2.B medido: 22 tok/s stream × 1 dev, escala linear até 16 streams, TTFT 0.44 sT2.A medido: 15 tok/s stream (tp=2), TTFT 0.44 s, ceiling ~30 tok/s aggmedido (T2.A é o C): all-reduce por camada trava o decode em ~30 tok/s agg — hop de rede por token confirma a leitura qualitativa; rail saudável não salva o decode
ConfiabilidadeT2.B confirma: single-node = menos pontos de falha (1 job, 1 nó)acoplamento ao Slurm segue real (incidente 08-21→09-05)pior: depende de 2 nós + interconnect + torchrun coordenados (ADR-0010: spark02 standalone crashava)
Custo$0 GPU (capacidade ociosa hoje)$0 GPU$0 GPU, mas overhead de serving distribuído reduz tokens/s por nó
Privacidadeprivadaprivadaprivada
Utilidade agentic codingduplica coding (HA de qwen-coder); não diversifica capabilitiesdiversifica: reasoning/architecture local (deepseek), alivia serverless pagocapacita modelos > 116 GB (não é necessidade atual)
Facilidade operacionalmédia: 1 perfil novo, perfil já existe em princípiomédia: em vigor hojepior: multi-node vLLM via torchrun + rdzv (complexidade alta, pouco uso)

Leitura parcial (pré-GPU): C perde em operacional/confiabilidade para uma necessidade que não existe (nenhum checkpoint > 116 GB no portfólio). A decisão real é A vs B, e depende de: (1) latência/throughput do deepseek warm vs. qwen warm (T2.A/T2.B); (2) se a dor atual é *diversidade de capability* (favorece B) ou *concorrência/HA do coding* (favorece A).

Leitura PÓS-bench (2026-09-05) — dependência (1) resolvida: a latência não é mais conjectura — qwen tp=1 single-node domina o deepseek tp=2 em tok/s/stream (22 vs 15) e em throughput escalável (linear até 16 vs ceiling ~30 agg). C segue eliminado por desempenho/operacional (e o T2.A provou que funciona, só que lento). A decisão A vs B restante é estratégica: HA/diversidade de coding (A: segunda instância do coder liberando spark02) vs diversidade de capability (B: deepseek reasoning local). O dado novo que favorece A: o tp=2 acapara os DOIS nós para 30 tok/s — em B, o deepseek tp=2 impede qualquer segundo modelo simultâneo; um deepseek tp=1 serverless pago na falta de warm local pode sair mais barato que acaparar 2 GPUs. Formalização final segue na Fase 4 com F2.4 (custo real por sessão) pendente.

Draft da política (a formalizar na Fase 4)

sem regressão vs. categoria atual + caso de uso capability real (não é "porque está no catálogo") + hardware cabendo no orçamento de memória do nó sem derrubar warm existente.

eviction (mecanismo existente); desligamento permanente = status: on-demand no YAML quando a capability for coberta por alternativa de custo/latência equivalente.

custo mensal projetado do serverless < custo de oportunidade do nó (hoje $0) — TBD número após T2.A/T2.B; fallback silencioso (fallback=true) deve gerar audit visível, não queima invisível (MR-028 já atribui o burn).

YAML e capability não coberta; remoção quando ocioso no router por X dias (TBD).

Aderência catálogo ↔ draft (estado hoje)

(nenhuma medição registrada ainda; vLLM órfão de 03:09 sugere tentativa sem sucesso)