# PBS Globals Surface, Identity, and Module Boundaries Agenda ## Status Open ## Parent Agenda This agenda derives from: - `19. Globals, Synthetic Module Init, and FRAME_RET Agenda` This is the first derived discussion under umbrella topic `19`. ## Purpose Define the source-level and module-level model for PBS runtime globals before lifecycle, entrypoint publication, or lowering details are discussed. This agenda exists to close the semantic base for: - the `declare global` surface; - storage ownership; - import/export/alias behavior; - and dependency/cycle rules at module boundary level. Later agendas under topic `19` must treat the outputs of this agenda as fixed input. ## Domain Owner `docs/compiler/pbs` Este tema pertence ao domínio PBS do compiler porque define surface language, linking semantics e boundaries de módulo para uma nova categoria de declaração top-level. ## Context Hoje o PBS já possui `declare const`, mas esse surface é estritamente compile-time: - `declare const` entra no value namespace; - `declare const` continua reservado a valores imutáveis que não representam storage mutável de módulo; - `declare const` não materializa storage mutável runtime; - o initializer de `declare const` pertence a um subset constante; - dependências de `declare const` são resolvidas por análise de dependência compile-time. Ao mesmo tempo: - a VM já expõe `GET_GLOBAL` e `SET_GLOBAL`; - a linguagem ainda não expõe globals mutáveis de módulo; - `mod.barrel` hoje já governa export/import de `const`, `fn`, tipos e outras famílias de declaração; - não existe ainda contrato explícito para storage compartilhado intermodular em source PBS. Antes de discutir init, frame wrapper ou `FRAME_RET`, precisamos fechar o que um `global` é no modelo da linguagem. ## Inputs Already Fixed Elsewhere Os seguintes inputs já parecem fixos e não devem ser reabertos aqui: - `declare const` não é storage mutável/runtime-initialized; - `declare const` continua semanticamente separado de `declare global`; - `declare const` continua voltado a valores imutáveis e não deve ser reutilizado como surface de global; - modules e globals devem compartilhar o mesmo tipo estrutural de análise de dependência; - essa análise comum deve vir de um refactor do algoritmo atual de modules para um `DependencyGraphAnaliser` em `util.structures` na infra; - top-level executable statements continuam proibidos; - a VM já suporta globals por slot; - esta fase ainda é compiler-driven e não deve exigir capability nova do runtime; - barrel continua sendo a fonte de visibilidade entre módulos. ## Decisions To Produce Esta agenda deve produzir direção suficiente para fechar: 1. a surface exata de `declare global`; 2. a obrigatoriedade de initializer em todos os globals de v1; 3. o namespace ocupado por globals; 4. a política de visibility/barrel para globals; 5. a identidade do storage owner; 6. a semântica de import, export e alias; 7. a política de dependência e ciclos entre globals. ## Core Questions 1. PBS deve introduzir exatamente `declare global name: T = expr;` como nova forma top-level? 2. `declare global` deve exigir type annotation explícita em todos os casos? 3. Quais formas de initializer executável são admissíveis para `declare global` em v1? 4. `declare global` entra no mesmo value namespace de `let` e `declare const`? 5. O barrel deve ganhar uma entrada `global` distinta? 6. Um `global` importado referencia sempre o storage do módulo owner original? 7. Como imports de globals usam alias quando necessário sem introduzir shadowing? 8. O que é proibido em imports de globals para evitar ambiguidade? 9. A dependência entre globals deve ser modelada por grafo determinístico semelhante ao de `declare const`, mas agora com efeito runtime? 10. Como ciclos entre globals intra-módulo e inter-módulo devem ser detectados e reportados? 11. Como o grafo de globals mapeia para o `DependencyGraphAnaliser` comum sem perder owner canônico nem attribution? ## Options ### Option A Adicionar `declare global` como nova declaração top-level explícita, com type annotation obrigatória, initializer obrigatório em v1, entry própria `global` em barrel, sem reexport e identidade de storage sempre pertencente ao módulo owner original. ### Option B Adicionar `declare global`, mas permitir globals sem initializer em v1 e tratar inicialização default como parte do modelo base. ## Tradeoffs ### Option A - Prós: - semântica explícita e fácil de ensinar; - evita ambiguidade entre constant value e mutable storage; - força o barrel e os imports a refletirem corretamente a nova categoria declarativa; - reduz risco de globals parcialmente formados sem política clara de init. - Contras: - aumenta a superfície da linguagem; - exige atualização de parser, AST, linking e barrel matching. ### Option B - Prós: - maior flexibilidade futura; - permite reservar globals antes de decidir a inicialização concreta. - Contras: - empurra complexidade para lifecycle e diagnostics; - enfraquece a previsibilidade de v1; - cria edge cases sobre leitura antes de materialização. ## Recommendation Seguir com a **Option A**. Direção recomendada: 1. `declare global` deve ser uma declaração top-level distinta de `declare const`; 2. type annotation explícita deve ser obrigatória; 3. initializer deve ser obrigatório em v1; 4. `declare const` não deve ser reutilizado para globals e continua reservado a valores imutáveis; 5. globals devem entrar no value namespace, mas com categoria declarativa distinta; 6. barrel deve refletir essa distinção explicitamente com `mod global` e `pub global`; 7. PBS não deve introduzir reexport de globals nesta linha; 8. imports de globals devem preservar a identidade do storage owner original e usar alias quando necessário; 9. shadowing entre imports de `fn`, `service`, `global` e `const` deve ser compile-time error; 10. dependências entre globals devem ser determinísticas e diagnosticáveis. Também fica registrado nesta agenda um direction técnico já decidido: 1. modules e globals usarão o mesmo tipo estrutural de análise de dependência; 2. isso deve nascer de um refactor do algoritmo atual de modules; 3. o artefato comum deve viver na infra como `DependencyGraphAnaliser` em `util.structures`; 4. cada domínio continua responsável por construir seus próprios nós canônicos, suas arestas e seu mapeamento de diagnóstico; 5. o que é compartilhado é o kernel estrutural de ordenação topológica e detecção de ciclos, não a semântica específica de cada grafo. ## Global Dependencies O ponto mais sensível desta agenda é a dependência entre globals. Com `declare const`, dependência significa apenas ordem de avaliação compile-time. Com `declare global`, dependência passa a significar ordem de materialização runtime, identidade de storage e risco real de efeito parcial. Exemplos do tipo de dependência que passam a existir: ```pbs declare global a: int = 1; declare global b: int = a + 1; ``` Aqui `b` depende de `a` porque o initializer de `b` lê o valor de `a`. ```pbs declare global origin: Vec2 = new Vec2(0, 0); declare global camera: Camera = new Camera(origin); ``` Aqui `camera` depende de `origin` porque o initializer usa o valor já materializado de outro global. Quando há múltiplos módulos, o problema cresce: ```pbs // module A declare global seed: int = 7; // module B import { seed } from @project:A; declare global rng: Rng = new Rng(seed); ``` Agora a ordem de materialização não é apenas intra-módulo. Ela atravessa módulos e precisa continuar determinística. ### Dependency Kinds Esta agenda precisa distinguir pelo menos três formas de dependência: 1. dependência local entre globals do mesmo módulo; 2. dependência intermodular por import de global do módulo owner original; 3. dependência indireta por alias de import, onde o nome local muda, mas o owner do storage permanece igual. ### Main Problems Os principais problemas de dependência de globals são: 1. ordem de inicialização deixa de poder depender de ordem textual do arquivo; 2. imports com alias podem esconder o owner real do storage; 3. leitura de global ainda não materializado precisa ser proibida por modelo, não tratada como comportamento oportunista; 4. ciclos deixam de ser apenas "ciclos de expressão" e passam a ser ciclos de materialização runtime; 5. o grafo de dependências pode cruzar múltiplos módulos e aliases, o que piora atribuição de diagnóstico. ### Risks Se a política de dependência de globals ficar frouxa, os riscos são altos: 1. inicialização parcialmente observável: um global pode ler outro antes de ele existir semanticamente; 2. ordem acidental por arquivo: a implementação pode acabar usando ordem textual ou ordem de carregamento do projeto, o que quebra determinismo; 3. aliasing ambíguo: aliases de import podem parecer símbolo novo quando na verdade são só outro nome para o mesmo owner; 4. ciclos opacos: `A -> B -> C -> A` pode ficar escondido atrás de import e alias, dificultando explicação ao usuário; 5. bootstrap contaminado: se essa agenda deixar dependência frouxa, a 19.2 herda um lifecycle impossível de explicar; 6. lowering prematuro: se o compiler materializar a ordem no backend sem política semântica firme, a arquitetura congela cedo demais. ### Direction for Discussion Minha direção recomendada para dependências de globals nesta agenda é: 1. toda leitura de outro global no initializer cria uma edge explícita no grafo de dependência; 2. a resolução do grafo deve ser determinística e independente de source-file order; 3. imports e aliases devem preservar o owner original do storage no grafo; 4. ciclos entre globals devem ser erro estático, não comportamento runtime com retry ou valor parcial; 5. a agenda deve deixar claro que esta política fecha apenas identidade e dependência; boot ordering completo continua pertencendo à `19.2`. ### Structural Reuse Decision Esta agenda também registra uma decisão arquitetural de implementação que afeta a evolução futura: 1. o algoritmo atual usado para dependência de modules deve ser refatorado em um componente estrutural reutilizável; 2. esse componente comum deve se chamar `DependencyGraphAnaliser`; 3. ele deve viver em `util.structures` na infra; 4. modules e globals devem consumir esse mesmo componente estrutural; 5. a semântica que descobre edges continua separada por domínio. Isso significa: - o import graph de modules e o init graph de globals não serão o mesmo grafo semântico; - mas ambos deverão usar o mesmo kernel estrutural para: - topological ordering, - cycle detection, - e suporte a diagnóstico determinístico. ## Current Direction Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte: 1. a surface correta é `declare global BLA: int = 1;`; 2. type annotation é obrigatória, como em `declare const`; 3. initializer é sempre obrigatório; 4. globals entram no value namespace como categoria declarativa distinta; 5. `mod.barrel` deve expor globals com entradas `mod global Name;` e `pub global Name;`; 6. imports de globals usam o mesmo esquema de alias quando necessário; 7. PBS não introduz reexport de globals nesta linha; 8. shadowing entre imports de `fn`, `service`, `global` e `const` é compile-time error e deve ser resolvido com alias; 9. detecção de dependência, ordenação e ciclo deve nascer do `DependencyGraphAnaliser` comum, com contexto semântico próprio de globals. Também fica explicitado o modelo de namespace: 1. globals entram no value namespace; 2. `declare const`, `declare global` e o singleton canônico de `service` convivem no espaço nominal de valores; 3. `fn`, `service`, `global` e `const` não podem introduzir o mesmo nome visível no mesmo scope de resolução; 4. essa colisão é erro de compile time, mesmo quando a ambiguidade nasce de import; 5. `locals > struct/class members > globals`, inclusive quando o global veio por import. ## Remaining Open Points Com a direção já consolidada nesta agenda, não restam pontos substantivos em aberto dentro do boundary de `19.1`. Os temas adicionais de lifecycle seguem encaminhados para a `19.2`. ## Initializer Boundary Esta agenda também precisa deixar explícita a fronteira entre: 1. init da declaração `global`; 2. init por módulo; 3. init de projeto. Direção recomendada: - o initializer de `declare global` deve permanecer restrito e simples; - ele existe para materializar o valor inicial da storage de módulo; - ele não deve carregar lógica procedural maior nem depender de top-level `fn`; - lógica adicional de setup pertence ao init por módulo; - setup de programa pertence ao init de projeto. Com isso, a linha proposta fica: 1. init da global: permite primitivas, operações simples com valor, member access com valor nessa etapa, `new`, e leitura de outras globals compatíveis com o dep graph; 2. init do módulo: permite lógica adicional de conveniência e mutações nas globals do próprio módulo após a materialização inicial; 3. init do projeto: permite setup do projeto como um todo, depois do fechamento do estado de módulo necessário. ### Consequence for `fn` in Global Initializers Seguindo essa separação, esta agenda recomenda que: 1. calls para top-level `fn` não sejam permitidas em initializer de `global` em v1; 2. a necessidade de lógica mais rica seja absorvida pelo init de módulo discutido na `19.2`; 3. isso mantenha o dep graph de globals focado em materialização declarativa, não em execução procedural arbitrária. Também fica recomendado que, em v1: 1. `some(...)` e `none` não façam parte do initializer declarativo de `global`; 2. `if` e `switch` não sejam permitidos diretamente na declaração de `global`. ## Diagnostics Recommendation Esta agenda fecha o seguinte catálogo pequeno, forte e didático de diagnósticos obrigatórios. ### 1. Invalid Global Initializer Quando o initializer usar uma forma não admissível em v1, o compiler deve emitir um erro apontando a subexpressão inválida. Mensagem semântica recomendada: - `global initializer uses unsupported form` Exemplos de motivo associado: - top-level `fn` call not allowed in global initializer; - `some(...)` not allowed in global initializer; - `if` not allowed in global initializer. ### 2. Global Dependency Cycle Quando houver ciclo, o compiler deve diagnosticar o global owner local e, quando possível, renderizar o caminho canônico do ciclo. Mensagem semântica recomendada: - `global dependency cycle detected` Detalhe recomendado: - incluir o símbolo local que participa do ciclo; - incluir o caminho canônico quando disponível, por exemplo: `@project:A.seed -> @project:B.rng -> @project:C.config -> @project:A.seed` ### 3. Shadowing Requires Alias Quando um import introduzir nome que colide com `fn`, `service`, `global` ou `const` já visível, o compiler deve rejeitar e exigir alias explícito. Mensagem semântica recomendada: - `imported symbol shadows existing visible symbol; alias required` ### 4. Global Import Category Mismatch Se o barrel e a importação não preservarem corretamente a categoria declarativa `global`, o compiler deve rejeitar explicitamente em vez de tentar degradar para `const` ou valor genérico. Mensagem semântica recomendada: - `global import must resolve through a global barrel entry` Essa escolha existe para preservar: - clareza semântica; - diagnósticos mais simples; - e uma separação limpa entre storage initialization e lifecycle hooks. ## Forwarded To 19.2 Os seguintes temas surgiram desta agenda, mas pertencem ao boundary de lifecycle e devem ser tratados na `19.2`: 1. init por módulo como fase procedural separada do initializer declarativo de `global`; 2. init de projeto como fase distinta de coordenação final; 3. permissão de loops em init de módulo e init de projeto; 4. proibição de host calls por padrão durante init; 5. permissão apenas para host calls marcadas com atributo reservado `[InitAllowed]`; 6. validação compile-time dessa admissibilidade; 7. separação entre restrição normativa de host interaction e recomendação de design para manter bootstrap leve. ## Expected Spec Material Se esta agenda fechar, a propagação esperada atinge pelo menos: - `3. Core Syntax Specification.md` - `4. Static Semantics Specification.md` - `11. AST Specification.md` - `12. Diagnostics Specification.md` ## Non-Goals Esta agenda não deve: 1. definir boot ordering; 2. definir `[Init]` ou `[Frame]`; 3. definir wrapper published entrypoint; 4. definir posicionamento de `FRAME_RET`; 5. escolher a representação de IR/bytecode para globals. ## Next Step Depois de fechar esta agenda, abrir ou aprofundar: - `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`