@cratis/pi 7.124.0 → 7.125.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/spec-writer.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/application-profile.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/framework.instructions.md +1 -0
- package/package/corpus/harnesses/copilot/instructions/specs.csharp.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/specs.scenarios.csharp.instructions.md +4 -4
- package/package/corpus/harnesses/copilot/instructions/verification-discipline.instructions.md +1 -0
- package/package/corpus/harnesses/copilot/instructions/vertical-slices.instructions.md +1 -1
- package/package/corpus/harnesses/pi/agents/spec-writer.md +1 -1
- package/package/corpus/rules/application-profile.md +1 -1
- package/package/corpus/rules/framework.md +1 -0
- package/package/corpus/rules/general.md +2 -1
- package/package/corpus/rules/specs.csharp.md +1 -1
- package/package/corpus/rules/specs.scenarios.csharp.md +4 -4
- package/package/corpus/rules/verification-discipline.md +1 -0
- package/package/corpus/rules/vertical-slices.md +1 -1
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +5 -4
- package/package/corpus/skills/cratis-application-slice-specifications/references/query-and-decision-scenarios.md +14 -16
- package/package/corpus/skills/cratis-arc-command/SKILL.md +1 -1
- package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +13 -7
- package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +3 -3
- package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-decision-reads/references/choosing-how-a-rule-holds.md +5 -6
- package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +8 -4
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +15 -0
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +2 -3
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +4 -4
- package/package/corpus/skills/cratis-specifications-csharp/references/running-specs.md +1 -1
- package/package.json +1 -1
|
@@ -94,7 +94,7 @@ public class and_all_information_is_valid : Specification
|
|
|
94
94
|
|
|
95
95
|
### What to specify
|
|
96
96
|
|
|
97
|
-
0. **Every contract specification first** — one spec each, named after it, using the contract's example values. Then add the code-derived cases below that the contract lacks and report them as proposals for the contract (the `.play` model when one covers the slice, otherwise the agreed outline); never present them as contract coverage. A `.play` specification maps to a plain-call spec for a pure decision, with a scenario added only for the composition
|
|
97
|
+
0. **Every contract specification first** — one spec each, named after it, using the contract's example values. Then add the code-derived cases below that the contract lacks and report them as proposals for the contract (the `.play` model when one covers the slice, otherwise the agreed outline); never present them as contract coverage. A `.play` specification maps to a plain-call spec for a pure decision, with a scenario added only for the pipeline composition it proves (never a simulated race); never edit, skip or delete a spec derived from the contract to make code pass — change the code or return an edit request.
|
|
98
98
|
1. **Happy path** — succeeds, correct event(s) appended.
|
|
99
99
|
2. **Each validation failure** — call the validator directly with supplied state; pipeline validation specs assert **both** `ShouldNotBeSuccessful()` and `ShouldHaveValidationErrors()`. Do not assert on message strings by default; assert exact text only when that wording is the specified behavior, and name that behavior in the fact. Violate **only** the rule the spec is named after (build the command valid in every other respect), or a neighbouring rule makes it pass.
|
|
100
100
|
3. **Business-rule violations** — call `Handle()` or the validator directly with the required model state and assert each rejection. Arc/Chronicle specs alone prove platform concurrency, conflict refusal and isolation. The application's only decision-read spec obligation is the single cheap shape-admission spec in `specs.scenarios.csharp.md`; do not repeat guard scenarios per decision.
|
|
@@ -74,7 +74,7 @@ Tagged **[contract]** (framework-enforced) or **[convention]** (house default).
|
|
|
74
74
|
3. **Code level** — infrastructure (hosting, DI composition, identity wiring, CI, deployment), clients, Screenplay code attachments and handlers, adapters in the render's customization area, and scope Stage cannot render yet (the model remains the contract). Framework repositories and brownfield work that is not opted in also stay code-first. Only the entry-point session may propose a model, at most once per session and never for trivial, bug-fix, infrastructure, client, framework or brownfield-maintenance work; if declined, do not ask again. Confirm Module/Feature, slice name, slice type and domain requirements as before; for new behavior or unclear event vocabulary run **cratis-chronicle-event-modeling** first, and record the agreed outline (fields, events, rules, scenarios) where the team tracks work, if anywhere. If you write code first where a model exists, say the model now lags.
|
|
75
75
|
4. **Trivial changes** keep the proportional-delegation policy; Phases 1–3 below apply to code you write at either level.
|
|
76
76
|
- **Phase 1 — Backend.** Implement a coherent slice change. **Gate:** incremental Debug build of the affected project (regenerates proxies, compiles `#if DEBUG` spec code).
|
|
77
|
-
- **Phase 2 — Specs.** Mandatory for every slice type. Start with plain calls for pure command/validator/reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints
|
|
77
|
+
- **Phase 2 — Specs.** Mandatory for every slice type. Start with plain calls for pure command/validator/reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints or declarative mapping. Follow [specs.scenarios.csharp.md](./specs.scenarios.csharp.instructions.md) for shared setup and cost budgets. **Gate:** tests pass.
|
|
78
78
|
- **Phase 3 — Frontend.** Build from the generated proxies, register in the composition page, wire routing. **Gate:** lint, conditional test, build.
|
|
79
79
|
|
|
80
80
|
**Backend before frontend, always** — the frontend depends on proxies that exist only after a successful build. Generate proxies from the **Debug** build (house convention); verify Release without re-running the generator: `dotnet build -c Release -p:CratisProxiesOutputPath=`. Why that property, and what to do when nothing is generated: the **cratis-arc-command** skill's proxy-generation reference.
|
|
@@ -50,6 +50,7 @@ Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dua
|
|
|
50
50
|
- **Backward compatibility is a contract.** A change to a public type, attribute, interface, or generated-proxy shape is a breaking change for every downstream app — label PRs by semver impact (`major`/`minor`/`patch`) and treat removals/renames of public surface as `major`.
|
|
51
51
|
- **Convention discovery is built here.** `IInstancesOf<T>` / `IImplementationsOf<T>`, attribute-based discovery, and source generation are the mechanisms the framework *provides*; use them internally too rather than hand-registration where a convention fits. A Fundamentals project reference does not carry the type-discovery analyzer like its NuGet package does: reference `Fundamentals.TypeDiscovery.Generator` explicitly, or your project's types may be absent from the generated universe.
|
|
52
52
|
- **Source generators / analyzers** (Arc's proxy generator, Fundamentals) follow Roslyn conventions; their output is consumed verbatim by apps, so treat generated shape as public API.
|
|
53
|
+
- **Analyzers and generators are written for speed** (fast feedback is a product requirement): incremental generators only; a syntactic prefilter (name or kind) before any semantic bind; compute shared evidence once per compilation, never once per analyzer or per symbol; touch it only after cheap relevance checks; never rebind every call site of the compilation. Each expensive analyzer gets a performance spec.
|
|
53
54
|
- **Orleans grains** in the Chronicle kernel follow `orleans.md`.
|
|
54
55
|
- **An alternate implementation of an interface must match the primary one's *semantics*, not just its signature.** Chronicle ships several implementations of the same storage interfaces (MongoDB, SQL, in-memory) and the in-memory ones exist precisely so the real kernel code paths can run without infrastructure. When you touch one, **diff it against the persistent implementations** — the signature tells you nothing about the contract. The specific trap: query criteria carry **sentinels meaning "do not narrow"** (`EventSourceId.Unspecified`, `EventSourceType.Unspecified`/`Default`, `EventStreamType.All`, `EventStreamId.Default`, an empty event-type set). Callers asking for "everything" pass those sentinels, never `null`, so a plain `is not null` check narrows every row away and the read silently returns nothing. A divergence here does not fail — it makes specs pass vacuously, which is worse.
|
|
55
56
|
- **A stub that silently succeeds is a bug, not a placeholder.** An unimplemented method returning `Task.CompletedTask`/an empty result lets a spec assert on work that never happened. Implement it, or make it fail loudly — never leave it quietly lying.
|
|
@@ -12,7 +12,7 @@ Extends the base [specs.md](./specs.instructions.md) (folder structure, naming,
|
|
|
12
12
|
|
|
13
13
|
> **Which spec surface?**
|
|
14
14
|
> - **Framework / library code** (Chronicle kernel, Arc pipeline, source generators, Fundamentals): the `Specification` base + NSubstitute in this file is the dominant mode — unit-test the classes under test in isolation. Reach for a `*Scenario` helper (in [specs.scenarios.csharp.md](./specs.scenarios.csharp.instructions.md)) **only** when testing the very engine your repo provides — Arc → `CommandScenario`, Chronicle → the event/projection/reactor scenarios. The **cratis-application-slice-specifications** skill is application-oriented, not for general framework specs.
|
|
15
|
-
> - **Event-sourced applications on Cratis** (commands, projections, reducers, reactors, constraints): use this base plus a direct call by default for pure `Handle()`, validator and reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints
|
|
15
|
+
> - **Event-sourced applications on Cratis** (commands, projections, reducers, reactors, constraints): use this base plus a direct call by default for pure `Handle()`, validator and reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints or declarative projections — see **[specs.scenarios.csharp.md](./specs.scenarios.csharp.instructions.md)** (`profile: application`) and the **cratis-application-slice-specifications** skill.
|
|
16
16
|
|
|
17
17
|
`Cratis.Specifications` keeps the approach of Machine.Specifications (MSpec): `Establish → Because → should_` maps to "Given → When → Then" and keeps each spec focused on *one setup, one action, one set of assertions*.
|
|
18
18
|
|
package/package/corpus/harnesses/copilot/instructions/specs.scenarios.csharp.instructions.md
CHANGED
|
@@ -15,16 +15,16 @@ Specs are **mandatory for every slice type**, including reactors.
|
|
|
15
15
|
|
|
16
16
|
## Start with the plain call; add a scenario where it adds proof
|
|
17
17
|
|
|
18
|
-
**Judgment-shaped convention:** call pure `Handle()`, validators, reducers and reactor decisions directly with their inputs, including read-model state. Add a scenario only for pipeline/authorization wiring, constraints
|
|
18
|
+
**Judgment-shaped convention:** call pure `Handle()`, validators, reducers and reactor decisions directly with their inputs, including read-model state. Add a scenario only for pipeline/authorization wiring, constraints or declarative projection mapping. Do not repeat every decision through the pipeline; name the extra behavior each scenario proves.
|
|
19
19
|
|
|
20
|
-
**Application specs supply state, not decision-read infrastructure.** Call `Handle()` or the validator directly with supplied read-model state. Never call `UseDecisionReads`, configure protection modes, seed events solely for infrastructure, or re-prove the platform's concurrency, conflict-refusal or isolation matrix; Arc/Chronicle specs own it. The application's **only decision-read spec obligation** is one cheap assembly-level shape-admission spec: `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` (`Cratis.Arc.Chronicle.Testing.Commands`). It checks the application's own models/projections without executing commands or running Chronicle, not the platform guards.
|
|
20
|
+
**Application specs supply state, not decision-read infrastructure.** Call `Handle()` or the validator directly with supplied read-model state. Never call `UseDecisionReads`, configure protection modes, seed events solely for infrastructure, or re-prove the platform's concurrency, conflict-refusal or isolation matrix; Arc/Chronicle specs own it. The application's **only decision-read spec obligation** is one cheap assembly-level shape-admission spec: `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` (`Cratis.Arc.Chronicle.Testing.Commands`). It checks the application's own models/projections without executing commands or running Chronicle, not the platform guards. Never simulate competing appends either (`AppendConcurrently` or any hand-built interleaving): concurrency is a framework concern a developer should not think about in tests, and Arc and Chronicle specs prove it. A rule that must hold under races is expressed in production by taking the read model as a `Handle` parameter under `[ReadProtection(On)]`; the spec gives that read model's state and asserts the outcome. Report harness state gaps upstream; never weaken production guards for speed. `AppendConcurrently` is an advanced framework-verification API: use only for an explicit need. Direction, no release claim: Arc will obsolete `UseDecisionReads`.
|
|
21
21
|
|
|
22
22
|
**Share setup and budget cost (judgment-shaped).** Keep shared lifecycle on; use `[PerFactSpecificationLifecycle]` only on a class whose facts genuinely mutate shared state and cannot move that mutation into `Because`. Plain decision specs should take roughly milliseconds; measure scenario facts and justify seconds by the extra behavior they prove. Compare TRX durations and suite wall time with unchanged concurrency; see [running-specs.md](../../../skills/cratis-specifications-csharp/references/running-specs.md). Do not multiply scenario startup by splitting assertions into classes or opting the project out of shared lifecycle.
|
|
23
23
|
|
|
24
24
|
| Tool | Tests | Use when |
|
|
25
25
|
|---|---|---|
|
|
26
26
|
| `Specification` (plain call) | `Handle()`, `Handle(providedValue)`, validator/reducer logic or a reactor's decision as a method call; or an isolated class with mocked collaborators | **default** for a decision that is a pure function of its arguments |
|
|
27
|
-
| `CommandScenario<TCommand>` | the real Arc command pipeline — authorization + validators + `Provide()` + `Handle()` + appended events | pipeline wiring, authorization
|
|
27
|
+
| `CommandScenario<TCommand>` | the real Arc command pipeline — authorization + validators + `Provide()` + `Handle()` + appended events | pipeline wiring, authorization or constraints adds proof |
|
|
28
28
|
| `QueryScenario<TReadModel>` | query pipeline: argument conversion, authorization, validation, interceptors; `Observe` buffers emissions | query composition matters; real MongoDB observations still need infrastructure |
|
|
29
29
|
| `EventScenario` | Chronicle-level append semantics, no command pipeline | constraint violations, raw stream sequencing/concurrency |
|
|
30
30
|
| `ReadModelScenario<TReadModel>` | projection/reducer state from a sequence of events (auto-detects model-bound / fluent / reducer) | one class per read model, many read-only assertions on shared setup |
|
|
@@ -121,7 +121,7 @@ arguments?, paging?, sorting?)`; `Observe(...)` returns `QueryObservation.Initia
|
|
|
121
121
|
and buffered `Next()`. Configure principal/policies in `Services`; schemes fail
|
|
122
122
|
closed without HTTP. Chronicle query `Given` can seed keyed models/events.
|
|
123
123
|
|
|
124
|
-
For query setup
|
|
124
|
+
For query setup, see **cratis-application-slice-specifications**,
|
|
125
125
|
`references/query-and-decision-scenarios.md`. Framework read-protection guards are not application spec obligations.
|
|
126
126
|
|
|
127
127
|
### `EventScenario` — constraints & append semantics
|
package/package/corpus/harnesses/copilot/instructions/verification-discipline.instructions.md
CHANGED
|
@@ -14,6 +14,7 @@ authored a file or preserve a chain of evidence about how it arrived.
|
|
|
14
14
|
- Run one phase per command with its real exit status. Budget targeted checks around 120 seconds and build/test phases around 300 seconds; explain any longer budget first, and obtain explicit approval before a phase exceeds 600 seconds. Stop on a failure; do not blindly retry or repeat passing tests on unchanged inputs without a flaky-test hypothesis or required matrix.
|
|
15
15
|
- Separate status/fetch from builds, Debug from Release, each test project, and frontend lint/compile/test/build. Do not combine these into an opaque command with a large outer timeout. Expose progress and cancellation; report the precise failed or timed-out phase and do not continue dependent phases after failure.
|
|
16
16
|
- Never use `build/test | grep | sort/head/tail` as gate evidence. Capture the producer's exit status before summarising output; `pipefail` alone is insufficient with early-closing consumers such as `head`. Printed zero-error counts are not proof of success. Preserve needed full diagnostics in task-scoped `.ai-work/` logs rather than hiding them in `/tmp`.
|
|
17
|
+
- Fast feedback is a product requirement: a spec takes milliseconds, the suite seconds; specs share setup and run in parallel; analyzers must not halt builds. CI builds the spec path without analyzers and enforces them, warnings as errors, in a parallel required job; the pre-push gate runs them. A slowdown is a defect.
|
|
17
18
|
- Add a focused specification for every behavior or rejection rule you change.
|
|
18
19
|
- Keep each check deterministic and runnable locally and in CI.
|
|
19
20
|
- Never replace a real behavior check with a checksum, inventory, generated
|
|
@@ -21,7 +21,7 @@ This file is the reference for *what* goes in each part of a slice. Layout, slic
|
|
|
21
21
|
|
|
22
22
|
- .NET / C# (ASP.NET Core) — **Cratis Arc** for CQRS / model-bound commands and queries, **Cratis Chronicle** for event sourcing, MongoDB or EF Core for read models.
|
|
23
23
|
- React + TypeScript (Vite) — Cratis Components 4.x + Arc-generated proxies, MVVM. Vitest + Mocha/Chai/Sinon for frontend specs.
|
|
24
|
-
- xUnit + Cratis.Specifications + NSubstitute for C# specs (`Specification` plus a direct call for pure command/validator/reducer decisions with supplied state; add scenarios only for pipeline/authorization wiring, constraints
|
|
24
|
+
- xUnit + Cratis.Specifications + NSubstitute for C# specs (`Specification` plus a direct call for pure command/validator/reducer decisions with supplied state; add scenarios only for pipeline/authorization wiring, constraints or declarative projections — see [specs.md](./specs.instructions.md)).
|
|
25
25
|
|
|
26
26
|
## Proxy generation — the build dependency
|
|
27
27
|
|
|
@@ -89,7 +89,7 @@ public class and_all_information_is_valid : Specification
|
|
|
89
89
|
|
|
90
90
|
### What to specify
|
|
91
91
|
|
|
92
|
-
0. **Every contract specification first** — one spec each, named after it, using the contract's example values. Then add the code-derived cases below that the contract lacks and report them as proposals for the contract (the `.play` model when one covers the slice, otherwise the agreed outline); never present them as contract coverage. A `.play` specification maps to a plain-call spec for a pure decision, with a scenario added only for the composition
|
|
92
|
+
0. **Every contract specification first** — one spec each, named after it, using the contract's example values. Then add the code-derived cases below that the contract lacks and report them as proposals for the contract (the `.play` model when one covers the slice, otherwise the agreed outline); never present them as contract coverage. A `.play` specification maps to a plain-call spec for a pure decision, with a scenario added only for the pipeline composition it proves (never a simulated race); never edit, skip or delete a spec derived from the contract to make code pass — change the code or return an edit request.
|
|
93
93
|
1. **Happy path** — succeeds, correct event(s) appended.
|
|
94
94
|
2. **Each validation failure** — call the validator directly with supplied state; pipeline validation specs assert **both** `ShouldNotBeSuccessful()` and `ShouldHaveValidationErrors()`. Do not assert on message strings by default; assert exact text only when that wording is the specified behavior, and name that behavior in the fact. Violate **only** the rule the spec is named after (build the command valid in every other respect), or a neighbouring rule makes it pass.
|
|
95
95
|
3. **Business-rule violations** — call `Handle()` or the validator directly with the required model state and assert each rejection. Arc/Chronicle specs alone prove platform concurrency, conflict refusal and isolation. The application's only decision-read spec obligation is the single cheap shape-admission spec in `specs.scenarios.csharp.md`; do not repeat guard scenarios per decision.
|
|
@@ -73,7 +73,7 @@ Tagged **[contract]** (framework-enforced) or **[convention]** (house default).
|
|
|
73
73
|
3. **Code level** — infrastructure (hosting, DI composition, identity wiring, CI, deployment), clients, Screenplay code attachments and handlers, adapters in the render's customization area, and scope Stage cannot render yet (the model remains the contract). Framework repositories and brownfield work that is not opted in also stay code-first. Only the entry-point session may propose a model, at most once per session and never for trivial, bug-fix, infrastructure, client, framework or brownfield-maintenance work; if declined, do not ask again. Confirm Module/Feature, slice name, slice type and domain requirements as before; for new behavior or unclear event vocabulary run **cratis-chronicle-event-modeling** first, and record the agreed outline (fields, events, rules, scenarios) where the team tracks work, if anywhere. If you write code first where a model exists, say the model now lags.
|
|
74
74
|
4. **Trivial changes** keep the proportional-delegation policy; Phases 1–3 below apply to code you write at either level.
|
|
75
75
|
- **Phase 1 — Backend.** Implement a coherent slice change. **Gate:** incremental Debug build of the affected project (regenerates proxies, compiles `#if DEBUG` spec code).
|
|
76
|
-
- **Phase 2 — Specs.** Mandatory for every slice type. Start with plain calls for pure command/validator/reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints
|
|
76
|
+
- **Phase 2 — Specs.** Mandatory for every slice type. Start with plain calls for pure command/validator/reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints or declarative mapping. Follow [specs.scenarios.csharp.md](./specs.scenarios.csharp.md) for shared setup and cost budgets. **Gate:** tests pass.
|
|
77
77
|
- **Phase 3 — Frontend.** Build from the generated proxies, register in the composition page, wire routing. **Gate:** lint, conditional test, build.
|
|
78
78
|
|
|
79
79
|
**Backend before frontend, always** — the frontend depends on proxies that exist only after a successful build. Generate proxies from the **Debug** build (house convention); verify Release without re-running the generator: `dotnet build -c Release -p:CratisProxiesOutputPath=`. Why that property, and what to do when nothing is generated: the **cratis-arc-command** skill's proxy-generation reference.
|
|
@@ -49,6 +49,7 @@ Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dua
|
|
|
49
49
|
- **Backward compatibility is a contract.** A change to a public type, attribute, interface, or generated-proxy shape is a breaking change for every downstream app — label PRs by semver impact (`major`/`minor`/`patch`) and treat removals/renames of public surface as `major`.
|
|
50
50
|
- **Convention discovery is built here.** `IInstancesOf<T>` / `IImplementationsOf<T>`, attribute-based discovery, and source generation are the mechanisms the framework *provides*; use them internally too rather than hand-registration where a convention fits. A Fundamentals project reference does not carry the type-discovery analyzer like its NuGet package does: reference `Fundamentals.TypeDiscovery.Generator` explicitly, or your project's types may be absent from the generated universe.
|
|
51
51
|
- **Source generators / analyzers** (Arc's proxy generator, Fundamentals) follow Roslyn conventions; their output is consumed verbatim by apps, so treat generated shape as public API.
|
|
52
|
+
- **Analyzers and generators are written for speed** (fast feedback is a product requirement): incremental generators only; a syntactic prefilter (name or kind) before any semantic bind; compute shared evidence once per compilation, never once per analyzer or per symbol; touch it only after cheap relevance checks; never rebind every call site of the compilation. Each expensive analyzer gets a performance spec.
|
|
52
53
|
- **Orleans grains** in the Chronicle kernel follow `orleans.md`.
|
|
53
54
|
- **An alternate implementation of an interface must match the primary one's *semantics*, not just its signature.** Chronicle ships several implementations of the same storage interfaces (MongoDB, SQL, in-memory) and the in-memory ones exist precisely so the real kernel code paths can run without infrastructure. When you touch one, **diff it against the persistent implementations** — the signature tells you nothing about the contract. The specific trap: query criteria carry **sentinels meaning "do not narrow"** (`EventSourceId.Unspecified`, `EventSourceType.Unspecified`/`Default`, `EventStreamType.All`, `EventStreamId.Default`, an empty event-type set). Callers asking for "everything" pass those sentinels, never `null`, so a plain `is not null` check narrows every row away and the read silently returns nothing. A divergence here does not fail — it makes specs pass vacuously, which is worse.
|
|
54
55
|
- **A stub that silently succeeds is a bug, not a placeholder.** An unimplemented method returning `Task.CompletedTask`/an empty result lets a spec assert on work that never happened. Implement it, or make it fail loudly — never leave it quietly lying.
|
|
@@ -13,7 +13,7 @@ Profile-specific rules declare a **`profile:`** in their frontmatter (`applicati
|
|
|
13
13
|
|
|
14
14
|
> **Arc is a standalone CQRS framework — not bound to event sourcing.** Even within the application profile, Arc provides model-bound commands/queries, validation, authorization, and full-stack proxy generation, and works **without** Chronicle (Arc.Core does not depend on Chronicle). A `[Command]` `Handle()` does not *have* to append events — it can return a response, return `void`, or work through injected services. The event-sourcing behavior (a returned event gets appended; `EventForEventSourceId`; "never inject `IEventLog`") comes from the **Arc + Chronicle** integration. This application is event-sourced, so the slice guidance assumes event-sourced commands — read the event-centric rules as the *house default for this app*, not universal Arc laws.
|
|
15
15
|
|
|
16
|
-
The framework is convention-over-configuration. **Idiomatic Cratis is the goal — not custom abstractions over it.** When something is unclear, prefer the Cratis convention; do not invent. The rules and skills under `.cratis/ai/` are the authoritative answer — if your question is not answered there, ask rather than inferring framework behavior from package internals.
|
|
16
|
+
The framework is convention-over-configuration. **Idiomatic Cratis is the goal — not custom abstractions over it.** Always recommend the idiomatic way unless explicitly needed otherwise. When something is unclear, prefer the Cratis convention; do not invent. The rules and skills under `.cratis/ai/` are the authoritative answer — if your question is not answered there, ask rather than inferring framework behavior from package internals.
|
|
17
17
|
|
|
18
18
|
## Project Philosophy
|
|
19
19
|
|
|
@@ -52,6 +52,7 @@ obtaining credentials, and other local conventions ("Product policy" above).
|
|
|
52
52
|
- Project context may explain which approved secret mechanism or local setup to
|
|
53
53
|
use, but it must never contain credential values, tokens, keys, passwords, or
|
|
54
54
|
other secrets.
|
|
55
|
+
- A repository's accepted decision records (`decisions/`) and project rules bind AI work: read those matching your paths, follow them, never work around one.
|
|
55
56
|
- Project-specific guidance wins when it deliberately narrows shared behavior,
|
|
56
57
|
but it may not weaken organization security, authorization, or required
|
|
57
58
|
quality gates.
|
|
@@ -11,7 +11,7 @@ Extends the base [specs.md](./specs.md) (folder structure, naming, philosophy) w
|
|
|
11
11
|
|
|
12
12
|
> **Which spec surface?**
|
|
13
13
|
> - **Framework / library code** (Chronicle kernel, Arc pipeline, source generators, Fundamentals): the `Specification` base + NSubstitute in this file is the dominant mode — unit-test the classes under test in isolation. Reach for a `*Scenario` helper (in [specs.scenarios.csharp.md](./specs.scenarios.csharp.md)) **only** when testing the very engine your repo provides — Arc → `CommandScenario`, Chronicle → the event/projection/reactor scenarios. The **cratis-application-slice-specifications** skill is application-oriented, not for general framework specs.
|
|
14
|
-
> - **Event-sourced applications on Cratis** (commands, projections, reducers, reactors, constraints): use this base plus a direct call by default for pure `Handle()`, validator and reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints
|
|
14
|
+
> - **Event-sourced applications on Cratis** (commands, projections, reducers, reactors, constraints): use this base plus a direct call by default for pure `Handle()`, validator and reducer decisions with supplied read-model state; add scenarios only for pipeline/authorization wiring, constraints or declarative projections — see **[specs.scenarios.csharp.md](./specs.scenarios.csharp.md)** (`profile: application`) and the **cratis-application-slice-specifications** skill.
|
|
15
15
|
|
|
16
16
|
`Cratis.Specifications` keeps the approach of Machine.Specifications (MSpec): `Establish → Because → should_` maps to "Given → When → Then" and keeps each spec focused on *one setup, one action, one set of assertions*.
|
|
17
17
|
|
|
@@ -14,16 +14,16 @@ Specs are **mandatory for every slice type**, including reactors.
|
|
|
14
14
|
|
|
15
15
|
## Start with the plain call; add a scenario where it adds proof
|
|
16
16
|
|
|
17
|
-
**Judgment-shaped convention:** call pure `Handle()`, validators, reducers and reactor decisions directly with their inputs, including read-model state. Add a scenario only for pipeline/authorization wiring, constraints
|
|
17
|
+
**Judgment-shaped convention:** call pure `Handle()`, validators, reducers and reactor decisions directly with their inputs, including read-model state. Add a scenario only for pipeline/authorization wiring, constraints or declarative projection mapping. Do not repeat every decision through the pipeline; name the extra behavior each scenario proves.
|
|
18
18
|
|
|
19
|
-
**Application specs supply state, not decision-read infrastructure.** Call `Handle()` or the validator directly with supplied read-model state. Never call `UseDecisionReads`, configure protection modes, seed events solely for infrastructure, or re-prove the platform's concurrency, conflict-refusal or isolation matrix; Arc/Chronicle specs own it. The application's **only decision-read spec obligation** is one cheap assembly-level shape-admission spec: `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` (`Cratis.Arc.Chronicle.Testing.Commands`). It checks the application's own models/projections without executing commands or running Chronicle, not the platform guards.
|
|
19
|
+
**Application specs supply state, not decision-read infrastructure.** Call `Handle()` or the validator directly with supplied read-model state. Never call `UseDecisionReads`, configure protection modes, seed events solely for infrastructure, or re-prove the platform's concurrency, conflict-refusal or isolation matrix; Arc/Chronicle specs own it. The application's **only decision-read spec obligation** is one cheap assembly-level shape-admission spec: `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` (`Cratis.Arc.Chronicle.Testing.Commands`). It checks the application's own models/projections without executing commands or running Chronicle, not the platform guards. Never simulate competing appends either (`AppendConcurrently` or any hand-built interleaving): concurrency is a framework concern a developer should not think about in tests, and Arc and Chronicle specs prove it. A rule that must hold under races is expressed in production by taking the read model as a `Handle` parameter under `[ReadProtection(On)]`; the spec gives that read model's state and asserts the outcome. Report harness state gaps upstream; never weaken production guards for speed. `AppendConcurrently` is an advanced framework-verification API: use only for an explicit need. Direction, no release claim: Arc will obsolete `UseDecisionReads`.
|
|
20
20
|
|
|
21
21
|
**Share setup and budget cost (judgment-shaped).** Keep shared lifecycle on; use `[PerFactSpecificationLifecycle]` only on a class whose facts genuinely mutate shared state and cannot move that mutation into `Because`. Plain decision specs should take roughly milliseconds; measure scenario facts and justify seconds by the extra behavior they prove. Compare TRX durations and suite wall time with unchanged concurrency; see [running-specs.md](../skills/cratis-specifications-csharp/references/running-specs.md). Do not multiply scenario startup by splitting assertions into classes or opting the project out of shared lifecycle.
|
|
22
22
|
|
|
23
23
|
| Tool | Tests | Use when |
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| `Specification` (plain call) | `Handle()`, `Handle(providedValue)`, validator/reducer logic or a reactor's decision as a method call; or an isolated class with mocked collaborators | **default** for a decision that is a pure function of its arguments |
|
|
26
|
-
| `CommandScenario<TCommand>` | the real Arc command pipeline — authorization + validators + `Provide()` + `Handle()` + appended events | pipeline wiring, authorization
|
|
26
|
+
| `CommandScenario<TCommand>` | the real Arc command pipeline — authorization + validators + `Provide()` + `Handle()` + appended events | pipeline wiring, authorization or constraints adds proof |
|
|
27
27
|
| `QueryScenario<TReadModel>` | query pipeline: argument conversion, authorization, validation, interceptors; `Observe` buffers emissions | query composition matters; real MongoDB observations still need infrastructure |
|
|
28
28
|
| `EventScenario` | Chronicle-level append semantics, no command pipeline | constraint violations, raw stream sequencing/concurrency |
|
|
29
29
|
| `ReadModelScenario<TReadModel>` | projection/reducer state from a sequence of events (auto-detects model-bound / fluent / reducer) | one class per read model, many read-only assertions on shared setup |
|
|
@@ -120,7 +120,7 @@ arguments?, paging?, sorting?)`; `Observe(...)` returns `QueryObservation.Initia
|
|
|
120
120
|
and buffered `Next()`. Configure principal/policies in `Services`; schemes fail
|
|
121
121
|
closed without HTTP. Chronicle query `Given` can seed keyed models/events.
|
|
122
122
|
|
|
123
|
-
For query setup
|
|
123
|
+
For query setup, see **cratis-application-slice-specifications**,
|
|
124
124
|
`references/query-and-decision-scenarios.md`. Framework read-protection guards are not application spec obligations.
|
|
125
125
|
|
|
126
126
|
### `EventScenario` — constraints & append semantics
|
|
@@ -13,6 +13,7 @@ authored a file or preserve a chain of evidence about how it arrived.
|
|
|
13
13
|
- Run one phase per command with its real exit status. Budget targeted checks around 120 seconds and build/test phases around 300 seconds; explain any longer budget first, and obtain explicit approval before a phase exceeds 600 seconds. Stop on a failure; do not blindly retry or repeat passing tests on unchanged inputs without a flaky-test hypothesis or required matrix.
|
|
14
14
|
- Separate status/fetch from builds, Debug from Release, each test project, and frontend lint/compile/test/build. Do not combine these into an opaque command with a large outer timeout. Expose progress and cancellation; report the precise failed or timed-out phase and do not continue dependent phases after failure.
|
|
15
15
|
- Never use `build/test | grep | sort/head/tail` as gate evidence. Capture the producer's exit status before summarising output; `pipefail` alone is insufficient with early-closing consumers such as `head`. Printed zero-error counts are not proof of success. Preserve needed full diagnostics in task-scoped `.ai-work/` logs rather than hiding them in `/tmp`.
|
|
16
|
+
- Fast feedback is a product requirement: a spec takes milliseconds, the suite seconds; specs share setup and run in parallel; analyzers must not halt builds. CI builds the spec path without analyzers and enforces them, warnings as errors, in a parallel required job; the pre-push gate runs them. A slowdown is a defect.
|
|
16
17
|
- Add a focused specification for every behavior or rejection rule you change.
|
|
17
18
|
- Keep each check deterministic and runnable locally and in CI.
|
|
18
19
|
- Never replace a real behavior check with a checksum, inventory, generated
|
|
@@ -20,7 +20,7 @@ This file is the reference for *what* goes in each part of a slice. Layout, slic
|
|
|
20
20
|
|
|
21
21
|
- .NET / C# (ASP.NET Core) — **Cratis Arc** for CQRS / model-bound commands and queries, **Cratis Chronicle** for event sourcing, MongoDB or EF Core for read models.
|
|
22
22
|
- React + TypeScript (Vite) — Cratis Components 4.x + Arc-generated proxies, MVVM. Vitest + Mocha/Chai/Sinon for frontend specs.
|
|
23
|
-
- xUnit + Cratis.Specifications + NSubstitute for C# specs (`Specification` plus a direct call for pure command/validator/reducer decisions with supplied state; add scenarios only for pipeline/authorization wiring, constraints
|
|
23
|
+
- xUnit + Cratis.Specifications + NSubstitute for C# specs (`Specification` plus a direct call for pure command/validator/reducer decisions with supplied state; add scenarios only for pipeline/authorization wiring, constraints or declarative projections — see [specs.md](./specs.md)).
|
|
24
24
|
|
|
25
25
|
## Proxy generation — the build dependency
|
|
26
26
|
|
|
@@ -12,7 +12,7 @@ Start a pure decision with a plain method call: `Handle()`,
|
|
|
12
12
|
`Handle(providedValue)`, reducer logic or a reactor's decision needs no host,
|
|
13
13
|
services or harness, including direct validator calls with supplied read-model state.
|
|
14
14
|
Add scenarios only for pipeline/authorization wiring, constraints, declarative
|
|
15
|
-
mapping
|
|
15
|
+
mapping; follow the
|
|
16
16
|
[scenario selection and cost rule](../../rules/specs.scenarios.csharp.md). The scenario family
|
|
17
17
|
exercises the real Arc and Chronicle code paths in-process — no HTTP, no fixture,
|
|
18
18
|
no server.
|
|
@@ -207,14 +207,15 @@ do not replay a projection merely to feed a pure command decision.
|
|
|
207
207
|
Both builder methods return `void`; there is nothing to await.
|
|
208
208
|
|
|
209
209
|
Read protection is invisible to application spec authors. Never configure modes,
|
|
210
|
-
call `UseDecisionReads`,
|
|
211
|
-
the platform concurrency/guard
|
|
210
|
+
call `UseDecisionReads`, simulate competing appends (`AppendConcurrently`), seed
|
|
211
|
+
events solely for infrastructure, or re-prove the platform concurrency/guard
|
|
212
|
+
matrix: give state, assert the outcome. Keep one cheap assembly-level
|
|
212
213
|
`DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` spec for the
|
|
213
214
|
application's own model/projection shapes: its only decision-read spec obligation.
|
|
214
215
|
If the harness cannot accept required state, report the upstream gap; never weaken
|
|
215
216
|
production guards for test speed. Read
|
|
216
217
|
[query and decision scenarios](references/query-and-decision-scenarios.md) for
|
|
217
|
-
query pipelines
|
|
218
|
+
query pipelines.
|
|
218
219
|
|
|
219
220
|
Validator and `Provide()` dependencies are registered in `_scenario.Services`;
|
|
220
221
|
the concrete validator itself is discovered automatically.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Contents
|
|
4
4
|
|
|
5
5
|
- Query pipeline
|
|
6
|
-
-
|
|
6
|
+
- Decision specifications
|
|
7
7
|
- Sources
|
|
8
8
|
|
|
9
9
|
<!-- Copyright (c) Cratis. All rights reserved. -->
|
|
@@ -67,7 +67,7 @@ execution runs the query through Arc's hosted query pipeline and establishes con
|
|
|
67
67
|
before `Provide`/`Handle` on the command path. A direct static query call does not
|
|
68
68
|
cover those pipeline hooks.
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## Decision specifications
|
|
71
71
|
|
|
72
72
|
Start with a direct decision call supplied with read-model state. Follow the
|
|
73
73
|
[scenario rule](../../../rules/specs.scenarios.csharp.md): application authors do
|
|
@@ -89,22 +89,20 @@ method bodies are not statically discovered. If the harness cannot accept
|
|
|
89
89
|
required state for a business decision, report the upstream gap; never weaken
|
|
90
90
|
production guards or invent guard doubles.
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
and the
|
|
95
|
-
|
|
92
|
+
Do not add a scenario to prove a race. A rule such as "two callers reserving the last
|
|
93
|
+
seat yield one reservation" is specified from state: supply a read model with no seats
|
|
94
|
+
left and assert the rejection, then supply one seat and assert the reservation.
|
|
95
|
+
Simulating competing appends is a framework concern a developer should not think
|
|
96
|
+
about in tests; Arc and Chronicle prove it. `AppendConcurrently` stays a public but
|
|
97
|
+
advanced framework-verification API (hidden from IntelliSense), outside application
|
|
98
|
+
testing guidance; use it only for a specific, explicit need. Production expresses
|
|
99
|
+
the guarantee with the read model as a `Handle` parameter under
|
|
100
|
+
`[ReadProtection(On)]`. Direction, not a release claim: Arc will obsolete
|
|
101
|
+
`UseDecisionReads`; do not adopt it.
|
|
102
|
+
`ShouldHaveCompletedStream(ClosedStreamScope)` may assert that a decision completed a
|
|
103
|
+
stream at the exact source and route (`Cratis.Arc.Chronicle.Testing.Commands`).
|
|
96
104
|
Use event history only when it is part of the domain example.
|
|
97
105
|
|
|
98
|
-
For an application-owned race/retry policy only, `AppendConcurrently(id, events...)`
|
|
99
|
-
(or its routed overload) can supply controlled interference. It is not required
|
|
100
|
-
for every guarded decision. Requires Arc 22.92.0 without explicit decision-read
|
|
101
|
-
setup; older limitations are upgrade/report concerns, not application setup
|
|
102
|
-
instructions. A competing append alone proves no policy: assert the intended
|
|
103
|
-
business outcome and ensure the decision would otherwise append.
|
|
104
|
-
`ShouldHaveCompletedStream(ClosedStreamScope)` can assert an application-owned
|
|
105
|
-
completion outcome at the exact source and route. These APIs are in
|
|
106
|
-
`Cratis.Arc.Chronicle.Testing.Commands`.
|
|
107
|
-
|
|
108
106
|
The Chronicle-backed `CommandScenario` discovers constraints automatically.
|
|
109
107
|
Assert domain constraint refusals instead of disabling them; use `EventScenario`
|
|
110
108
|
for append-time uniqueness examples. Do not subclass or substitute its engine.
|
|
@@ -276,7 +276,7 @@ Components guidance, not to this skill.
|
|
|
276
276
|
|
|
277
277
|
Start pure `Handle()` and validator decisions with direct calls and supplied
|
|
278
278
|
read-model state. Add scenarios only for pipeline/authorization wiring,
|
|
279
|
-
constraints
|
|
279
|
+
constraints, never read-protection plumbing or simulated concurrency;
|
|
280
280
|
follow the [scenario selection and cost rule](../../rules/specs.scenarios.csharp.md).
|
|
281
281
|
|
|
282
282
|
- The command is a `record`, carries `[Command]`, and declares a public instance
|
|
@@ -15,6 +15,13 @@ Source: Arc. These features require `Cratis.Arc.Chronicle`.
|
|
|
15
15
|
|
|
16
16
|
## Pick the guarded read
|
|
17
17
|
|
|
18
|
+
**Idiomatic default:** a state-dependent rule takes the read model as a `Handle()`
|
|
19
|
+
(or validator-constructor) parameter, with `[ReadProtection(On)]` where it must hold
|
|
20
|
+
under concurrent writers. Do not take `IDecisionReads` in `Handle()`: it is not
|
|
21
|
+
recommended with Arc and is not an investment target. A computed key stays in
|
|
22
|
+
`Provide()` until a read-model parameter covers it. Direction, not a release claim:
|
|
23
|
+
Arc will pin protected parameters so the idiomatic shape needs no further ceremony.
|
|
24
|
+
|
|
18
25
|
Under read protection `On` (`<CratisReadProtection>On</CratisReadProtection>`, or
|
|
19
26
|
`[ReadProtection(ReadProtectionMode.On)]` on a command), a read model that is a
|
|
20
27
|
parameter of `Handle()` or of a `CommandValidator<T>` constructor is read fresh from
|
|
@@ -178,19 +185,18 @@ source id/type and stream route; reactor tuples/collections cannot mix it with e
|
|
|
178
185
|
Call `Handle()` and validators directly with read-model state for pure business
|
|
179
186
|
decisions. Follow the [scenario rule](../../../rules/specs.scenarios.csharp.md):
|
|
180
187
|
read-protection plumbing is invisible to application spec authors. They never
|
|
181
|
-
call `UseDecisionReads`, configure modes,
|
|
182
|
-
or re-prove the platform concurrency, conflict-refusal or isolation matrix;
|
|
188
|
+
call `UseDecisionReads`, configure modes, simulate competing appends
|
|
189
|
+
(`AppendConcurrently`), seed events solely for infrastructure, or re-prove the platform concurrency, conflict-refusal or isolation matrix;
|
|
183
190
|
Arc/Chronicle specs own it. The application's only decision-read spec obligation
|
|
184
191
|
is one cheap assembly-level shape-admission spec from that rule.
|
|
185
192
|
Never weaken production guards for test speed. Report a harness state-setup gap
|
|
186
193
|
upstream instead of working around it in application specs.
|
|
187
194
|
|
|
188
|
-
Add scenarios for pipeline/authorization wiring
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
Add scenarios for pipeline/authorization wiring or constraints. Never simulate
|
|
196
|
+
competing appends: assert the business outcome from supplied state (for example, no
|
|
197
|
+
copies left rejects). Read
|
|
191
198
|
[query and decision scenarios](../../cratis-application-slice-specifications/references/query-and-decision-scenarios.md)
|
|
192
|
-
for
|
|
193
|
-
and measure the added cost.
|
|
199
|
+
for the query and decision setup. Keep shared lifecycle on and measure the added cost.
|
|
194
200
|
|
|
195
201
|
## Sources
|
|
196
202
|
|
|
@@ -268,10 +268,10 @@ authorization and camelCase member paths are separate contracts.
|
|
|
268
268
|
|
|
269
269
|
Every rule gets a failure specification: instantiate the validator with its
|
|
270
270
|
read-model state and validate directly, asserting the specific rejection. Add
|
|
271
|
-
`CommandScenario<TCommand>` only for pipeline/authorization wiring, constraints
|
|
272
|
-
|
|
271
|
+
`CommandScenario<TCommand>` only for pipeline/authorization wiring, constraints.
|
|
272
|
+
Follow the
|
|
273
273
|
[scenario rule](../../rules/specs.scenarios.csharp.md): application specs never
|
|
274
|
-
configure read-protection modes, call `UseDecisionReads`, seed events solely for
|
|
274
|
+
configure read-protection modes, call `UseDecisionReads`, simulate competing appends, seed events solely for
|
|
275
275
|
infrastructure, or re-prove platform guards. Keep the single cheap assembly-level
|
|
276
276
|
application-shape admission spec specified by that rule; it is the application's
|
|
277
277
|
only decision-read spec obligation. Report harness gaps upstream; never weaken
|
|
@@ -199,5 +199,5 @@ deciding writer is guarded or the rule is a constraint.
|
|
|
199
199
|
changes, absence guards, empty checked appends, isolation and commit lifecycle.
|
|
200
200
|
Their real-client/kernel integration proves the boundary; a default
|
|
201
201
|
`EventScenario` scope strategy returning `None` is not concurrency evidence.
|
|
202
|
-
-
|
|
203
|
-
|
|
202
|
+
- Application specs never simulate competing appends or repeat that matrix.
|
|
203
|
+
Never weaken production guards for spec speed.
|
|
@@ -316,12 +316,11 @@ assembly-level `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)`
|
|
|
316
316
|
check of its own models/projections, not per-decision scenarios. Production
|
|
317
317
|
protection stays unchanged regardless of spec cost.
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
borrowers competing for the last copy
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
the upstream gap rather than adding infrastructure setup to application specs.
|
|
319
|
+
Do not simulate competing appends in an application spec, even for a rule such as
|
|
320
|
+
two borrowers competing for the last copy. Give the state (no copies left) and assert
|
|
321
|
+
the domain outcome (rejected); the guarantee that only one wins is proven by Arc and
|
|
322
|
+
Chronicle. If the harness cannot accept required state, report the upstream gap
|
|
323
|
+
rather than adding infrastructure setup to application specs.
|
|
325
324
|
|
|
326
325
|
## Costs
|
|
327
326
|
|
|
@@ -144,10 +144,14 @@ handle it. Pitfall: without `merge_group` the required check never reports in th
|
|
|
144
144
|
queue. Read `references/required-checks-and-path-filters.md`.
|
|
145
145
|
|
|
146
146
|
**Compile once, analyze once.** Fits any workflow where one push compiles the same
|
|
147
|
-
code several times. Default: build
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
code several times. Default: build the spec path without analyzers
|
|
148
|
+
(`-p:RunAnalyzers=false`) and reuse the output; enforce every analyzer with warnings
|
|
149
|
+
as errors in one parallel **required** job that fails early on compile and analyzer
|
|
150
|
+
errors, while the local fast loop may skip analyzers and the pre-push gate runs them.
|
|
151
|
+
Pitfall: dropping analyzers from the only build that consumers enforce, or leaving
|
|
152
|
+
the analyzer job out of the required checks. Measure analyzer cost per rule before
|
|
153
|
+
and after (binlog analyzer timings), and fix a slow analyzer at its source rather
|
|
154
|
+
than switching it off. Read `references/test-setup-cost.md`.
|
|
151
155
|
|
|
152
156
|
**Cores per job before job count.** Fits uniformly slow jobs. Default: check `nproc`
|
|
153
157
|
and the runner's resources before sharding; undersized runners make every job slow.
|
|
@@ -11,6 +11,7 @@ a suite re-tests a dependency, or when compile errors surface late.
|
|
|
11
11
|
- Test each guarantee where it can break
|
|
12
12
|
- Surface compile errors early
|
|
13
13
|
- Count compiles per push
|
|
14
|
+
- Analyzer cost
|
|
14
15
|
|
|
15
16
|
## Time hidden outside per-test timing
|
|
16
17
|
|
|
@@ -80,3 +81,17 @@ Each extra compile is avoidable: build once, reuse the output (see
|
|
|
80
81
|
`build-once-and-shard.md`). Analyzers can roughly double compile time; run them once
|
|
81
82
|
in a parallel lint job and disable them in the shared build, while keeping the
|
|
82
83
|
strictest configuration that consumers enforce somewhere on the required path.
|
|
84
|
+
|
|
85
|
+
## Analyzer cost
|
|
86
|
+
|
|
87
|
+
Analyzers that run in the spec path stall every build. Take per-analyzer timings
|
|
88
|
+
from a binlog of the slow project, with the same inputs and concurrency before and
|
|
89
|
+
after. Rank by cumulative time per rule, not by assembly. Three results are
|
|
90
|
+
typical: rules that cannot apply to the repository (switch them off; a bulk
|
|
91
|
+
severity setting can run an analyzer whose own rules are `none`), an analyzer that
|
|
92
|
+
rebinds the whole compilation (fix it upstream: syntactic prefilter, evidence
|
|
93
|
+
computed once per compilation, touched only after cheap relevance checks), and
|
|
94
|
+
generators, which are rarely the cost. In one measured application, compiling with
|
|
95
|
+
analyzers took 395 s, 180 s after removing inapplicable rules, and 90 s with
|
|
96
|
+
analyzers off. Pass means the spec-path build skips analyzers, the parallel
|
|
97
|
+
required job still fails on any analyzer warning, and both timings are recorded.
|
|
@@ -13,7 +13,7 @@ of contents, and each file states one setup, one action, and one or more
|
|
|
13
13
|
focused assertions.
|
|
14
14
|
|
|
15
15
|
Read [query and decision scenarios](../cratis-application-slice-specifications/references/query-and-decision-scenarios.md)
|
|
16
|
-
when specifying query emissions
|
|
16
|
+
when specifying query emissions.
|
|
17
17
|
Follow the [scenario selection and cost rule](../../rules/specs.scenarios.csharp.md):
|
|
18
18
|
application specs supply read-model state and test business decisions, never
|
|
19
19
|
read-protection plumbing. `Perform`/`Observe` need configured services/principal;
|
|
@@ -90,8 +90,7 @@ before changing runner or package family.
|
|
|
90
90
|
The plain `Specification` base is the universal foundation and the dominant mode
|
|
91
91
|
in library and framework code. In applications, start pure decisions with a
|
|
92
92
|
plain call, including direct validator calls, and add scenarios only for
|
|
93
|
-
pipeline/authorization wiring, constraints, declarative mapping
|
|
94
|
-
race policies. Keep shared lifecycle on; measure scenario cost using
|
|
93
|
+
pipeline/authorization wiring, constraints, or declarative mapping. Keep shared lifecycle on; measure scenario cost using
|
|
95
94
|
[running-specs.md](references/running-specs.md). Read
|
|
96
95
|
[application-scenarios.md](references/application-scenarios.md) before using
|
|
97
96
|
one. Out-of-process integration specifications are an advanced case reserved for
|
package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md
CHANGED
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
|
|
11
11
|
The four scenario helpers exercise the real Arc and Chronicle pipelines
|
|
12
12
|
in-process. Follow the [scenario selection and cost rule](../../../rules/specs.scenarios.csharp.md):
|
|
13
|
-
use them for pipeline/authorization wiring, constraints, declarative mapping
|
|
14
|
-
|
|
13
|
+
use them for pipeline/authorization wiring, constraints, or declarative mapping;
|
|
14
|
+
specify pure `Handle()`, validator, reducer and
|
|
15
15
|
reactor decisions first as plain calls with supplied read-model state. A library or framework repository reaches for a scenario only to test the
|
|
16
16
|
very engine it provides.
|
|
17
17
|
|
|
18
18
|
Read [query and decision scenarios](../../cratis-application-slice-specifications/references/query-and-decision-scenarios.md)
|
|
19
|
-
when using `QueryScenario<T>`, buffered emissions
|
|
19
|
+
when using `QueryScenario<T>`, or buffered emissions.
|
|
20
20
|
Read-protection plumbing is the harness's responsibility, never application setup.
|
|
21
21
|
|
|
22
22
|
| Helper | Exercises | Use for |
|
|
23
23
|
| --- | --- | --- |
|
|
24
|
-
| `CommandScenario<TCommand>` | Authorization, validators, `Provide()`, `Handle()`, appended events | Pipeline wiring, authorization, domain constraints
|
|
24
|
+
| `CommandScenario<TCommand>` | Authorization, validators, `Provide()`, `Handle()`, appended events | Pipeline wiring, authorization, domain constraints |
|
|
25
25
|
| `QueryScenario<TReadModel>` | Argument conversion, authorization, validation, interceptors and buffered observations | Query pipeline behavior |
|
|
26
26
|
| `EventScenario` | Chronicle append semantics without the command pipeline | Domain constraints; raw engine guards belong in framework specs |
|
|
27
27
|
| `ReadModelScenario<TReadModel>` | Projection or reducer state from a sequence of events | Declarative mapping/wiring, one class per model |
|
|
@@ -63,7 +63,7 @@ project on its own; `dotnet test` on the whole solution does not work there.
|
|
|
63
63
|
Apply the [scenario cost budget](../../../rules/specs.scenarios.csharp.md): plain
|
|
64
64
|
decision specs should take roughly milliseconds, not seconds. Measure scenario
|
|
65
65
|
facts and justify their cost by pipeline/authorization wiring, constraints,
|
|
66
|
-
declarative mapping
|
|
66
|
+
or declarative mapping that a plain call cannot
|
|
67
67
|
prove. Prefer fewer startups, not fewer assertions or weaker production guards.
|
|
68
68
|
|
|
69
69
|
Capture TRX for the affected project before and after the change. With VSTest,
|