# PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda ## Status Open ## Parent Agenda This agenda derives from: - `19. Globals, Synthetic Module Init, and FRAME_RET Agenda` Expected fixed input from previous stage: - `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` ## Purpose Define the observable lifecycle model of PBS once runtime globals exist. This agenda must close: - whether `[Init]` and `[Frame]` become official source markers; - the relationship between module init and program init; - boot one-shot behavior; - failure policy; - and the semantic role of the user's frame root. ## Domain Owner `docs/compiler/pbs` Este tema pertence ao domínio PBS porque define lifecycle observável da linguagem, não apenas mecanismo de backend. ## Context Depois que `declare global` existir como storage runtime de módulo, o compiler precisará definir: - quando os globals são materializados; - em que ordem isso acontece; - se existe um hook explícito de init de programa; - se existe um init procedural por módulo separado do initializer declarativo de `global`; - como a linguagem identifica o frame root do usuário; - e o que acontece quando o boot falha. Esta agenda ainda não decide a forma exata do wrapper published entrypoint nem o shape do IR. Ela define primeiro o comportamento observável que essas camadas posteriores terão de respeitar. ## Inputs Already Fixed Elsewhere Os seguintes inputs devem ser tratados como fechados ou fortemente estáveis aqui: - o modelo base de globals vindo de `19.1`; - o initializer declarativo de `global` permanece restrito a primitivas, `new` e leitura de outras globals compatíveis com o dep graph; - top-level `fn` não são permitidas em initializer de `global` em v1; - `FRAME_SYNC` permanece como safepoint normativo; - PBS v1 continua determinístico e single-threaded; - esta fase continua evitando mudanças novas no runtime. ## Decisions To Produce Esta agenda deve produzir direção suficiente para fechar: 1. se `[Init]` e `[Frame]` entram na surface oficial; 2. targets válidos, unicidade e assinaturas exigidas; 3. ordem entre module init, init de programa e frame; 4. política de boot one-shot; 5. política de falha; 6. papel semântico de `frame()` do usuário; 7. política de loops e host calls admissíveis durante init. ## Core Questions 1. PBS deve introduzir `[Init]` e `[Frame]` como atributos reservados? 2. `[Init]` deve ser permitido tanto por módulo quanto no init final de projeto? 3. `[Frame]` deve existir exatamente uma vez por programa? 4. `[Init]` deve existir no máximo uma vez por programa? 5. `[Init]` e `[Frame]` devem exigir assinatura fixa `fn ...() -> void`? 6. Todos os module inits devem rodar antes do `[Init]` do usuário? 7. A ausência de `[Init]` deve ser válida? 8. A ausência de `[Frame]` deve ser erro hard para programa executável? 9. Em caso de falha durante module init ou `[Init]`, o programa deve falhar definitivamente ou pode haver retry? 10. Qual é a definição semântica correta de `frame()` do usuário: root lógico do tick, callable publicado, ou apenas callable invocado por infraestrutura sintética futura? 11. Loops devem ser permitidos em init de módulo e init de projeto? 12. Host calls devem ser proibidas por padrão durante init? 13. Apenas host calls marcadas com `[InitAllowed]` devem ser admissíveis durante init? 14. Como a admissibilidade de `[InitAllowed]` é validada em compile time? ## Options ### Option A Introduzir `[Init]` e `[Frame]` como markers reservados explícitos, com assinaturas fixas, `[Init]` opcional por módulo e por projeto, `[Frame]` obrigatório e único por projeto executável, permitindo init procedural por módulo e mantendo política restritiva de host interaction durante init. ### Option B Introduzir apenas `[Frame]` e manter init inteiramente sintético, sem hook de programa do usuário nesta fase. ### Option C Manter lifecycle implícito, sem markers source-level, e continuar derivando entrypoint/configuração fora da linguagem. ## Tradeoffs ### Option A - Prós: - deixa lifecycle explícito na linguagem; - reduz dependência de configuração paralela; - dá base clara para wrapper, manifest e lowering posteriores. - Contras: - amplia a surface de atributos reservados; - exige validação de target, unicidade e assinatura. ### Option B - Prós: - escopo menor; - adia parte da discussão de init. - Contras: - resolve só metade do lifecycle; - pode forçar redesign quando o hook de init do usuário voltar. ### Option C - Prós: - menor custo imediato. - Contras: - mantém a autoridade do lifecycle fora da linguagem; - enfraquece a coerência da série 19. ## Recommendation Seguir com a **Option A**. Direção recomendada: 1. `[Init]` e `[Frame]` devem ser markers reservados explícitos; 2. `declare global` sempre lowera para o init sintético do módulo owner; 3. `[Init]` de módulo deve ser opcional e executar depois de todos os `declare global` do módulo; 4. o init de projeto deve seguir o mesmo modelo, mas associado ao projeto que contém o `[Frame]`; 5. `[Init]` de projeto deve ser opcional; 6. `[Frame]` deve ser obrigatório para programa executável e único por projeto; 7. `[Init]` e `[Frame]` devem exigir assinatura fixa `fn name() -> void`; 8. boot deve ser one-shot; 9. falha de boot deve seguir direção fail-fast, salvo argumento forte em contrário; 10. loops devem ser permitidos em init de módulo e init de projeto; 11. host calls devem ser proibidas por padrão durante init; 12. apenas host calls com atributo reservado `[InitAllowed]` devem ser admissíveis durante init; 13. `[InitAllowed]` é atributo reservado de SDK, não userland. ## Additional Lifecycle Concerns Esta agenda também precisa fechar a separação entre três camadas de bootstrap: 1. initializer declarativo de `global`; 2. init por módulo; 3. init de projeto. Direção herdada da `19.1`: - `global` materializa storage inicial; - init de módulo executa lógica procedural de conveniência sobre globals do próprio módulo; - init de projeto executa coordenação final do programa. Com esse modelo: - loops são legítimos em init de módulo e init de projeto, especialmente para carga e preparação de arrays e estruturas derivadas; - a restrição normativa mais forte deve cair sobre host interaction; - "bootstrap leve" continua sendo recomendação de design, não um limite impossível de verificar semanticamente. ## Current Direction Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte: 1. `[Init]` e `[Frame]` entram como atributos reservados explícitos; 2. `declare global X: T = expr;` lowera sempre para o init sintético do módulo owner; 3. cada arquivo pode declarar opcionalmente um `[Init]` procedural próprio; 4. o `[Init]` de cada arquivo roda sempre depois das globals daquele arquivo e participa do init sintético do módulo; 5. existe também um init de projeto opcional, que é o `[Init]` associado ao projeto que contém o `[Frame]`; 6. `[Frame]` é obrigatório e único por projeto executável; 7. `[Init]` e `[Frame]` seguem a forma recomendada: ```pbs [Init] fn init() -> void { ... } ``` ```pbs [Frame] fn frame() -> void { ... } ``` 8. a assinatura exigida é sempre `fn name() -> void`; 9. loops são permitidos nos inits; 10. host calls são proibidas por padrão durante init; 11. apenas host calls com `[InitAllowed]` podem ser usadas durante init; 12. `[InitAllowed]` pertence às superfícies reservadas de SDK, não a userland; 13. falha de boot é fail-fast com mensagem coerente. Também fica fechada a seguinte regra operacional: 14. o `[Init]` que estiver no mesmo arquivo que o `[Frame]` é o init de projeto; 15. `[Init]` em outros arquivos continuam sendo init de módulo; 16. `[Frame]` e o init de projeto devem ser co-localizados no mesmo arquivo por decisão deliberada de source organization. 17. cada arquivo pode declarar no máximo um `[Init]`; 18. cada módulo possui exatamente um init sintético de módulo, dentro do qual os inits por arquivo são ordenados e compostos; 19. a distinção entre init de módulo e init de projeto é apenas de ordenação e papel semântico, não de surface diferente; 20. como consequência, existe no máximo um `[Init]` de projeto por projeto executável. 21. arquivos sem globals podem declarar um `[Init]`, desde que continuem respeitando a regra de no máximo um `[Init]` por arquivo; 22. o `project init` segue exatamente a mesma assinatura `fn init() -> void`. ## Lifecycle Order Direction Esta agenda também já aponta para a seguinte ordem lógica de bootstrap: 1. materialização das globals de cada arquivo do módulo conforme a ordem determinada pelo dependency graph; 2. execução do `[Init]` daquele arquivo, quando existir; 3. composição desses passos em um único init sintético do módulo; 4. depois do fechamento dos módulos necessários, execução do `[Init]` de projeto, quando existir; 5. entrada no primeiro `frame()`. Lendo essa ordem de forma operacional: 1. cada arquivo inicializa suas próprias globals; 2. cada arquivo pode então executar seu `[Init]` opcional; 3. tudo isso se aninha dentro de um único init sintético por módulo; 4. o `[Init]` co-localizado com `[Frame]` é elevado a init de projeto por ordem e papel semântico. Também fica fechada a seguinte direção adicional: 5. a ordem entre arquivos do mesmo módulo deve seguir a ordem derivada do `DependencyGraphAnaliser` das globals; 6. quando dois arquivos não tiverem dependência entre si, o compiler deve usar uma ordem determinística estável. ## Remaining Open Points Com a direção já consolidada nesta agenda, não restam pontos substantivos em aberto dentro do boundary de `19.2`. Os temas seguintes agora pertencem à `19.3`. ## InitAllowed Direction Esta agenda fecha também o seguinte shape normativo inicial para `[InitAllowed]`: 1. `[InitAllowed]` é um atributo reservado sem argumentos em v1; 2. ele é válido apenas em host methods de SDK; 3. ele é inválido em userland; 4. ele é inválido em `fn`, `global`, `service` e demais superfícies que não sejam host methods de SDK; 5. seu papel é exclusivamente validar, em compile time, quais host calls podem aparecer durante init; 6. ele não faz distinção entre init de módulo e init de projeto; 7. a diferença entre esses inits é de ordenação e papel semântico, não de permissão separada de host call. Exemplo recomendado: ```pbs declare host Runtime { [Host(module = "runtime", name = "random_u32", version = 1)] [Capability(name = "runtime")] [InitAllowed] fn random_u32() -> int; } ``` ## Diagnostics Recommendation Esta agenda fecha o seguinte catálogo mínimo de diagnósticos de lifecycle e bootstrap. ### 1. Project Init Must Be Colocated With Frame Mensagem semântica recomendada: - `project init must be colocated with frame` ### 2. Multiple Project Init Functions Detected Mensagem semântica recomendada: - `multiple project init functions detected` ### 3. Multiple Frame Functions Detected Mensagem semântica recomendada: - `multiple frame functions detected` ### 4. Missing Frame Function For Executable Project Mensagem semântica recomendada: - `missing frame function for executable project` ### 5. Invalid Init Signature Mensagem semântica recomendada: - `init function must have signature fn name() -> void` ### 6. Invalid Frame Signature Mensagem semântica recomendada: - `frame function must have signature fn name() -> void` ### 7. Host Call Not Allowed During Init Mensagem semântica recomendada: - `host call not allowed during init` ### 8. Invalid InitAllowed Target Mensagem semântica recomendada: - `InitAllowed is valid only on SDK host methods` ### 9. Boot Failed During Module Init Mensagem semântica recomendada: - `boot failed during module init` ### 10. Boot Failed During Project Init Mensagem semântica recomendada: - `boot failed during project init` ### 11. Multiple Module Init Functions Detected Mensagem semântica recomendada: - `multiple module init functions detected` ### 12. Init Attribute Target Invalid Mensagem semântica recomendada: - `Init attribute target invalid` ## Expected Spec Material Se esta agenda fechar, a propagação esperada atinge pelo menos: - `3. Core Syntax Specification.md` - `4. Static Semantics Specification.md` - `9. Dynamic Semantics Specification.md` - `12. Diagnostics Specification.md` ## Non-Goals Esta agenda não deve: 1. decidir o nome físico do wrapper published entrypoint; 2. decidir o nome físico do entrypoint no manifest; 3. definir shape de IR; 4. definir como `FRAME_RET` será reposicionado materialmente. ## Next Step Depois de fechar esta agenda, abrir ou aprofundar: - `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`