Linked repository document
cavern-asset-bake — designer flow and process contract
examples/cavern_lab/bake/README.md
This document retains its design, example or evidence context. References outside this guide show their repository paths.
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, aCaveBakeRequestResource: 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, aCaveBakeDataResource: 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
- 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.
- 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 environmentgododin runuses) and runs the pure kernel'sprocess_maskon the mask bytes. - 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. - Cancel — the shell may cancel an outstanding bake: it terminates the child process. A cancelled bake never touches the destination.
- 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. - 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
.tresitself is not byte-compared: the engine writes a fresh resource UID into every save, and the kernel's wall-clockgeneration_usecis a measurement, not identity. - Freshness —
FRESHwhen the asset's recorded digest equals the current request digest;STALEwhen it differs;MISSINGbefore 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_FAILEDwith 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.