# Code Generation Model

Code generation turns a Masterbelt program into source files in one or more target languages. This document defines the user-visible parts of that pipeline shared by every target language.

## Inputs and Outputs

Code generation consumes the Masterbelt program after type checking has completed and lowering has produced normalized program modules. Each Masterbelt source file contributes one program module to the generation input. Type declarations contribute to generation when the target language requires a native form for them (for example, a Go struct type for a product-typed declaration); otherwise their substitution has already been applied to types reaching this stage.

For each configured target, code generation produces a set of output files. Each output file is identified by a relative path. The path is relative to the target's configured output root.

A generation invocation reports diagnostics emitted by the targets it ran. A target that reports any error severity diagnostic is treated as a failed target and no further files for that target are written.

## Targets

A target represents one code generation output. A target has:

- A kind identifier such as `golang`, `typescript`, or `csharp`. The kind selects which generation behavior is used.
- An output root directory. Generated file paths are interpreted relative to this directory.
- An options object whose contents are interpreted only by the target whose kind it carries. The shape of the options object is defined by each target's own specification.

Multiple targets of the same kind are allowed; they generate independently with their own output roots and options.

A target's generation is deterministic with respect to its inputs and options. The same input program and the same options produce the same files.

## Output Files

Every generated file is identified by:

- A path relative to the target's output root, using forward slashes as separators.
- A byte content that is the file's exact contents.

A target generates a self-consistent file set: every file required to use the generated code is included. Targets do not produce loose fragments that the user must combine.

How the file set maps to language constructs (one file per module, multiple files, header/runtime split) is defined by each target's own specification.

## Overwrite Behavior

Generated files always overwrite any file at the same path. Code generation is not incremental: each invocation writes the complete file set for each target.

## Target Selection

The set of targets to run is configured in the project configuration. The project configuration also carries each target's output root and options. See `tooling/configuration` for the schema.

Tools that run code generation either run every configured target or the explicitly selected subset of them. Selecting a target that is not configured is a usage error.

## Symbol References and Imports

Generated code refers to two kinds of symbols: symbols declared by the same generation invocation, and symbols from outside the generated package such as standard library entries or hand-written runtime helpers. The generation model treats every reference as a pair of (origin, name), where origin is either the local package being generated or an external module identifier whose meaning is target-specific.

Targets do not concatenate raw import paths into rendered source. Targets express references as symbols, and the rendering layer is responsible for:

- Producing the language's import declaration block for every external origin reached during rendering, exactly once.
- Choosing a unique import alias when two external origins share the same default alias.
- Rewriting symbol references in the rendered source to use the chosen alias.

This responsibility lives in the rendering layer because the set of imports cannot be determined until every reference has been visited. The rendering layer is also where conflict-free aliasing is decided. Targets that bypass the rendering layer and inline import strings forfeit this guarantee.

The user-visible consequence is that the generated file's import block is always minimal (no unused imports) and conflict-free (no two import declarations bind the same alias to different origins).

## Effects and Propagation

A callable symbol may declare one or more effects. The currently defined effects are:

- `cancellable`: the symbol participates in cooperative cancellation. The caller passes a cancellation token; the symbol must observe it.
- `failable`: the symbol may report a recoverable failure to its caller. The caller must observe and propagate or handle the failure.
- `asyncable`: the symbol completes in the future. The caller observes a deferred completion value rather than a direct result.

Effects are an open set; future effects may be added by extending this specification and every target's mapping.

Effects propagate from callee to caller. A caller that invokes a symbol carrying any effect inherits that effect unless the caller explicitly absorbs it (for example, by handling a failable result without re-raising). The generation model relies on the IR to record the effect set for every callable so targets can render effect-aware signatures without re-deriving them.

A target translates each effect to its language's native idiom. Each target document defines those mappings concretely; a target that cannot represent an effect must reject programs that require it, not generate code that silently drops the obligation.

## Reachability and Public Symbols

The default generation policy emits only those symbols reachable from at least one symbol declared with the `pub` modifier in the source program. A non-public symbol that is not referenced, directly or transitively, by any public symbol is dead code at the generation boundary and MUST NOT appear in the generated output.

Reachability is computed as follows:

- Every public symbol is a root.
- A symbol referenced by an already-reachable symbol becomes reachable.
- The set of reachable symbols is the transitive closure of these rules.

The default produces output that mirrors the program's public surface area: public symbols are always emitted, helpers used to express them are emitted under their non-public name, and helpers that nothing public depends on are dropped. This avoids leaking dead identifiers into generated source and avoids unnecessary churn when private helpers are renamed or removed.

A target MAY override the default with a documented reason; the default applies otherwise.

## Extending With New Targets

Adding a new target kind requires its own specification document under `codegen/` that defines:

- The kind identifier.
- The supported options.
- The mapping from program modules to output files.
- The mapping from Masterbelt types and values to target language constructs.
- The mapping from each effect to the target language's idiom.
- The runtime requirements, if any.

Targets share the same generation model and use the same output-file, symbol, and effect abstractions, but their per-language mappings are independent.
