Rendering must support all of our constructs. Three whole construct families render to nothing, and none of them produces a diagnostic.
Measured against a captured document for a real 229-slice application:
Declared in the .play |
Rendered |
Reported |
authorize — 200 |
nothing |
no |
query — 81 |
nothing |
no |
constraints / unique — 69 |
nothing |
no |
A read model always receives a fixed All<Plural> / <Type>ById pair regardless of what queries the document declares — so a declared query is neither rendered nor mentioned, and a query the document never declared is emitted anyway. Query performer blocks (file, or inline csharp / sql) are ignored entirely.
The authorization case is the serious one
A .play carrying policy and authorize renders into an application with no authorization at all:
Source/Contracts/Commands/CommandDefinition.cs has no authorization member.
Source/Contracts/Screenplay/ has no policy or persona converter.
Source/Stage/Api/StageQueryPerformer.cs hard-codes AllowsAnonymousAccess => true and IsAuthorized(context) => true.
So a document that carefully states who may do what produces a system where anyone may do anything, silently.
Minimum viable
An authorization member on the command and query definitions; role "x" → [Roles("x")]; require authenticated → [Authorize]; absent → [AllowAnonymous]; a conjunction → a synthesized composite. That covers the whole declarative surface a large production application actually uses.
Beyond that, rendering into an authorization command filter — which runs inside the command pipeline with the payload in hand — is the natural home for the cases an attribute cannot express.
Whatever the scope, the silent part should go first: a construct that cannot be rendered should say so, the way the projection blocks now do.
Rendering must support all of our constructs. Three whole construct families render to nothing, and none of them produces a diagnostic.
Measured against a captured document for a real 229-slice application:
.playauthorize— 200query— 81unique— 69A read model always receives a fixed
All<Plural>/<Type>ByIdpair regardless of what queries the document declares — so a declared query is neither rendered nor mentioned, and a query the document never declared is emitted anyway. Queryperformerblocks (file, or inlinecsharp/sql) are ignored entirely.The authorization case is the serious one
A
.playcarryingpolicyandauthorizerenders into an application with no authorization at all:Source/Contracts/Commands/CommandDefinition.cshas no authorization member.Source/Contracts/Screenplay/has no policy or persona converter.Source/Stage/Api/StageQueryPerformer.cshard-codesAllowsAnonymousAccess => trueandIsAuthorized(context) => true.So a document that carefully states who may do what produces a system where anyone may do anything, silently.
Minimum viable
An authorization member on the command and query definitions;
role "x"→[Roles("x")];require authenticated→[Authorize]; absent →[AllowAnonymous]; a conjunction → a synthesized composite. That covers the whole declarative surface a large production application actually uses.Beyond that, rendering into an authorization command filter — which runs inside the command pipeline with the payload in hand — is the natural home for the cases an attribute cannot express.
Whatever the scope, the silent part should go first: a construct that cannot be rendered should say so, the way the projection blocks now do.