diff --git a/Directory.Packages.props b/Directory.Packages.props
index 1a78e45d..f37409b0 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,9 +5,9 @@
22.54.0
0.24.0
0.18.0
- 4.134.0
+ 4.137.0
- 4.72.0
+ 4.73.0
diff --git a/Documentation/reference/screenplay-mcp.md b/Documentation/reference/screenplay-mcp.md
index 4d5d453d..c678eae4 100644
--- a/Documentation/reference/screenplay-mcp.md
+++ b/Documentation/reference/screenplay-mcp.md
@@ -3,9 +3,9 @@ title: Screenplay MCP
description: Run the embedded Screenplay MCP server and configure project-local AI host registrations safely.
---
-`cratis screenplay mcp` hosts the embedded Screenplay 4.134.0 Model Context Protocol (MCP) server over standard input and output. `cratis version` shows the bundled compiler version; JSON output includes `screenplay.version`. It does not install tools, download packages, or check for CLI updates at startup. Native and Homebrew CLI distributions include the runtime; this command does not require a separate .NET installation.
+`cratis screenplay mcp` hosts the embedded Screenplay 4.137.0 Model Context Protocol (MCP) server over standard input and output. `cratis version` shows the bundled compiler version; JSON output includes `screenplay.version`. It does not install tools, download packages, or check for CLI updates at startup. Native and Homebrew CLI distributions include the runtime; this command does not require a separate .NET installation.
-The server can author and bind every ESM version the bundled Screenplay compiler reads; this does not establish renderability. The CLI's bundled Stage 4.72.0 renderer admits ESM v1 through v10, including event sources, streams and routes, and renders policy negation and authored XML documentation, but refuses generated command values (`STAGE-ESM-028`), command responses (`STAGE-ESM-029`), reactions, captures, triggers and Automation/Translate slices (`STAGE-ESM-024`), read-model absence assertions (`STAGE-ESM-027`), public events and event-target projections and reducers (`STAGE-ESM-032`), foreign origins and event-source captures (`STAGE-ESM-033`), reaction system identity (`STAGE-ESM-034`), reaction observer filters (`STAGE-ESM-035`) and per-production route overrides (`STAGE-ESM-036`); reducer observer filters render. A specification whose unauthenticated caller carries roles or claims is refused with `STAGE-ESM-011`, including the unchanged canonical negation example. See [Screenplay rendering](screenplay.md#executable-model-versions) for command-specific compatibility.
+The server can author and bind every ESM version the bundled Screenplay compiler reads; this does not establish renderability. The CLI's bundled Stage 4.73.0 renderer admits ESM v1 through v10, including event sources, streams and routes, and renders policy negation and authored XML documentation, but refuses generated command values (`STAGE-ESM-028`), command responses (`STAGE-ESM-029`), reactions, captures, triggers and Automation/Translate slices (`STAGE-ESM-024`), read-model absence assertions (`STAGE-ESM-027`), public events and event-target projections and reducers (`STAGE-ESM-032`), foreign origins and event-source captures (`STAGE-ESM-033`), reaction system identity (`STAGE-ESM-034`), reaction observer filters (`STAGE-ESM-035`) and per-production route overrides (`STAGE-ESM-036`); reducer observer filters render. A specification whose unauthenticated caller carries roles or claims is refused with `STAGE-ESM-011`, including the unchanged canonical negation example. See [Screenplay rendering](screenplay.md#executable-model-versions) for command-specific compatibility.
For Claude Desktop and ChatGPT Desktop **installation**, see
[Screenplay desktop MCP](screenplay-desktop-mcp.md). Desktop management uses
diff --git a/Documentation/reference/screenplay.md b/Documentation/reference/screenplay.md
index 82b554c9..3f0594a3 100644
--- a/Documentation/reference/screenplay.md
+++ b/Documentation/reference/screenplay.md
@@ -12,7 +12,7 @@ cratis screenplay mcp [PATH]
cratis screenplay desktop install
```
-The CLI bundles Screenplay 4.134.0 (including its MCP server), Stage 4.72.0, and the Arc source adapter 22.54.0. `cratis render` admits ESM v1 through v10, including the canonical screen-composition corpus observable query and query-only specification shapes, and preserves authored Scene layouts, profiles, templates, navigation and forms when a model declares screens. Guarded screen actions render as runnable Scene guards: the generated frontend evaluates the authored guard, including enum-typed comparisons against the read model's declared members, and shows the action only when it passes. The renderer still refuses unsupported constructs within those versions: reactions, captures, triggers and Automation/Translate slices report `STAGE-ESM-024`, read-model absence assertions report `STAGE-ESM-027`, and the v9 and v10 constructs report their own codes (`STAGE-ESM-032` to `STAGE-ESM-036`, listed in the admission table below). Reducer observer filters render. It also refuses an evolved event until Stage can render its event-type migrations. Validation rejects `numbers exact` and `implementation` attachments on concept, built-in, and whole-command rules.
+The CLI bundles Screenplay 4.137.0 (including its MCP server), Stage 4.73.0, and the Arc source adapter 22.54.0. `cratis render` admits ESM v1 through v10, including the canonical screen-composition corpus observable query and query-only specification shapes, and preserves authored Scene layouts, profiles, templates, navigation and forms when a model declares screens. Guarded screen actions render as runnable Scene guards: the generated frontend evaluates the authored guard, including enum-typed comparisons against the read model's declared members, and shows the action only when it passes. The renderer still refuses unsupported constructs within those versions: reactions, captures, triggers and Automation/Translate slices report `STAGE-ESM-024`, read-model absence assertions report `STAGE-ESM-027`, and the v9 and v10 constructs report their own codes (`STAGE-ESM-032` to `STAGE-ESM-036`, listed in the admission table below). Reducer observer filters render. It also refuses an evolved event until Stage can render its event-type migrations. Validation rejects `numbers exact` and `implementation` attachments on concept, built-in, and whole-command rules.
For the embedded stdio server, the `visualize-model` MCP App, and native AI host registration, see [Screenplay MCP](screenplay-mcp.md). For Claude Desktop and ChatGPT Desktop installation, see [Screenplay desktop MCP](screenplay-desktop-mcp.md).
@@ -30,7 +30,7 @@ A newer bundled compiler can produce a newer executable semantic model (ESM) ver
| `cratis screenplay mcp` | Admitted for authoring and reading. The embedded server binds v7 models, pages their executable model (generated properties, responses, generation fixtures and return expectations) and reports execution readiness. Reference execution is not offered: neither the CLI nor the embedded server runs specifications. |
| `cratis render` | Admitted. Policy negation renders. Generated command values and command responses are refused by the renderer with `STAGE-ESM-028` and `STAGE-ESM-029`, respectively; see [Cratis/Stage#175](https://github.com/Cratis/Stage/issues/175). Stage refuses a specification whose unauthenticated caller carries roles or claims with `STAGE-ESM-011`; this includes the unchanged canonical negation example. A refusal leaves no publishable artifacts. Versions newer than v10 are still blocked by `CLI-RENDER-004`, naming the version. |
| `cratis screenplay generate` | From Arc 22.52.0, the Arc adapter recovers supported generated UUID values and command responses by default for commands without successful scenarios. Output containing these constructs compiles to ESM v7, which `cratis render` admits, but the renderer refuses generated values with `STAGE-ESM-028` and responses with `STAGE-ESM-029`, even without `--authoring-only-constructs`; see [Cratis/Stage#175](https://github.com/Cratis/Stage/issues/175). Unsupported shapes and values needed by pre-generation protection remain in code with `SP0052`. Marten and Critter Stack retain their existing recovery surface. |
-| `cratis run` | The Stage 4.72.0 container compiles the mounted `.play` files with its own Screenplay release, 4.133.3. Passing `cratis screenplay validate` does not establish Stage support for every construct. |
+| `cratis run` | The Stage 4.73.0 container compiles the mounted `.play` files with its own Screenplay release, 4.137.0. Passing `cratis screenplay validate` does not establish Stage support for every construct. |
The bundled Screenplay reader supports ESM schemas through v10. ESM v5 adds keyed read-model absence assertions; v8 adds event sources, streams, command routes and specification routes. ESM v9 adds public events, foreign event origins, translation direction, event-target projections/reducers and event-source captures; v10 adds reaction system identity (`runsAs`), per-production route overrides (`SemanticProducedEvent.Route`) and observer filters (`SemanticReaction.From` and `SemanticReducer.From`). Version reading and command admission are separate:
@@ -42,8 +42,8 @@ The bundled Screenplay reader supports ESM schemas through v10. ESM v5 adds keye
| `cratis screenplay generate` | Checks recovered source with the bundled compiler. The Arc adapter's output remains ESM v7; recovery is provider-owned. | Does not execute or render these constructs. Recovery remains provider-owned. | Does not execute or render these constructs. Recovery remains provider-owned. |
| `cratis view` | Serves embedded or generated source through the bundled event-model explorer. | Viewing is not renderer admission. | Viewing is not renderer admission. |
| Generation statistics | Count declarations in compiled source, including documents with event routes. | Counts do not establish executable or renderer support. | Counts do not establish executable or renderer support. |
-| `cratis render` | Admitted through Stage 4.72.0, including routed commands and supported routed specifications. Unsupported constructs still block publication. | Admitted for construct-level planning. Public events and event-target projections/reducers report `STAGE-ESM-032`; foreign origins and event-source captures report `STAGE-ESM-033`; translation direction reports `STAGE-ESM-024`. | Admitted for construct-level planning. Reaction `runsAs` reports `STAGE-ESM-034`; reaction `from` filters (`SemanticReaction.From`) report `STAGE-ESM-035`; per-production route overrides (`SemanticProducedEvent.Route`) report `STAGE-ESM-036`. Reducer `from` filters (`SemanticReducer.From`) render as Chronicle source/stream attributes; specifications requiring filtered read-model replay remain refused. |
-| `cratis run` | Refused by the Stage 4.72.0 container: `cratis run` starts Stage's default `eventmodel` engine, which reports `STAGE-ESM-030` for named event sources, streams and routes because only Stage's semantic engine runs them. Render the model with `cratis render` instead. | Stage applies its own runtime admission; CLI validation is not Stage admission. | Stage applies its own runtime admission; CLI validation is not Stage admission. |
+| `cratis render` | Admitted through Stage 4.73.0, including routed commands and supported routed specifications. Unsupported constructs still block publication. | Admitted for construct-level planning. Public events and event-target projections/reducers report `STAGE-ESM-032`; foreign origins and event-source captures report `STAGE-ESM-033`; translation direction reports `STAGE-ESM-024`. | Admitted for construct-level planning. Reaction `runsAs` reports `STAGE-ESM-034`; reaction `from` filters (`SemanticReaction.From`) report `STAGE-ESM-035`; per-production route overrides (`SemanticProducedEvent.Route`) report `STAGE-ESM-036`. Reducer `from` filters (`SemanticReducer.From`) render as Chronicle source/stream attributes; specifications requiring filtered read-model replay remain refused. |
+| `cratis run` | Refused by the Stage 4.73.0 container: `cratis run` starts Stage's default `eventmodel` engine, which reports `STAGE-ESM-030` for named event sources, streams and routes because only Stage's semantic engine runs them. Render the model with `cratis render` instead. | Stage applies its own runtime admission; CLI validation is not Stage admission. | Stage applies its own runtime admission; CLI validation is not Stage admission. |
Version admission does not admit every construct. A selected scope without unsupported constructs can plan normally at v9 or v10; a typed renderer refusal leaves no publishable artifacts. ESM v11 and newer remain blocked by `CLI-RENDER-004` before target planning or publication.
@@ -95,7 +95,7 @@ For example, `cratis render ./plays --name MyApplication --project-name Delivery
The bundled Stage renderer applies `--root-namespace Company.MyApplication` to the generated project and C# namespaces. This remains independent of `--project-name` and does not rename the application. Rendering admits only supported backend semantics; a successful artifact plan is not a generated-application build or runtime verification. Screenplay validation accepts events with multiple declared generations, but the bundled Stage renderer does not yet render an evolved event: `cratis render` reports `STAGE-ESM-026` naming the event and its revision, because Stage cannot render the Chronicle event-type migrations it needs yet, and publishes no artifacts. Stage's direct `.play` syntax route refuses event generations with `STAGE-EVENT-001`. `cratis screenplay validate` only checks the Screenplay model, not Stage renderer support.
-Navigation contributions that declare `id`, `icon`, `presentation`, `group`, or `destination outlet|dialog|external` are refused with `CLI-RENDER-015`: the bundled Stage renderer does not support these properties yet. The diagnostic names the contribution and property. Scoped and unscoped renders write nothing on this refusal; contributions without these properties retain their existing behavior.
+Navigation contributions render with everything they declare: `id`, `icon`, `presentation`, `group` and `destination outlet|dialog|external` reach the Scene the bundled Stage renderer plans, and the running application honours them - the menu shows the entry as its `presentation` asks and opens an outlet or a dialog destination through the Scene navigation host. A contribution on a module reaches every screen beneath the module, and a screen no entry lists is shown under its own module and feature. A `toolbar` renders with its items' destinations and presentation hints. (`CLI-RENDER-015`, which refused these properties before Stage 4.73.0, is retired.)
The initial `cratis` target covers the released backend vertical: concepts and composite types, a command with `not empty` validation, its event destination and mappings, a one-instance projection, an optional snapshot by-key query, and generated success/rejection specifications. Unsupported reachable semantics are blocking diagnostics, never omitted behavior or generated TODOs.
diff --git a/README.md b/README.md
index a90993a9..9e7a192c 100644
--- a/README.md
+++ b/README.md
@@ -459,7 +459,7 @@ The CLI repository carries additional command groups whose exact behavior and st
- `cratis arc` inspects registered commands and queries in a running [Arc](https://github.com/Cratis/Arc) application.
- `cratis view` opens a .NET application as an event model in the browser, from the Screenplay documents it embeds or ones generated from its source. See the [View command reference](https://github.com/Cratis/cli/blob/main/Documentation/reference/view.md).
-- `cratis screenplay` and `cratis render` work with Cratis Screenplay (`.play`) documents — generation, validation, and rendering from files, with nothing running. The CLI bundles Screenplay 4.131.0 and Stage 4.72.0; rendering admits ESM v8, including event sources, streams, routed commands and policy negation, and carries authored `description` and event `documentation` into XML doc comments. Generated values and command responses remain renderer refusals (`STAGE-ESM-028`/`STAGE-ESM-029`); specifications whose unauthenticated callers carry roles or claims are refused with `STAGE-ESM-011`. See the [Screenplay command reference](https://github.com/Cratis/cli/blob/main/Documentation/reference/screenplay.md) for the supported constructs and other renderer limits.
+- `cratis screenplay` and `cratis render` work with Cratis Screenplay (`.play`) documents — generation, validation, and rendering from files, with nothing running. The CLI bundles Screenplay 4.137.0 and Stage 4.73.0; rendering admits ESM v8, including event sources, streams, routed commands and policy negation, and carries authored `description` and event `documentation` into XML doc comments. Generated values and command responses remain renderer refusals (`STAGE-ESM-028`/`STAGE-ESM-029`); specifications whose unauthenticated callers carry roles or claims are refused with `STAGE-ESM-011`. See the [Screenplay command reference](https://github.com/Cratis/cli/blob/main/Documentation/reference/screenplay.md) for the supported constructs and other renderer limits.
- `cratis screenplay desktop install --clients claude,chatgpt` acquires verified, self-contained local Screenplay desktop packages. Complete installation/enabling in each host's UI; use `status`, `update`, and `uninstall` to manage Cratis-owned sources safely. See [desktop MCP installation](https://github.com/Cratis/cli/blob/main/Documentation/reference/screenplay-desktop-mcp.md).
- The [canonical CLI page](https://cratis.io/cli/) carries the currently admitted command-group documentation.
diff --git a/Source/Cli.Specs/for_CratisRenderTarget/when_planning_a_supported_application.cs b/Source/Cli.Specs/for_CratisRenderTarget/when_planning_a_supported_application.cs
index 9d214e79..5c139cb3 100644
--- a/Source/Cli.Specs/for_CratisRenderTarget/when_planning_a_supported_application.cs
+++ b/Source/Cli.Specs/for_CratisRenderTarget/when_planning_a_supported_application.cs
@@ -32,7 +32,7 @@ Task Because()
[Fact] void should_plan_the_exact_facade_renderer() => _result.Renderer.ShouldEqual(_expected.Renderer);
[Fact] void should_plan_the_exact_facade_renderer_version() => _result.RendererVersion.ShouldEqual(_expected.RendererVersion);
[Fact] void should_load_the_released_stage_44910_renderer_package() =>
- typeof(CratisRendering).Assembly.GetCustomAttribute()!.InformationalVersion.Split('+')[0].ShouldEqual("4.72.0");
+ typeof(CratisRendering).Assembly.GetCustomAttribute()!.InformationalVersion.Split('+')[0].ShouldEqual("4.73.0");
[Fact] void should_plan_the_same_application_name() => _result.ApplicationName.ShouldEqual(_expected.ApplicationName);
[Fact] void should_plan_the_same_semantic_revision() => _result.SemanticRevision.ShouldEqual(_expected.SemanticRevision);
[Fact] void should_plan_the_exact_facade_artifacts() =>
diff --git a/Source/Cli.Specs/for_RunCommand/when_running/with_a_folder_and_the_default_stage_tag.cs b/Source/Cli.Specs/for_RunCommand/when_running/with_a_folder_and_the_default_stage_tag.cs
index 2e40e80d..c19c7458 100644
--- a/Source/Cli.Specs/for_RunCommand/when_running/with_a_folder_and_the_default_stage_tag.cs
+++ b/Source/Cli.Specs/for_RunCommand/when_running/with_a_folder_and_the_default_stage_tag.cs
@@ -16,7 +16,7 @@ [Unix.Fact] void should_start_the_released_stage_image_that_matches_the_renderer
DockerArguments.ShouldContain($"cratis/stage:{StageContainer.DefaultTag}");
[Unix.Fact] void should_run_stage_44910_by_default() =>
- DockerArguments.ShouldContain("cratis/stage:4.72.0");
+ DockerArguments.ShouldContain("cratis/stage:4.73.0");
[Unix.Fact] void should_mount_only_the_selected_folder_read_only() =>
DockerArguments.ShouldContain($"{_folder}:/eventmodel:ro");
diff --git a/Source/Cli.Specs/for_RunCommand/when_running/with_a_play_file_and_the_default_stage_tag.cs b/Source/Cli.Specs/for_RunCommand/when_running/with_a_play_file_and_the_default_stage_tag.cs
index b05c05a4..1f078aef 100644
--- a/Source/Cli.Specs/for_RunCommand/when_running/with_a_play_file_and_the_default_stage_tag.cs
+++ b/Source/Cli.Specs/for_RunCommand/when_running/with_a_play_file_and_the_default_stage_tag.cs
@@ -21,7 +21,7 @@ [Unix.Fact] void should_start_the_released_stage_image_that_matches_the_renderer
DockerArguments.ShouldContain($"cratis/stage:{StageContainer.DefaultTag}");
[Unix.Fact] void should_run_stage_44910_by_default() =>
- DockerArguments.ShouldContain("cratis/stage:4.72.0");
+ DockerArguments.ShouldContain("cratis/stage:4.73.0");
[Unix.Fact] void should_mount_only_the_selected_file_read_only() =>
DockerArguments.ShouldContain($"{_path}:/eventmodel/input.play:ro");
diff --git a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_an_unsupported_icon.cs b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_an_unsupported_icon.cs
deleted file mode 100644
index e7207ca2..00000000
--- a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_an_unsupported_icon.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Cratis. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Cratis.Cli.for_ScreenplayPlanning.when_planning_navigation_contributions;
-
-public class with_an_unsupported_icon : given.a_navigation_contribution
-{
- ScreenplayRenderPlan[] _results = null!;
-
- void Establish() => AddProperties("icon work");
- async Task Because() => _results = [await PlanContribution(), await PlanContribution("Workspaces.Tracking.CreateWorkItem")];
-
- [Fact] void should_refuse_scoped_and_unscoped_plans() => _results.All(result => !result.Success).ShouldBeTrue();
- [Fact] void should_report_only_the_typed_refusal() => _results.All(result => result.Diagnostics.Count(diagnostic => diagnostic.Severity == ScreenplayDiagnosticSeverity.Error && diagnostic.Code == NavigationContributionAdmission.UnsupportedPropertyCode) == 1).ShouldBeTrue();
- [Fact] void should_name_the_contribution_and_property() => _results.All(result => result.Diagnostics.Any(diagnostic => diagnostic.Message.Contains("Workspaces.Tracking.contribute to Navigation[0]", StringComparison.Ordinal) && diagnostic.Message.Contains("property 'icon'", StringComparison.Ordinal) && diagnostic.Message.Contains("bundled Stage renderer", StringComparison.Ordinal))).ShouldBeTrue();
- [Fact] void should_not_plan_artifacts() => _results.All(result => result.Artifacts is null).ShouldBeTrue();
-}
diff --git a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_authored_navigation_metadata.cs b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_authored_navigation_metadata.cs
new file mode 100644
index 00000000..60ecd0e1
--- /dev/null
+++ b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_authored_navigation_metadata.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Cratis. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace Cratis.Cli.for_ScreenplayPlanning.when_planning_navigation_contributions;
+
+public class with_authored_navigation_metadata : given.a_navigation_contribution
+{
+ ScreenplayRenderPlan[] _results = null!;
+
+ void Establish() => AddProperties("id work-items", "icon work", "presentation rail", "group work", "destination external \"https://example.com\"");
+ async Task Because() => _results = [await PlanContribution(), await PlanContribution("Workspaces.Tracking.CreateWorkItem")];
+
+ [Fact] void should_render_scoped_and_unscoped_plans() => _results.All(result => result.Success).ShouldBeTrue();
+ [Fact] void should_report_no_error() => _results.SelectMany(result => result.Diagnostics).Any(diagnostic => diagnostic.Severity == ScreenplayDiagnosticSeverity.Error).ShouldBeFalse();
+ [Fact] void should_carry_the_metadata_in_the_planned_scene() => new[] { "\"id\":\"work-items\"", "\"icon\":\"work\"", "\"presentation\":\"rail\"", "\"group\":\"work\"", "https://example.com" }
+ .All(text => Scene(_results[0]).Contains(text, StringComparison.Ordinal)).ShouldBeTrue();
+
+ static string Scene(ScreenplayRenderPlan plan) => Encoding.UTF8.GetString(plan.Artifacts!.Artifacts.Single(artifact => string.Equals(artifact.RelativePath, "scene.json", StringComparison.Ordinal)).Bytes.AsSpan());
+}
diff --git a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_module_and_nested_feature_properties.cs b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_module_and_nested_feature_properties.cs
deleted file mode 100644
index ba079949..00000000
--- a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_module_and_nested_feature_properties.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Cratis. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Cratis.Cli.for_ScreenplayPlanning.when_planning_navigation_contributions;
-
-#pragma warning disable MA0136 // Fixture line endings do not affect normalized rendered artifacts.
-
-public class with_module_and_nested_feature_properties : given.a_navigation_contribution
-{
- ScreenplayRenderPlan _plan = null!;
-
- void Establish()
- {
- var path = Path.Combine(_folder, "Workspaces", "Tracking", "Tracking.play");
- var source = File.ReadAllText(path).Replace("module Workspaces", "module Workspaces\n contribute to Navigation\n label \"Workspaces\"\n icon work", StringComparison.Ordinal);
- File.WriteAllText(path, $"{source.TrimEnd()}\n" + """
- feature Nested
- contribute to Navigation
- label "Outside"
- destination external "https://example.com"
- """);
- }
-
- async Task Because() => _plan = await PlanContribution("Workspaces.Tracking.CreateWorkItem");
-
- [Fact] void should_refuse_properties_even_outside_the_selected_slice() => _plan.Success.ShouldBeFalse();
- [Fact] void should_check_the_module_contribution() => _plan.Diagnostics.ShouldContain(diagnostic => diagnostic.Code == NavigationContributionAdmission.UnsupportedPropertyCode && diagnostic.Message.Contains("Workspaces.contribute to Navigation[0]", StringComparison.Ordinal) && diagnostic.Message.Contains("property 'icon'", StringComparison.Ordinal));
- [Fact] void should_check_the_nested_feature_contribution() => _plan.Diagnostics.ShouldContain(diagnostic => diagnostic.Code == NavigationContributionAdmission.UnsupportedPropertyCode && diagnostic.Message.Contains("Workspaces.Tracking.Nested.contribute to Navigation[0]", StringComparison.Ordinal) && diagnostic.Message.Contains("property 'destination'", StringComparison.Ordinal));
- [Fact] void should_not_plan_artifacts() => _plan.Artifacts.ShouldBeNull();
-}
diff --git a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_multiple_unsupported_properties.cs b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_multiple_unsupported_properties.cs
deleted file mode 100644
index efd66c36..00000000
--- a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/with_multiple_unsupported_properties.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Cratis. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Cratis.Cli.for_ScreenplayPlanning.when_planning_navigation_contributions;
-
-public class with_multiple_unsupported_properties : given.a_navigation_contribution
-{
- ScreenplayRenderPlan[] _results = null!;
-
- void Establish() => AddProperties("id work-items", "icon work", "presentation rail", "group work", "destination external \"https://example.com\"");
- async Task Because() => _results = [await PlanContribution(), await PlanContribution("Workspaces.Tracking.CreateWorkItem")];
-
- [Fact] void should_refuse_scoped_and_unscoped_plans() => _results.All(result => !result.Success).ShouldBeTrue();
- [Fact] void should_report_every_unsupported_property() => _results.All(result => result.Diagnostics.Count(diagnostic => diagnostic.Code == NavigationContributionAdmission.UnsupportedPropertyCode && diagnostic.Severity == ScreenplayDiagnosticSeverity.Error) == 5).ShouldBeTrue();
- [Fact] void should_name_every_property() => new[] { "id", "icon", "presentation", "group", "destination" }.All(property => _results.All(result => result.Diagnostics.Any(diagnostic => diagnostic.Message.Contains($"property '{property}'", StringComparison.Ordinal)))).ShouldBeTrue();
- [Fact] void should_not_plan_artifacts() => _results.All(result => result.Artifacts is null).ShouldBeTrue();
-}
diff --git a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/without_unsupported_properties.cs b/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/without_unsupported_properties.cs
deleted file mode 100644
index 99b864f8..00000000
--- a/Source/Cli.Specs/for_ScreenplayPlanning/when_planning_navigation_contributions/without_unsupported_properties.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Cratis. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Cratis.Cli.for_ScreenplayPlanning.when_planning_navigation_contributions;
-
-public class without_unsupported_properties : given.a_navigation_contribution
-{
- ScreenplayRenderPlan _plan = null!;
-
- async Task Because() => _plan = await PlanContribution();
-
- [Fact] void should_render_the_existing_contribution() => _plan.Success.ShouldBeTrue();
- [Fact] void should_have_artifacts() => _plan.Artifacts!.Artifacts.ShouldNotBeEmpty();
- [Fact] void should_not_report_unsupported_properties() => _plan.Diagnostics.Where(diagnostic => diagnostic.Code == NavigationContributionAdmission.UnsupportedPropertyCode).ShouldBeEmpty();
-}
diff --git a/Source/Cli.Specs/for_StageContainer/when_resolving_the_default_tag.cs b/Source/Cli.Specs/for_StageContainer/when_resolving_the_default_tag.cs
index 13fa2eb5..8ce92c73 100644
--- a/Source/Cli.Specs/for_StageContainer/when_resolving_the_default_tag.cs
+++ b/Source/Cli.Specs/for_StageContainer/when_resolving_the_default_tag.cs
@@ -26,7 +26,7 @@ void Establish() => _renderer = typeof(ArtifactRenderPlan).Assembly
[Fact] void should_run_the_stage_the_renderer_came_from() => _tag.ShouldEqual(_renderer);
- [Fact] void should_run_the_released_stage_4720_image() => _tag.ShouldEqual("4.72.0");
+ [Fact] void should_run_the_released_stage_4730_image() => _tag.ShouldEqual("4.73.0");
[Fact] void should_not_run_a_moving_tag() => _tag.ShouldNotEqual(StageContainer.FallbackTag);
diff --git a/Source/Cli/Commands/Render/NavigationContributionAdmission.cs b/Source/Cli/Commands/Render/NavigationContributionAdmission.cs
deleted file mode 100644
index ec050681..00000000
--- a/Source/Cli/Commands/Render/NavigationContributionAdmission.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) Cratis. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using Cratis.Cli.Commands.Screenplay;
-using Cratis.Screenplay.Syntax;
-
-namespace Cratis.Cli.Commands.Render;
-
-///
-/// Refuses navigation contribution properties the bundled Stage Scene converter cannot preserve.
-///
-internal static class NavigationContributionAdmission
-{
- ///
- /// The diagnostic code for a navigation contribution property not supported by the bundled renderer.
- ///
- public const string UnsupportedPropertyCode = "CLI-RENDER-015";
-
- ///
- /// Checks contributions throughout the authored module and feature hierarchy.
- ///
- /// The parsed application before Scene conversion.
- /// Blocking diagnostics naming each unsupported contribution property.
- public static IEnumerable Check(ApplicationSyntax application) => application.Modules.SelectMany(module =>
- Check(module.Contributions ?? [], module.Name).Concat(CheckFeatures(module.Features, module.Name)));
-
- static IEnumerable CheckFeatures(IEnumerable features, string parent) => features.SelectMany(feature =>
- Check(feature.Contributions ?? [], $"{parent}.{feature.Name}").Concat(CheckFeatures(feature.Features, $"{parent}.{feature.Name}")));
-
- static IEnumerable Check(IEnumerable contributions, string parent) => contributions.SelectMany((contribution, index) =>
- {
- var name = $"{parent}.contribute to {contribution.ContributionPoint}[{index}]";
- (string Property, object? Value)[] properties =
- [
- ("id", contribution.Id),
- ("icon", contribution.Icon),
- ("presentation", contribution.Presentation),
- ("group", contribution.Group),
- ("destination", contribution.Destination)
- ];
-
- return properties.Where(property => property.Value is not null).Select(property => new ScreenplayDiagnostic(
- ScreenplayDiagnosticSeverity.Error,
- UnsupportedPropertyCode,
- $"Navigation contribution '{name}' property '{property.Property}' is not supported by the bundled Stage renderer yet.",
- $"{contribution.Location.Path ?? "Screenplay"}({contribution.Location.Line},{contribution.Location.Column})"));
- });
-}
diff --git a/Source/Cli/Commands/Render/ScreenplayPlanning.cs b/Source/Cli/Commands/Render/ScreenplayPlanning.cs
index 711ef58e..9a442015 100644
--- a/Source/Cli/Commands/Render/ScreenplayPlanning.cs
+++ b/Source/Cli/Commands/Render/ScreenplayPlanning.cs
@@ -197,7 +197,6 @@ static CratisPlanOptions ScaffoldOptionsFor(string applicationName, ScreenplayDo
return null;
}
- diagnostics.AddRange(NavigationContributionAdmission.Check(compilation.Result.Value!));
if (diagnostics.Exists(diagnostic => diagnostic.Severity == ScreenplayDiagnosticSeverity.Error))
{
return null;