diff --git a/docs/compiler/pbs/agendas/19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md b/docs/compiler/pbs/agendas/19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md index 26264557..40d4b5fa 100644 --- a/docs/compiler/pbs/agendas/19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md +++ b/docs/compiler/pbs/agendas/19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md @@ -4,6 +4,26 @@ Open +## Purpose + +Define how PBS should introduce runtime globals and lifecycle-driven executable bootstrap without changing the runtime contract in this phase. + +This document is the umbrella agenda for topic `19`. + +It exists to: + +- keep the full problem framed in one place; +- define the dependency order between discussions; +- prevent later discussions from re-opening earlier boundaries casually; +- and provide the parent reference for any follow-up agendas created under this topic. + +This agenda must converge on: + +- the source-level model for mutable module storage; +- the lifecycle model for module init, optional program init, and frame execution; +- the ownership of `FRAME_RET` once the published entrypoint stops being the user's `frame()` directly; +- the migration path from explicit `FrontendSpec` entrypoint configuration to source-derived PBS entrypoint discovery. + ## Domain Owner `docs/compiler/pbs` @@ -66,10 +86,10 @@ O cenário motivador é permitir globals de módulo no PBS sem exigir, nesta fas Também queremos aproveitar essa discussão para mover a detecção de entrypoint para a source language do PBS, usando atributos explícitos: ```pbs -[INIT] +[Init] fn init() -> void {} -[FRAME] +[Frame] fn frame() -> void {} ``` @@ -82,9 +102,9 @@ Essa direção permitiria ao frontend PBS: Esta agenda também cobre a extensão desse modelo para discutir: -1. se `[INIT]` deve existir apenas como hook final de programa ou também como surface por módulo; -2. qual é exatamente o comportamento operacional de `[FRAME]` como root lógico de frame do usuário; -3. como `[INIT]` por módulo, `[INIT]` final de programa, wrapper sintético e `FRAME_RET` se compõem sem ambiguidade. +1. se `[Init]` deve existir apenas como hook final de programa ou também como surface por módulo; +2. qual é exatamente o comportamento operacional de `[Frame]` como root lógico de frame do usuário; +3. como `[Init]` por módulo, `[Init]` final de programa, wrapper sintético e `FRAME_RET` se compõem sem ambiguidade. Isso empurra a solução para o compiler: @@ -95,6 +115,16 @@ Isso empurra a solução para o compiler: 5. detecção de `init`/`frame` a partir de atributos de source; 6. remoção progressiva das configs explícitas atuais em `FrontendSpec`. +## Inputs + +Relevant inputs already present in the repository: + +- `docs/vm-arch/ISA_CORE.md` already exposes `GET_GLOBAL` and `SET_GLOBAL`; +- `docs/compiler/pbs/specs/13. Lowering IRBackend Specification.md` currently requires a canonical executable entrypoint to be declared through `FrontendSpec`; +- `docs/compiler/pbs/specs/7. Cartridge Manifest and Runtime Capabilities Specification.md` currently expects PBS v1 manifest `entrypoint` to align with frontend-declared `frame`. + +The discussion here must preserve compatibility with those contracts unless it explicitly proposes the propagation work needed to evolve them. + ## Core Questions 1. PBS deve introduzir `declare global` como declaração top-level distinta de `declare const`? @@ -102,10 +132,10 @@ Isso empurra a solução para o compiler: 3. O compiler deve sintetizar um module init por módulo que contenha `declare global`? 4. A inicialização deve rodar eager no boot lógico do programa ou lazy no primeiro frame? 5. Deve existir um `init()` custom do usuário que roda depois de todos os module inits e antes do primeiro `frame()`? -6. O PBS deve introduzir atributos explícitos `[INIT]` e `[FRAME]` para identificar as funções corretas do usuário? +6. O PBS deve introduzir atributos explícitos `[Init]` e `[Frame]` para identificar as funções corretas do usuário? 7. A descoberta de entrypoint no frontend PBS deve deixar de depender de configuração explícita em `FrontendSpec`? -8. `[INIT]` deve poder existir também em escopo/módulo de forma declarativa para orientar module init explícito, ou o compiler deve manter module init sempre totalmente sintético? -9. Qual é o contrato preciso de comportamento de `[FRAME]` no PBS: callable obrigatório, assinatura fixa, frequência esperada e relação com o frame lógico publicado? +8. `[Init]` deve poder existir também em escopo/módulo de forma declarativa para orientar module init explícito, ou o compiler deve manter module init sempre totalmente sintético? +9. Qual é o contrato preciso de comportamento de `[Frame]` no PBS: callable obrigatório, assinatura fixa, frequência esperada e relação com o frame lógico publicado? 10. O published frame entrypoint deve passar a ser um wrapper sintético, por exemplo `__pbs_frame()`, em vez do `frame()` do usuário? 11. `FRAME_RET` deve continuar significando "fim do frame lógico" e apenas mudar de owner, saindo da função do usuário para o wrapper sintético? 12. Como o compiler deve tratar ordem topológica, dependências e ciclos entre globals de módulos distintos? @@ -123,11 +153,31 @@ Os seguintes pontos já parecem fixos ou fortemente estabelecidos e não devem s - o frontend PBS hoje ainda carrega configuração explícita de entrypoint fora da source language; - nesta fase queremos evitar mudanças novas no runtime e concentrar a evolução no compiler. +## Decisions To Produce + +Como umbrella agenda, esta agenda não deve tentar fechar toda a solução normativa de uma vez. + +Ela deve sair com: + +1. a decomposição oficial do tema em discussões derivadas; +2. a ordem canônica dessas discussões; +3. os inputs e outputs esperados de cada boundary; +4. a lista de artefatos que não podem ser editados antes do boundary anterior fechar. + +Depois que as discussões derivadas fecharem, o conjunto deve produzir direção suficiente para virar uma `decision` cobrindo pelo menos: + +1. a surface syntax e o modelo semântico de `declare global`; +2. o modelo de bootstrap entre module init sintético, `[Init]` de programa e `[Frame]`; +3. o owner real do frame lógico publicado e o ponto correto de emissão de `FRAME_RET`; +4. a política de descoberta de entrypoint a partir da source language do PBS; +5. a política de ordenação, ciclos e falhas para globals e module init; +6. a política de imports/exports para globals entre módulos. + ## Options ### Option A -Adicionar `declare global`, introduzir `[INIT]` e `[FRAME]` como superfícies explícitas para lifecycle/entrypoint, discutir `[INIT]` final vs `[INIT]` por módulo, gerar module init sintético por módulo, gerar wrapper sintético de frame published entrypoint e mover o `FRAME_RET` para esse wrapper. +Adicionar `declare global`, introduzir `[Init]` e `[Frame]` como superfícies explícitas para lifecycle/entrypoint, discutir `[Init]` final vs `[Init]` por módulo, gerar module init sintético por módulo, gerar wrapper sintético de frame published entrypoint e mover o `FRAME_RET` para esse wrapper. ### Option B @@ -155,7 +205,7 @@ Adicionar `declare global`, mas exigir lazy materialization no primeiro acesso e - remove um acoplamento indesejado entre frontend PBS e configuração manual de entrypoint em `FrontendSpec`. - Contras: - exige nova modelagem no compiler para globals, init synthesis e published frame wrapper; - - exige regras novas de atributo e validação de unicidade para `[INIT]` e `[FRAME]`; + - exige regras novas de atributo e validação de unicidade para `[Init]` e `[Frame]`; - obriga decisão clara sobre ordem, ciclos e falhas; - muda a relação atual entre `frame()` do usuário e entrypoint publicado. @@ -201,86 +251,439 @@ Direção recomendada para discussão: 2. permitir inicializadores executáveis lowerables, incluindo `new` e calls compatíveis com o modelo de lowering executável; 3. sintetizar um module init por módulo owner de globals; 4. ordenar os module inits de forma determinística e topológica; -5. introduzir `[INIT]` e `[FRAME]` como superfícies explícitas de detecção do init/frame do usuário; +5. introduzir `[Init]` e `[Frame]` como superfícies explícitas de detecção do init/frame do usuário; 6. remover da evolução do PBS a dependência de configuração explícita de entrypoint em `FrontendSpec`, migrando a seleção para a análise da source language; -7. discutir explicitamente se `[INIT]` por módulo será uma surface do usuário ou se módulo continuará com init apenas sintético; +7. discutir explicitamente se `[Init]` por módulo será uma surface do usuário ou se módulo continuará com init apenas sintético; 8. permitir um `init()` custom opcional do usuário, executado depois de todos os module inits; 9. publicar um wrapper sintético de frame, por exemplo `__pbs_frame()`, como verdadeiro frame root; 10. tratar `frame()` do usuário como callable normal invocado por esse wrapper; 11. manter `FRAME_RET` como marcador do fim do frame lógico, mas emitido no wrapper sintético publicado em vez de no `frame()` do usuário; 12. manter toda a primeira fase restrita ao compiler e ao backend pipeline, sem novos requisitos para o runtime além dos contratos já existentes. +Essa recomendação ainda deixa alguns pontos para fechamento na `decision`, mas já estabelece um shape arquitetural coerente: + +- storage global pertence ao módulo owner; +- bootstrap observável pertence ao compiler, não ao runtime; +- `frame()` do usuário deixa de ser o entrypoint publicado e passa a ser o root lógico invocado pelo wrapper; +- `FRAME_RET` continua significando fim do frame lógico, apenas com novo owner sintético; +- a seleção de entrypoint deixa de ser configuração paralela e vira semântica explícita da linguagem. + ## Open Questions 1. O nome surface deve ser exatamente `declare global`, ou outra forma top-level? 2. Globals devem exigir initializer obrigatório em v1, ou existirão shells reservados parecidos com builtin const? -3. `[INIT]` e `[FRAME]` devem ser atributos reservados do PBS ou outra forma de marker surface? -4. `[INIT]` deve exigir assinatura fixa `fn init() -> void`? -5. `[FRAME]` deve exigir assinatura fixa `fn frame() -> void`? -6. Deve existir no máximo um `[INIT]` e um `[FRAME]` por programa, por módulo owner, ou por outro escopo? -7. `[INIT]` por módulo deve ser permitido como surface explícita do usuário ou ser non-goal da primeira fase? -8. Se `[INIT]` por módulo existir, ele roda antes ou no lugar do module init sintético de globals? -9. A ausência de `[INIT]` deve ser válida, mas a ausência de `[FRAME]` deve ser erro hard? -10. O `init()` do usuário pertence apenas ao módulo owner do published frame entrypoint ou pode vir de qualquer módulo visível? -11. O compiler deve sintetizar `boot_done` como global oculto de programa, local estático do wrapper, ou outro mecanismo interno? -12. Em caso de trap/falha durante module init ou `init()`, o próximo frame deve tentar novamente ou o programa deve entrar em estado terminal? -13. Módulos podem ler globals de outros módulos durante init, desde que a ordem topológica já os tenha materializado? -14. Como diagnosticar ciclos entre globals intra-módulo e inter-módulo de forma didática? -15. Qual é a semântica exata de `[FRAME]` para o compiler e para a documentação da linguagem: raiz de tick, raiz de frame lógico, ou apenas callable nomeado para publicação? -16. O barrel/export de `global` deve seguir a mesma superfície de `const`, ou precisamos de distinção explícita na documentação/export metadata? -17. O `IRBackend` deve ganhar instruções explícitas `GET_GLOBAL`/`SET_GLOBAL`, ou globals devem ser lowered por outra representação intermediária antes de virar bytecode? -18. Em que etapa da migração a configuração explícita atual em `FrontendSpec` deixa de existir por completo? +3. `[Init]` e `[Frame]` devem ser atributos reservados do PBS ou outra forma de marker surface? +4. `[Init]` deve exigir assinatura fixa `fn init() -> void`? +5. `[Frame]` deve exigir assinatura fixa `fn frame() -> void`? +6. Deve existir no máximo um `[Init]` e um `[Frame]` por programa, por módulo owner, ou por outro escopo? +7. Module init deve permanecer sempre sintético em v1, ou o usuário pode anotar hooks por módulo em alguma forma futura? +8. A política de falha de init deve ser fail-fast definitivo no boot, ou existe algum caso legítimo para retry controlado? +9. Reexport de globals entre módulos deve preservar identidade de storage do owner original ou materializar aliases/import bindings sem storage próprio? +10. O manifest `entrypoint` deve continuar expondo `frame` por compatibilidade nominal ou passar a refletir o símbolo sintético publicado? -## Expected Decisions to Produce +## Main Difficulties -1. A surface language e a gramática de `declare global`. -2. A surface language e a política de detecção de entrypoint via `[INIT]` e `[FRAME]`. -3. O papel de `[INIT]` por módulo versus module init totalmente sintético. -4. O contrato semântico de globals de módulo em PBS. -5. O modelo de inicialização sintética por módulo. -6. O contrato de `init()` custom do usuário. -7. A semântica comportamental de `[FRAME]` como root lógico do usuário. -8. A política de ordering e ciclo para init/global dependencies. -9. O novo owner do `FRAME_RET` no pipeline de frame. -10. O plano de remoção das configs explícitas atuais em `FrontendSpec`. -11. O recorte exato desta fase como mudança somente de compiler. +Os principais pontos de dificuldade desta agenda não são sintáticos; eles estão na composição entre contratos já existentes. + +### 1. `declare global` colide com o recorte atual de `declare const` + +Hoje a semântica estática do PBS fixa que: + +- `declare const` entra no value namespace; +- `declare const` não materializa storage mutável runtime; +- inicializadores de `declare const` pertencem a um subset estritamente compile-time; +- dependências entre `declare const` são acíclicas e resolvidas por análise de dependência, não por ordem textual. + +Introduzir `declare global` exige decidir o que é reaproveitado desse modelo e o que deixa de valer: + +- namespace e visibilidade podem reaproveitar parte do modelo atual; +- constant evaluation não pode ser reutilizada como está; +- o modelo de dependência deixa de ser apenas compile-time e passa a produzir efeitos runtime. + +### 2. A surface de atributos hoje tem um conjunto reservado fechado + +O PBS já trata atributos como metadata compile-time com lowering explícito apenas quando outra spec define esse efeito. + +Isso é favorável para `[Init]` e `[Frame]`, mas cria trabalho em três frentes: + +- reservar novos atributos no conjunto normativo; +- definir targets válidos, unicidade e diagnóstico; +- definir o lowering sem deixar atributos "soltos" como metadata sem efeito operacional claro. + +### 3. O entrypoint publicado hoje ainda está acoplado ao `FrontendSpec` + +Existe uma obrigação atual em `13. Lowering IRBackend Specification.md` para o frontend declarar um `EntrypointRef` canônico. + +A agenda 19 quer mover a descoberta para a source language, mas isso abre uma transição delicada: + +- PBS precisa derivar esse `EntrypointRef` da source language; +- o contrato de `IRBackend` não deve perder determinismo; +- a migração não pode deixar coexistirem por muito tempo duas autoridades independentes para entrypoint. + +### 4. O manifest ainda assume `frame` como callable publicado + +`7. Cartridge Manifest and Runtime Capabilities Specification.md` hoje sugere alinhamento nominal entre manifest `entrypoint` e callable `frame`. + +Se o compiler publicar `__pbs_frame()`: + +- ou o manifest passa a refletir o símbolo sintético real; +- ou o manifest preserva um nome lógico enquanto o símbolo real do artefato muda; +- ou a pipeline passa a distinguir entrypoint lógico e entrypoint físico. + +Sem fechar isso, a solução de wrapper fica tecnicamente incompleta. + +### 5. `FRAME_RET` hoje coincide com o fim do callable do usuário + +O ponto difícil não é só "mover um opcode". É redefinir qual callable delimita semanticamente o frame lógico: + +- `frame()` do usuário continua sendo apenas código de frame; +- o wrapper sintético vira o owner do frame published entrypoint; +- `FRAME_RET` continua com o mesmo significado semântico, mas sua posição material muda. + +Isso afeta lowering, testes de conformance e a forma de explicar o modelo da linguagem. + +### 6. Globals intermodulares introduzem um problema novo de identidade e ordem + +Hoje `declare const` exportado via `mod.barrel` é simples porque não há storage mutável compartilhado. + +Com `declare global`, a agenda precisa fechar: + +- quem é o owner real do storage; +- o que um import recebe: binding para o owner ou cópia/snapshot; +- como ciclos entre módulos são detectados; +- se init pode ler globals de módulos predecessores; +- qual é a ordem determinística entre módulos quando há efeitos de inicialização. + +### 7. A política de falha deixa de ser apenas rejeição de build + +Hoje boa parte do pipeline falha antes da emissão. + +Com module init e `init()` do usuário, surge um problema runtime-observable: + +- o que acontece quando o boot parcial falha; +- se o programa entra em estado terminal; +- se existe retry; +- como isso se relaciona com o fato de `FRAME_SYNC` permanecer o safepoint normativo. + +## Work Boundaries + +Para manter a agenda executável e evitar mistura de artefatos, o trabalho pode ser separado nos seguintes boundaries. + +### Boundary A. Surface Language and AST + +Owner principal: syntax + AST. + +Inclui: + +- gramática de `declare global`; +- superfície de atributos `[Init]` e `[Frame]`; +- targets permitidos desses atributos; +- novos nós ou flags obrigatórios no AST para globals e lifecycle markers. + +Pergunta de fechamento: + +- o parser apenas aceita as superfícies ou já impõe parte das restrições estruturais de target/shape? + +### Boundary B. Static Semantics and Linking + +Owner principal: static semantics + linking. + +Inclui: + +- namespace e visibilidade de `declare global`; +- regras de initializer obrigatório ou opcional; +- compatibilidade de tipo do initializer; +- unicidade e assinatura válida para `[Init]` e `[Frame]`; +- regras de import/export/barrel para globals; +- detecção de ciclos de dependência entre globals; +- política de identidade do storage através de imports e reexports. + +Pergunta de fechamento: + +- globals entram no mesmo value namespace de `let`/`declare const` ou exigem distinção semântica adicional apesar do namespace compartilhado? + +### Boundary C. Dynamic Semantics and Lifecycle Model + +Owner principal: dynamic semantics. + +Inclui: + +- ordem observável entre module init, `[Init]` de programa e `[Frame]`; +- definição de boot one-shot; +- política de falha de init; +- contrato semântico de `[Frame]` como raiz lógica do tick/frame do usuário; +- relação entre frame lógico do usuário e entrypoint efetivamente publicado. + +Pergunta de fechamento: + +- o programa tem dois conceitos distintos, `logical frame root` e `published runtime entrypoint`, ou a spec tenta esconder essa distinção do usuário? + +### Boundary D. IR and Backend Lowering + +Owner principal: lowering executável. + +Inclui: + +- representação de globals no `IRBackend` ou boundary imediatamente anterior; +- synthesis de module init; +- synthesis de wrapper published entrypoint; +- materialização do guard one-shot de boot; +- reposicionamento do `FRAME_RET`; +- preservação do `EntrypointRef` canônico para o restante do backend. + +Pergunta de fechamento: + +- globals entram como primitivo explícito no IR ou aparecem apenas em lowering posterior antes de IRVM/bytecode? + +### Boundary E. Artifact and Manifest Publication + +Owner principal: artifact contracts. + +Inclui: + +- nome do entrypoint exposto no manifest; +- relação entre callable do usuário, símbolo sintético e entrypoint published; +- compatibilidade com o contrato atual do cartridge manifest; +- possíveis ajustes na leitura de tooling sobre qual callable é o entrypoint "real". + +Pergunta de fechamento: + +- o manifest publica identidade lógica da linguagem ou identidade física do artefato executável? + +### Boundary F. Diagnostics and Conformance + +Owner principal: diagnostics + fixture model. + +Inclui: + +- diagnósticos para target inválido de `[Init]` e `[Frame]`; +- duplicidade ou ausência de markers obrigatórios; +- initializer inválido de `declare global`; +- ciclos intra/inter-módulo; +- imports/reexports ilegais de globals; +- fixture coverage para init ordering, wrapper published entrypoint e `FRAME_RET`. + +Pergunta de fechamento: + +- quais erros pertencem ao frontend/linking e quais só podem ser cobertos por fixtures de toolchain completo? + +## Discussion Order + +As discussões derivadas desta umbrella agenda devem seguir a ordem abaixo. + +O objetivo da ordem é simples: + +- fechar primeiro autoridade semântica e surface; +- depois fechar comportamento observável; +- só então descer para lowering, artefato publicado e conformance. + +### Stage 1. Globals Surface and Static Identity + +Boundary owner: + +- `Boundary A. Surface Language and AST` +- `Boundary B. Static Semantics and Linking` + +Esta discussão deve fechar primeiro porque todas as outras dependem da definição do que é um global no PBS. + +Ela precisa decidir: + +- a forma exata de `declare global`; +- initializer obrigatório ou opcional; +- namespace, visibilidade e barrel/export/import; +- identidade do storage owner; +- política de reexport; +- ciclos e dependências entre globals em nível de linking/static semantics. + +Sem esse fechamento: + +- lifecycle ainda não sabe o que precisa inicializar; +- lowering ainda não sabe que entidade precisa materializar; +- manifest ainda não sabe se está publicando símbolos que dependem de storage global importado. + +### Stage 2. Lifecycle Markers and Program Bootstrap Semantics + +Boundary owner: + +- `Boundary C. Dynamic Semantics and Lifecycle Model` + +Esta discussão vem depois de Stage 1 porque init e frame só fazem sentido quando o modelo de globals já estiver fixado. + +Ela precisa decidir: + +- se `[Init]` e `[Frame]` entram como superfícies oficiais; +- unicidade e assinatura desses markers; +- ordem entre module init, `[Init]` de programa e `[Frame]`; +- política de boot one-shot; +- política de falha; +- papel semântico exato de `frame()` do usuário. + +Sem esse fechamento: + +- o wrapper sintético não tem contrato observável estável; +- `FRAME_RET` não tem owner definido; +- qualquer modelagem de IR corre risco de materializar o comportamento errado. + +### Stage 3. Published Entrypoint, Wrapper Ownership, and `FRAME_RET` + +Boundary owner: + +- `Boundary C. Dynamic Semantics and Lifecycle Model` +- `Boundary D. IR and Backend Lowering` +- `Boundary E. Artifact and Manifest Publication` + +Esta discussão depende de Stage 2 porque ela não decide mais "o que é lifecycle"; ela decide como lifecycle é publicado. + +Ela precisa decidir: + +- se o published entrypoint é um wrapper sintético; +- qual é a relação entre `frame()` do usuário e esse wrapper; +- onde `FRAME_RET` passa a ser emitido; +- se o manifest expõe entrypoint lógico, entrypoint físico ou ambos; +- como o `EntrypointRef` do frontend continua determinístico durante a transição. + +Sem esse fechamento: + +- não existe contrato estável para lowering final; +- specs de manifest e `IRBackend` ficam em tensão; +- o tooling pode continuar com duas autoridades concorrentes para entrypoint. + +### Stage 4. IR Representation and Lowering Mechanics + +Boundary owner: + +- `Boundary D. IR and Backend Lowering` + +Esta discussão vem depois de Stage 3 porque a forma do IR depende do que exatamente precisa ser publicado e executado. + +Ela precisa decidir: + +- se globals entram como primitivo explícito do IR ou apenas em lowering posterior; +- como module init é representado; +- como o guard de boot é materializado; +- como o wrapper published entrypoint é emitido; +- como `FRAME_RET` é reposicionado mantendo o mesmo significado. + +Sem esse fechamento: + +- código pode ser implementado cedo demais sobre contratos ainda móveis; +- a propagação para specs gerais de lowering fica prematura; +- testes de backend podem congelar um shape errado. + +### Stage 5. Diagnostics, Gates, and Conformance Coverage + +Boundary owner: + +- `Boundary F. Diagnostics and Conformance` + +Esta discussão deve vir por último porque ela consolida o que as anteriores já fixaram. + +Ela precisa decidir: + +- catálogo mínimo de diagnósticos novos; +- divisão entre erro de syntax/AST, linking/static semantics, lowering e toolchain; +- fixtures obrigatórios para globals, lifecycle, wrapper e entrypoint publication; +- critérios de aceite para a migração de `FrontendSpec` entrypoint config para source-derived entrypoint discovery. + +Fazer isso antes cria dois riscos: + +- congelar diagnósticos para regras ainda instáveis; +- ou escrever fixtures de conformance que depois precisam ser reabertas por mudança arquitetural. + +## Derived Agenda Outline + +Se quisermos quebrar a umbrella agenda em agendas filhas, a ordem recomendada é: + +1. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` +2. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda` +3. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda` +4. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda` +5. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda` + +Cada agenda filha deve declarar explicitamente: + +- que deriva da umbrella agenda `19`; +- quais stages anteriores já são input fixo; +- e quais outputs ela precisa entregar para a agenda seguinte. + +## Boundary Locking Rules + +Para evitar que discussões posteriores prejudiquem as anteriores, esta umbrella agenda fixa as seguintes regras de sequenciamento: + +1. `19.2` não redefine surface syntax ou identidade de globals já fechadas em `19.1`. +2. `19.3` não redefine o significado semântico de `[Init]`, `[Frame]` ou boot ordering já fechados em `19.2`. +3. `19.4` não reabre decisões de linguagem ou de lifecycle; ela apenas escolhe a representação e o mecanismo de lowering compatíveis com elas. +4. `19.5` não reabre arquitetura; ela consolida diagnostics, manifest propagation e coverage. +5. Qualquer ponto que force reabertura de stage anterior deve voltar explicitamente para a agenda filha owner correta, em vez de ser resolvido informalmente na etapa posterior. + +## Likely Propagation Targets + +Mesmo sem virar `decision` ainda, esta agenda já mostra impacto provável nos seguintes artefatos. + +### PBS Specs + +- `3. Core Syntax Specification.md` +- `4. Static Semantics Specification.md` +- `9. Dynamic Semantics Specification.md` +- `11. AST Specification.md` +- `12. Diagnostics Specification.md` +- `13. Lowering IRBackend Specification.md` +- `7. Cartridge Manifest and Runtime Capabilities Specification.md` + +### Cross-Domain / VM Architecture + +- `docs/vm-arch/ISA_CORE.md` provavelmente não precisa mudar em capability, mas precisa ser referenciado explicitamente como base de `GET_GLOBAL`/`SET_GLOBAL`; +- specs gerais de lowering fora de `docs/compiler/pbs` podem precisar propagação posterior se `IRBackend` ganhar representação explícita de globals ou novo contrato para entrypoint published. + +### Compiler / Implementation Areas + +- parser e AST model; +- linking/resolution; +- static semantics; +- IR model do frontend PBS; +- executable lowering para `IRBackend` e `IRVM`; +- montagem do manifest/cartridge metadata; +- suites de fixture de frontend, lowering e toolchain. + +## Boundary Risks + +Se os boundaries acima não forem respeitados, os riscos mais prováveis são: + +1. criar `declare global` como açúcar superficial sem lifecycle coerente; +2. introduzir `[Init]` e `[Frame]` sem autoridade clara sobre `FrontendSpec`; +3. mover `FRAME_RET` sem redefinir com precisão o owner do frame lógico; +4. resolver globals intra-módulo mas deixar imports/reexports semanticamente ambíguos; +5. fechar a solução do compiler sem fechar o contrato do manifest; +6. misturar nesta agenda decisões de produto/runtime que deveriam continuar fora de escopo. ## Expected Spec Material -- atualização da Core Syntax specification para `declare global`; -- atualização da Core Syntax specification para `[INIT]` e `[FRAME]`; -- atualização da Static Semantics specification para typing, visibility e rules de init/global; -- atualização da Dynamic Semantics specification para lifecycle de globals e boot one-shot; -- atualização da Lowering spec para globals, module init synthesis, entrypoint detection e published frame wrapper; -- eventual atualização de AST/IR contracts se essas superfícies forem documentadas. +Se esta agenda virar `decision`, a propagação esperada deve atingir pelo menos: + +- spec de declarações top-level do PBS para introduzir `declare global`; +- spec de lifecycle/entrypoint attributes para `[Init]` e `[Frame]`; +- spec de lowering executável/`IRBackend` para module init synthesis, wrapper published entrypoint e ownership de `FRAME_RET`; +- spec de cartridge manifest para esclarecer a relação entre entrypoint lógico do usuário e entrypoint publicado no artefato; +- diagnósticos de validação para unicidade, assinatura inválida, ciclos de init e uso incorreto de globals. ## Non-Goals -- redefinir a VM para adicionar uma nova capacidade de globals; -- introduzir um novo hook explícito de runtime nesta fase; -- redesenhar todo o lifecycle de cartridge/firmware fora do que o compiler já publica como entrypoint; -- resolver lazy module loading ou hot reload; -- manter indefinidamente configuração duplicada de entrypoint em `FrontendSpec` e na source language; -- projetar persistência/snapshot/save-state de globals como parte desta discussão inicial. +Esta agenda não deve: -## Next Step Suggested +1. redesenhar o runtime ou introduzir novas instruções de VM; +2. escrever a spec normativa final de globals e lifecycle; +3. redefinir o modelo geral de módulos do compiler fora do necessário para globals/init; +4. resolver todos os possíveis hooks futuros de programa além de `[Init]` e `[Frame]`; +5. discutir otimizações de performance de init além do necessário para garantir semântica determinística. -Converter esta agenda em uma `decision` do domínio `compiler/pbs` fechando: +## Next Step -1. a forma de `declare global`; -2. a superfície `[INIT]`/`[FRAME]` e a nova detecção de entrypoints; -3. o modelo de module init sintético; -4. o papel do `init()` do usuário; -5. o published frame wrapper; -6. o reposicionamento do `FRAME_RET`; -7. a remoção da configuração explícita atual em `FrontendSpec`. +Usar esta agenda como parent reference e abrir as agendas filhas na ordem abaixo: -Depois disso, abrir um `pull-request/plan` que separe explicitamente: +1. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` +2. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda` +3. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda` +4. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda` +5. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda` -1. parser/AST; -2. semântica de atributos `[INIT]`/`[FRAME]` e resolução de entrypoint; -3. semântica e barrel/export/import; -4. IR/backend model para globals; -5. synthesis de init e frame wrapper; -6. remoção das configs explícitas antigas no frontend registry/specs; -7. testes de regressão do pipeline compilador -> IR -> bytecode. +Somente depois do fechamento dessas agendas derivadas esta linha deve virar uma `decision` consolidada em `docs/compiler/pbs/decisions`. diff --git a/docs/compiler/pbs/agendas/19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md b/docs/compiler/pbs/agendas/19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md new file mode 100644 index 00000000..a820bedf --- /dev/null +++ b/docs/compiler/pbs/agendas/19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md @@ -0,0 +1,406 @@ +# 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` diff --git a/docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md b/docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md new file mode 100644 index 00000000..d366321a --- /dev/null +++ b/docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md @@ -0,0 +1,361 @@ +# 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` diff --git a/docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md b/docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md new file mode 100644 index 00000000..5212cda3 --- /dev/null +++ b/docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md @@ -0,0 +1,203 @@ +# Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda + +## Status + +Open + +## Parent Agenda + +This agenda derives from: + +- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda` + +Expected fixed inputs from previous stages: + +- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` +- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda` + +## Purpose + +Define how PBS lifecycle is published into the executable artifact once globals and lifecycle semantics are already fixed. + +This agenda must close: + +- whether the published entrypoint becomes a synthetic wrapper; +- the semantic and publication relationship between user `frame()` and the published entrypoint; +- the new owner of `FRAME_RET`; +- and the contract boundary between source-derived entrypoint discovery, `FrontendSpec`, and cartridge manifest publication. + +## Domain Owner + +`docs/compiler/pbs` + +Este tema pertence ao domínio PBS porque decide a fronteira entre semântica da linguagem, entrypoint publicado e artefato executável. + +## Context + +Se `frame()` do usuário deixar de ser o callable publicado diretamente, o compiler precisará publicar outro root executável. + +Isso abre quatro perguntas acopladas: + +- quem é o entrypoint físico do artefato; +- qual callable continua sendo o root lógico do código do usuário; +- onde `FRAME_RET` passa a ser emitido; +- e como manifest e `FrontendSpec` representam isso sem ambiguidade. + +Esta agenda existe para fechar esse contrato antes de discutir detalhe de representação de IR. + +## Inputs Already Fixed Elsewhere + +Os seguintes inputs devem ser tratados como fixos aqui: + +- o modelo de globals vindo de `19.1`; +- o modelo de lifecycle e markers vindo de `19.2`; +- `FRAME_RET` continua significando fim do frame lógico; +- o runtime continua esperando um entrypoint published por frame. + +## Decisions To Produce + +Esta agenda deve produzir direção suficiente para fechar: + +1. se o published entrypoint é um wrapper sintético; +2. qual é a relação entre `frame()` do usuário e esse wrapper; +3. onde `FRAME_RET` passa a viver; +4. como a autoridade de entrypoint sai de `FrontendSpec` e passa ao compiler PBS; +5. como o protocolo de runtime/manifest representa esse entrypoint. + +## Core Questions + +1. O compiler deve publicar um wrapper sintético como entrypoint real? +2. `frame()` do usuário deixa de ser o callable publicado e passa a ser apenas root lógico interno? +3. `FRAME_RET` deve ser emitido no wrapper, não mais no callable do usuário? +4. O compiler PBS deve se tornar a única autoridade para definir o entrypoint publicado? +5. O wrapper sintético deve ocupar protocolarmente o entrypoint físico `0`? +6. O campo `entrypoint` deve deixar de existir no `manifest.json` como estado alvo do protocolo? +7. Existe algum caso em que o wrapper não seja necessário depois de `19.2`? + +## Options + +### Option A + +Publicar um wrapper sintético como entrypoint físico, tratar `frame()` do usuário como root lógico interno, mover `FRAME_RET` para o wrapper, tornar o compiler PBS a autoridade exclusiva de entrypoint e fixar protocolarmente o entrypoint físico em `0`. + +### Option B + +Manter `frame()` do usuário como entrypoint publicado e tentar acoplar boot/lifecycle diretamente nele. + +### Option C + +Publicar wrapper sintético, mas manter `entrypoint` no manifest como autoridade nominal paralela. + +## Tradeoffs + +### Option A + +- Prós: + - separa lifecycle publicado do callable do usuário; + - acomoda boot one-shot de forma limpa; + - preserva o significado de `FRAME_RET` com owner mais correto. + - alinha melhor o protocolo físico do artefato com a política já existente de `func_id = 0` como entrypoint; + - remove autoridade duplicada entre compiler, manifest e `FrontendSpec`. +- Contras: + - exige trabalho claro de migração em manifest, runtime e `FrontendSpec`; + - torna a relação lógico/físico explicitamente dupla. + +### Option B + +- Prós: + - preserva a superfície atual de publicação. +- Contras: + - mistura responsabilidades demais no callable do usuário; + - enfraquece a clareza do lifecycle. + +### Option C + +- Prós: + - parece reduzir custo de transição imediata. +- Contras: + - mantém duas autoridades para entrypoint; + - cria dívida documental e de runtime desnecessária; + - enfraquece a ideia de entrypoint como protocolo fixo do artefato. + +## Recommendation + +Seguir com a **Option A**. + +## Current Direction + +Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte: + +1. o compiler deve publicar um wrapper sintético como entrypoint físico real; +2. esse wrapper deve conter: + - boot one-shot, + - os inits necessários apenas uma vez, + - a chamada ao `frame()` do usuário, + - e o `FRAME_RET` final; +3. `frame()` anotado com `[Frame]` permanece como root lógico do usuário; +4. o wrapper sintético é o root físico publicado; +5. `FRAME_RET` sai do final do `frame()` do usuário e passa a existir no wrapper; +6. `FrontendSpec` perde autoridade para referenciar quem é o entrypoint; +7. a autoridade de entrypoint fica outorgada exclusivamente ao compiler PBS; +8. o wrapper sintético deve ser compilado no entrypoint físico `0`; +9. o estado alvo do protocolo deve remover `entrypoint` do `manifest.json`; +10. o runtime/loader deve tratar o entrypoint como protocolo fixo do artefato, não como metadado nominal configurável no manifest. + +## Manifest and Runtime Direction + +Esta agenda também já aponta para a seguinte direção de contrato: + +1. o campo `entrypoint` deve deixar de existir no `manifest.json` como estado final do protocolo; +2. o runtime deve assumir protocolarmente o entrypoint físico `0`; +3. o compiler garante que esse índice `0` pertence ao wrapper sintético publicado; +4. export nominal do callable deixa de ser a autoridade de boot; +5. qualquer compatibilidade temporária com manifest nominal deve ser tratada apenas como transição, não como contrato final desejado. + +## Exports Boundary + +Esta agenda também fecha a seguinte separação: + +1. exports nominais de funções podem continuar existindo no artefato; +2. esses exports deixam de ser usados como autoridade de loader/boot; +3. boot passa a depender exclusivamente do entrypoint físico `0` publicado pelo compiler; +4. exports nominais permanecem apenas como superfície útil para tooling, debug, introspection e casos correlatos. + +## Remaining Open Points + +Com a direção acima, os pontos que ainda pedem fechamento real nesta agenda ficam reduzidos a: + +1. a forma de propagação normativa dessa mudança para specs gerais de bytecode, lowering e cartridge contract. + +## Runtime Propagation + +Esta agenda também deve referenciar explicitamente a discussão correspondente no domínio runtime: + +- `../runtime/docs/runtime/agendas/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md` + +Direção fechada desta agenda: + +1. não há linha de compatibilidade desejada como estado-alvo; +2. a remoção de `entrypoint` do runtime deve ser executada em prioridade alinhada ao compiler; +3. a agenda de runtime é o owner da discussão operacional de loader/VM/manifest no outro domínio. + +## Expected Spec Material + +Se esta agenda fechar, a propagação esperada atinge pelo menos: + +- `9. Dynamic Semantics Specification.md` +- `13. Lowering IRBackend Specification.md` +- `7. Cartridge Manifest and Runtime Capabilities Specification.md` +- `12. Diagnostics Specification.md` + +## Non-Goals + +Esta agenda não deve: + +1. escolher o encoding exato do wrapper no IR; +2. definir estrutura detalhada de module init lowering; +3. escrever fixtures completos de conformance. + +## Next Step + +Depois de fechar esta agenda, abrir ou aprofundar: + +- `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda` diff --git a/docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md b/docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md new file mode 100644 index 00000000..11e95101 --- /dev/null +++ b/docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md @@ -0,0 +1,147 @@ +# Globals and Lifecycle Lowering to IRBackend/IRVM Agenda + +## Status + +Open + +## Parent Agenda + +This agenda derives from: + +- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda` + +Expected fixed inputs from previous stages: + +- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` +- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda` +- `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda` + +## Purpose + +Define how the already-decided globals and lifecycle model are represented and lowered through the executable compiler pipeline. + +This agenda must close: + +- the representation boundary for globals; +- module init synthesis; +- boot guard materialization; +- wrapper lowering; +- and the executable path that preserves the chosen `FRAME_RET` ownership. + +## Domain Owner + +`docs/compiler/pbs` + +Este tema pertence ao domínio PBS, mas encosta diretamente nas specs gerais de lowering e nas interfaces entre frontend e backend. + +## Context + +Depois que surface, lifecycle e publication contract estiverem fechados, ainda restará decidir: + +- em que boundary globals passam a existir como entidade explícita; +- se `IRBackend` carrega globals diretamente ou só uma forma anterior; +- como module init sintético é representado; +- como o wrapper published entrypoint é emitido; +- como o guard one-shot de boot é materializado. + +Esta agenda é mecânica/arquitetural. Ela não deve reabrir decisões de linguagem. + +## Inputs Already Fixed Elsewhere + +Os seguintes inputs devem ser tratados como fixos aqui: + +- surface e identidade de globals vindas de `19.1`; +- lifecycle semântico vindo de `19.2`; +- owner do published entrypoint e de `FRAME_RET` vindo de `19.3`; +- `GET_GLOBAL` e `SET_GLOBAL` já existem na VM. + +## Decisions To Produce + +Esta agenda deve produzir direção suficiente para fechar: + +1. se globals entram explicitamente no `IRBackend` ou apenas em lowering posterior; +2. como module init é sintetizado; +3. como o guard one-shot de boot é materializado; +4. como o wrapper é lowered; +5. como `FRAME_RET` é preservado no ponto correto; +6. quais contracts gerais de lowering precisam propagação. + +## Core Questions + +1. `IRBackend` deve ganhar representação explícita para globals? +2. Se não, qual é o boundary intermediário responsável por materializá-los antes de `IRVM`? +3. Module init sintético é emitido como callable próprio por módulo? +4. O boot guard é global oculto, local estático de wrapper, ou outra forma interna? +5. O wrapper published entrypoint é um callable sintético explícito no graph do frontend? +6. Como manter attribution e diagnostics úteis para código sintético? +7. Que mudanças mínimas precisam acontecer em specs gerais fora de `docs/compiler/pbs`? + +## Options + +### Option A + +Dar representação explícita a globals e callables sintéticos já no boundary de `IRBackend`, preservando attribution e identidade suficientes para lowering posterior. + +### Option B + +Manter `IRBackend` sem globals explícitos e adiar essa materialização para um lowering mais baixo. + +### Option C + +Tratar globals como açúcar compilado diretamente para slots/ops sem entidade intermediária estável. + +## Tradeoffs + +### Option A + +- Prós: + - boundary mais explícito e testável; + - menor inferência textual em lowers posteriores; + - facilita explicar wrapper e init synthesis. +- Contras: + - aumenta o contrato do `IRBackend`; + - pode exigir propagação além do domínio PBS. + +### Option B + +- Prós: + - preserva o boundary atual por mais tempo. +- Contras: + - empurra complexidade para fases posteriores; + - dificulta conformance do shape intermediário. + +### Option C + +- Prós: + - menor aparente custo de modelagem. +- Contras: + - fraco para teste, attribution e manutenção; + - mistura lowering demais cedo. + +## Recommendation + +Seguir com a **Option A**, salvo impedimento forte de boundary cross-domain. + +## Expected Spec Material + +Se esta agenda fechar, a propagação esperada atinge pelo menos: + +- `13. Lowering IRBackend Specification.md` +- specs gerais de lowering/backend fora do domínio PBS, se necessário +- `12. Diagnostics Specification.md` + +## Non-Goals + +Esta agenda não deve: + +1. redefinir surface syntax; +2. redefinir lifecycle; +3. redefinir manifest publication; +4. fechar catálogo final de fixtures. + +## Next Step + +Depois de fechar esta agenda, abrir ou aprofundar: + +- `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda` + diff --git a/docs/compiler/pbs/agendas/19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md b/docs/compiler/pbs/agendas/19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md new file mode 100644 index 00000000..4c065aeb --- /dev/null +++ b/docs/compiler/pbs/agendas/19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md @@ -0,0 +1,133 @@ +# Diagnostics, Manifest Propagation, and Conformance Coverage Agenda + +## Status + +Open + +## Parent Agenda + +This agenda derives from: + +- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda` + +Expected fixed inputs from previous stages: + +- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda` +- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda` +- `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda` +- `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda` + +## Purpose + +Consolidate the propagation layer of topic `19` after the architectural decisions are already fixed. + +This agenda must close: + +- the diagnostics surface; +- manifest-facing propagation details; +- fixture and conformance coverage; +- and the acceptance gates for declaring topic `19` ready to become a decision plus implementation plan. + +## Domain Owner + +`docs/compiler/pbs` + +Este tema pertence ao domínio PBS, mas toca tanto specs normativas quanto critérios de teste e artefato publicado. + +## Context + +Depois que surface, lifecycle, published entrypoint e lowering estiverem fechados, ainda faltará consolidar: + +- quais erros novos são obrigatórios; +- em que fase cada erro aparece; +- como o manifest final reflete a arquitetura escolhida; +- e que coverage mínima de fixtures e gates garante que a série 19 ficou estável. + +Esta agenda é de consolidação. Ela não deve rediscutir a arquitetura central. + +## Inputs Already Fixed Elsewhere + +Os seguintes inputs devem ser tratados como fixos aqui: + +- shape de globals vindo de `19.1`; +- lifecycle vindo de `19.2`; +- publication contract vindo de `19.3`; +- lowering mechanics vindo de `19.4`. + +## Decisions To Produce + +Esta agenda deve produzir direção suficiente para fechar: + +1. catálogo mínimo de diagnósticos; +2. fase responsável por cada diagnóstico; +3. propagação final para manifest/specs; +4. fixture matrix mínima; +5. critérios de aceite para converter a série 19 em `decision` e depois `pull-request/plan`. + +## Core Questions + +1. Quais diagnósticos são obrigatórios para `declare global`, imports/reexports e ciclos? +2. Quais diagnósticos são obrigatórios para `[Init]` e `[Frame]`? +3. Quais erros pertencem a parser/AST, static semantics/linking, lowering, ou toolchain full pipeline? +4. Como o manifest final deve refletir entrypoint lógico e/ou físico escolhido em `19.3`? +5. Que fixtures mínimas precisam existir para globals, module init, boot failure, wrapper e `FRAME_RET`? +6. Em que ponto a configuração explícita antiga de entrypoint em `FrontendSpec` pode ser considerada removida? +7. Quais gates de conformance precisam ser atualizados para cobrir a série 19? + +## Options + +### Option A + +Consolidar diagnostics e coverage somente depois que os quatro stages anteriores estiverem fechados, com fixture matrix explícita por fase. + +### Option B + +Começar fixtures e diagnostics cedo, mesmo com arquitetura ainda mudando. + +## Tradeoffs + +### Option A + +- Prós: + - reduz retrabalho; + - evita congelar erro e coverage cedo demais; + - combina melhor com a disciplina de umbrella agenda. +- Contras: + - posterga parte da validação final. + +### Option B + +- Prós: + - feedback mais cedo. +- Contras: + - alto risco de churn e reabertura de artefatos; + - conflita com os locking rules da umbrella 19. + +## Recommendation + +Seguir com a **Option A**. + +## Expected Spec Material + +Se esta agenda fechar, a propagação esperada atinge pelo menos: + +- `7. Cartridge Manifest and Runtime Capabilities Specification.md` +- `12. Diagnostics Specification.md` +- `13. Lowering IRBackend Specification.md` +- docs de conformance/fixtures relevantes + +## Non-Goals + +Esta agenda não deve: + +1. redefinir semântica de globals; +2. redefinir lifecycle; +3. redefinir wrapper ou ownership de `FRAME_RET`; +4. redefinir shape de IR. + +## Next Step + +Depois do fechamento desta agenda, a linha `19` fica pronta para: + +- virar uma `decision` consolidada em `docs/compiler/pbs/decisions`; +- e então ser decomposta em `pull-request/plan` de execução. diff --git a/docs/compiler/pbs/agendas/README.md b/docs/compiler/pbs/agendas/README.md index 5f90ce08..596ce817 100644 --- a/docs/compiler/pbs/agendas/README.md +++ b/docs/compiler/pbs/agendas/README.md @@ -13,6 +13,11 @@ Closed agendas are moved to `docs/pbs/agendas/archive`. 5. `18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md` 6. `18.5. Ignored Call Results in Executable Lowering Agenda.md` 7. `19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md` +8. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md` +9. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md` +10. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md` +11. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md` +12. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md` ## Purpose diff --git a/docs/compiler/pbs/decisions/Globals Surface, Identity, and Module Boundaries Decision.md b/docs/compiler/pbs/decisions/Globals Surface, Identity, and Module Boundaries Decision.md new file mode 100644 index 00000000..6c2c41ec --- /dev/null +++ b/docs/compiler/pbs/decisions/Globals Surface, Identity, and Module Boundaries Decision.md @@ -0,0 +1,154 @@ +# Globals Surface, Identity, and Module Boundaries Decision + +Status: Accepted +Date: 2026-03-22 +Related Agenda: `docs/compiler/pbs/agendas/19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md` + +## Context + +PBS v1 needed a precise language and linking policy for runtime globals before lifecycle, published entrypoint, and lowering work under topic `19` could proceed safely. + +The open problem was not merely syntax. +It also required closing: + +- how globals differ from `declare const`, +- how globals participate in value visibility and import flow, +- how module ownership of storage is preserved, +- how dependency order between globals is modeled, +- and which diagnostics are mandatory when that model is violated. + +Important fixed inputs already existed: + +- `declare const` is compile-time only and does not denote mutable module storage, +- top-level executable statements remain forbidden, +- the VM already exposes global-slot access, +- and `mod.barrel` remains the visibility authority for module exports. + +## Decision + +PBS adopts the following policy for runtime globals in v1: + +1. PBS introduces a distinct top-level declaration form: + - `declare global Name: T = expr;` +2. `declare global` is not a variant of `declare const`. +3. `declare const` remains reserved to immutable values and must not be reused as runtime module storage. +4. `declare global` requires: + - an explicit type annotation, + - and an explicit initializer in all ordinary v1 cases. +5. Globals participate in the value namespace, but remain a distinct declaration category. +6. `mod.barrel` must expose globals through explicit `global` entries: + - `mod global Name;` + - `pub global Name;` +7. PBS does not introduce global re-export in this line of work. +8. Import of a global preserves the storage identity of the original owner module. +9. Imports may use aliasing when needed, but aliasing changes only the local visible name, never the canonical storage owner. +10. Shadowing between visible `fn`, `service`, `global`, and `const` names is a compile-time error and must be resolved with aliasing. +11. Lookup precedence remains: + - locals, + - then struct/class members, + - then globals, + including globals introduced by import. +12. Global dependency order is defined by a deterministic dependency graph: + - every read of another global in a global initializer creates a dependency edge, + - imports and aliases preserve canonical owner identity in that graph, + - source-file order must not affect dependency resolution. +13. Cycles between globals are compile-time errors. +14. Modules and globals must share the same structural dependency-analysis kernel through a refactor of the existing module dependency algorithm into: + - `DependencyGraphAnaliser` + - located in infra `util.structures`. +15. What is shared is the structural graph analysis kernel: + - topological ordering, + - cycle detection, + - deterministic traversal support. +16. What is not shared is domain semantics: + - each domain remains responsible for constructing canonical nodes, edges, and diagnostics. + +## Global Initializer Policy + +PBS v1 adopts the following initializer policy for `declare global`: + +1. The initializer exists only to materialize the initial module storage value. +2. Admissible forms in v1 include: + - primitive literals and simple value operations, + - value-bearing member access at this stage, + - `new Struct(...)`, + - and reads of other globals compatible with the dependency graph. +3. Top-level `fn` calls are not permitted in a global initializer in v1. +4. `some(...)` and `none` are not permitted in a global initializer in v1. +5. `if` and `switch` are not permitted directly in the declaration initializer in v1. +6. Richer procedural setup belongs to later lifecycle stages rather than the declaration initializer itself. + +## Rationale + +This decision intentionally keeps global declarations narrow and explicit. + +That choice: + +- prevents semantic collapse between immutable constants and mutable runtime storage, +- keeps import and visibility rules legible, +- makes dependency analysis deterministic and explainable, +- avoids hiding lifecycle logic inside declaration expressions, +- and prepares a clean handoff to later topic `19` work on module init, project init, and published entrypoint behavior. + +The decision also rejects implicit complexity: + +- no silent reuse of `const`, +- no global re-export, +- no ambiguous cross-category name merging, +- and no procedural `fn`-driven initialization inside `declare global`. + +## Mandatory Diagnostics + +PBS must provide, at minimum, the following diagnostics for this policy: + +1. `global initializer uses unsupported form` + - emitted at the invalid subexpression inside a global initializer. +2. `global dependency cycle detected` + - emitted on the local participating global, + - and should include the canonical cycle path when available. +3. `imported symbol shadows existing visible symbol; alias required` + - emitted when an imported `fn`, `service`, `global`, or `const` collides with an already-visible symbol of those categories. +4. `global import must resolve through a global barrel entry` + - emitted when import resolution would otherwise degrade a global into another category. + +## Invariants + +1. `declare const` and `declare global` remain semantically distinct. +2. Runtime storage ownership remains attached to the canonical owner module. +3. Global dependency order is semantic, not textual. +4. Alias spelling must not change canonical global identity. +5. The dependency-analysis kernel may be shared structurally, but semantic graph construction remains domain-owned. + +## Explicit Non-Decisions + +1. This decision does not define module init or project init behavior. +2. This decision does not define `[INIT]`, `[FRAME]`, or lifecycle markers. +3. This decision does not define published entrypoint or `FRAME_RET` ownership. +4. This decision does not define the final IR representation of globals. +5. This decision does not define host-call admissibility during lifecycle hooks. + +## Spec Impact + +This decision should feed at least: + +1. `docs/compiler/pbs/specs/3. Core Syntax Specification.md` +2. `docs/compiler/pbs/specs/4. Static Semantics Specification.md` +3. `docs/compiler/pbs/specs/11. AST Specification.md` +4. `docs/compiler/pbs/specs/12. Diagnostics Specification.md` + +It also constrains future topic `19` work in: + +1. `docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md` +2. `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md` +3. `docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md` + +## Validation Notes + +At minimum, validation for this decision should include: + +1. accepted fixtures for `declare global` with primitive, member-value, `new`, and dependent-global initializers; +2. rejection fixtures for forbidden initializer forms such as top-level `fn`, `some(...)`, `if`, and `switch`; +3. import fixtures proving alias-based disambiguation; +4. negative fixtures for cross-category collisions; +5. dependency fixtures proving deterministic ordering independent of source-file order; +6. cycle fixtures proving deterministic detection and diagnostics for intra-module and inter-module cycles. diff --git a/docs/compiler/pbs/decisions/Lifecycle Markers, Program Init, and Frame Root Semantics Decision.md b/docs/compiler/pbs/decisions/Lifecycle Markers, Program Init, and Frame Root Semantics Decision.md new file mode 100644 index 00000000..9f982eb2 --- /dev/null +++ b/docs/compiler/pbs/decisions/Lifecycle Markers, Program Init, and Frame Root Semantics Decision.md @@ -0,0 +1,194 @@ +# Lifecycle Markers, Program Init, and Frame Root Semantics Decision + +Status: Accepted +Date: 2026-03-22 +Related Agenda: `docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md` + +## Context + +After closing the globals surface and module-boundary model, PBS v1 needed a precise lifecycle policy for: + +- module bootstrap, +- project bootstrap, +- frame-root identification, +- host-call admissibility during init, +- and failure behavior at boot. + +The key requirement was to keep initialization expressive enough for real setup work, while preserving deterministic semantics and preventing the declaration initializer of `global` from becoming a general procedural execution surface. + +Important fixed inputs already existed: + +- `declare global` lowers into module-owned runtime storage, +- global initializers remain declarative and restricted, +- top-level `fn` calls are not allowed inside `declare global` initializers, +- `FRAME_SYNC` remains the only normative safepoint, +- and PBS v1 remains deterministic and single-threaded. + +## Decision + +PBS adopts the following lifecycle-marker and bootstrap policy in v1: + +1. PBS introduces the reserved userland attributes: + - `[Init]` + - `[Frame]` +2. `[Frame]` is mandatory for an executable project. +3. `[Frame]` is unique per executable project. +4. `[Init]` is optional. +5. `[Init]` may appear in ordinary userland source both for module-local bootstrap and for project bootstrap. +6. Both `[Init]` and `[Frame]` require the same signature shape: + - `fn name() -> void` +7. Recommended canonical source forms are: + +```pbs +[Init] +fn init() -> void { ... } +``` + +```pbs +[Frame] +fn frame() -> void { ... } +``` + +## Module Init and Project Init Policy + +PBS adopts the following bootstrap layering: + +1. Every module has exactly one synthetic module init. +2. `declare global` always lowers into that synthetic module init. +3. Each file may declare at most one `[Init]`. +4. A file may declare `[Init]` even when it declares no globals. +5. For one file: + - that file's globals are materialized first, + - then that file's `[Init]`, if present, executes. +6. File-level init fragments are then composed into the one synthetic module init. +7. The `[Init]` colocated in the same file as `[Frame]` is the project init. +8. `[Init]` in other files remains module init. +9. The distinction between module init and project init is one of ordering and semantic role, not one of different source syntax. +10. There is therefore at most one project init per executable project. +11. Project init uses the same signature shape: + - `fn init() -> void` + +## Bootstrap Order + +PBS adopts the following logical bootstrap order: + +1. materialize globals for each file according to dependency order, +2. execute that file's `[Init]`, if present, +3. compose those steps into one synthetic module init, +4. after required module work is complete, execute project init, if present, +5. then enter the first `frame()`. + +Within one module: + +1. file ordering must follow the order derived from the globals `DependencyGraphAnaliser`, +2. and when two files have no dependency edge between them, the compiler must still use a deterministic stable order. + +## Host Interaction During Init + +PBS adopts the following init-time host-call policy: + +1. Loops are permitted in module init and project init. +2. Host calls are forbidden by default during init. +3. The only host calls admissible during init are host methods marked with `[InitAllowed]`. +4. `[InitAllowed]` is a reserved SDK attribute, not a userland attribute. +5. `[InitAllowed]` has no arguments in v1. +6. `[InitAllowed]` is valid only on SDK host methods. +7. `[InitAllowed]` is invalid on userland `fn`, `global`, `service`, or any non-host-method surface. +8. `[InitAllowed]` does not distinguish module init from project init. +9. The difference between those phases is ordering and semantic role, not a separate host-permission class. +10. Admissibility of `[InitAllowed]` must be checked at compile time. + +Illustrative shape: + +```pbs +declare host Runtime { + [Host(module = "runtime", name = "random_u32", version = 1)] + [Capability(name = "runtime")] + [InitAllowed] + fn random_u32() -> int; +} +``` + +## Failure Policy + +PBS adopts a fail-fast boot policy: + +1. Failure during module init aborts boot. +2. Failure during project init aborts boot. +3. No automatic retry occurs on the next frame. +4. Implementations must surface a coherent failure message identifying the failing boot phase. + +## Rationale + +This decision keeps the declaration initializer of `global` simple, while still allowing practical bootstrap work in later lifecycle stages. + +That balance matters because: + +- arrays and derived data often require loops during setup, +- module bootstrap must remain expressive enough for real projects, +- host interaction during boot must still be tightly controlled, +- and the runtime model must remain deterministic and explainable. + +Colocation of project init with frame was chosen deliberately as a source-organization rule. +It avoids introducing a second project-level marker while keeping project bootstrap discoverable in source. + +## Mandatory Diagnostics + +PBS must provide, at minimum, the following diagnostics for this policy: + +1. `project init must be colocated with frame` +2. `multiple project init functions detected` +3. `multiple frame functions detected` +4. `missing frame function for executable project` +5. `init function must have signature fn name() -> void` +6. `frame function must have signature fn name() -> void` +7. `host call not allowed during init` +8. `InitAllowed is valid only on SDK host methods` +9. `boot failed during module init` +10. `boot failed during project init` +11. `multiple module init functions detected` +12. `Init attribute target invalid` + +## Invariants + +1. `[Frame]` remains unique per executable project. +2. Project init is identified by colocation with `[Frame]`. +3. Each file contributes at most one init fragment. +4. Each module contributes exactly one synthetic module init. +5. Host-call admissibility during init is explicit and compile-time validated. +6. Boot ordering remains deterministic. + +## Explicit Non-Decisions + +1. This decision does not define the published synthetic wrapper entrypoint. +2. This decision does not define `FRAME_RET` ownership. +3. This decision does not define the final IR encoding of bootstrap. +4. This decision does not define cartridge manifest publication details. + +## Spec Impact + +This decision should feed at least: + +1. `docs/compiler/pbs/specs/3. Core Syntax Specification.md` +2. `docs/compiler/pbs/specs/4. Static Semantics Specification.md` +3. `docs/compiler/pbs/specs/9. Dynamic Semantics Specification.md` +4. `docs/compiler/pbs/specs/12. Diagnostics Specification.md` + +It also constrains future topic `19` work in: + +1. `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md` +2. `docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md` +3. `docs/compiler/pbs/agendas/19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md` + +## Validation Notes + +At minimum, validation for this decision should include: + +1. accepted fixtures for `[Init]` and `[Frame]` with correct signatures; +2. accepted fixtures for file-level `[Init]` without globals; +3. accepted fixtures for loops inside module init and project init; +4. rejection fixtures for invalid marker targets and invalid signatures; +5. rejection fixtures for illegal host calls during init; +6. accepted fixtures for SDK host calls marked `[InitAllowed]`; +7. failure fixtures that distinguish module-init boot failure from project-init boot failure; +8. ordering fixtures proving deterministic file ordering within one module. diff --git a/docs/compiler/pbs/decisions/Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Decision.md b/docs/compiler/pbs/decisions/Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Decision.md new file mode 100644 index 00000000..feffdc75 --- /dev/null +++ b/docs/compiler/pbs/decisions/Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Decision.md @@ -0,0 +1,130 @@ +# Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Decision + +Status: Accepted +Date: 2026-03-22 +Related Agenda: `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md` + +## Context + +After closing globals and lifecycle semantics, PBS v1 still needed a precise publication contract for executable boot. + +The remaining problem was no longer how initialization behaves in userland. +It was how that behavior is published into the artifact and consumed by backend stages and runtime. + +The open points were: + +- whether the published entrypoint is still the user `frame()` callable, +- whether a synthetic wrapper becomes the true physical entrypoint, +- where `FRAME_RET` must live once lifecycle bootstrap exists, +- whether `FrontendSpec` continues to hold authority over entrypoint identity, +- and whether `manifest.json` remains part of entrypoint authority. + +Important fixed inputs already existed: + +- `[Frame]` identifies the userland logical frame root, +- module init and project init are already defined in lifecycle terms, +- boot is one-shot and fail-fast, +- and general backend specs already converge on entrypoint function index `0`. + +## Decision + +PBS adopts the following publication and ownership policy for executable boot in v1: + +1. The compiler publishes a synthetic wrapper as the physical executable entrypoint. +2. The userland callable marked with `[Frame]` remains the logical frame root of user code. +3. The synthetic wrapper is therefore the physical root, while `[Frame]` remains the logical root. +4. The wrapper must contain: + - one-shot boot orchestration, + - the required init execution exactly once, + - invocation of the userland `[Frame]` callable, + - and the final `FRAME_RET`. +5. `FRAME_RET` no longer belongs at the end of the userland `frame()` body. +6. `FRAME_RET` belongs to the published wrapper. +7. The published wrapper must occupy physical entrypoint index `0`. + +## Entrypoint Authority + +PBS adopts the following authority model: + +1. `FrontendSpec` no longer holds authority to decide which callable is the published entrypoint for PBS. +2. Entrypoint authority is owned exclusively by the PBS compiler. +3. Source-derived lifecycle semantics determine the logical frame root. +4. The compiler then publishes the physical wrapper that realizes that lifecycle contract. +5. Backend handoff must therefore preserve the compiler-selected published wrapper as the effective entrypoint identity. + +## Manifest and Runtime Protocol + +PBS adopts the following target protocol direction: + +1. `entrypoint` must stop being part of the final `manifest.json` contract. +2. Runtime boot must not depend on nominal entrypoint resolution from the manifest. +3. Runtime boot must treat physical entrypoint index `0` as protocol. +4. The compiler guarantees that the published wrapper occupies that index. +5. Any temporary compatibility line with manifest-declared nominal entrypoint is transitional only and is not the target contract. + +## Exports Boundary + +PBS adopts the following boundary for nominal exports: + +1. Nominal function exports may continue to exist in the emitted artifact. +2. Those exports are no longer authoritative for loader or boot. +3. Boot depends exclusively on the published physical entrypoint at index `0`. +4. Nominal exports remain useful only for tooling, debug, introspection, and related non-boot concerns. + +## Rationale + +This decision keeps logical user semantics and physical boot publication clearly separated. + +That matters because: + +- the user `frame()` callable should remain the semantic root of frame logic, +- the one-shot bootstrap sequence must still execute before normal frame work, +- `FRAME_RET` should mark the true end of the logical published frame, +- and the compiler must be the single authority that turns source lifecycle into executable publication. + +The decision also deliberately removes duplicated authority: + +- not `FrontendSpec`, +- not manifest nominal metadata, +- and not PBX nominal exports +are allowed to compete with the compiler-selected physical wrapper as boot authority. + +## Invariants + +1. `[Frame]` remains the userland logical frame root. +2. The published wrapper remains the physical executable root. +3. `FRAME_RET` belongs to the published wrapper. +4. Physical entrypoint index `0` belongs to that wrapper. +5. Nominal exports are not boot authority. +6. Entrypoint authority for PBS belongs to the compiler, not to `FrontendSpec` or manifest metadata. + +## Explicit Non-Decisions + +1. This decision does not define the final IR encoding of the wrapper body. +2. This decision does not define the detailed lowering mechanics of globals and lifecycle into IR. +3. This decision does not define the runtime-side migration implementation plan in detail. +4. This decision does not define the final diagnostics catalog for backend/runtime structural failures. + +## Spec Impact + +This decision should feed at least: + +1. `docs/compiler/pbs/specs/9. Dynamic Semantics Specification.md` +2. `docs/compiler/pbs/specs/13. Lowering IRBackend Specification.md` +3. `docs/compiler/pbs/specs/7. Cartridge Manifest and Runtime Capabilities Specification.md` +4. `docs/compiler/general/specs/15. Bytecode and PBX Mapping Specification.md` +5. `docs/compiler/general/specs/20. IRBackend to IRVM Lowering Specification.md` + +It also requires explicit cross-domain propagation to: + +1. `../runtime/docs/runtime/agendas/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md` + +## Validation Notes + +At minimum, validation for this decision should include: + +1. emitted artifact evidence that the published wrapper occupies function index `0`; +2. conformance evidence that the userland `[Frame]` callable is invoked by that wrapper rather than being published directly; +3. evidence that `FRAME_RET` is emitted in the wrapper path; +4. evidence that nominal exports, when present, do not participate in boot authority; +5. integration evidence that runtime boot aligns with the fixed physical entrypoint protocol.