# Refactor Log

Este arquivo registra o que mudou a cada etapa do refactor incremental.

Nota:
- as entradas `000` a `010` foram escritas antes da consolidacao da estrutura atual do repositorio
- por isso, varias delas ainda referenciam caminhos antigos sem o prefixo `src/`
- a partir da entrada `011`, os caminhos refletem o layout atual da raiz + `src/`

## Como preencher

Para cada mudanca relevante, registrar:
- data
- objetivo
- arquivos alterados
- comportamento preservado
- comportamento alterado
- risco conhecido
- validacao executada
- proximo passo

## Entrada 000 - Baseline documental

- Data: 2026-03-27
- Objetivo: criar uma base de documentacao viva para acompanhar o refactor incremental
- Arquivos alterados:
  - `README.md`
  - `docs/README.md`
  - `docs/refactor-plan.md`
  - `docs/refactor-log.md`
  - `docs/api-overview.md`
- Comportamento preservado: nenhum codigo de execucao foi alterado
- Comportamento alterado: nenhum
- Risco conhecido: a documentacao precisa ser mantida junto das mudancas, senao perde valor
- Validacao executada: revisao manual do conteudo criado
- Proximo passo: iniciar Fase 1 com extracao dos adapters de pipeline, speech, bridge e export

## Entrada 001 - Fase 1 / adapters extraidos

- Data: 2026-03-27
- Objetivo: extrair boundaries de pipeline, speech, bridge e export sem mudar o comportamento publico da API
- Arquivos alterados:
  - `app/livekit/main.py`
  - `app/livekit/adapters/pipeline_adapter.py`
  - `app/livekit/adapters/speech_service.py`
  - `app/livekit/adapters/bridge_gateway.py`
  - `app/livekit/adapters/export_service.py`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - contrato do websocket do bridge
  - fluxo STT -> pipeline -> TTS
  - notificacao `DONE` para o bridge
  - exportacao final de sessao
- Comportamento alterado:
  - nenhum comportamento publico planejado
  - `app/livekit/main.py` passa a delegar responsabilidades para adapters
- Risco conhecido:
  - como a extracao preserva a logica inline, ainda existe acoplamento forte no runtime
  - faltam testes automatizados de regressao para interrupcao, idle nudge e finalizacao
- Validacao executada:
  - revisao manual do diff
  - validacao sintatica prevista apos a extracao
- Proximo passo:
  - reduzir `nonlocal` no runtime com um `CallRuntime` explicito
  - preparar o terreno para policies e scheduler unificados

## Entrada 002 - Fase 2 / runtime explicito

- Data: 2026-03-27
- Objetivo: encapsular o fluxo da chamada em um `CallRuntime` com `CallState` explicito, reduzindo estado implícito e `nonlocal` em `app/livekit/main.py`
- Arquivos alterados:
  - `app/livekit/main.py`
  - `app/livekit/runtime/state.py`
  - `app/livekit/runtime/call_runtime.py`
  - `docs/refactor-log.md`
  - `docs/api-overview.md`
- Comportamento preservado:
  - contrato do websocket do bridge
  - fluxo STT -> pipeline -> TTS
  - idle nudge, interrupcao e finalizacao continuam com a mesma logica operacional
  - exportacao e notificacao `DONE` continuam sendo disparadas pelo agent
- Comportamento alterado:
  - `app/livekit/main.py` passa a ser majoritariamente wiring do session e construcao do runtime
  - o estado mutavel da chamada fica concentrado em `CallState`
- Risco conhecido:
  - as regras ainda nao foram transformadas em policies puras; a logica segue acoplada ao runtime, apenas mais organizada
  - ainda faltam testes automatizados para cenarios concorrentes de fala, interrupcao e fechamento
- Validacao executada:
  - revisao manual do diff
  - `PYTHONDONTWRITEBYTECODE=1 python3 -m py_compile app/livekit/main.py app/livekit/adapters/bridge_gateway.py app/livekit/adapters/export_service.py app/livekit/adapters/pipeline_adapter.py app/livekit/adapters/speech_service.py app/livekit/runtime/state.py app/livekit/runtime/call_runtime.py`
- Proximo passo:
  - introduzir command/execution boundaries no runtime
  - preparar a migracao de interrupcao, idle e finalize para policies + scheduler

