This page defines the generator-facing shell ownership rules that prevent surface code from emitting shell-owned primitives.
The normative checker behavior remains in Generation Boundaries Guide. This page explains how generators should consume the same semantics.
contract.shell.owns: global shell-owned primitivessurface.mustNotEmit: per-surface override for banned primitivesshell.contentSlot: the place where surface-owned content is expected to mount- descriptor
primitives: emitted roles, counts, and sources for generated output
If surface.mustNotEmit is missing, generators should fall back to contract.shell.owns.
- Load the contract.
- Compute
banList = surface.mustNotEmit || contract.shell?.owns || []. - Generate only inside the surface-owned content slot or boundary.
- Convert generated output into descriptor primitives.
- Fail fast with
shell-owned-primitive-emittedif any banned primitive is emitted.
- lock or reserve shell-owned frames
- expose only the content slot for generation
- emit descriptor primitives for anything the builder still creates
- ban shell-owned imports or components from generated output
- keep shell/layout files out of the writable scope for the surface change
- run generation guard checks before code is committed or promoted
- normalize generated output into descriptor primitives
- treat shell-boundary findings as hard generation-time stops
- keep a workspace validation fallback in CI/CD
The shell boundary is the earliest reliable place to prevent duplicate navigation, duplicate auth wrappers, and other chrome re-emission failures. Generators should use it as a generation-time constraint, not only as a later validation failure.