Limitação conhecida do conserto que entrou na PR #27 (commit 96b7b4d). Não há defeito vivo hoje — é lacuna latente, e nenhum teste a pegaria.
O que o conserto faz
lib/cli.py, em run_cmd: nos modos de máquina (--json e --stream-json), o stdout dos passos é desviado para stderr com contextlib.redirect_stdout(sys.stderr), para que stdout carregue só a saída declarada. Isso existe porque o motor vendorado tem dois print() incondicionais no passo 0 (lib/motores/crystalball_llm.py:1166,1168) e é proibido editá-lo.
O limite
redirect_stdout troca sys.stdout, que é objeto de nível Python. Escapam:
subprocess com o stdout do filho herdado do processo pai. O filho escreve no fd 1 direto, e o desvio não o alcança.
os.write(1, ...), ou qualquer escrita por descritor.
- extensões C que escrevam no
stdout do C runtime.
Qualquer um dos três, num passo, volta a intercalar lixo no NDJSON e a quebrar a promessa de "uma linha por evento".
Por que não morde hoje
O único subprocesso alcançável a partir de um passo é higgsfield_cli_client._run, que chama subprocess.run(..., capture_output=True) — o filho escreve num pipe, não no fd 1 herdado. Nenhum outro caminho de passo escreve por descritor.
Conserto, quando valer
Trocar o desvio de nível Python por desvio de descritor (os.dup2 do fd 1 para o fd 2 durante a execução dos passos, restaurando depois), que pega subprocesso e os.write junto. Custa mais e exige cuidado com o CliRunner dos testes, que não tem fd real — por isso não entrou agora.
Gatilho para revisitar: o primeiro passo que precise de um subprocesso com stdout herdado.
Limitação conhecida do conserto que entrou na PR #27 (commit
96b7b4d). Não há defeito vivo hoje — é lacuna latente, e nenhum teste a pegaria.O que o conserto faz
lib/cli.py, emrun_cmd: nos modos de máquina (--jsone--stream-json), o stdout dos passos é desviado para stderr comcontextlib.redirect_stdout(sys.stderr), para que stdout carregue só a saída declarada. Isso existe porque o motor vendorado tem doisprint()incondicionais no passo 0 (lib/motores/crystalball_llm.py:1166,1168) e é proibido editá-lo.O limite
redirect_stdouttrocasys.stdout, que é objeto de nível Python. Escapam:subprocesscom o stdout do filho herdado do processo pai. O filho escreve no fd 1 direto, e o desvio não o alcança.os.write(1, ...), ou qualquer escrita por descritor.stdoutdo C runtime.Qualquer um dos três, num passo, volta a intercalar lixo no NDJSON e a quebrar a promessa de "uma linha por evento".
Por que não morde hoje
O único subprocesso alcançável a partir de um passo é
higgsfield_cli_client._run, que chamasubprocess.run(..., capture_output=True)— o filho escreve num pipe, não no fd 1 herdado. Nenhum outro caminho de passo escreve por descritor.Conserto, quando valer
Trocar o desvio de nível Python por desvio de descritor (
os.dup2do fd 1 para o fd 2 durante a execução dos passos, restaurando depois), que pega subprocesso eos.writejunto. Custa mais e exige cuidado com oCliRunnerdos testes, que não tem fd real — por isso não entrou agora.Gatilho para revisitar: o primeiro passo que precise de um subprocesso com stdout herdado.