## Entrada 003 - Fase 3 / commands e executor

- Data: 2026-03-29
- Objetivo: separar efeitos colaterais do `CallRuntime` por meio de comandos tipados e um executor dedicado
- Arquivos alterados:
  - `app/livekit/main.py`
  - `app/livekit/runtime/commands.py`
  - `app/livekit/runtime/command_executor.py`
  - `app/livekit/runtime/call_runtime.py`
  - `docs/refactor-log.md`
  - `docs/api-overview.md`
- Comportamento preservado:
  - contrato do websocket do bridge
  - fluxo STT -> pipeline -> TTS
  - sequencia de idle nudge, interrupcao e finalizacao
  - integracao com LiveKit, pipeline e export sem troca de contrato
- Comportamento alterado:
  - `CallRuntime` deixa de chamar diretamente bridge/export/speech/pipeline para os principais side effects
  - side effects passam a trafegar por comandos (`commands.py`) executados por `RuntimeCommandExecutor`
- Risco conhecido:
  - ainda existe conhecimento de regras dentro de `CallRuntime`; a extracao atual isola efeitos, mas nao transforma as regras em policies puras
  - `agent._ready`, `agent._run_lock` e coordenacao de fila ainda pertencem ao runtime
- Validacao executada:
  - revisao manual do diff
  - validacao sintatica com `python3 -c 'from pathlib import Path; paths = [...]; [compile(Path(p).read_text(), p, "exec") for p in paths]'`
- Proximo passo:
  - extrair policies de interrupcao, idle e finalizacao
  - introduzir scheduler unico para timers e reduzir logica condicional no runtime

## Entrada 004 - Fase 4 / policies e scheduler

- Data: 2026-03-29
- Objetivo: mover regras de interrupcao, idle e finalize-once para policies dedicadas e centralizar timers em um scheduler unico
- Arquivos alterados:
  - `app/livekit/main.py`
  - `app/livekit/policies/interrupt_policy.py`
  - `app/livekit/policies/idle_policy.py`
  - `app/livekit/policies/finalization_policy.py`
  - `app/livekit/runtime/scheduler.py`
  - `app/livekit/runtime/state.py`
  - `app/livekit/runtime/call_runtime.py`
  - `docs/refactor-log.md`
  - `docs/api-overview.md`
- Comportamento preservado:
  - contrato do websocket do bridge
  - fluxo STT -> pipeline -> TTS
  - timers de idle nudge e idle close continuam ativos
  - finalizacao por `DONE`, `room_empty`, `shutdown_callback` e `no_user_response` continua existindo
- Comportamento alterado:
  - `InterruptPolicy` passa a decidir interrupcao por stage e filtro de backchannel
  - `IdlePolicy` passa a concentrar regras de nudge/close
  - `FinalizationPolicy` passa a concentrar regras de finalize-once e room-empty
  - `TimerScheduler` passa a concentrar arm/cancel/token dos timers
  - `CallState` deixa de carregar estado interno de timers
- Risco conhecido:
  - o `CallRuntime` ainda conhece a ordem operacional completa da chamada; as policies reduzem acoplamento, mas ainda nao existe reducer/event engine
  - `RuntimeConfig` ainda carrega campos hoje parcialmente sobrepostos pelas policies; isso pode ser simplificado em um corte futuro
- Validacao executada:
  - revisao manual do diff
  - validacao sintatica com `python3 -c 'from pathlib import Path; paths = [...]; [compile(Path(p).read_text(), p, "exec") for p in paths]'`
- Proximo passo:
  - avaliar se vale introduzir eventos/comandos mais declarativos no runtime ou parar aqui e estabilizar
  - se seguir, o proximo salto natural e um reducer/event engine ou a evolucao da integracao de IA (`llm_node` ou agente remoto)

## Entrada 005 - Estabilizacao / testes unitarios do runtime

- Data: 2026-03-29
- Objetivo: adicionar cobertura automatizada para os cenarios mais criticos do runtime sem depender de LiveKit real
- Arquivos alterados:
  - `tests/__init__.py`
  - `tests/livekit/__init__.py`
  - `tests/livekit/test_runtime.py`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - nenhum contrato publico da API foi alterado
  - nenhum fluxo de audio ou websocket foi modificado
