cratis-stage-rendering-and-sandbox · git:20261017.620d528 · 2026-10-17 · sha256 d612b19fc2181385
cratis-stage-rendering-and-sandbox git:20261017.620d528A
Immutable. This exact content never changes and is served at /api/v1/blob/d612b19fc2181385.
--- name: cratis-stage-rendering-and-sandbox description: "What Cratis Stage and `cratis render` do with a Screenplay `.play` model: the model shape Stage admits and refuses (`STAGE-ESM-*`, `PLAY0268` render refusals), what it emits (C# Arc/Chronicle backend, React/Vite scaffold with Arc `CommandForm` shell emission over Scene typed bindings, Debug specifications), managed publication, `--force`, recovery, scoped renders (`--scope`) and `--check`, authored-UI omission/parity checks, the unmanaged `Customizations/` seam, and the `cratis/stage` sandbox and `cratis/stage-specrunner` job. Use when deciding whether Stage can render a model, reading a blocked render, re-rendering safely, checking generated/runtime screen parity, or running the sandbox. Not for: authoring the model (use `cratis-screenplay-model-authoring`) or the render and gap-fill workflow (use `cratis-screenplay-render-and-gap-fill`)." license: MIT --- # What Stage renders, and what it refuses Stage turns a Screenplay `.play` model into a Cratis Arc + Chronicle application. It ships a **renderer** (a .NET library, driven from a terminal by `cratis render`), a disposable **sandbox** container (`cratis/stage`, started by `cratis run`) and a **specification runner** container (`cratis/stage-specrunner`). A model Stage cannot render exactly produces **no artifacts**, never thinner ones. Probe the model; admission rules are not a render result. Requires cratis CLI ≥ 3.57 (`cratis --version`) to render ESM v14 and v15 models; an older CLI refuses newer ESM versions with `CLI-RENDER-004` (or `STAGE-ESM-016` from Stage directly). Requires Cratis CLI 3.74.0 to render ESM v21–v26 models and 3.75.0 for v27; CLI 3.66.0–3.73.0 refuse v21 and later with `CLI-RENDER-004`, and every CLI refuses v28 and later with it. Above the ceiling, a construct the bundled compiler cannot bind reports PLAY0268 before `CLI-RENDER-004` is reached. ## Batches, described handlers, text rules and protected reads Read [language admission](../cratis-screenplay-toolchain/references/language-admission.md) for v22–v25: text rules and admitted protected reads render; atomic batches and described bodies do not. Semantic execution is separate from rendering. Stub mode emits no described-body stubs. Keep protection and report refusal. ## When to use - Deciding whether a model can be rendered, or reading a blocked render. - Re-rendering safely after the model or a managed file changed. - Checking what the generated UI does and does not prove. - Running the sandbox or the specification runner, or a behavior walk. Not for authoring the model (`cratis-screenplay-model-authoring`), the render and gap-fill workflow (`cratis-screenplay-render-and-gap-fill`), or generated C# (`cratis-arc-command`, `cratis-chronicle-read-model`). ## Model-first rule The `.play` model is the source of truth; Stage-managed output is derived from it. - Change the model, then render again. Never edit a file listed in `.cratis-render.json`: the next render replaces it or refuses. - Hand-written code goes in `Customizations/` (unmanaged), in a separate project, or in an explicitly authorized gap-fill for scope Stage cannot render (`cratis-screenplay-render-and-gap-fill`). - A customization never makes a rejected model renderable, and never weakens modeled authorization, validation or personal-data and secret markers to get past a refusal. - Never claim a whole-application result from a subset of the model. ## Render ```bash cratis render ./model --name Marina --destination ./out cratis render --workspace ./application.workspace.json --destination ./out ``` | Option | Meaning | | --- | --- | | `[PATH]` | A `.play` file or a folder (all `**/*.play`, one application). Defaults to the current directory; exclusive with `--workspace` | | `--workspace <FILE>` | Canonical workspace envelope (Screenplay MCP `export-workspace`, at most 32 MiB). Keeps its application name and identities | | `--name <NAME>` | **Required for plain source**, a C# identifier; sets the application identity (Chronicle event store, MongoDB database). With `--workspace` optional, and it must equal the workspace name | | `--destination <DIR>` | Publication directory, default `./out`. It never defines identity | | `--target` | Only `cratis` is bundled | | `--project-name`, `--root-namespace` | Rendering overrides (dot-separated C# identifiers); do not change identity | | `--scope <ADDRESS>` | Render only a module, feature or slice (`Module[.Feature…][.Slice]`, exact case); repeatable. See "Scoped renders" | | `--check` | Plan against the real destination without writing: exit `0` current, `6` changes pending, `5` planning, refusal or pending recovery. Combine with `--scope` and `--force` | | `--package-set <FILE>` | Approved package set (JSON) of custom runtime packages the `ui profile` may use; the frontend installs exactly these | | `--force` | See "Publication and recovery" | Order: recover any interrupted publication, compile, bind, build the plan, plan the target (Stage admission), validate artifacts, then publish. Exit `0` is a published render, `5` is a refusal with nothing published (diagnostics are printed), `1` is a missing input. Add `-o json` for the counts and the publication receipt. Key facts: - **Binding uses the CLI's bundled compiler**, not the standalone one. Version admission does not imply construct support: exact ESM v1–v27 pairs are admitted; v28 and mixed pairs refuse `STAGE-ESM-016`. Requires Stage 4.139.0 for v22 admission; older Stage refuses v22 with `-016`, while atomic mode still refuses `-043`. Requires Stage 4.141.0 to render v26 Date/DateTime command comparisons; older renderers refuse `-046`. Read [references/date-comparisons.md](references/date-comparisons.md) when rendering dates for the remaining refusals and input-binding differences. Pattern/random generation and checksum validation render with an admitting renderer; `generate rule` renders in a new enough bundle (the Host and legacy syntax engine still refuse it with `STAGE-ESM-028`). Read [references/admission.md](references/admission.md) for the introducing-release prerequisites, all-Proven unpinned specifications and construct/pin checks (-011/-038). An older CLI bundle can refuse `CLI-RENDER-004` (direct Stage: `STAGE-ESM-016`); keep refused models for gap-fill. - **Render never builds, tests or runs** the output. A published render is admission and publication only; build and tests are separate results (see "Verify"). Admission can be green while a rendered Debug test fails (for example a query assertion on the key). - **Implementation attachments are read from the model root**: the folder, or the single file's parent directory. Use a dedicated model folder. A required body that is missing or changed blocks the render with `STAGE-ESM-020`. A workspace envelope has no attachment root, so `file` references there fail the same way. - `cratis render` and `cratis screenplay validate` are different gates: a model can validate and still refuse here. ### Scoped renders `--scope` renders an admitted part while other slices wait for hand-written code or renderer support. The whole model must still compile and bind, so a `PLAY0268`, protected identity/enum, attached handler or unsupported ESM version anywhere blocks even a scoped render. `PLAN-*` problems in unselected slices become warnings and `STAGE-ESM-*` refusals in unselected slices do not block. A scoped plan has no application scaffold or default Scene (with no manifest in the destination the plain scaffold is added). A dependency in another slice must be rendered first or listed too (`CLI-RENDER-014`); unknown scope is `-011`, ambiguous `-012`, aggregate policy layout `-013` (render the whole application once first). Unselected managed files are preserved. A scoped result is evidence for that scope only. ## Publication and recovery Read [publication and recovery](references/publication-and-recovery.md) before publishing or using `--force`. Commit `.cratis-render.json`, never the `.cratis-render/` control directory. Force never overwrites unmanaged files or modified stale artifacts. Recovery runs before planning: `recovered: true` means stop and reconcile. Use `--check` for drift, not MCP-to-manifest revision comparisons. ## Admission One blocker publishes nothing. Requires Stage 4.146.0 to collect independent admission refusals in one plan; older renderers stop at earlier batches of checks. Target-profile and unaudited-version refusals still stop first. Codes, limits and fixes: [references/admission.md](references/admission.md). - **Renders:** concepts/types/collections/optionals; portable StateChange and StateView slices, flat/scoped projections, pure reducers and reducer `from` filters; keyed optional snapshots, observable lists with equality filters; portable authorization and unique constraints; v8 sources/streams/routes and routed companion replay; case tables, `long` whole numbers and enum numbers; required scalar UUID/String generation strategies and v15 freshness, responses and fixtures; concept compliance; supported event-triggered Automation with `runs as`/`from` as `[OnceOnly]` reactors; single-hop reaction append specifications, Debug specifications and authored UI through Scene. - **Refused:** Translate/captures, non-event triggers, opaque bodies and clock specs (`STAGE-ESM-024`); mixed effects (`STAGE-ESM-037`, redelivery duplicates events); unsupported reaction mappings (`-039`), protected identities/enums (`-040`); unsupported generated types/results (`-028`/`-038`); appends beyond single-hop/cascade specs (`-011`), absence (`-027`), evolution (`STAGE-ESM-026`), public/foreign events (`-032`/`-033`), claim-reading/opaque `runs as` gates (`-034`), legacy filters (`-035`), production overrides (`-036`), code validation (`-005`), DateTime filters (`-010`), unsupported conditional productions, composite read-model keys (`STAGE-ESM-048`, and `-047` for a single-instance query by parts) and unsupported `all` shapes. Protected reads render as Arc read protection in a new enough bundle; shapes it cannot preserve, and every protected read in an older bundle, refuse `STAGE-ESM-044` (see admission.md). The renderer refuses described handlers `STAGE-IMPL-002` (even Stub mode), and atomic mode in admitted pairs `STAGE-ESM-043`. - **Attached command handlers (`PLAY0800`):** file/inline handlers permanently require constrained implementation attachments: gap-fill the slice in code, not by waiting for ESM admission. Read the required typed `arguments.subject` for the command, never match message text. Requires Screenplay 4.210.0 (`screenplay --version`); older bundled binders use PLAY0268 for these handlers. - **Binding refusals:** read toolchain `references/executable-subset.md` for `PLAY0268`/`PLAY0271` families; binding is not rendering. V27 keys are admitted but refuse rendering (`STAGE-ESM-048`). Never drop protection. A refusal is not a licence to weaken the model: drop no specification, event generation or protection to get a render; keep the model, record the capability gap and gap-fill. **Descriptions and documentation render only as XML documentation comments** (`<summary>`, `<remarks>`), never as validation, authorization or behavior, so a rule that exists only in prose is not enforced. A documentation edit changes managed-file hashes (a `--check` exit `6`), and characters invalid in XML block rendering with `CLI-RENDER-005`. Generated identities: read [shop strategy choices](references/choosing-generation.md) before rendering a model with generated values. Case tables and whole numbers: [case tables and whole numbers](references/case-tables-and-whole-numbers.md). Gap-fill `[ProtectedDecision]`/`DecisionRead<T>` use still needs admission and unit-of-work enrollment. ## What it emits Application plans hold the backend scaffold, concepts, commands/events/validators, read models/queries and policies, plus Scene and React/Vite frontend artifacts. Read the per-file scaffold, dependency and `Customizations/` contract, including the opt-in self-reducing layout for confirmed new Cratis C# applications: [references/rendered-application.md](references/rendered-application.md). Scene package ids, host capabilities and the boundary from hand-built Components pages: [references/scene-runtime.md](references/scene-runtime.md). A complete renderable model: [references/render-example.md](references/render-example.md). Modeled specifications become xunit classes compiled in **Debug only** (`IsTestProject` when Debug): a command spec `when_<snake>` in namespace `<slice namespace>.when_<snake>` (so `when_x.when_x`), queries `when_<snake>_is_queried`, read models `when_<snake>_is_projected`. A case table expands to one class per case (`<Specification>_<Case>`). ### UI parity The scaffold emits Arc `CommandForm` shells over Scene typed bindings, with `scene.json` and `src/bindings.ts` registering the modeled commands and queries. Record what the generated output claims separately from what the model authored, and claim UI fidelity only from a browser run. Require a generated plan entry, manifest entry or artifact for each screen, template, form, toolbar, component, outlet, route and package-icon use, or a blocking diagnostic explaining why it was not generated. `STAGE-SCENE-ACTION-001` and `STAGE-SCENE-INTERACTION-001` refuse a guard Stage cannot evaluate: no artifacts. Silent fallback to a default screen is a failure, not a partial render. ## Sandbox and specification runner `cratis run [PATH]` (Docker required) starts the disposable `cratis/stage`, not a generated application: API on `9090`, Workbench on `https://localhost:35000`. Requires Cratis CLI 3.73.0 for the semantic engine by default, 3.75.0 for v27 keys; older CLIs use the legacy EventModel engine, which does not enforce authorization. Unsigned caller headers make sandbox authorization no security boundary. Read [references/sandbox-and-specrunner.md](references/sandbox-and-specrunner.md) before running either image: engine selection, protected reads, outside-append conflicts/retries, reached bodies, authored occurrence and generated-spec limits live there. `cratis/stage-specrunner --engine semantic` reports `Passed`, `Failed`, `Unsupported` or `Cancelled`; deprecated structural mode is model-level only. Neither proves V4 or rendered Debug tests. Exit `0` means the report was written **even on failed specs**: read outcomes. Exit `1` means missing/uncompilable input; `2` invalid arguments. ## Behavior walk (optional, after V3) Walk each persona's commands and screens in the sandbox's semantic engine and record what changes, when a domain expert should check the model by using it. It yields findings for the model owner only, changes nothing, is not UI review and is not V4 or V5 evidence. Prerequisites, the walk, finding kinds, limits and hand-off: Read [references/behavior-walk.md](references/behavior-walk.md) when planning or running it. ## Legacy direct-write rendering The syntax-based `IRenderer` and `Cratis.Stage.Rendering.Cratis.Scaffolding` write directly to disk with no managed staging and no safe stale-file removal; a failure can leave the target unsafe and incomplete. Use `cratis render`. ## Verify - `cratis render` exits 0 and reports `recovered: false`, with `written + unchanged` equal to the artifact count (for `--scope`, the scope's artifacts); otherwise the render is not a result. State the scope in the V5 report. - Report V5 as separate results, each a result or "not run": admission, publication, Debug build (`dotnet build <destination>/<Project>.csproj -c Debug`), Debug tests (`dotnet test` on the same project) and runtime. Render alone is the first two. - A refusal is kept verbatim as reported: `PLAY*` (compile or bind), `PLAN-*` (execution plan), `STAGE-*` (admission), `CLI-RENDER-*`, or a plain ownership error for a managed file. The fix is an intent-preserving model change or a recorded gap, never an edit of managed output and never a weakened model. - No file under `.cratis-render/` is staged; managed files carry no local edits. - Stage's plan is deterministic (same bytes and hashes); that is not a review, and Stage never reviews, stages or approves anything. - Sandbox expectations account for the rules, constraints, authorization and query authorization the legacy EventModel engine does not enforce. - Runtime screen smoke coverage uses the same model root or workspace export as `cratis render`, names package/image versions, and fails on dropped authored UI or silent default composition. ## Route near misses Read [references/neighbouring-skills.md](references/neighbouring-skills.md) when the work is authoring or checking the model, tooling, the render workflow, generated C# or the Chronicle store.