Carry the Screenplay 2.x constructs on the contract - #27
Conversation
The contract records are positional records, so adding a trailing optional parameter is source compatible and binary breaking: it replaces the constructor and Deconstruct in the compiled signature, and a consumer built against the older package fails at run time with a missing method and no compiler error anywhere. Studio consumes these records, so the fault would surface in the designer rather than here. Baselined at 2.0.0, the last released version of all three packable projects. The current contract passes it unchanged.
Both are about to be needed by constructs beyond a produces declaration - a 'for' clause names an event source with the same expression vocabulary, and a 'require' rule carries the same condition tree a 'produces when' guard does. The language has one condition grammar, so the converter should be one too rather than a second tree that can drift from it. Pure move: no behavior changes.
Command authorization, 'require' rules, 'reads', where a produced event lands, event tags and specification read model steps had no member on the contract, so a document declaring them arrived at Studio with them gone. Every addition is an init property rather than a trailing constructor parameter, so none of it breaks a consumer compiled against 2.0.0. Authorization is a tree, not a list of policy names: a flat list cannot distinguish 'A or B and C' from '(A or B) and C', which is what makes it unable to answer whether a caller is allowed. Policies() gives the flat set to a consumer that only wants the names. The specification read model steps close an orphan - SpecificationRunStepKind already had ThenReadModel with nothing able to feed it.
The members are useless until the converters populate them, so this is where the constructs actually start surviving an import. Concept compliance markers are the one that was not a fidelity nicety. SchemaSynthesizer resolves a concept to its underlying primitive, which erased @pii and @sensitive entirely - a billing contact address arrived indistinguishable from any other string, with no way for a compliance reader to find it. The concept name and its declared attributes, with the reason each was declared for, now travel on the property's schema node. The marker is stated, not enforced; Chronicle's own compliance keyword that drives encryption at rest is a separate and deliberate step. Specs compile real .play source through the loader rather than asserting on hand-built syntax trees, so they cover the whole import path.
|
Reviewer context — not release notes. The premise this was planned on is wrong, and the build now proves itThe plan was "copy Screenplay's discipline: trailing optional parameters plus
The trailing optionals in Screenplay ( I turned package validation on first and measured it rather than reasoning about it. Adding The same addition as an This is why the PR is Second correction:
|
Added
CommandDefinitionnow carries the command'sauthorizerequirement, itsrequirerules and itsreadsdeclarations (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).PolicyReferenceandLogicalRequirement— soA or B and Cstays distinguishable from(A or B) and C.AuthorizationRequirement.Policies()gives the flat set of names to a consumer that only needs those (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).ProducedEventnow carries the event source aproduces … forclause names (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).EventDefinitionnow carries the tags declared on the event (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).Specificationnow carriesgiven readmodelandthen readmodelsteps, which the existingSpecificationRunStepKind.ThenReadModelhad nothing to feed it (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).@piiand@sensitiveattributes, and the reason each was declared for, now travel on the schema of every property typed as that concept. They were dropped entirely on import, leaving personal data indistinguishable from any other value (Stage.Contracts cannot express the Screenplay 2.x constructs, so they cannot survive a round trip #23).Fixed