15 KiB
| id | ticket | title | status | created | resolved | decision | tags | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| AGD-0011 | compiler-analyze-compile-build-pipeline-split | Desacoplar o pipeline do compiler em analyze, compile e build | accepted | 2026-03-30 | 2026-03-30 | DEC-0007 |
|
Pain
Hoje o pipeline principal do compiler exposto por BuilderPipelineService e monolitico: ele resolve dependencias, carrega fontes, roda frontend, lowering, otimizacao, emissao, verificacao e sempre termina escrevendo build/program.pbx.
Isso acopla tres intencoes diferentes num unico fluxo:
- analisar codigo e produzir diagnosticos/estado semantico;
- compilar ate um resultado executavel em memoria;
- materializar artefato final em disco.
Esse acoplamento atrapalha diretamente o proximo wave do Studio editor e o futuro LSP:
- o editor precisa de
analyzesem forcar emissao de PBX; - um consumidor de semantica pode precisar de
compileem memoria sem write side effects; builddeve continuar existindo como fluxo de artefato, mas nao como unica forma de usar o compiler.
Context
Domain owner: compiler
Owner surface: docs/specs/compiler
Cross-domain input: studio
Superficies relevantes hoje:
prometeu-compiler/prometeu-build-pipeline/.../BuilderPipelineService.javaregistra uma lista fixa de stages e sempre incluiWriteBytecodeArtifactPipelineStageno fim;EmitBytecodePipelineStageja produzctx.bytecodeModuleectx.bytecodeBytesem memoria antes de qualquer write em disco;WriteBytecodeArtifactPipelineStageapenas persistebuild/program.pbx, o que mostra que a emissao de artefato ja e uma preocupacao separavel;docs/specs/compiler/15. Bytecode and PBX Mapping Specification.mdnormatiza a fronteira de emissao PBX/bytecode, mas nao exige que todo consumo do compiler materialize artefato em disco;- na discussion do editor (
DSC-0010), ja ficou aceito queSourceProviderFactorysera mantido como boundary de leitura, com providers mais especificos no futuro para sessao documental do editor. - embora PBS seja hoje o frontend mais avancado nesse caminho, esta agenda pertence ao dominio
compilere precisa preservar um contrato de pipeline frontend-agnostico, reutilizavel por PBS e por futuros FEs sem regressao no comportamento decompile.
Boundary explicitamente fechado para esta agenda:
SourceProviderFactorycontinua sendo a fronteira de leitura do compiler;- esta agenda NAO vai discutir ainda o novo provider do editor;
- esta agenda vai discutir apenas como expor
analyze,compileebuildcomo entradas distintas do compiler. - o split do pipeline nao pode introduzir semantica especial de PBS na API operacional do compiler; compatibilidade com o
compileatual de PBS deve ser tratada como restricao obrigatoria.
Open Questions
- Qual deve ser o corte exato entre
analyzeecompile:analyzepara no frontend/diagnostics, ou inclui tambem lowering/backend facts uteis para tooling? Recomendacao:analyzedeve terminar emFrontendPhasePipelineStage, isto e,ResolveDeps + LoadSources + FrontendPhase, expondo diagnosticos e facts semanticos orientados a tooling sem avancar para lowering ou emissao. compiledeve ir atebytecodeModule/bytecodeBytesem memoria sem write, ou deve parar emIRVMe deixar emissao parabuild? Recomendacao:compiledeve terminar emVerifyBytecodePipelineStage, produzindobytecodeModuleebytecodeBytesverificados em memoria sem write side effects; parar emIRVMdeixaria a superficie incompleta para consumidores que precisam de resultado executavel sem persistencia.- A verificacao (
VerifyBytecodePipelineStage) pertence acompile, abuild, ou a ambos conforme perfil? Recomendacao:VerifyBytecodePipelineStagee o stage terminal decompile, ebuildapenas adicionaWriteBytecodeArtifactPipelineStagedepois disso;compilenao deve devolver bytes nao verificados. - Como representar esses tres modos: services separados, perfis de pipeline, ou uma composicao explicita de stage groups?
Recomendacao: expor tres chamadas canonicas no mesmo pipeline compartilhado, por exemplo
analyze,compileebuild, evitando tanto tres pipelines independentes quanto um unicorunmonolitico com semantica implicita. - O resultado de
analyzedeve expor umAnalysisSnapshotestavel para editor/LSP, ou apenas diagnosticos + facts minimos no primeiro wave? Recomendacao:analyzedeve expor umAnalysisSnapshotestavel ja no primeiro wave, mas com shape minimo e pragmatico, carregando apenas os facts e handles necessarios para editor/LSP. - O CLI atual e os callsites existentes devem continuar mapeando
buildcomo comportamento default? Recomendacao: sim; a mudanca deve ampliar a superficie operacional do compiler sem quebrar o comportamento default atual de artefato em disco. - Como evitar que
buildecompilepassem a divergir semanticamente por ordem de stages ou gates diferentes? Recomendacao:builddeve ser definido normativamente como o mesmo fluxo decompile, encerrado porWriteBytecodeArtifactPipelineStage, sem reorder ou gates semanticos exclusivos fora da persistencia terminal. - LSP/editor devem usar outro pipeline, ou o mesmo pipeline com chamadas e contextos diferentes? Recomendacao: devem usar o mesmo pipeline canonico, mas atraves de chamadas diferentes e configs/contextos distintos por entrypoint; mudar inputs, sinks e shape de resultado e valido, mas mudar a semantica central dos stages canonicos nao.
- O
runatual deve continuar existindo como alias, ou deve ser absorvido porbuild? Recomendacao:runnao deve permanecer como entrypoint publico; o comportamento default de hoje deve ser absorvido porbuild, com contexto/config de filesystem construido fora do pipeline em si. - Quais contratos ou specs precisam receber propagacao quando o pipeline deixar de ter uma unica entrada monolitica? Recomendacao: a propagacao principal deve atingir a spec operacional do pipeline do compiler, os contratos de CLI/callsites e a documentacao de resultados intermediarios; a spec de PBX continua authority de emissao, nao de persistencia em disco.
Options
Option A - Manter BuilderPipelineService monolitico e adicionar flags
- Approach: Preservar o pipeline atual e usar flags condicionais para pular write de artefato ou parar em stages intermediarios.
- Pro: Menor mudanca inicial.
- Con: Esconde perfis diferentes dentro de um fluxo ad hoc, torna os cortes menos legiveis e aumenta risco de combinacoes invalidas.
- Maintainability: Fraca. O comportamento fica implicito e espalhado por condicionais.
Option B - Definir tres entrypoints normativos sobre um pipeline composavel
- Approach: Modelar o pipeline como composicao reutilizavel de stage groups e expor tres modos canonicos:
analyze,compileebuild. - Pro: Torna o contrato explicito, reaproveita as mesmas stages onde fizer sentido e separa claramente analise, compilacao em memoria e emissao de artefato.
- Con: Exige fechar com precisao o corte entre as fases e o shape dos resultados intermediarios.
- Maintainability: Forte. O compiler ganha uma superficie operacional clara para CLI, Studio, testes e LSP.
Option C - Separar services independentes por responsabilidade
- Approach: Criar services distintos e quase autossuficientes para
AnalyzeService,CompileServiceeBuildService, cada um com seu proprio encadeamento. - Pro: As responsabilidades ficam bem nomeadas.
- Con: Se a composicao nao for rigorosamente compartilhada, o risco de drift entre os fluxos cresce rapido.
- Maintainability: Media. Pode funcionar, mas so se a infraestrutura comum ficar bem centralizada.
Discussion
O codigo atual ja mostra o seam principal que queremos aproveitar:
- primeiro o pipeline resolve e analisa a workspace;
- depois produz artefatos executaveis em memoria;
- por fim escreve
program.pbxem disco.
O problema nao e falta de separacao conceitual. O problema e que essa separacao ainda nao virou API normativa nem entrypoints distintos.
Para o editor e o LSP, isso importa muito:
analyzeprecisa ser barato em side effects e orientado a snapshot;compileprecisa produzir um resultado coerente em memoria sem obrigar write de artefato;buildprecisa continuar sendo o fluxo que materializaprogram.pbx.
Ao mesmo tempo, esta agenda nao deve misturar dois assuntos:
- como o compiler le fontes;
- e como ele expõe seus perfis de execucao.
O primeiro assunto fica travado: SourceProviderFactory continua sendo o boundary.
O segundo e o alvo desta discussion: desacoplar a intencao operacional do pipeline.
Tambem precisamos manter a classificacao correta do problema:
- PBS nao e o owner desta decisao; ele e um frontend consumidor importante;
- o split precisa servir ao compiler como plataforma multi-frontend;
- isso significa que a nova API de
analyze/compile/builddeve preservar o comportamento correto que o caminho atual ja entrega para PBS, sem acoplar o contrato a detalhes exclusivos desse frontend.
Tambem fica fechado que LSP/editor nao introduzem "outro pipeline" no dominio compiler.
O que muda sao as chamadas e os contextos de execucao:
- o pipeline canonico permanece unico;
analyze,compileebuildsao entrypoints distintos sobre esse mesmo pipeline;- configs/contextos diferentes podem ajustar leitura, coletores, sinks e shape de retorno por caso de uso;
- esses contextos nao devem redefinir a semantica central dos stages canonicos.
- o comportamento default atual deixa de se chamar
rune passa a ser obuildconstruido com config/contexto de filesystem montado pelo callsite, nao pelo pipeline em si.
A direcao mais saudavel parece ser explicitar tres perfis canonicos:
analyzetermina emFrontendPhasePipelineStage, isto e, resolve deps, carrega fontes, roda frontend e produzAnalysisSnapshotcom diagnosticos e facts semanticos sem executar lowering, emissao ou write de artefato.compiletermina emVerifyBytecodePipelineStage, isto e, reaproveita o mesmo eixo semantico deanalyze, avanca por lowering, otimizacao, emissao, link precheck e verificacao preload, e produz resultado executavel validado em memoria sem escrever arquivo.buildtermina emWriteBytecodeArtifactPipelineStage, isto e, e definido comocompileseguido apenas da etapa terminal de materializacao do artefato em disco.
Isso preserva um unico eixo semantico e reduz o risco de o Studio ou o LSP precisarem inventar um "mini-compiler" paralelo.
Em termos de superficie de servico, o caminho recomendado elimina run como entrypoint normativo.
O servico deve passar a expor entrypoints explicitos, por exemplo:
analyze(config, logs)ou equivalente;compile(config, logs)ou equivalente;build(config, logs)ou equivalente.
Cada chamada pode receber config/contexto apropriado ao caso de uso, mas continua percorrendo o mesmo pipeline canonico ate o stage terminal definido para aquele entrypoint.
O comportamento que hoje existe em run deve ser reexpresso como build(filesystem-config, logs) ou equivalente, com a construcao do contexto default acontecendo fora do pipeline itself.
Fechamentos recomendados para a decisao:
analyzetermina emFrontendPhasePipelineStagee nao inclui lowering/backend execution artifacts.compiletermina emVerifyBytecodePipelineStagee vai atebytecodeModuleebytecodeBytesem memoria.compileincluiLinkBytecodeeVerifyBytecodepara que o resultado em memoria ja seja semanticamente confiavel.buildtermina emWriteBytecodeArtifactPipelineStage; ele nao recompila por outro caminho e apenas reaproveitacompilecom a persistencia terminal.- a API publica deve expor snapshots/resultados estaveis por perfil, sem vazar
BuilderPipelineContextcomo contrato externo. - o CLI e os callsites existentes continuam apontando para
buildcomo comportamento default. - a decisao deve preservar compatibilidade comportamental com o
compileatual usado por PBS, tratando esse fluxo como baseline de corretude e nao como detalhe descartavel de um frontend especifico. - a superficie nova deve permanecer frontend-agnostica, para que futuros FEs possam reutilizar o mesmo contrato sem herdar semantica acidental de PBS.
BuilderPipelineServicenao deve manterruncomo entrypoint publico; ele deve exporanalyze,compileebuildsobre o mesmo pipeline compartilhado.- o comportamento atual de
rundeve ser absorvido porbuildcom config/contexto de filesystem construido fora do pipeline em si. - configs/contextos distintos por entrypoint sao permitidos para suportar CLI, editor e LSP, desde que nao alterem a semantica central dos stages canonicos.
Resolution
Recommended direction: seguir com Option B.
A agenda deve convergir para uma decisao com os seguintes fechamentos:
SourceProviderFactorypermanece como boundary de leitura do compiler;- o compiler deve expor tres entrypoints normativos:
analyze,compileebuild; buildnao e mais sinonimo de "todo uso do compiler", mas apenas o perfil que materializa artefato;analyzedeve ser definido como o perfil que termina emFrontendPhasePipelineStage, isto e,ResolveDeps + LoadSources + FrontendPhase, retornandoAnalysisSnapshotestavel e sem write side effects;compiledeve ser definido como o perfil que termina emVerifyBytecodePipelineStage, isto e,analyze + LowerToIRVM + OptimizeIRVM + EmitBytecode + LinkBytecode + VerifyBytecode, retornando resultado validado em memoria;builddeve ser definido como o perfil que termina emWriteBytecodeArtifactPipelineStage, isto e,compile + WriteBytecodeArtifact, sem reorder semantico ou gates adicionais fora da persistencia terminal;- a API publica deve retornar resultados estaveis por perfil em vez de expor o
BuilderPipelineContextdiretamente; - o CLI/build atual deve continuar como comportamento default para compatibilidade;
- a decisao deve preservar compatibilidade comportamental com o
compileatual de PBS como baseline de corretude, sem transformar PBS em detalhe normativo do contrato publico; - a superficie
analyze/compile/builddeve permanecer frontend-agnostica para acomodar multiplos FEs no dominiocompiler; BuilderPipelineServicedeve removerruncomo entrypoint publico e exporanalyze,compileebuild, cada um com config/contexto apropriado ao seu caso de uso;- o comportamento default de hoje deve ser preservado como
buildcom config/contexto de filesystem, construido fora do pipeline itself; - configs/contextos diferentes por entrypoint sao parte do modelo, mas nao podem redefinir a semantica central dos stages canonicos;
- a propagacao deve atingir a spec operacional do pipeline, os contratos de CLI/callsites e a documentacao dos resultados intermediarios, preservando a spec de PBX como authority de emissao.
Next step suggestion: converter esta agenda em uma decision que feche o stage boundary de cada perfil, o contrato dos resultados intermediarios e a compatibilidade do CLI/build atual com o novo modelo.