- Comportamento alterado:
  - o repositorio passa a ter uma suite unitária para policies, scheduler, command executor e cenarios críticos do `CallRuntime`
- Risco conhecido:
  - os testes ainda usam doubles/fakes e nao substituem validacao integrada com LiveKit real
  - ainda faltam cenarios mais completos de timer real, callback de room e speech handle real
- Validacao executada:
  - `python3 -m unittest tests.livekit.test_runtime -v`
  - `python3 -m unittest discover -s tests -v`
- Proximo passo:
  - ampliar cobertura para speech handle real e integracao de callbacks com objetos LiveKit reais, se isso passar a ser area de regressao
  - ou encerrar a fase de estabilizacao e voltar a discutir a evolucao da camada de IA

## Entrada 006 - Backend remoto via websocket

- Data: 2026-03-29
- Objetivo: permitir trocar a pipeline local por um agent remoto via websocket, preservando o fluxo STT -> IA -> TTS e o runtime atual
- Arquivos alterados:
  - `app/livekit/main.py`
  - `app/livekit/adapters/agent_backend.py`
  - `app/livekit/adapters/backend_factory.py`
  - `app/livekit/adapters/pipeline_adapter.py`
  - `app/livekit/adapters/remote_agent_ws_adapter.py`
  - `app/livekit/runtime/command_executor.py`
  - `requirements.txt`
  - `tests/livekit/test_remote_agent_ws_adapter.py`
  - `docs/refactor-log.md`
  - `docs/api-overview.md`
- Comportamento preservado:
  - contrato do websocket do bridge
  - fluxo de audio com LiveKit e TTS no agent local
  - runtime de interrupcao, idle nudge e finalizacao
  - backend `langgraph` segue como default
- Comportamento alterado:
  - o backend da camada de IA passa a ser selecionavel por `AGENT_BACKEND`
  - quando `AGENT_BACKEND=remote_ws`, o agent envia cada turno transcrito para um websocket remoto e vocaliza a resposta retornada
  - a finalizacao pode opcionalmente buscar um `result` remoto via mensagem `type=end`
  - o bridge agora repassa `agent`, `RouterCallKeyDay`, `RouterCallKey`, `ANI`, `GSM` e `ID_FATURA` para o agent quando esses campos vierem no metadata do cliente
  - o adapter remoto roteia a chamada para endpoints diferentes de acordo com `agent` (`conta`, `oferta`, `cobranca`)
  - o agent `conta` passou a usar contrato proprio em websocket com `action/payload` na entrada e `result.content` na resposta
- Risco conhecido:
  - o contrato do websocket remoto ainda e interno e precisa ser homologado com o agent externo real
  - o adapter atual usa conexao websocket por turno, nao uma sessao persistente
  - se o agent remoto nao devolver `stage`, a politica local dependera do ultimo stage conhecido ou do default configurado
  - o campo `timestamp` e gerado localmente no momento de cada turno; se o integrador exigir outro formato, isso ainda precisa ser alinhado
- Validacao executada:
  - testes unitarios do adapter remoto e factory
  - execucao da suite `unittest`
- Proximo passo:
  - homologar o contrato do websocket remoto com payload/resposta reais
  - decidir se a conexao remota deve continuar por turno ou evoluir para sessao persistente

## Entrada 007 - Cliente web de voz e call_config por chamada

- Data: 2026-03-30
- Objetivo: disponibilizar um cliente web para testar o fluxo de voz pelo navegador e permitir overrides de `STT`, `TTS` e `AGENT` por chamada
- Arquivos alterados:
  - `app/ws_gateway/main.py`
  - `app/ws_gateway/voice_client.html`
  - `app/ws_gateway/call_config.py`
  - `app/livekit/main.py`
  - `app/livekit/call_config.py`
  - `app/livekit/adapters/backend_factory.py`
  - `tests/config/test_call_config.py`
  - `docs/api-overview.md`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - fluxo principal de audio via `/ws/agent`
  - bridge continua recebendo `start`, audio binario e encerrando com `stop`
  - defaults de `STT`, `TTS` e backend continuam vindo de env quando nao houver override
