Skip to content

Studio reimplements the Screenplay-to-Stage converter that Cratis.Stage.Contracts already ships #101

Description

@woksin

Cratis.Stage.Contracts — already a dependency, and shipping this since well before the Screenplay 2.x wave — contains a complete Screenplay-to-Stage converter under Cratis.Stage.Contracts.Screenplay:

ScreenplayEventModelVisitor  SliceConverter    CommandConverter       ReadModelConverter
ProjectionConverter          ProducesConverter EventConverter         SpecificationConverter
ValidationRuleConverter      SchemaSynthesizer ScreenplayExpression   DeterministicId

ScreenplayEventModelVisitor : IApplicationSyntaxVisitor<EventModel> — the exact signature of Studio's Source/Core/Screenplay/EventModelSyntaxVisitor.cs:14.

Studio never references it. It maintains roughly 530 lines doing the same job across nine files: EventModelSyntaxVisitor (26), ModuleSyntaxVisitor (27), FeatureSyntaxVisitor (26), SliceSyntaxVisitor (114), SpecificationSyntaxVisitor (71), SyntaxValidationExtensions (73), SyntaxSchemaExtensions (85), SyntaxEventReferenceExtensions (40), ScreenplayEventOwners (66).

Stage's version is ahead of Studio's

CommandConverter fills Produces and resolves the command's Identifier. EventConverter carries constraints. Studio passes Produces: [] at SliceSyntaxVisitor.cs:56 and raises a warning saying it dropped both — data the contract can already hold, dropped by code written before the contract grew the ability to hold it.

The cost is drift, and it has already happened once

Screenplay 2.x made SliceSyntax.Projections plural, so both implementations had to decide how to name a read model when a slice declares several. Stage's ReadModelConverter resolved it as projection?.ReadModel ?? query return type ?? projection?.Name ?? slice.Name. Studio's resolved it differently — meaning the same document could come back from a round trip named differently from how it went out.

Cratis/Studio#1108 aligned Studio to Stage by hand and left a comment at SliceSyntaxVisitor.ReadModelName saying "change both together or neither". A comment is the weakest available mechanism for keeping two implementations honest, and it only works for as long as someone reads it.

Suggested direction

Delete Studio's chain and call ScreenplayEventModelVisitor. This is not a pure refactor — there are two real behavioural differences to decide first:

  1. Identity. Stage uses DeterministicId.From(path); Studio uses Guid.NewGuid(). Deterministic identity is arguably better, since re-importing the same document would yield the same graph rather than a new one — but it changes what an import produces.
  2. Cross-slice event ownership. Studio's ScreenplayEventOwners assigns each State Change slice's events an identity up front, so a consuming slice references the producing slice's event rather than a fresh one. Stage has no equivalent and relies on path-derived determinism instead. Whether that preserves Studio's incoming arrows needs checking before anything is deleted.

Both belong in the same design conversation as Cratis/Stage#23. Worth settling before the contract widens rather than after — widening it twice, in two implementations, is how a round trip acquires its third disagreement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions