Release v3.2.0
Added
- Stage resolves a render plan per deployment target from a translated Screenplay application — one per
ui profileper platform, with the profile's packages expanded to their transitive closure in override-priority order, every component name a screen references bound to the package that wins it, the selected shell and theme resolved, screen templates nested inside the shell, and every arrangement evaluated at the target's size class.EventModelLoader.LoadRenderPlanFromDirectoryAsync(directory, catalog)compiles and resolves in one call;RenderPlanner.Plan(application, catalog)resolves an application you already hold. (#39) - A render plan reports what a target could not resolve as build findings on the result rather than throwing — a package the catalog does not declare, a dependency nothing satisfies, a version conflict, a dependency cycle, a shell or theme nothing declares, a theme incompatible with an active package, a component name that binds to nothing, an unplaced or cyclic screen template, a screen left on another shell, and a freeform arrangement with no variant for the target's size class.
IsCompleteis the single check a build gates on. (#39) - A
ui profile'slayoutandthemenow survive translation intoCratis.Scene.Model, so a target's shell and theme are resolved from what the document actually declares instead of being dropped. - Render plans documents what a plan contains, every finding and what it means, and the multi-target answer.
Changed
Cratis.Stage.ContractstakesCratis.Scene.Model1.1.0 and addsCratis.Scene.Engine1.1.0. Every resolution rule — package closure and priority, component binding, theme compatibility, template placement, size classes, arrangement evaluation — is Scene's engine used unmodified, so a build-time plan and a running renderer can never disagree about what a screen resolves to.
Multi-target builds — the open question in #39, answered: one invocation produces one plan per target, never a build per target.
Targets come out of a single compile of a single .play source set, so planning them together is the only way they are guaranteed to describe the same application; a build per target compiles the same source once per target and can only compare outcomes afterwards, if at all. It is also what makes "this template is unplaceable on the phone but fine on the web" answerable at all, and what lets a build fail once, coherently, with every target's findings in hand. Planning together does not force emitting together — Targets is a list and each entry is independently emittable, so shipping one target now and another later is a filter over the plan. The split belongs at emission, where the artifacts genuinely differ, not back at compilation, where they do not. The reasoning is stated on ApplicationRenderPlan itself, and RenderPlanner deliberately exposes no single-target entry point.
On #39's third bullet — build diagnostics through Screenplay's channel. Not done, and deliberately. EventModelLoader throws InvalidEventModel before any of this runs when the compilation has errors, so a plan is always built on a diagnostic-clean tree. What a plan finds is a different class: valid source that turns out to be under-specified for one concrete target. It belongs to a target rather than to a span of source text, which is what Screenplay's diagnostic channel describes — so it lives on the returned plan. Piping these back would be its own piece of work and would need a target-attributed diagnostic first.
Documented gaps. A catalog carries package names and the names of what each package contributes, never structures — so a shell provided by a blueprint package is named in the plan (LayoutName) and carries no structure, and its arrangements and template placements are not part of that plan. Emission itself is out of scope: a plan is the resolved input an emitter consumes.