- Comportamento alterado:
  - `/voice-client` agora serve um cliente web para capturar microfone e ouvir o audio retornado
  - o `start` pode carregar `call_config` com overrides por chamada
  - o agent agora aplica overrides de backend, STT e TTS para a sessao corrente
- Risco conhecido:
  - o cliente web usa `ScriptProcessorNode`, que e suficiente para homologacao mas nao e a opcao mais moderna da Web Audio API
  - os providers dinamicos suportados ainda sao os que ja existem no projeto (`internal_http` e `elevenlabs`)
- Validacao executada:
  - testes puros de `call_config`
  - execucao da suite `unittest`
- Proximo passo:
  - se o cliente web passar a ser usado em rotina de homologacao, vale migrar a captura/playback para `AudioWorklet`
  - se surgirem novos providers de STT/TTS, plugar nas factories por chamada

## Entrada 008 - Timeline estruturada por chamada

- Data: 2026-03-30
- Objetivo: criar observabilidade ponta a ponta para entender o caminho `bridge -> livekit -> stt -> backend -> tts -> stop` por chamada
- Arquivos alterados:
  - `app/utils/call_timeline.py`
  - `app/ws_gateway/main.py`
  - `app/livekit/main.py`
  - `app/livekit/runtime/call_runtime.py`
  - `app/livekit/adapters/backend_factory.py`
  - `app/livekit/adapters/pipeline_adapter.py`
  - `app/livekit/adapters/remote_agent_ws_adapter.py`
  - `app/livekit/adapters/bridge_gateway.py`
  - `app/providers/stt_internal_livekit.py`
  - `tests/utils/test_call_timeline.py`
  - `docs/api-overview.md`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - contrato publico de `WS /ws/agent`
  - fluxo de audio ja existente entre cliente, bridge, LiveKit e agent
  - backends de IA, STT e TTS seguem com a mesma responsabilidade funcional
- Comportamento alterado:
  - bridge e agent agora escrevem uma timeline estruturada em `jsonl` compartilhada por chamada
  - a timeline usa o mesmo `timeline_id` e o mesmo `origin_unix_ms` entre os dois processos para manter a ordem relativa dos eventos
  - o bridge passou a registrar eventos como `ready_sent`, `dispatch_started`, `agent_join`, `client_audio_enabled`, `done_packet_received` e `call_end`
  - o agent passou a registrar eventos como `user_transcript_final`, `pipeline_run_started`, `pipeline_run_completed`, `tts_stage_started`, `interrupt_marked`, `finalize_started` e `finalize_completed`
  - o provider de STT agora registra etapas de reconhecimento (`stt_recognize_started`, `stt_vosk_completed`, `stt_http_completed`)
  - o backend remoto por websocket agora registra `remote_agent_request` e `remote_agent_response`
- Risco conhecido:
  - a timeline registra payloads de request do backend remoto, o que aumenta a verbosidade e pode expor dados sensiveis em ambiente de debug
  - o arquivo `jsonl` e compartilhado entre dois processos locais; o uso atual com `flock` e suficiente para dev/homologacao, mas nao substitui observabilidade centralizada
- Validacao executada:
  - `py_compile` dos arquivos alterados
  - teste unitario novo de timeline
  - execucao completa da suite `unittest`
- Proximo passo:
  - decidir se a timeline deve continuar sempre habilitada em dev ou ficar atras de flag por ambiente
  - se a homologacao exigir, adicionar visualizador simples da timeline no cliente web

## Entrada 009 - Fake remoto para homologacao via UI

- Data: 2026-03-30
- Objetivo: permitir testar o fluxo `STT -> remote_ws -> TTS` pela UI mesmo sem o agent remoto real estar de pe
- Arquivos alterados:
  - `app/ws_gateway/fake_remote_agent.py`
  - `app/ws_gateway/main.py`
  - `app/ws_gateway/voice_client.html`
  - `app/livekit/adapters/backend_factory.py`
  - `tests/ws_gateway/test_fake_remote_agent.py`
  - `tests/livekit/test_remote_agent_ws_adapter.py`
  - `docs/api-overview.md`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - backend `remote_ws` continua exigindo URL real quando selecionado
  - o contrato do adapter remoto segue o mesmo
