@cratis/pi 7.128.0 → 7.130.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/corpus/agents/coordinator.md +1 -1
- package/package/corpus/agents/orchestrator.md +1 -1
- package/package/corpus/agents/planner.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/csharp.instructions.md +2 -2
- package/package/corpus/harnesses/copilot/instructions/framework.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/orleans.instructions.md +2 -1
- package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/specs.csharp.instructions.md +1 -1
- package/package/corpus/harnesses/pi/agents/coordinator.md +1 -1
- package/package/corpus/harnesses/pi/agents/orchestrator.md +1 -1
- package/package/corpus/harnesses/pi/agents/planner.md +1 -1
- package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +1 -1
- package/package/corpus/hooks/README.md +17 -5
- package/package/corpus/hooks/pre-commit.md +2 -2
- package/package/corpus/hooks/scripts/cratis-quality-gate.sh +1 -0
- package/package/corpus/hooks/scripts/cratis-run-specs.sh +147 -0
- package/package/corpus/hooks/scripts/quality-gates.json +5 -7
- package/package/corpus/product-sync.json +4 -4
- package/package/corpus/rules/csharp.md +2 -2
- package/package/corpus/rules/framework.md +1 -1
- package/package/corpus/rules/orleans.md +2 -1
- package/package/corpus/rules/pull-requests.md +1 -1
- package/package/corpus/rules/specs.csharp.md +1 -1
- package/package/corpus/skills/binlog-generation/SKILL.md +1 -1
- package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +1 -1
- package/package/corpus/skills/cratis-application-slice-conformance/SKILL.md +1 -1
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +1 -1
- package/package/corpus/skills/cratis-arc-command-execution/references/command-refusals.md +1 -1
- package/package/corpus/skills/cratis-arc-command-execution/references/occurrence-commands.md +1 -1
- package/package/corpus/skills/cratis-arc-command-operation/references/testing.md +1 -1
- package/package/corpus/skills/cratis-arc-command-validation/references/input-binding.md +1 -1
- package/package/corpus/skills/cratis-arc-command-validation/references/validation-severity.md +1 -1
- package/package/corpus/skills/cratis-arc-react-page/references/from-screenplay.md +5 -5
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/immediate-append-refusal.md +1 -1
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/occurrences.md +1 -1
- package/package/corpus/skills/cratis-chronicle-event-constraints/references/storage-uniqueness.md +1 -1
- package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +1 -1
- package/package/corpus/skills/cratis-chronicle-event-type-migration/references/explicit-migrations.md +1 -1
- package/package/corpus/skills/cratis-chronicle-reactor/references/starting-and-replaying.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model/references/collection-observation.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +1 -1
- package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +1 -1
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/build-once-and-shard.md +7 -3
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +1 -1
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +1 -1
- package/package/corpus/skills/cratis-commits-and-pull-requests/references/pr-labels-and-release.md +1 -1
- package/package/corpus/skills/cratis-engineering-ci-gates/SKILL.md +3 -2
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +5 -1
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/worked-examples.md +17 -8
- package/package/corpus/skills/cratis-orchestration-lanes/references/context-handoff.md +1 -1
- package/package/corpus/skills/cratis-orchestration-lanes/references/lane-brief.md +2 -2
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +6 -1
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +1 -1
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +5 -5
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/statemachines-and-workflows.md +164 -0
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +12 -15
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/translate-example.md +10 -4
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/complete-examples.md +2 -2
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +8 -2
- package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +5 -4
- package/package/corpus/skills/cratis-screenplay-command-surface/references/described-handlers.md +12 -8
- package/package/corpus/skills/cratis-screenplay-command-surface/references/validate-rules.md +5 -5
- package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +1 -1
- package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +6 -3
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generated-recovery.md +4 -4
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -2
- package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +3 -1
- package/package/corpus/skills/cratis-screenplay-read-surface/references/screen-patterns.md +2 -2
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +4 -4
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/delivery-protocol.md +2 -2
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +6 -5
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +2 -2
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-design.md +0 -3
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-example.md +8 -3
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +17 -9
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +4 -3
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/version-skew.md +25 -14
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/view-and-story-specs.md +7 -6
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/verification.json +1 -1
- package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +1 -1
- package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +1 -1
- package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +3 -3
- package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +8 -5
- package/package/corpus/skills/cratis-screenplay-specifications/references/actions-beyond-commands.md +4 -2
- package/package/corpus/skills/cratis-screenplay-specifications/references/child-ordering.md +12 -3
- package/package/corpus/skills/cratis-screenplay-specifications/references/reactions-and-cascades.md +70 -21
- package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +3 -2
- package/package/corpus/skills/cratis-screenplay-specifications/verification.json +2 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +3 -3
- package/package/corpus/skills/cratis-screenplay-toolchain/references/automation-translate-example.md +5 -8
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +12 -11
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostic-arguments.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +2 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +10 -7
- package/package/corpus/skills/cratis-screenplay-toolchain/references/fast-path.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +4 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/preferred-syntax.md +4 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +4 -4
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract-exceptions.json +0 -70
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +4743 -623
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +1 -1
- package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +6 -0
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/action-subjects.md +73 -0
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/file-references.md +4 -3
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/response-continuations.md +1 -1
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/worked-flow.md +1 -1
- package/package/corpus/skills/cratis-specifications-csharp/references/running-specs.md +7 -3
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +8 -6
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +8 -5
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/render-example.md +1 -1
- package/package/corpus/skills/csharp-refactoring/SKILL.md +2 -2
- package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +2 -1
- package/package/corpus/skills/filter-syntax/SKILL.md +1 -1
- package/package/corpus/skills/msbuild/references/build-perf-baseline.md +4 -1
- package/package/corpus/skills/run-tests/SKILL.md +9 -0
- package/package.json +1 -1
|
@@ -139,7 +139,7 @@ When handing off to a specialist agent:
|
|
|
139
139
|
For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate:
|
|
140
140
|
|
|
141
141
|
- [ ] `dotnet build` — zero errors, zero warnings
|
|
142
|
-
- [ ] `dotnet test`
|
|
142
|
+
- [ ] Built C# spec executables — all specs pass; `dotnet test <project> --no-build` only for VSTest (see specs.csharp)
|
|
143
143
|
- [ ] `yarn lint` — zero errors (if frontend present)
|
|
144
144
|
- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present)
|
|
145
145
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
@@ -165,7 +165,7 @@ When handing off to any agent or sub-orchestrator:
|
|
|
165
165
|
For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate:
|
|
166
166
|
|
|
167
167
|
- [ ] `dotnet build` — zero errors, zero warnings
|
|
168
|
-
- [ ] `dotnet test`
|
|
168
|
+
- [ ] Built C# spec executables — all specs pass; `dotnet test <project> --no-build` only for VSTest (see specs.csharp)
|
|
169
169
|
- [ ] `yarn lint` — zero errors (if frontend present)
|
|
170
170
|
- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present)
|
|
171
171
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
@@ -133,7 +133,7 @@ For an implemented application slice, require the applicable changed-lane gates
|
|
|
133
133
|
- [ ] `dotnet build` succeeds with zero errors and zero warnings
|
|
134
134
|
- [ ] `yarn lint` passes with zero errors (if frontend is present)
|
|
135
135
|
- [ ] `npx tsc -b` passes with zero errors (if frontend is present)
|
|
136
|
-
- [ ] All integration specs pass (`dotnet test`)
|
|
136
|
+
- [ ] All integration specs pass (built C# spec executables; `dotnet test <project> --no-build` only for VSTest; see specs.csharp)
|
|
137
137
|
- [ ] All TypeScript specs pass (`yarn test`) if applicable
|
|
138
138
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
139
139
|
- [ ] `Documentation/verify-markdown.sh` passes when documentation is added or changed
|
|
@@ -13,8 +13,8 @@ The goal is minimal ceremony, maximum clarity. Modern C# (13+) gives us records,
|
|
|
13
13
|
## Building
|
|
14
14
|
|
|
15
15
|
- Use `dotnet build` from the command line.
|
|
16
|
-
-
|
|
17
|
-
-
|
|
16
|
+
- Follow `.editorconfig`; run `dotnet format` only when CI requires it.
|
|
17
|
+
- Run affected spec executables; use `dotnet test <project> --no-build` only for VSTest (see `specs.csharp.md`).
|
|
18
18
|
|
|
19
19
|
## Formatting
|
|
20
20
|
|
|
@@ -60,7 +60,7 @@ Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dua
|
|
|
60
60
|
## Quality gates (framework)
|
|
61
61
|
|
|
62
62
|
- Build clean (Debug and Release) with **zero warnings, zero errors**.
|
|
63
|
-
- Specs pass for affected projects (C#
|
|
63
|
+
- Specs pass for affected projects (C# spec executables (VSTest only: `dotnet test <project> --no-build`); TS packages via their test command; Components also `build-storybook`).
|
|
64
64
|
- For public-facing changes (APIs, attributes, generated output, component props): update the product documentation and verify it.
|
|
65
65
|
- Match the repo's existing patterns; when a deep architectural question isn't answered by the universal rules or this file, consult the **repo's own docs/CONTRIBUTING** or ask — do not infer framework internals from a single call site.
|
|
66
66
|
|
|
@@ -63,7 +63,8 @@ using Microsoft.AspNetCore.Builder;
|
|
|
63
63
|
using MongoDB.Driver;
|
|
64
64
|
|
|
65
65
|
var builder = WebApplication.CreateBuilder(args);
|
|
66
|
-
|
|
66
|
+
var connectionString = builder.Configuration.GetConnectionString("Mongo")
|
|
67
|
+
?? throw new InvalidOperationException("Configure the Mongo connection string.");
|
|
67
68
|
builder.AddCratisOrleans(new CratisOrleansOptions
|
|
68
69
|
{
|
|
69
70
|
ClusterId = "my-service",
|
|
@@ -32,6 +32,6 @@ applyTo: "**/*"
|
|
|
32
32
|
## Before you create or edit a PR
|
|
33
33
|
|
|
34
34
|
- Run `node .cratis/ai/hooks/scripts/cratis-check-pr.mjs --body-file <file> --label <intent>`; it applies the exact `policy / verify` release-note rules and the Bash hook runs it on `gh pr create` and `gh pr edit`. If it fails, fix the description, not the code. Before every body edit, run `git diff --stat origin/main...HEAD` and delete bullets the diff no longer supports.
|
|
35
|
-
- Run the affected-project gates before marking work ready (
|
|
35
|
+
- Run the affected-project gates before marking work ready (build, built specs, lint and type-check; zero warnings), and the repository's required CI checks after an authorized push. `no-release` and documentation-only PRs still satisfy every required check; none is a blanket exemption from red CI.
|
|
36
36
|
- Group small related changes into one branch and one PR; see the skill for consolidation and the release-action windows.
|
|
37
37
|
- Open the PR once, when verified: each push starts CI. One PR per body of work, opened by the orchestrator (`cratis-engineering-release-trains`), with `--assignee @me`.
|
|
@@ -50,7 +50,7 @@ public class when_combining_parts : Specification
|
|
|
50
50
|
|
|
51
51
|
The shared lifecycle is the default on xUnit v2 and v3 since 5.0; the package registers the framework, so delete any hand-written `[assembly: Xunit.TestFramework(...)]` (it fails with `CS0579`). Eligible classes derive from `Specification`, have one public constructor with no arguments or only framework-managed fixture arguments, and contain only plain facts. Construction, Establish/Because and Destroy run once; all facts share the instance and must not mutate it. `IDisposable` specifications also share the lifecycle since Cratis.Specifications 4.4.0: one construction and one `Dispose` after the last fact. Initialization failure fails every fact. Theories and `ITestOutputHelper` constructors keep per-fact execution. Keep shared lifecycle on; `[PerFactSpecificationLifecycle]` opts out only the class whose facts genuinely mutate shared state and cannot move the mutation into `Because`. `CRSPEC0008` (a fact modifies the shared context) is an error by default: move the change into `Establish` or `Because`. See the **cratis-specifications-csharp** skill's shared-lifecycle reference.
|
|
52
52
|
|
|
53
|
-
Run specifications as
|
|
53
|
+
Run xUnit v3, TUnit and native-runner specifications as each project's built executable: restore and build once, then run its matching configuration/TFM output. Only identified VSTest projects use `dotnet test <project> --no-build`. Never default to solution-wide `dotnet test` in a mixed suite. Filters and the 4.x → 5.0 checklist are in the **cratis-specifications-csharp** skill's [running-specs reference](../../../skills/cratis-specifications-csharp/references/running-specs.md).
|
|
54
54
|
|
|
55
55
|
CRSPEC0001–CRSPEC0007 are warnings. Since 4.5 the analyzers ship only in `Cratis.Specifications`, transitively used by the framework packages; excluding analyzers on a framework package does not remove them. Derived xUnit/NUnit test attributes are recognized since 4.1.2. `Given`/`When` are aliases since 4.4 (declaring both aliases for one phase is CRSPEC0009), but house style stays `Establish`/`Because`. With warnings as errors, a non-`should_` fact, multiple specs per file (given contexts exempt), a fact on a given context, a `should_` without a test attribute, explicit base lifecycle calls, non-public specs with facts, or `Because` on a given context fail the build. Follow **cratis-specification-by-example**; do not suppress these diagnostics.
|
|
56
56
|
|
|
@@ -135,7 +135,7 @@ When handing off to a specialist agent:
|
|
|
135
135
|
For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate:
|
|
136
136
|
|
|
137
137
|
- [ ] `dotnet build` — zero errors, zero warnings
|
|
138
|
-
- [ ] `dotnet test`
|
|
138
|
+
- [ ] Built C# spec executables — all specs pass; `dotnet test <project> --no-build` only for VSTest (see specs.csharp)
|
|
139
139
|
- [ ] `yarn lint` — zero errors (if frontend present)
|
|
140
140
|
- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present)
|
|
141
141
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
@@ -161,7 +161,7 @@ When handing off to any agent or sub-orchestrator:
|
|
|
161
161
|
For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate:
|
|
162
162
|
|
|
163
163
|
- [ ] `dotnet build` — zero errors, zero warnings
|
|
164
|
-
- [ ] `dotnet test`
|
|
164
|
+
- [ ] Built C# spec executables — all specs pass; `dotnet test <project> --no-build` only for VSTest (see specs.csharp)
|
|
165
165
|
- [ ] `yarn lint` — zero errors (if frontend present)
|
|
166
166
|
- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present)
|
|
167
167
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
@@ -129,7 +129,7 @@ For an implemented application slice, require the applicable changed-lane gates
|
|
|
129
129
|
- [ ] `dotnet build` succeeds with zero errors and zero warnings
|
|
130
130
|
- [ ] `yarn lint` passes with zero errors (if frontend is present)
|
|
131
131
|
- [ ] `npx tsc -b` passes with zero errors (if frontend is present)
|
|
132
|
-
- [ ] All integration specs pass (`dotnet test`)
|
|
132
|
+
- [ ] All integration specs pass (built C# spec executables; `dotnet test <project> --no-build` only for VSTest; see specs.csharp)
|
|
133
133
|
- [ ] All TypeScript specs pass (`yarn test`) if applicable
|
|
134
134
|
- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates
|
|
135
135
|
- [ ] `Documentation/verify-markdown.sh` passes when documentation is added or changed
|
|
@@ -394,7 +394,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
394
394
|
const last = latestGateLog(gateLogDirectory(sessionId), started);
|
|
395
395
|
const tail = last ? tailLines(last.file, TAIL_LINES) : "";
|
|
396
396
|
throw new Error(`The Cratis quality gate TIMED OUT after ${duration(timeoutSeconds * 1000)}${last ? ` while running '${last.gate}'${last.cwd ? ` (cwd: ${last.cwd})` : ""}` : ""}. This is not a pass: nothing was verified.` +
|
|
397
|
-
(last ? `\nRun a narrower command instead: ${last.gate === "backend-specs" ? "dotnet test <
|
|
397
|
+
(last ? `\nRun a narrower command instead: ${last.gate === "backend-specs" ? "./<affected-project-dir>/bin/Debug/<TFM>/<AssemblyName> (or dotnet <TargetPath.dll> without apphost); dotnet test <project> --configuration Debug --no-build only for VSTest. Repeat for affected dependents." : "run the affected project alone using this gate's configured command."}\nConfigure it in .cratis/ai/quality-gates.project.json.\n\nGate log: ${last.file}` : "") +
|
|
398
398
|
(tail ? `\n\n--- last ${TAIL_LINES} lines ---\n${tail}\n--- end ---` : ""));
|
|
399
399
|
};
|
|
400
400
|
const reportInterrupted = () => {
|
|
@@ -636,17 +636,29 @@ the script stops the command's process group (TERM, then KILL after one second),
|
|
|
636
636
|
reports **NOT VERIFIED**, the gate, its directory, log tail, and `timeoutHint` (advice, never executed).
|
|
637
637
|
Commands that create separate sessions/process groups can escape this cleanup; this is not a sandbox.
|
|
638
638
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
639
|
+
The default runs `cratis-run-specs.sh` through the absolute `CRATIS_HOOKS_SCRIPTS_DIR`
|
|
640
|
+
exported by the gate, including nested solutions and bundled Pi installations. The runner
|
|
641
|
+
requires Node, Bash and Git, the same prerequisites as the hooks (not an additional runtime). It evaluates
|
|
642
|
+
MSBuild metadata without building, runs supported built xUnit v3/TUnit/native executables
|
|
643
|
+
(or `dotnet <TargetPath.dll>` without apphost), and uses project-scoped `dotnet test --no-build`
|
|
644
|
+
only for identified VSTest projects. Restore/build matching Debug outputs first. Missing or
|
|
645
|
+
ambiguous metadata/output, custom application entrypoints, failed suites and zero-selected
|
|
646
|
+
suites are not passes; unsupported runners need a repository-owned invocation override.
|
|
647
|
+
|
|
648
|
+
For a large solution, replace the placeholder below with the affected project directory,
|
|
649
|
+
TFM and AssemblyName and repeat for affected dependents. Use that executable's filter/report
|
|
650
|
+
flags (see [running-specs](../skills/cratis-specifications-csharp/references/running-specs.md)),
|
|
651
|
+
not VSTest logger switches. Override `command` rather than raising a timeout without diagnosis:
|
|
642
652
|
|
|
643
653
|
```json
|
|
644
|
-
{ "gates": [{ "id": "backend-specs", "command": ["
|
|
654
|
+
{ "gates": [{ "id": "backend-specs", "command": ["./<project-dir>/bin/Debug/<TFM>/<AssemblyName>"], "timeoutSeconds": 120, "timeoutHint": "Run each affected project's built spec executable separately; dotnet test <project> --configuration Debug --no-build only for VSTest." }] }
|
|
645
655
|
```
|
|
646
656
|
|
|
647
657
|
This is not automatic affected-project selection: imported/conditional MSBuild references and
|
|
648
658
|
linked or shared sources require evaluation to establish coverage safely. The default retains
|
|
649
|
-
solution
|
|
659
|
+
all solution projects, executing each test project independently rather than silently missing
|
|
660
|
+
dependents. Non-test projects are explicitly skipped; a solution with none reports no verified
|
|
661
|
+
specifications. A timeout is never a pass. Reports are local under `.ai-work/spec-runs/`.
|
|
650
662
|
|
|
651
663
|
**Profile note.** The C# patterns are application-profile and scoped to `Source/**/*.cs`, which is
|
|
652
664
|
the application source root [`../rules/general.md`](../rules/general.md) documents. A
|
|
@@ -26,9 +26,9 @@ Apply before an authorized `git commit`, including `rtk git commit` or `rtk prox
|
|
|
26
26
|
|
|
27
27
|
3. **Run specs for each affected .NET project**:
|
|
28
28
|
```
|
|
29
|
-
|
|
29
|
+
./<project-dir>/bin/<Config>/<TFM>/<AssemblyName>
|
|
30
30
|
```
|
|
31
|
-
Use
|
|
31
|
+
Use the project's verified built spec executable (or `dotnet <TargetPath.dll>` without apphost; see [running-specs](../skills/cratis-specifications-csharp/references/running-specs.md)). Only VSTest uses `dotnet test <project> --no-build`. Require current matching outputs; otherwise incrementally build the affected specs project first. If the owning specs project cannot be identified, inspect project references or report the uncertainty; do not default to a root-wide test run.
|
|
32
32
|
|
|
33
33
|
4. **Run specs for each affected TypeScript project**:
|
|
34
34
|
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Copyright (c) Cratis. All rights reserved.
|
|
3
|
+
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
4
|
+
|
|
5
|
+
# Read-only MSBuild evaluation followed by built runners. Children inherit the gate's process group.
|
|
6
|
+
exec node --input-type=module - "$@" <<'NODE'
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync } from 'node:fs';
|
|
9
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
10
|
+
import { parseArgs } from 'node:util';
|
|
11
|
+
|
|
12
|
+
function refuse(message) {
|
|
13
|
+
console.error(`cratis-run-specs: ${message}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { values } = parseArgs({ args: process.argv.slice(2), options: {
|
|
18
|
+
project: { type: 'string' }, solution: { type: 'string' }, configuration: { type: 'string', default: 'Debug' },
|
|
19
|
+
framework: { type: 'string' }, 'no-build': { type: 'boolean' },
|
|
20
|
+
} });
|
|
21
|
+
if (!values['no-build']) refuse('--no-build is required; restore and build once before running specs.');
|
|
22
|
+
if (values.project && values.solution) refuse('Select either --project or --solution, not both.');
|
|
23
|
+
|
|
24
|
+
function dotnet(arguments_) {
|
|
25
|
+
const result = spawnSync('dotnet', arguments_, { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 });
|
|
26
|
+
if (result.error || result.status !== 0) refuse(`Metadata evaluation failed: dotnet ${arguments_.join(' ')}\n${result.error?.message ?? result.stderr}`);
|
|
27
|
+
return result.stdout;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const properties = 'IsTestProject,IsTestingPlatformApplication,UseMicrosoftTestingPlatformRunner,OutputType,TargetPath,TargetFramework,TargetFrameworks,AssemblyName,XunitAutoGeneratedEntryPoint';
|
|
31
|
+
function evaluate(project, framework) {
|
|
32
|
+
const arguments_ = ['msbuild', project, '-nologo', `-p:Configuration=${values.configuration}`];
|
|
33
|
+
if (framework) arguments_.push(`-p:TargetFramework=${framework}`);
|
|
34
|
+
arguments_.push(`-getProperty:${properties}`, '-getItem:PackageReference');
|
|
35
|
+
try {
|
|
36
|
+
const metadata = JSON.parse(dotnet(arguments_));
|
|
37
|
+
if (!metadata.Properties || !Array.isArray(metadata.Items?.PackageReference)) throw new Error('Missing evaluated Properties or PackageReference items');
|
|
38
|
+
return metadata;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
refuse(`Cannot evaluate ${project}: ${error.message}. Restore/build the matching configuration first; configure a repository-owned gate override for unsupported projects.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let projects;
|
|
45
|
+
if (values.project) projects = [resolve(values.project)];
|
|
46
|
+
else {
|
|
47
|
+
const solutions = values.solution ? [values.solution] : readdirSync('.').filter(name => /\.slnx?$/.test(name));
|
|
48
|
+
if (solutions.length !== 1) refuse('Expected one solution in the working directory; select --solution or --project explicitly in a gate override.');
|
|
49
|
+
const solution = resolve(solutions[0]);
|
|
50
|
+
// Ignore localized headings; accept only actual project entries, relative to the selected solution.
|
|
51
|
+
projects = dotnet(['sln', solution, 'list']).split(/\r?\n/).map(line => line.trim())
|
|
52
|
+
.filter(line => /\.(?:cs|fs|vb)proj$/i.test(line)).map(line => resolve(dirname(solution), line.replaceAll('\\', '/')));
|
|
53
|
+
if (!projects.length) refuse(`No project entries could be established for ${solution}; no specifications verified.`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function classify(metadata, project) {
|
|
57
|
+
const properties = metadata.Properties;
|
|
58
|
+
const packages = new Set(metadata.Items.PackageReference.map(item => String(item.Identity).toLowerCase()));
|
|
59
|
+
const platform = properties.IsTestingPlatformApplication?.toLowerCase() === 'true';
|
|
60
|
+
const xunit = ['xunit.v3', 'xunit.v3.core', 'xunit.v3.mtp-off', 'xunit.v3.core.mtp-off',
|
|
61
|
+
'xunit.v3.mtp-v1', 'xunit.v3.core.mtp-v1', 'xunit.v3.mtp-v2', 'xunit.v3.core.mtp-v2']
|
|
62
|
+
.some(name => packages.has(name));
|
|
63
|
+
const native = packages.has('cratis.specifications.runner');
|
|
64
|
+
const tunit = packages.has('tunit');
|
|
65
|
+
const legacy = ['xunit', 'nunit', 'mstest.testframework'].some(name => packages.has(name));
|
|
66
|
+
const test = properties.IsTestProject?.toLowerCase() === 'true' || platform || xunit || native || tunit || legacy;
|
|
67
|
+
if (!test) return 'non-test';
|
|
68
|
+
if (properties.XunitAutoGeneratedEntryPoint?.toLowerCase() === 'false') refuse(`${project}: custom application entrypoint; configure a repository-owned spec invocation override (do not start the server).`);
|
|
69
|
+
if (['exe', 'winexe'].includes(properties.OutputType?.toLowerCase())) {
|
|
70
|
+
if (xunit && (packages.has('xunit.v3.mtp-off') || packages.has('xunit.v3.core.mtp-off')
|
|
71
|
+
|| properties.UseMicrosoftTestingPlatformRunner?.toLowerCase() !== 'true')) return 'xunit-mtp-off';
|
|
72
|
+
if (platform || xunit || native || tunit) return 'mtp';
|
|
73
|
+
}
|
|
74
|
+
// Test.Sdk can generate an Exe entrypoint for legacy VSTest projects too.
|
|
75
|
+
if (properties.IsTestProject?.toLowerCase() === 'true' && !platform && !xunit && !native && !tunit && legacy && packages.has('microsoft.net.test.sdk')) return 'vstest';
|
|
76
|
+
refuse(`${project}: unsupported/unknown test runner; configure a repository-owned backend-specs override instead of falling back to dotnet test.`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let reportRoot;
|
|
80
|
+
function reportPath() {
|
|
81
|
+
if (!reportRoot) {
|
|
82
|
+
const repository = spawnSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' });
|
|
83
|
+
const root = repository.status === 0 ? repository.stdout.trim() : process.cwd();
|
|
84
|
+
const artifacts = join(root, '.ai-work', 'spec-runs');
|
|
85
|
+
mkdirSync(artifacts, { recursive: true });
|
|
86
|
+
reportRoot = mkdtempSync(join(artifacts, 'run-'));
|
|
87
|
+
}
|
|
88
|
+
return join(reportRoot, `${executed}.trx`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function verifyCounts(runner, output, report, project) {
|
|
92
|
+
let total;
|
|
93
|
+
let passed;
|
|
94
|
+
let failed;
|
|
95
|
+
let skipped;
|
|
96
|
+
if (runner === 'xunit-mtp-off' && existsSync(report)) {
|
|
97
|
+
const counters = /<(?:\w+:)?Counters\b([^>]*)\/?\s*>/.exec(readFileSync(report, 'utf8'))?.[1];
|
|
98
|
+
const count = name => { const value = new RegExp(`\\b${name}="(\\d+)"`).exec(counters ?? ''); return value ? Number(value[1]) : undefined; };
|
|
99
|
+
total = count('total'); passed = count('passed'); failed = count('failed'); skipped = count('notExecuted') ?? 0;
|
|
100
|
+
} else if (runner !== 'xunit-mtp-off') {
|
|
101
|
+
const count = expression => { const match = expression.exec(output); return match ? Number(match[1]) : undefined; };
|
|
102
|
+
total = count(/\btotal:\s*(\d+)/i);
|
|
103
|
+
passed = count(/\b(?:succeeded|passed):\s*(\d+)/i);
|
|
104
|
+
failed = count(/\bfailed:\s*(\d+)/i);
|
|
105
|
+
skipped = count(/\bskipped:\s*(\d+)/i) ?? 0;
|
|
106
|
+
}
|
|
107
|
+
if (total === 0) refuse(`${project}: zero tests executed; no specifications verified.`);
|
|
108
|
+
if (total === undefined || passed === undefined || failed === undefined) refuse(`${project}: UNVERIFIED — runner count evidence unavailable. Configure a repository-owned invocation with verified reports.`);
|
|
109
|
+
if (failed !== 0 || passed + skipped !== total || passed === 0) refuse(`${project}: not all specifications passed (total=${total}, passed=${passed}, failed=${failed}).`);
|
|
110
|
+
console.log(`cratis-run-specs: verified total=${total}, passed=${passed}, failed=${failed}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let executed = 0;
|
|
114
|
+
for (const project of projects) {
|
|
115
|
+
if (!existsSync(project)) refuse(`Solution project does not exist: ${project}`);
|
|
116
|
+
const initial = evaluate(project);
|
|
117
|
+
const frameworks = (initial.Properties.TargetFrameworks || initial.Properties.TargetFramework || '').split(';').filter(Boolean);
|
|
118
|
+
const runner = classify(initial, project);
|
|
119
|
+
if (runner === 'non-test') { console.log(`cratis-run-specs: SKIP non-test ${project}`); continue; }
|
|
120
|
+
if (!frameworks.length) refuse(`${project}: target framework unavailable; evaluate the restored project or supply an override.`);
|
|
121
|
+
if (values.framework && !frameworks.includes(values.framework)) refuse(`${project}: requested framework ${values.framework} not in ${frameworks.join(', ')}.`);
|
|
122
|
+
for (const framework of values.framework ? [values.framework] : frameworks) {
|
|
123
|
+
const metadata = initial.Properties.TargetFrameworks ? evaluate(project, framework) : initial;
|
|
124
|
+
const selectedRunner = classify(metadata, project);
|
|
125
|
+
if (selectedRunner === 'non-test') refuse(`${project} (${framework}): inconsistent test metadata; no suite may be omitted.`);
|
|
126
|
+
const target = metadata.Properties.TargetPath;
|
|
127
|
+
if (!target || !isAbsolute(target)) refuse(`${project}: evaluated TargetPath unavailable; perform the matching ${values.configuration}/${framework} build first.`);
|
|
128
|
+
const apphost = target.replace(/\.dll$/i, process.platform === 'win32' ? '.exe' : '');
|
|
129
|
+
const useApphost = apphost !== target && existsSync(apphost);
|
|
130
|
+
if (!useApphost && !existsSync(target)) refuse(`${project}: missing built output ${target}; perform the matching ${values.configuration}/${framework} build first.`);
|
|
131
|
+
const report = selectedRunner === 'xunit-mtp-off' ? reportPath() : undefined;
|
|
132
|
+
const command = selectedRunner === 'vstest' || !useApphost ? 'dotnet' : apphost;
|
|
133
|
+
const arguments_ = selectedRunner === 'vstest'
|
|
134
|
+
? ['test', project, '--configuration', values.configuration, '--no-build', '--framework', framework]
|
|
135
|
+
: [...(useApphost ? [] : [target]), ...(report ? ['-trx', report] : [])];
|
|
136
|
+
console.log(`cratis-run-specs: RUN ${project} runner=${selectedRunner} framework=${framework} configuration=${values.configuration}`);
|
|
137
|
+
const result = spawnSync(command, arguments_, { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 });
|
|
138
|
+
process.stdout.write(result.stdout ?? '');
|
|
139
|
+
process.stderr.write(result.stderr ?? '');
|
|
140
|
+
if (result.error) refuse(`${project}: ${result.error.message}`);
|
|
141
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
142
|
+
verifyCounts(selectedRunner, (result.stdout ?? '') + (result.stderr ?? ''), report, project);
|
|
143
|
+
executed++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
console.log(executed ? `cratis-run-specs: verified ${executed} project/framework suite(s).` : 'cratis-run-specs: NO-OP — no test projects; no specifications verified.');
|
|
147
|
+
NODE
|
|
@@ -117,9 +117,9 @@
|
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"id": "backend-specs",
|
|
120
|
-
"description": "
|
|
120
|
+
"description": "Built C# spec executables (Debug, no rebuild); VSTest-only fallback \u2014 zero failures",
|
|
121
121
|
"timeoutSeconds": 120,
|
|
122
|
-
"timeoutHint": "dotnet test <
|
|
122
|
+
"timeoutHint": "./<affected-project-dir>/bin/Debug/<TFM>/<AssemblyName> (or dotnet <TargetPath.dll> without apphost); only VSTest: dotnet test <project> --configuration Debug --no-build. Repeat for affected dependents.",
|
|
123
123
|
"changed": [
|
|
124
124
|
"**/*.cs",
|
|
125
125
|
"**/*.csproj",
|
|
@@ -145,11 +145,9 @@
|
|
|
145
145
|
"**/*.sln"
|
|
146
146
|
],
|
|
147
147
|
"command": [
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"--configuration"
|
|
151
|
-
"Debug",
|
|
152
|
-
"--no-build"
|
|
148
|
+
"bash",
|
|
149
|
+
"-c",
|
|
150
|
+
"exec bash \"$CRATIS_HOOKS_SCRIPTS_DIR/cratis-run-specs.sh\" --configuration Debug --no-build"
|
|
153
151
|
]
|
|
154
152
|
},
|
|
155
153
|
{
|
|
@@ -171,9 +171,9 @@
|
|
|
171
171
|
}
|
|
172
172
|
],
|
|
173
173
|
"synced": {
|
|
174
|
-
"version": "
|
|
175
|
-
"date": "2026-
|
|
176
|
-
"by": "Cratis/AI#
|
|
174
|
+
"version": "5.1.0",
|
|
175
|
+
"date": "2026-11-02",
|
|
176
|
+
"by": "Cratis/AI#975"
|
|
177
177
|
},
|
|
178
178
|
"covers": {
|
|
179
179
|
"skills": [
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
],
|
|
202
202
|
"rules": []
|
|
203
203
|
},
|
|
204
|
-
"notes": "Cratis/AI#820: reviewed v4.245.0 release; protected-read constraint precedence preserved. Review correction: removed unsupported parser-repair and inbound-public refusal release attributions and the incorrect PLAY0136 event-key claim, restoring prior teaching. Published contract asset is byte-identical to the previous snapshot; pin and compatibility entry advanced together. Prior: Cratis/AI#779: reference-runner capability refusals taught as scoped per specification (introduced in v4.213.2, Cratis/Screenplay#897) from the v4.216.0 tool and MCP documentation and plan source: an unadmitted projection (UnsupportedEventContext, UnsupportedProjectionBlock) marks unsupported only the specifications that reach it or its read model, the others run and planIssues lists deferred issues; application-level issues still block every selected specification; no new render/runtime probe. Prior: Cratis/AI#776: PLAY0802 ReservedStoredName (introduced in v4.213.3, Cratis/Screenplay#893) taught from the v4.216.0 compilers and documentation: stored event source `Default` and stored event stream `All` (ordinal, name or `id` pin) refused at authoring time, a pin away from the reserved name valid, PLAY0273 kept as the binding backstop; no new render/runtime probe. Prior: Cratis/AI#784: standalone Screenplay 4.216.0 pinned; compiler contract replaced by the v4.216.0 release asset (adds the propose-repair destinationIntent v1 schema and PLAY0802 ReservedStoredName). Source-checked decision 0096 and the MCP reference for the explicit author-intent PLAY0470 repair: repair-intents discovery, intentActions feature detection, complete per-production selections, retained production-destination report and identity views, explicit apply and refusals. No new render/runtime probe. Prior: Cratis/AI#771: standalone Screenplay 4.213.0 pinned; regenerated compiler contract is byte-identical to the v4.213.0 release asset and unchanged from 4.212.4. Reviewed the full v4.212.4-v4.213.0 delta against tagged decision 0093 and MCP reference: pre-binding container identities and stable binding/migration continuity, own-slice member substitutions, containerIdentities completeness/ambiguity/collision refusals, retained ambiguous notes, explicit semanticRenames/retirements, binding fixes through MCP, exact reopen exception, notes/identity rollback and exact-ID re-add anchoring. No grammar, binder, ESM or diagnostic-code changes; no new render/runtime probe. Prior: Cratis/AI#772: standalone Screenplay 4.212.4 pinned; regenerated compiler contract is byte-identical to the v4.212.4 release asset. Source-checked joined-event automap/no automap overrides and level fallback in executable binding; PLAY0380 covers only all inside children/nested. No new render/runtime probe. Prior: Cratis/AI#769: standalone Screenplay 4.212.3 pinned; regenerated compiler contract is byte-identical to the v4.212.3 release asset. Source-checked both compilers and projection documentation for PLAY0801 DuplicateEventInProjectionScope: shared from/removal/clear set, separate join set, fresh sets per children/nested/variant level, and no two-row update through repeated from blocks with different keys. No new render/runtime probe. Prior: Cratis/AI#768: standalone Screenplay 4.212.2 pinned; regenerated compiler contract is byte-identical to the v4.212.2 release asset (unchanged from the previous contract). Source-checked v4.212.0 split-model dotted note targets, open-workspace applicationIdentity and complete add/reanchor substitutions; unbound container identities are not claimed. v4.212.1 aligns PLAY0535 collection fields, optional parameters and single-result identity inference. v4.212.2 counts read-only query denials for SPEC004, not SPEC006. No new render/runtime probe. Prior: Cratis/AI#762 and #761: source-checked v4.210.0 and v4.211.0 contracts for PLAY0800 CommandHandlerRequiresAttachment (required typed subject, permanent code-attachment requirement, other PLAY0268 families unchanged), independent reference remove/add batches, located same-text ambiguity conflicts and string MCP conflict/move-report document fields. v4.211.1 mapping changes inspected but excluded from this guidance update at the user's request; no typed PLAY0273 property/type arguments are claimed. Standalone Screenplay 4.211.1 and its compiler contract pinned; the contract is a byte-identical copy of the v4.211.1 release asset. No new render/runtime probe. Prior: Standalone 4.205.0 and byte-identical compiler contract pinned. Cratis/AI#746: Uuid ==/!= in command require and produces when (ESM v28): same-concept rule, bare Uuid against a concept, canonical literals, protected read paths in require only; PLAY0268 (different concepts, ordering, Uuid validation and concept rules, read paths in produces when) and PLAY0273 (non-canonical literal) checked against the 4.205.0 compiler, v28 selection read from the MCP executable-model view; Stage admits exact v1-v21 and v23-v26 pairs so v28 is refused STAGE-ESM-016, not probed against a Stage image; CLI 3.74.0 renders through v26. Prior: Standalone 4.204.0 and byte-identical compiler contract pinned. Cratis/AI#702 and #691: PLAY0690 reducer identity (Screenplay 4.170.0, native compiler only) and the screenplay.json validation gate (Screenplay 4.165.0; cratis screenplay validate reads it from CLI 3.65.0) are taught and probed against the 4.204.0 compiler. Cratis/AI#743: flat composite read-model keys (ESM v27): untyped projection key blocks on root from and remove with, equality-filter lists, single-instance by blocks and per-part fixtures, with PLAY0661/PLAY0662/PLAY0268 refusals checked against the 4.204.0 compiler; Stage origin/main still refuses v27 with STAGE-ESM-016 (stage-rendering.md); Stage v4.135.0 v26 admission (Host and executor run date comparisons; renderer STAGE-ESM-046) was source-checked for this sync; no render or runtime probe. Prior: Standalone 4.201.0 and byte-identical compiler contract pinned. Cratis/AI#733: the ui profile root template, shell options, appearance and new screens default (PLAY0788-PLAY0799, quick fix for the legacy layout line, ui-profiles MCP tool, 44 tools). Cratis/AI#735: chronological Date/DateTime ordering in command conditions and command/property literal validation (ESM v26), UTC tick precision and pre-rule offset validation; then matching remains ordinal. Source-checked Screenplay v4.199.0 commands, diagnostics, interoperability and specifications documentation plus decision 0087. Stage v4.127.1 still refuses v26 with STAGE-ESM-016 (stage-rendering.md and SemanticVersionFeatures.Supports); no render/runtime probe. Cratis/AI#576: prior mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
|
|
204
|
+
"notes": "Cratis/AI#975: reviewed every release v4.246.0 through v5.1.0. Standalone 5.1.0 and its byte-identical contract pinned; the onboarding/environment contract exceptions are gone. v5.0.0: objects and lists are indented blocks (`member = value`, `item`, `none`, `empty`), inline JSON is PLAY0833, and every skill example uses the block form. v4.246.0 (decision 0115): a specification runs only its own slice; command specifications state their own events, automations state cross-slice hand-overs with `then invokes` (ESM v34), and every cross-slice expectation in the examples moved to the producing slice. v4.248.0: action subjects `for item`/`for screen` with PLAY0817-PLAY0821; every example action states its subject by intent. v4.250.0 (decision 0117): attached handlers beside unconditional produces with a resolved body bind as the v23 result contract; PLAY0800 only for the remaining shapes; PLAY0035 retired. v4.254.0: `$eventContext.occurred` runs in scoped projections for facts appended under `given clock` (probed on the 5.1.0 tool; a `given` fact carries none). v4.257.0: PLAY0824/PLAY0825 preferred-syntax rows. v5.1.0: `statemachine` and `workflow` (ESM v36) taught with a compiled, passing example; Stage 4.214.0 refuses v36. Cratis.Orleans engine hosting remains Cratis/AI#972. Editor-only, host-provider and board releases need no teaching change. Prior: Cratis/AI#820: reviewed v4.245.0 release; protected-read constraint precedence preserved. Review correction: removed unsupported parser-repair and inbound-public refusal release attributions and the incorrect PLAY0136 event-key claim, restoring prior teaching. Published contract asset is byte-identical to the previous snapshot; pin and compatibility entry advanced together. Prior: Cratis/AI#779: reference-runner capability refusals taught as scoped per specification (introduced in v4.213.2, Cratis/Screenplay#897) from the v4.216.0 tool and MCP documentation and plan source: an unadmitted projection (UnsupportedEventContext, UnsupportedProjectionBlock) marks unsupported only the specifications that reach it or its read model, the others run and planIssues lists deferred issues; application-level issues still block every selected specification; no new render/runtime probe. Prior: Cratis/AI#776: PLAY0802 ReservedStoredName (introduced in v4.213.3, Cratis/Screenplay#893) taught from the v4.216.0 compilers and documentation: stored event source `Default` and stored event stream `All` (ordinal, name or `id` pin) refused at authoring time, a pin away from the reserved name valid, PLAY0273 kept as the binding backstop; no new render/runtime probe. Prior: Cratis/AI#784: standalone Screenplay 4.216.0 pinned; compiler contract replaced by the v4.216.0 release asset (adds the propose-repair destinationIntent v1 schema and PLAY0802 ReservedStoredName). Source-checked decision 0096 and the MCP reference for the explicit author-intent PLAY0470 repair: repair-intents discovery, intentActions feature detection, complete per-production selections, retained production-destination report and identity views, explicit apply and refusals. No new render/runtime probe. Prior: Cratis/AI#771: standalone Screenplay 4.213.0 pinned; regenerated compiler contract is byte-identical to the v4.213.0 release asset and unchanged from 4.212.4. Reviewed the full v4.212.4-v4.213.0 delta against tagged decision 0093 and MCP reference: pre-binding container identities and stable binding/migration continuity, own-slice member substitutions, containerIdentities completeness/ambiguity/collision refusals, retained ambiguous notes, explicit semanticRenames/retirements, binding fixes through MCP, exact reopen exception, notes/identity rollback and exact-ID re-add anchoring. No grammar, binder, ESM or diagnostic-code changes; no new render/runtime probe. Prior: Cratis/AI#772: standalone Screenplay 4.212.4 pinned; regenerated compiler contract is byte-identical to the v4.212.4 release asset. Source-checked joined-event automap/no automap overrides and level fallback in executable binding; PLAY0380 covers only all inside children/nested. No new render/runtime probe. Prior: Cratis/AI#769: standalone Screenplay 4.212.3 pinned; regenerated compiler contract is byte-identical to the v4.212.3 release asset. Source-checked both compilers and projection documentation for PLAY0801 DuplicateEventInProjectionScope: shared from/removal/clear set, separate join set, fresh sets per children/nested/variant level, and no two-row update through repeated from blocks with different keys. No new render/runtime probe. Prior: Cratis/AI#768: standalone Screenplay 4.212.2 pinned; regenerated compiler contract is byte-identical to the v4.212.2 release asset (unchanged from the previous contract). Source-checked v4.212.0 split-model dotted note targets, open-workspace applicationIdentity and complete add/reanchor substitutions; unbound container identities are not claimed. v4.212.1 aligns PLAY0535 collection fields, optional parameters and single-result identity inference. v4.212.2 counts read-only query denials for SPEC004, not SPEC006. No new render/runtime probe. Prior: Cratis/AI#762 and #761: source-checked v4.210.0 and v4.211.0 contracts for PLAY0800 CommandHandlerRequiresAttachment (required typed subject, permanent code-attachment requirement, other PLAY0268 families unchanged), independent reference remove/add batches, located same-text ambiguity conflicts and string MCP conflict/move-report document fields. v4.211.1 mapping changes inspected but excluded from this guidance update at the user's request; no typed PLAY0273 property/type arguments are claimed. Standalone Screenplay 4.211.1 and its compiler contract pinned; the contract is a byte-identical copy of the v4.211.1 release asset. No new render/runtime probe. Prior: Standalone 4.205.0 and byte-identical compiler contract pinned. Cratis/AI#746: Uuid ==/!= in command require and produces when (ESM v28): same-concept rule, bare Uuid against a concept, canonical literals, protected read paths in require only; PLAY0268 (different concepts, ordering, Uuid validation and concept rules, read paths in produces when) and PLAY0273 (non-canonical literal) checked against the 4.205.0 compiler, v28 selection read from the MCP executable-model view; Stage admits exact v1-v21 and v23-v26 pairs so v28 is refused STAGE-ESM-016, not probed against a Stage image; CLI 3.74.0 renders through v26. Prior: Standalone 4.204.0 and byte-identical compiler contract pinned. Cratis/AI#702 and #691: PLAY0690 reducer identity (Screenplay 4.170.0, native compiler only) and the screenplay.json validation gate (Screenplay 4.165.0; cratis screenplay validate reads it from CLI 3.65.0) are taught and probed against the 4.204.0 compiler. Cratis/AI#743: flat composite read-model keys (ESM v27): untyped projection key blocks on root from and remove with, equality-filter lists, single-instance by blocks and per-part fixtures, with PLAY0661/PLAY0662/PLAY0268 refusals checked against the 4.204.0 compiler; Stage origin/main still refuses v27 with STAGE-ESM-016 (stage-rendering.md); Stage v4.135.0 v26 admission (Host and executor run date comparisons; renderer STAGE-ESM-046) was source-checked for this sync; no render or runtime probe. Prior: Standalone 4.201.0 and byte-identical compiler contract pinned. Cratis/AI#733: the ui profile root template, shell options, appearance and new screens default (PLAY0788-PLAY0799, quick fix for the legacy layout line, ui-profiles MCP tool, 44 tools). Cratis/AI#735: chronological Date/DateTime ordering in command conditions and command/property literal validation (ESM v26), UTC tick precision and pre-rule offset validation; then matching remains ordinal. Source-checked Screenplay v4.199.0 commands, diagnostics, interoperability and specifications documentation plus decision 0087. Stage v4.127.1 still refuses v26 with STAGE-ESM-016 (stage-rendering.md and SemanticVersionFeatures.Supports); no render/runtime probe. Cratis/AI#576: prior mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
|
|
205
205
|
},
|
|
206
206
|
{
|
|
207
207
|
"id": "scene",
|
|
@@ -12,8 +12,8 @@ The goal is minimal ceremony, maximum clarity. Modern C# (13+) gives us records,
|
|
|
12
12
|
## Building
|
|
13
13
|
|
|
14
14
|
- Use `dotnet build` from the command line.
|
|
15
|
-
-
|
|
16
|
-
-
|
|
15
|
+
- Follow `.editorconfig`; run `dotnet format` only when CI requires it.
|
|
16
|
+
- Run affected spec executables; use `dotnet test <project> --no-build` only for VSTest (see `specs.csharp.md`).
|
|
17
17
|
|
|
18
18
|
## Formatting
|
|
19
19
|
|
|
@@ -59,7 +59,7 @@ Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dua
|
|
|
59
59
|
## Quality gates (framework)
|
|
60
60
|
|
|
61
61
|
- Build clean (Debug and Release) with **zero warnings, zero errors**.
|
|
62
|
-
- Specs pass for affected projects (C#
|
|
62
|
+
- Specs pass for affected projects (C# spec executables (VSTest only: `dotnet test <project> --no-build`); TS packages via their test command; Components also `build-storybook`).
|
|
63
63
|
- For public-facing changes (APIs, attributes, generated output, component props): update the product documentation and verify it.
|
|
64
64
|
- Match the repo's existing patterns; when a deep architectural question isn't answered by the universal rules or this file, consult the **repo's own docs/CONTRIBUTING** or ask — do not infer framework internals from a single call site.
|
|
65
65
|
|
|
@@ -62,7 +62,8 @@ using Microsoft.AspNetCore.Builder;
|
|
|
62
62
|
using MongoDB.Driver;
|
|
63
63
|
|
|
64
64
|
var builder = WebApplication.CreateBuilder(args);
|
|
65
|
-
|
|
65
|
+
var connectionString = builder.Configuration.GetConnectionString("Mongo")
|
|
66
|
+
?? throw new InvalidOperationException("Configure the Mongo connection string.");
|
|
66
67
|
builder.AddCratisOrleans(new CratisOrleansOptions
|
|
67
68
|
{
|
|
68
69
|
ClusterId = "my-service",
|
|
@@ -31,6 +31,6 @@ applyTo: "**/*"
|
|
|
31
31
|
## Before you create or edit a PR
|
|
32
32
|
|
|
33
33
|
- Run `node .cratis/ai/hooks/scripts/cratis-check-pr.mjs --body-file <file> --label <intent>`; it applies the exact `policy / verify` release-note rules and the Bash hook runs it on `gh pr create` and `gh pr edit`. If it fails, fix the description, not the code. Before every body edit, run `git diff --stat origin/main...HEAD` and delete bullets the diff no longer supports.
|
|
34
|
-
- Run the affected-project gates before marking work ready (
|
|
34
|
+
- Run the affected-project gates before marking work ready (build, built specs, lint and type-check; zero warnings), and the repository's required CI checks after an authorized push. `no-release` and documentation-only PRs still satisfy every required check; none is a blanket exemption from red CI.
|
|
35
35
|
- Group small related changes into one branch and one PR; see the skill for consolidation and the release-action windows.
|
|
36
36
|
- Open the PR once, when verified: each push starts CI. One PR per body of work, opened by the orchestrator (`cratis-engineering-release-trains`), with `--assignee @me`.
|
|
@@ -49,7 +49,7 @@ public class when_combining_parts : Specification
|
|
|
49
49
|
|
|
50
50
|
The shared lifecycle is the default on xUnit v2 and v3 since 5.0; the package registers the framework, so delete any hand-written `[assembly: Xunit.TestFramework(...)]` (it fails with `CS0579`). Eligible classes derive from `Specification`, have one public constructor with no arguments or only framework-managed fixture arguments, and contain only plain facts. Construction, Establish/Because and Destroy run once; all facts share the instance and must not mutate it. `IDisposable` specifications also share the lifecycle since Cratis.Specifications 4.4.0: one construction and one `Dispose` after the last fact. Initialization failure fails every fact. Theories and `ITestOutputHelper` constructors keep per-fact execution. Keep shared lifecycle on; `[PerFactSpecificationLifecycle]` opts out only the class whose facts genuinely mutate shared state and cannot move the mutation into `Because`. `CRSPEC0008` (a fact modifies the shared context) is an error by default: move the change into `Establish` or `Because`. See the **cratis-specifications-csharp** skill's shared-lifecycle reference.
|
|
51
51
|
|
|
52
|
-
Run specifications as
|
|
52
|
+
Run xUnit v3, TUnit and native-runner specifications as each project's built executable: restore and build once, then run its matching configuration/TFM output. Only identified VSTest projects use `dotnet test <project> --no-build`. Never default to solution-wide `dotnet test` in a mixed suite. Filters and the 4.x → 5.0 checklist are in the **cratis-specifications-csharp** skill's [running-specs reference](../skills/cratis-specifications-csharp/references/running-specs.md).
|
|
53
53
|
|
|
54
54
|
CRSPEC0001–CRSPEC0007 are warnings. Since 4.5 the analyzers ship only in `Cratis.Specifications`, transitively used by the framework packages; excluding analyzers on a framework package does not remove them. Derived xUnit/NUnit test attributes are recognized since 4.1.2. `Given`/`When` are aliases since 4.4 (declaring both aliases for one phase is CRSPEC0009), but house style stays `Establish`/`Because`. With warnings as errors, a non-`should_` fact, multiple specs per file (given contexts exempt), a fact on a given context, a `should_` without a test attribute, explicit base lifecycle calls, non-public specs with facts, or `Because` on a given context fail the build. Follow **cratis-specification-by-example**; do not suppress these diagnostics.
|
|
55
55
|
|
|
@@ -16,7 +16,7 @@ Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, a
|
|
|
16
16
|
|
|
17
17
|
You MUST add the `/bl:{}` flag to:
|
|
18
18
|
- `dotnet build`
|
|
19
|
-
- `dotnet test`
|
|
19
|
+
- `dotnet test` when it is the selected VSTest runner; built spec executables do not produce MSBuild binlogs
|
|
20
20
|
- `dotnet pack`
|
|
21
21
|
- `dotnet publish`
|
|
22
22
|
- `dotnet restore`
|
|
@@ -202,7 +202,7 @@ if ($testProjects.Count -eq 0) {
|
|
|
202
202
|
Write-Host "TEST_OUTPUT_ROOT:$testOutputRoot"
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
-
- If `ENTRY_TYPE:NotFound` and SDK-style test projects were found →
|
|
205
|
+
- If `ENTRY_TYPE:NotFound` and SDK-style test projects were found → pass the selected projects to `run-tests` discovery: supported executable suites use their built runners; only VSTest uses `dotnet test <project> --no-build`.
|
|
206
206
|
- If `ENTRY_TYPE:NotFound` and classic test projects were found → use only the repository's documented coverage command; do not infer `dotnet test`.
|
|
207
207
|
- If `ENTRY_TYPE:NotFound` and no test projects found → stop: `No .sln, .slnx, or test projects found under <path>. Provide the path to your .NET solution, filter, or project.`
|
|
208
208
|
- A missing/unreadable requested path, failed lookup, or ambiguous entry point is a discovery blocker, not measured zero coverage or evidence of an empty suite. Do not continue collection after a discovery error.
|
|
@@ -44,7 +44,7 @@ This skill is a method: it names no API of its own. When the Screenplay skills a
|
|
|
44
44
|
| --- | --- |
|
|
45
45
|
| Where each rule lives (validator, `Provide()`, handler result, constraint, exception) | `rules/vertical-slices.md` "The decision matrix" |
|
|
46
46
|
| A customization never makes a rejected model renderable; managed output is never hand-edited | Stage (`Customizations/` is the unmanaged seam; managed output is regenerated) |
|
|
47
|
-
| Attached file or inline command handlers
|
|
47
|
+
| Attached file or inline command handlers bind beside unconditional `produces` with a resolved body (Screenplay 4.250.0) and are otherwise refused with PLAY0800 (4.210.0 to 4.249.x refuse every attached handler; older binders report PLAY0268); pending handlers with unconditional productions bind v23 as described commands, but reached bodies are Unsupported ImplementationBody and Stage refuses STAGE-IMPL-002 even in Stub mode | Screenplay and Stage; use the model as the gap-fill contract |
|
|
48
48
|
|
|
49
49
|
## Procedure
|
|
50
50
|
|
|
@@ -302,6 +302,6 @@ ideas recorded in `references/provenance.md`. Read `references/provenance.md` wh
|
|
|
302
302
|
## How it is proven
|
|
303
303
|
|
|
304
304
|
`dotnet build -c Debug` — it compiles the `#if DEBUG` specification code — then
|
|
305
|
-
|
|
305
|
+
the owning project's built spec executable (see [specs.csharp](../../rules/specs.csharp.md)), both clean, with a specification for the happy path and one per
|
|
306
306
|
rejection. Before trusting a rejection specification green, remove the condition
|
|
307
307
|
that causes the rejection once and confirm it goes red.
|
|
@@ -59,7 +59,7 @@ These non-refusal failures and unhandled refusals fail the observer for recovery
|
|
|
59
59
|
## Verify
|
|
60
60
|
|
|
61
61
|
Run `dotnet build -c Debug` and the affected specification project with
|
|
62
|
-
|
|
62
|
+
the owning project's built spec executable (see [specs.csharp](../../../rules/specs.csharp.md)). Cover selector ordering, each handled refusal, unchanged
|
|
63
63
|
remaining-command collaborators, branch append failure, and a concurrency or
|
|
64
64
|
exception failure that must not be acknowledged. Assert earlier committed effects
|
|
65
65
|
separately; a failed result does not prove rollback.
|
package/package/corpus/skills/cratis-arc-command-execution/references/occurrence-commands.md
CHANGED
|
@@ -76,4 +76,4 @@ append behavior. Deliver the same occurrence twice under the same effect name:
|
|
|
76
76
|
assert one committed effect and a recorded result on the second delivery. Cover
|
|
77
77
|
a terminal refusal, a retryable concurrency conflict, insufficient capability,
|
|
78
78
|
and commit-then-lost-reply recovery. Run the owning specification project with
|
|
79
|
-
|
|
79
|
+
the owning project's built spec executable (see [specs.csharp](../../../rules/specs.csharp.md)); passing means those assertions ran, not just that compilation succeeded.
|
|
@@ -237,7 +237,7 @@ not uncertain remote acknowledgments or the external provider's durability.
|
|
|
237
237
|
`UncompensatedCount`/`FailedCompensationCount`, and remaining callbacks attempted.
|
|
238
238
|
|
|
239
239
|
Arc's [failure recipes](https://github.com/Cratis/Arc/blob/main/Documentation/backend/csharp/testing/command-operation-failures.md)
|
|
240
|
-
contain the full cases. Run
|
|
240
|
+
contain the full cases. Run the owning project's built spec executable (see [specs.csharp](../../../rules/specs.csharp.md)); assert behavior,
|
|
241
241
|
not just command success. These corpus excerpts are source-checked, not compiled
|
|
242
242
|
by the corpus text-verification gate. Test provider ownership, repeated finalized
|
|
243
243
|
requests, conflicting keys, and delayed creates at the provider integration boundary.
|
|
@@ -61,6 +61,6 @@ Arc can fail to bind such results to the matching form field.
|
|
|
61
61
|
|
|
62
62
|
Add specs for offset-less rejection, an accepted offset, malformed input under
|
|
63
63
|
both authorized and denied callers, and nested/indexed member paths. Assert
|
|
64
|
-
server `Members` using camelCase and run
|
|
64
|
+
server `Members` using camelCase and run the owning spec project's built executable (see [specs.csharp](../../../rules/specs.csharp.md)).
|
|
65
65
|
For form behavior, assert the rejection appears on its intended field, not only
|
|
66
66
|
in a command-wide error list.
|
package/package/corpus/skills/cratis-arc-command-validation/references/validation-severity.md
CHANGED
|
@@ -18,4 +18,4 @@ remove the floor, and an explicit attribute wins. Check with
|
|
|
18
18
|
|
|
19
19
|
Specify both the default refusal and a caller sending a permissive severity.
|
|
20
20
|
Assert the command did not write events; a displayed message alone is not proof
|
|
21
|
-
that validation blocked execution. Run
|
|
21
|
+
that validation blocked execution. Run the owning spec project's built executable (see [specs.csharp](../../../rules/specs.csharp.md)).
|