IRAI · Intraday Risk Appetite Index

Migração de charts para lightweight-charts & plano de continuidade

Os 5 gráficos da página de detalhe migraram de Recharts para TradingView lightweight-charts v5, reconstruídos por engenharia reversa do bundle de produção. Este documento registra a entrega e reconcilia o backlog de correções — revisado por fable-reasoner e codex, que corrigiram três status otimistas demais.

752419 kB
Bundle · −44%
59130
Módulos
5 / 5
Charts migrados
7 / 9
Tarefas
◆ O fato mais acionável

Hoje o localhost mostra V1 e a produção mostra V2 sob o mesmo rótulo “DINÂMICO (KALMAN)”: o polling primário (App.jsx:645) pede version=both, que o engine trata como V1 estático, enquanto o firebase_sync pede v2.

O painel de pesos Kalman recém-migrado exibe pesos estáticos no local. Resolver a Fase 2 não é limpeza — é convergir o local com o que a produção já entrega.

Parte 1 — O que foi entregue

Cinco charts reconstruídos, sem perder fidelidade

A fonte da produção foi perdida — só existe o bundle minificado. Cada componente foi extraído por engenharia reversa (displayNameforwardRef → corpo) numa migração strangler-fig: Recharts e lightweight-charts coexistiram até o último chart sair, com build, lint, deploy e revisão do Codex a cada etapa.

#ChartComponenteCommit
3Pair-spread z-score (piloto)TVPairwiseZScoreChartb47e3b1
4Probabilidade P(↑) dinâmicaTVProbabilityChart87d7fd9
5Divergência-preço z-scoreTVPriceDivergeZScoreChart1f43499
6Pesos dinâmicos (Kalman)TVKalmanWeightsChart552f64f
7Movimento do índice (NWE)TVNweChart9cc6066 · 2be2ecf

Decisões de projeto

Parte 2 — O plano anterior ainda é pertinente?

Sim — e com urgência maior do que estava escrito

A migração é ortogonal ao backlog: mexe na apresentação e não resolve nenhum P0 de sinal. As duas revisões independentes rebaixaram três status que eu havia marcado com otimismo — as Fases 3 e 4 são bugs vivos hoje, não “a verificar”. Status conferidos contra o código nesta data:

FaseTemaStatusEvidência
1Schema divergence_config Parcial Migração idempotente existe, mas init_db() não a chama e o loader mantém except Exception: rows=[] — “0 models” segue silencioso em instalação limpa
2Contrato version=both Pendente Divergência V1/V2 entre ambientes (ver callout) — impacto maior que “limpeza de contrato”
3Ghost bars / pré-mercado P0 vivo Só a detecção de ghost foi corrigida; win_return=0 nunca é restaurado. No v2 o retorno falso alimenta o Kalman por ~180 barras M5 antes da abertura B3
4Persistência Kalman monotônica Corrupção viva INSERT OR REPLACE sem guard de timestamp; irai_current itera datas antigas em v2 e sobrescreve o estado live
5NWE causal (backend) Pendente get_center do overview soma sobre range(n) → lookahead de 1 barra no slope dos cards
6API não-bloqueante Pendente Sem single-flight nem threadpool em main.py
7Contrato Firebase completo Pendente history_closes nunca chega em produção; falta is_b3. Mas accuracy viaja em summaries[target] → B1 não depende desta fase
8.1Acurácia no detalhe Fix trivial seriesInfo.accuracy é lido mas nunca setado → sempre fallback 80. summary.accuracy já está nos dois payloads
8.2Corridas de request Pendente fetchSeries sem AbortController/sequence-id
10Modularização App.jsx Parcial 5 charts extraídos; App.jsx ainda ~1190 linhas (gauge, computeNWE, cliente de dados inline)

Duas dependências novas criadas pela migração: os sinais inertes do TVNweChart (markers pair/z, GEX) precisam do backend emitir eventos discretos por barra (Fases 2/7); e a paridade do chart em produção depende da Fase 7 (contrato Firebase).

Parte 3 — Ordem de execução recomendada

Corrigir o sinal, depois polir o visual

A ordem original (fechar o frontend antes do quantitativo) foi rejeitada por ambas as revisões: adiar a correção deixa a corrupção de estado Kalman ativa em produção, e trocar a UI para v2 (B2) sem antes corrigir o pré-mercado expõe o caminho bugado que o version=both hoje esconde ao cair no V1.

1
Cleanup Recharts ≈5 min #9
Remover recharts do package.json + build final. Varrer código morto — sem tocar o flatten weight_${…} (o chart Kalman consome).
2
Persistência Kalman monotônica urgente Fase 4
Corrupção viva em produção. Guard de timestamp no save_kalman_state + persist_state=False para replay histórico. Independente de tudo.
3
Acurácia no detalhe trivial B1 · Fase 8.1
Propagar summary.accuracy para seriesInfo nos dois ramos de fetchSeries. Não depende da Fase 7.
4
Pré-mercado + trocar UI para V2 Fase 3 + B2
Restaurar win_return=0 no pré-mercado antes de mudar para version=v2. Só então o local converge com a produção.
5
Contrato Firebase B3 · Fase 7
Propagar history_closes + is_b3 + schema_version. Paridade NWE/eixo local vs. produção; pré-req do TVNweChart hospedado.
6
NWE causal no backend Fase 5
Limitar o kernel a j ≤ i e ao lookback de 95; idealmente calcular o NWE no backend. Vem antes das melhorias visuais.
7
Melhorias da migração Trilha C
Testes primeiro (Vitest: computeNWE causal + paridade %-vs-preço) → validação visual do chart de movimento → touch/mobile (canvas ≠ SVG) → eixo BRT via tickMarkFormatter → sync de crosshair → modularizar App.jsx.
8
API não-bloqueante Fase 6
Single-flight por (target,date,version), trabalho síncrono para threadpool, invalidação seletiva de cache. Isolada, pode ficar por último.
9
Investigação de fonte GEX A1 · #8
Não há fonte de gamma/opções no pipeline (coletor só puxa OHLCV M5). Definir se/como ingerir; até lá o scaffolding fica inerte por design.

Regra transversal (workflow do projeto): toda mudança de sinal/contrato (Fases 2–5, B1, B2) entra com regressão permanente antes da correção. Hoje tests/ só cobre z-score/pair — mínimo novo: test_engine_premarket, test_engine_kalman_state, test_api_contract, test_nwe_causality.

Riscos