- Comportamento alterado:
  - o `bridge` agora expoe `WS /fake-agent/ws`
  - a UI ganhou a opcao `remote_ws_fake`
  - quando `remote_ws_fake` e selecionado, o agent local aponta para `REMOTE_AGENT_WS_FAKE_URL` ou usa por padrao `ws://127.0.0.1:8000/fake-agent/ws`
  - o fake responde nos contratos `conta` e generico, com progressao simples de stages e encerramento por palavras-chave como `encerrar`, `obrigado` e `tchau`
- Risco conhecido:
  - o fake nao simula comportamento de negocio real; ele serve apenas para homologacao tecnica do fluxo de voz
  - o fake e stateless por conexao, entao a progressao depende do `stage` enviado pelo agent local
- Validacao executada:
  - testes unitarios do fake remoto
  - testes do backend fake no adapter remoto
  - execucao completa da suite `unittest`
- Proximo passo:
  - se a homologacao pedir cenarios mais realistas, adicionar scripts por agent (`conta`, `oferta`, `cobranca`) com respostas configuraveis

## Template de nova entrada

- Data:
- Objetivo:
- Arquivos alterados:
- Comportamento preservado:
- Comportamento alterado:
- Risco conhecido:
- Validacao executada:
- Proximo passo:

## Entrada 010 - Correcao do roteamento `remote_ws_fake`

- Data: 2026-03-30
- Objetivo: garantir que a selecao `remote_ws_fake` na UI nao seja sobrescrita pela URL real configurada em `REMOTE_AGENT_WS_URL`
- Arquivos alterados:
  - `app/livekit/adapters/backend_factory.py`
  - `app/livekit/adapters/remote_agent_ws_adapter.py`
  - `tests/livekit/test_remote_agent_ws_adapter.py`
  - `docs/api-overview.md`
  - `docs/refactor-log.md`
- Comportamento preservado:
  - `remote_ws` continua usando `REMOTE_AGENT_WS_URL`
  - o adapter remoto continua sendo o mesmo para backend real e fake
- Comportamento alterado:
  - `remote_ws_fake` agora prioriza sempre `REMOTE_AGENT_WS_FAKE_URL`, mesmo quando `REMOTE_AGENT_WS_URL` existe no ambiente
  - a timeline do adapter remoto agora diferencia `backend=remote_ws_fake` de `backend=remote_ws`
- Risco conhecido:
  - aliases como `fake_remote_ws` e `ws_fake` continuam sendo tratados como `remote_ws_fake`, mas o label emitido na timeline fica canonico como `remote_ws_fake`
- Validacao executada:
  - `python3 -m unittest tests.livekit.test_remote_agent_ws_adapter -v`
  - `python3 -m py_compile app/livekit/adapters/backend_factory.py app/livekit/adapters/remote_agent_ws_adapter.py tests/livekit/test_remote_agent_ws_adapter.py`
- Proximo passo:
  - validar na chamada real da UI que o timeline e o request usam `ws://127.0.0.1:8000/fake-agent/ws`

## Entrada 011 - Reorganizacao da raiz e remocao de boilerplate

- Data: 2026-04-06
- Objetivo: consolidar a estrutura real do projeto na raiz do repositorio, mantendo `src/app` e `src/agent` como codigo-fonte canonico
- Arquivos alterados:
  - `README.md`
  - `makefile`
  - `Dockerfile`
  - `pytest.ini`
  - `.env.example`
  - `.gitignore`
  - `.dockerignore`
  - `requirements.txt`
  - `livekit.yaml`
  - `docs/*`
  - `tests/*`
  - `k8s/deployment.yaml`
  - remocao de `pyproject.toml`, `uv.lock`, `README copy.md`, `configs/config.example.yaml` e scripts herdados do boilerplate
- Comportamento preservado:
  - `src/app` e `src/agent` permanecem como raiz do codigo de execucao
  - o bridge FastAPI continua em `src/app/ws_gateway/main.py`
  - o projeto continua usando `PYTHONPATH=src`
- Comportamento alterado:
  - a raiz do repositorio passa a refletir o projeto real, e nao mais o boilerplate original
  - `requirements.txt` passa a ser a fonte principal de dependencias
  - artefatos de runtime (`logs`, `timeline`, `__pycache__`) deixam de ser versionados
