Manifests
A full-stack test case declares its contents in a test-case.toml manifest in
the version folder and is resolved by the same rules an
end-to-end case is: the same required tables,
the same fields, the same validation. This page documents the differences.
Read End to End → Manifests first. Every field
it describes behaves identically on a full-stack case: slug, name,
difficulty, tags, summary, description, changelog, prompt,
max_runtime_hours, experimental, workspace, init, the required [build]
table, variants, [instrumentation], and the [[spec]], [[reference]],
[[proof]], [[check]], [[review_item]], and [[domain]] tables. The
reviewer checklist may equally use the categories grammar ([review] format = 2)
in place of [[review_item]].
type = "full-stack"
Section titled “type = "full-stack"”The type key is what identifies the type. An end-to-end case omits it or sets
type = "end-to-end"; a full-stack case sets it explicitly:
type = "full-stack"The type and asset_dimension together select the
run image and put that image’s
asset-generation binaries on the model’s PATH. A case that declares the type
alone runs in the 2D image with the six 2D binaries.
asset_dimension
Section titled “asset_dimension”asset_dimension says which dimension the case’s produced art is in, and so
which of the two full-stack images the run executes in:
type = "full-stack"asset_dimension = "3d""2d"is the default and selectstest-cabinet-full-stack-2d, carryingdraw,draw-sheet,particle-2d,sfx-synth,sfx-sample, andmusic."3d"selectstest-cabinet-full-stack-3d, which addsvoxel,voxel-anim, andparticle-3dto that same set.
It is a root key, so it sits above the first table header. It is a property of the whole version rather than a per-variant choice, so every variant of a version runs in the same image. Resolution accepts it on a full-stack case and rejects it on every other test type.
[build]
Section titled “[build]”A full-stack case builds a static site through the same fixed build interface,
so the [build] table is required with the same install and build commands
and the same rules as an end-to-end build: both stated, neither empty, emitting
the static site into dist/, build/, or out/. Resolution rejects a
build.module path, which belongs to the wasm-artifact types.
packages
Section titled “packages”The packages key names the repo’s shippable @clockwyrks/* runtime
libraries the build imports as ordinary dependencies. It is valid on an
end-to-end, full-stack, or game-jam case. The same shipped-package.json
file: contract and npm install-at-init rules apply as for an
end-to-end case.
Its most common use here is
@clockwyrks/particle-runtime,
so a game can play a particle system.json the model itself produced during the
run:
packages = ["@clockwyrks/particle-runtime"]A 3d case that ships a produced voxel model declares
@clockwyrks/voxel-runtime the same
way, so the game can decode each part’s .glb and pose the produced rig.
[audio]
Section titled “[audio]”A full-stack run produces its own sound with sfx-synth, sfx-sample, and
music, and [audio] declares the audio packs those binaries may reach. The
run container is staged with the declared packs and no others, so the table is
the boundary of what list-samples and list-instruments browse. Every version
declares it, either the full published set or the subset the case needs:
[audio]packs = []packs is the only key the table takes here. Each entry is a name@version ref
naming a published pack,
both halves required, and naming one pack twice is an error. sample_rate,
channels, and max_duration_ms are rejected: they fix the single clip an
audio asset-generation case
emits, while a full-stack run emits as many clips as its game needs.
A version carrying no [audio] table at all receives a fixed set pinned in
crates/core: [email protected], [email protected], [email protected], and
[email protected], in that order. The set is pinned by ref rather than read from
containers/sample-packs/, so publishing a pack leaves it unchanged and a
frozen version keeps the palette it was
authored and reviewed against. scripts/ci/audio-packs-check.mjs requires the
table on every version that is not frozen, so a frozen version is the only thing
that reaches the pinned set.
Order decides defaults. The model writes its own tool config during the run and
usually names no pack, and a config that names none plays the first declared
pack of its kind. Listing the pack a case wants an unqualified sfx-sample or
music invocation to play ahead of the others of its kind is what fixes that.
scripts/ci/audio-packs-check.mjs resolves every ref against
containers/sample-packs/ on the commit hook and in CI, and prints the defaults
each version’s order resolves to.
A case’s specs/ name the packs it declares,
because the packs the run holds are the packs the model may browse.
Forbidden asset-generation tables
Section titled “Forbidden asset-generation tables”A full-stack case produces its assets at run time with the on-PATH binaries,
so it declares no asset to generate. Resolution rejects the whole
asset-generation-only surface, exactly as it does on an end-to-end case:
- the
asset_kindkey and the[sheet]table; [canvas],[tool], and[output];[voxel],[model],[ui],[material], and[particle].
asset_dimension is a full-stack key of its own, unrelated to asset_kind: it
picks the tooling the run carries rather than an asset to generate.
What a full-stack case says about its produced assets belongs in its specs: what the program needs, and to what bar. The quality directive prepended to every full-stack prompt already tells the model to use the binaries and to hold the assets to the code’s bar.