# ADR 0006: Pure Deterministic Generation Plans

> **Ownership update:** generation implementation lives in
> `github.com/spice-framework/toolchain`; generated output remains owned by
> each consuming application.

Status: Accepted (amended for manifest schema 5)

## Decision

`compiler/generate` converts one valid immutable application model into a pure
in-memory `Plan`. The compiler phase never writes files, reloads packages,
rebuilds dependency resolution, executes source declarations, or accesses the
network.

The preferred package-main target layout is:

```text
internal/spicegen/<target>/spice_contracts_gen.go
internal/spicegen/<target>/spice_configuration_gen.go
internal/spicegen/<target>/spice_providers_gen.go
internal/spicegen/<target>/spice_assembly_gen.go
internal/spicegen/<target>/spice_features_gen.go
internal/spicegen/<target>/spice_http_gen.go
internal/spicegen/<target>/spice_http_route_<symbol>_<id>_gen.go
internal/spicegen/<target>/spice_lifecycle_gen.go
internal/spicegen/<target>/spice_command_gen.go
internal/spicegen/<target>/sources/<source-directory>/<source>_spice_gen.go
.spice/<target>.manifest.json
```

There is no catch-all target file. Concern-named units make execution boundaries
obvious, the assembly unit only sequences bounded phases, and every HTTP route
uses a readable stable symbol-and-hash-derived filename. Every contributing handwritten file
owns one mirrored source unit. The command package import-path base supplies
the default target name and portable ID. Target IDs use the portable
`[a-z][a-z0-9_]*` form. A target records one module root as an execution-only
field; the root is never serialized. Manifest schema 5 records the application
package layout, concern roles, exact source ownership, and generated ranges.
Schema-4 monoliths remain accepted only for guarded migration.

## Generated source

Generated source:

- begins with `// Code generated by Spice. DO NOT EDIT.`;
- assigns explicit import aliases from sorted import paths;
- invokes exported `@Bean` functions directly in the application IR's
  dependency-first order;
- passes dependency variables using the already validated graph edges;
- checks and wraps provider errors with stable provider and output identities;
- registers cleanup immediately after each successful provider call;
- aborts construction through `lifecycle.Coordinator` on failure;
- stores explicit exported start/stop method values in construction order;
- exposes `NewApplication`, `State`, `Start`, `Stop`, and caller-policy `Run`;
- uses no reflection, service locator, runtime scanning, or global registry.

Providers remain in importable module packages and generated calls require
exported provider/hook declarations. Same-package targets also reject
collisions with fixed generated API names. Legacy dedicated packages retain
their import-cycle and package-main restrictions.

## Ownership manifest

The canonical JSON manifest records:

- schema, target, module, package, output, and manifest identities;
- Spice generator and Go formatter compatibility versions;
- a SHA-256 hash of canonical application IR and target inputs;
- sorted generated paths, concern roles, source mappings, and exact SHA-256
  content hashes.

It contains no timestamps, absolute paths, raw environment values, random data,
or host information. Manifest bytes and generated Go are byte-identical for the
same model, target, schema, and supported formatter line.

Filesystem validation, locking, guarded replacement, stale removal,
manual-edit detection, check mode, and bounded diffs are a separate layer that
consumes the plan.