- Risco conhecido:
  - arquivos de infra legados fora do fluxo principal ainda poderiam carregar suposicoes antigas do boilerplate
  - a migracao para `requirements.txt` simplifica a operacao, mas remove o lockfile anterior
- Validacao executada:
  - `python3 -m compileall src tests`
  - `python3 -m pytest tests/utils/test_call_timeline.py -q`
- Proximo passo:
  - revisar a infra auxiliar restante e reduzir ruido operacional na raiz

## Entrada 012 - Simplificacao do compose local de observabilidade

- Data: 2026-04-06
- Objetivo: transformar o `docker-compose.yml` em uma stack minima e coerente para Langfuse local
- Arquivos alterados:
  - `docker-compose.yml`
- Comportamento preservado:
  - a stack opcional de Langfuse continua disponivel para uso local
  - a aplicacao principal segue fora do compose, operada via `make`
- Comportamento alterado:
  - remocao do servico `mongo`
  - consolidacao apenas de `langfuse-web`, `langfuse-worker`, `postgres`, `redis`, `clickhouse` e `minio`
  - reducao de duplicacao com anchors para configuracoes compartilhadas
- Risco conhecido:
  - o compose continua sendo opcional e depende de configuracao explicita do projeto para apontar para Langfuse self-hosted
- Validacao executada:
  - validacao sintatica do YAML com parser local
- Proximo passo:
  - se a equipe mantiver uso frequente, considerar alvos dedicados no `makefile` para subir e derrubar a stack

## Entrada 013 - Provider TTS opcional desacoplado do import global

- Data: 2026-04-06
- Objetivo: impedir que a falta do SDK do ElevenLabs quebrasse o import do modulo inteiro de TTS
- Arquivos alterados:
  - `src/app/providers/tts.py`
  - `tests/providers/test_tts.py`
- Comportamento preservado:
  - selecao de provider TTS por configuracao
  - suporte aos providers ja existentes
- Comportamento alterado:
  - o SDK do ElevenLabs deixa de ser carregado no topo do modulo e passa a ser resolvido sob demanda
  - ausencia do SDK passa a gerar `missing_elevenlabs_sdk`, em vez de falha de import que derruba testes e providers nao relacionados
- Risco conhecido:
  - o provider continua opcional, mas a disciplina de dependencias ainda segue concentrada em `requirements.txt`
- Validacao executada:
  - `python3 -m pytest tests/providers/test_tts.py -q`
  - `python3 -m pytest tests/adapters/test_azure_tts.py -q`
- Proximo passo:
  - continuar removendo acoplamentos desnecessarios entre providers e entrypoints

## Entrada 014 - Remocao de mocks e hardcodes dos pipelines de texto

- Data: 2026-04-06
- Objetivo: tirar codigo de demonstracao do caminho produtivo dos endpoints de texto
- Arquivos alterados:
  - `src/app/services/session_context.py`
  - `src/app/services/text_pipeline.py`
  - `src/app/services/text_pipeline_stream.py`
  - `src/app/ws_gateway/main.py`
  - `tests/services/test_session_context.py`
- Comportamento preservado:
  - os endpoints `/ws/text` e `/ws/text_stream` continuam aceitando a mesma sessao de entrada
  - os pipelines continuam recebendo `mailing` e `intro`
- Comportamento alterado:
  - remocao do uso de `app.models.mock`
  - remocao de protocolo e dados fixos hardcoded nos pipelines
  - introducao de extracao explicita de protocolo via `session_context`
- Risco conhecido:
  - se existiam fluxos de dev que dependiam dos mocks antigos, eles passam a precisar de payloads reais
- Validacao executada:
  - `python3 -m pytest -q`
  - resultado observado na etapa: `36 passed`
- Proximo passo:
  - consolidar contratos duplicados entre gateway e runtime

## Entrada 015 - Unificacao de `call_config`

- Data: 2026-04-06
- Objetivo: eliminar duplicacao entre as implementacoes de `call_config` do gateway e do runtime LiveKit
- Arquivos alterados:
  - `src/app/common/call_config.py`
  - `src/app/ws_gateway/call_config.py`
  - `src/app/livekit/call_config.py`
  - `tests/config/test_call_config.py`
