# cavern-asset-bake — designer flow and process contract

This directory owns the Phase 14 workload definition. Godot owns the editable
mask/settings Resource, the output asset, the scene integration, and the
editor UI; the pure Odin cavern kernel does the substantial computation; the
existing six-stage build authority remains the only compiler and publication
owner. This admits one native tool, not a general cooking or EditorPlugin
framework.

## Resources

- **Request** — `res://bake/bake_request.tres`, a `CaveBakeRequest` Resource:
  one occupancy mask (`Image`, 8-bit L8, 0/255) plus the settings fields the
  kernel already validates (`smoothing_steps`, `minimum_region_size`). The
  designer edits it in the Inspector with the editor's own undo.
- **Output** — `res://bake/cave_bake_data.tres`, a `CaveBakeData` Resource: the
  baked floor grid (`PackedByteArray`), its width/height, the kernel
  diagnostics hash, the request digest it was baked from, and the native
  source revision that produced it.
- **Destination policy** — the output path is fixed by the request Resource's
  `output_path`; one request owns exactly one destination asset.

## Designer flow

1. **Edit** — the designer changes the mask or settings on the request
   Resource. Inspector edits use the editor's standard undo/redo; nothing here
   touches the output asset.
2. **Bake** — the Bake Shell (a GDScript panel in the authoring editor, or its
   scripted equivalent in evidence runs) saves the request, then launches one
   bounded headless child process: the same editor binary, this project, 
   `--headless --script res://bake/bake_process.gd`, with the request path,
   output path, and the request digest as user arguments. The child loads the
   current accepted native image through the standard runtime staging contract
   (the same environment `gododin run` uses) and runs the pure kernel's
   `process_mask` on the mask bytes.
3. **Inspect** — when the child prints `GODODIN_BAKE_PUBLISH`, the destination
   asset has been atomically replaced; the scene reimport/reload picks it up on
   the next open or explicit reload, and the shell's preview refreshes from the
   file. The shell streams the child's sentinels into its log.
4. **Cancel** — the shell may cancel an outstanding bake: it terminates the
   child process. A cancelled bake never touches the destination.
5. **Repair** — if the child cannot load an accepted image
   (`GODODIN_BAKE_NOIMAGE`), the shell surfaces the diagnostic and the normal
   rebuild path (the editor addon / `gododin build`) repairs it; the bake shell
   never compiles, links, or stages an artifact itself.
6. **Reopen/reimport** — the output is an ordinary Resource. On reopen, the
   freshness state below decides the inspector badge; the asset stays loadable
   in every state.

## Identity and freshness

- **Request digest** — SHA-256 over the canonicalized mask bytes plus the
  settings fields, computed by the shell before launch and recomputed inside
  the child before processing. A mismatch fails the bake; the shell never
  bakes a request it cannot digest identically to the child. (The engine
  exposes plain SHA-256 over files, so the shared digest helper hashes the
  canonical bytes through a per-process temporary file.)
- **Output identity** — the destination ResourcePath plus the recorded request
  digest and native source revision. Deterministic repeat: the same digest and
  the same pure kernel produce an identical payload and provenance — grid
  bytes, dimensions, diagnostics, digest, and revision — asserted by the
  campaign. The serialized `.tres` itself is not byte-compared: the engine
  writes a fresh resource UID into every save, and the kernel's wall-clock
  `generation_usec` is a measurement, not identity.
- **Freshness** — `FRESH` when the asset's recorded digest equals the current
  request digest; `STALE` when it differs; `MISSING` before the first
  successful bake. Staleness is a badge, never a blocker: the last valid asset
  remains loaded, exported, and inspectable.
- **Undo/redo** — request edits are undoable through the Inspector's own
  history. Output publication is a file replacement, not an editor action, so
  it is recorded in the shell log instead of the undo history; this is stated
  behavior, not a gap.

## Ownership, failure, and publication bounds

- One outstanding bake per request resource. Launching a new bake supersedes
  the outstanding one: the child is terminated and its partial output ignored.
- The child validates the kernel result (bounds, border safety, single-region
  validation, expected byte count) **before** publication. Publication is
  atomic: write to a temporary file in the same directory, then rename over the
  destination. A failed, cancelled, or superseded bake preserves the last valid
  asset byte for byte.
- Process failure — non-zero exit, missing sentinel, or timeout — is bounded:
  the shell reports `BAKE_FAILED` with the child's log tail and keeps the last
  valid asset. The child owns native execution; project native code never runs
  inside the recovery shell or the panel.
- The child keeps no engine state beyond the run: no scene is saved, no editor
  state is read, and the process exits after publishing or failing.

## The committed designer asset

The configured project carries one committed product of this flow:
`live/project/bake/cave_bake_request.tres` (a 256x192 L8 mask with smoothing 5
and minimum region 48) and its published destination
`live/project/bake/cave_bake_data.tres`. They were produced by the real shell
and supervised child through `bake_authoring.gd`, which also verifies the
published asset the way a consumer does — freshness against the recomputed
request digest and oracle parity with the accepted kernel. Exported
applications consume this asset in a bake-consume self-check: the app loads
the asset, recomputes the digest, verifies `FRESH` and kernel parity through
the normal installed-image path, and tears down with zero owners. The harness
gates both export profiles on that sentinel and on a bundle closure with no
compiler, OLS, or CLI helper (`verify_bake_export.py`).

## Evidence obligations (Phase 14 bullets)

The real-editor exercises run through the `bake_probe` plugin
(`live/project/editor/bake_probe/`, a no-op outside the exercise mode): the
no-image editor drives the real shell into the unavailable-image refusal with
the destination preserved, and the accepted-image editor proves deterministic
repeat, mid-bake cancellation, native-process failure, the stale reimport
through the editor's own import pipeline, and two consumers sharing the cached
request Resource (`bake_editor=true` in the installed sentinel). Editor reload
while a bake is outstanding is exercised in the same real-editor run as the
background workload's reload exercise (the harness signals the probe when the
addon's rebuild child exits, so the supervised bake child is in flight when
`reload_extension` lands; `reload=true` in the installed sentinel). The shared
C3 checkpoint is complete: the SDK/user docs and the affected release-matrix
rows updated with it.