- Comportamento preservado:
  - API publica de `build_call_config(...)`
  - API publica de `normalize_call_config(...)` e resolucao dos campos auxiliares
- Comportamento alterado:
  - a normalizacao passa a ter um nucleo compartilhado em `src/app/common/call_config.py`
  - `ws_gateway` e `livekit` viram wrappers leves para o mesmo contrato
- Risco conhecido:
  - qualquer evolucao futura de `call_config` passa a ter impacto compartilhado entre bridge e agent, o que e desejado, mas exige disciplina de compatibilidade
- Validacao executada:
  - `python3 -m pytest tests/config/test_call_config.py -q`
  - `python3 -m pytest -q`
  - resultado observado na etapa: `36 passed`
- Proximo passo:
  - iniciar a quebra incremental do monolito em `src/app/ws_gateway/main.py`

## Entrada 016 - Extracao do parsing inicial da sessao no bridge

- Data: 2026-04-06
- Objetivo: remover do `ws_gateway/main.py` a logica de parsing da mensagem `start`, resolucao de mailing e montagem de `intro`/`nudge`
- Arquivos alterados:
  - `src/app/ws_gateway/session_start.py`
  - `src/app/ws_gateway/main.py`
  - `tests/ws_gateway/test_session_start.py`
- Comportamento preservado:
  - contrato de primeira mensagem `type=start`
  - geracao de `mailing`, `intro` e `nudge`
  - construcao do contexto do agente remoto a partir de metadata + mailing
- Comportamento alterado:
  - criacao da dataclass `StartSessionContext`
  - centralizacao de `parse_start_payload`, `recv_start_message` e `build_remote_agent_context` em modulo proprio
  - `/ws/agent`, `/ws/text` e `/ws/text_stream` passam a consumir um contexto estruturado, e nao uma tuple solta
- Risco conhecido:
  - o contrato de entrada continua dependente do payload do cliente; a extracao melhora testabilidade, mas nao redefine o protocolo
- Validacao executada:
  - `python3 -m compileall src/app/ws_gateway src/app/services tests/ws_gateway`
  - `python3 -m pytest tests/ws_gateway/test_session_start.py -q`
  - `python3 -m pytest -q`
  - resultado observado na etapa: `39 passed`
- Proximo passo:
  - extrair o bootstrap da chamada para reduzir ainda mais a responsabilidade do endpoint

## Entrada 017 - Extracao do bootstrap da chamada do bridge

- Data: 2026-04-06
- Objetivo: separar a preparacao da chamada do runtime do endpoint `/ws/agent`
- Arquivos alterados:
  - `src/app/ws_gateway/session_bootstrap.py`
  - `src/app/ws_gateway/main.py`
  - `tests/ws_gateway/test_session_bootstrap.py`
- Comportamento preservado:
  - geracao de token de acesso ao LiveKit
  - montagem de `call_config`, `remote_agent_context`, `timeline` e `dispatch_metadata`
  - fallbacks de protocolo e telefone
- Comportamento alterado:
  - introducao da dataclass `BridgeSessionBootstrap`
  - centralizacao de `room_name`, `identity`, `token`, `protocol`, `phone_number` e `dispatch_metadata` em um builder dedicado
  - `main.py` passa a consumir um pacote pronto de bootstrap
- Risco conhecido:
  - o bootstrap ainda depende de envs e factories externas; a extracao organiza responsabilidade, mas nao muda a politica de configuracao
- Validacao executada:
  - `python3 -m compileall src/app/ws_gateway tests/ws_gateway`
  - `python3 -m pytest tests/ws_gateway/test_session_bootstrap.py -q`
  - `python3 -m pytest -q`
  - resultado observado na etapa: `41 passed`
- Proximo passo:
  - extrair o ciclo de vida da sessao LiveKit do endpoint

## Entrada 018 - Extracao do lifecycle da sessao LiveKit no bridge

- Data: 2026-04-06
- Objetivo: remover do endpoint os handlers de participante, o processamento do pacote `DONE` e o watcher de encerramento
- Arquivos alterados:
  - `src/app/ws_gateway/session_lifecycle.py`
  - `src/app/ws_gateway/main.py`
  - `tests/ws_gateway/test_session_lifecycle.py`
- Comportamento preservado:
  - deteccao de entrada e saida do agente remoto
  - processamento do pacote `agent.stage` com `DONE`
  - envio de `stop` para o cliente ao final da chamada
- Comportamento alterado:
  - criacao de `RoomLifecycleState` para concentrar `agent_participant` e `done_payload`
  - extracao de `register_room_lifecycle_handlers(...)`
  - extracao de `watch_call_done(...)`
- Risco conhecido:
  - o fluxo ainda depende de coordenacao concorrente entre tasks do bridge; a extracao reduz tamanho do endpoint, mas nao muda o modelo de concorrencia
- Validacao executada:
  - `python3 -m compileall src/app/ws_gateway tests/ws_gateway`
  - `python3 -m pytest tests/ws_gateway/test_session_lifecycle.py -q`
  - `python3 -m pytest -q`
  - resultado observado na etapa: `43 passed`
- Proximo passo:
  - extrair a camada de intro/sinalizacao do bridge

## Entrada 019 - Extracao da intro TTS e da sinalizacao de audio no bridge

- Data: 2026-04-07
- Objetivo: isolar do endpoint o trecho responsavel por intro TTS, liberacao do audio do cliente, sinalizacao `client_audio_enabled` e bootstrap do streaming do agente
- Arquivos alterados:
  - `src/app/ws_gateway/session_audio.py`
  - `src/app/ws_gateway/main.py`
  - `tests/ws_gateway/test_session_audio.py`
- Comportamento preservado:
  - intro sintetizada antes da liberacao do audio do cliente
  - emissao do controle `client_audio_enabled` para o agente
  - inicializacao do worker que consome audio do agente quando ele fica pronto
- Comportamento alterado:
  - extracao de `play_intro_to_client(...)`
  - extracao de `notify_client_audio_enabled(...)`
  - extracao de `stream_agent_audio_when_ready(...)`
  - `main.py` passa a gerenciar explicitamente a task `t_control`, em vez de disparar a notificacao como fire-and-forget
  - ajuste de typing para evitar import-time acidental de `audioop` em testes unitarios do modulo novo
- Risco conhecido:
  - o caminho quente de audio continua centralizado em `main.py`; ainda faltam as primitivas de transporte para o arquivo deixar de ser monolitico
- Validacao executada:
  - `python3 -m compileall src/app/ws_gateway tests/ws_gateway`
  - `python3 -m pytest tests/ws_gateway/test_session_audio.py -q`
  - `python3 -m pytest -q`
  - resultado observado na etapa: `46 passed`
- Proximo passo:
  - extrair as primitivas de transporte de audio e LiveKit (`ws_audio_receiver`, `publish_queue_to_livekit`, `connect_publish_livekit`, `stream_agent_audio_to_queue`)

## Entrada 020 - Validacao do Dockerfile para CI/CD

- Data: 2026-04-07
- Objetivo: revisar o `Dockerfile` frente ao layout atual do projeto e corrigir o principal risco de compatibilidade para pipeline
- Arquivos alterados:
  - `Dockerfile`
- Comportamento preservado:
  - execucao do bridge via `uvicorn app.ws_gateway.main:app`
  - exposicao da porta `8000`
  - `PYTHONPATH=/app/src`
  - healthcheck em `/health`
- Comportamento alterado:
  - troca da base de `python:3.13-slim` para `python:3.12-slim`
  - o ajuste foi necessario porque o projeto ainda depende de `audioop` em `src/app/ws_gateway/main.py` e `src/app/utils/background.py`
- Risco conhecido:
  - o build real da imagem nao conseguiu ser concluido nesta maquina porque nem o daemon Docker nem a conexao efetiva do Podman estavam operacionais no momento da validacao
  - portanto, a validacao foi estrutural e de coerencia do arquivo, nao um smoke test completo de container
- Validacao executada:
  - revisao manual de `Dockerfile`, `.dockerignore`, `requirements.txt`, `makefile` e `k8s/deployment.yaml`
  - tentativa de `docker build`, bloqueada por daemon indisponivel
  - tentativa de `podman build`, bloqueada por conexao local com a VM do Podman
- Proximo passo:
  - executar um build real da imagem assim que houver runtime de containers disponivel no host ou direto no pipeline
