Skip to content

Declarative-first: the language must describe everything before code exists - 'file' must never be required #40

Description

@woksin

Principle

Screenplay's own workflow statement is author the document first, then Stage performs it. That only works if the language can describe everything before any code exists. A file <path> reference is realization metadata — a pointer attached once a slice has been implemented — and must never be the only way to give a construct meaning. Today the language mostly honors this, but not everywhere, and the exceptions break the authoring-first story.

Audit of where the language stands

Construct Declarative story file/code required?
command produces (+ mappings, conditions) No — handler is an optional escape hatch. OK
policy require conditions No — code block is an alternative. OK
screen title, sections, tables, data, action, navigate, layout No — file is an alternative. OK
constraint unique … forms Custom logic has only file — acceptable as an escape hatch, but see #32 for declarative predicates
reactor None Yes — every on trigger must carry a file or an inline code block; the parser rejects a trigger with no body.
projections fully declarative (PDL) No. OK
reducers / computed read models none yet (#39) — the constructs proposed in #39 must follow this principle too: file optional, not required

The reactor row is the defect. A greenfield author cannot write:

reactor AcceptedInvitationProvisioner
  on InvitationToJoinAdaAccepted

— "when an invitation is accepted, provision the account" — without first creating a code file to point at. The construct's meaning is locked inside the escape hatch.

Evidence from a generated document

A document generated from a real Arc application (Ada, via Cratis.Arc.Screenplay 20.65.0) contains 24 reactors, every one of the shape:

reactor AcceptedInvitationProvisioner
  on InvitationToJoinAdaAccepted
    file Admin/Invitations/Provision/Provision.cs

The file reference satisfies the parser and tells a reader nothing. This is not the generator's fault — the language offers no other way to state what a reactor does. (#34 proposes declaring reactor outputs — produces <Event> / executes <Command> — which is the missing declarative body.)

Suggested changes

  1. Make reactor trigger bodies optional. A trigger with no body is a valid statement of intent ("this reactor observes this event"); a trigger with declared outputs (reactor: declare produced side effects (events and executed commands) #34) is a complete declarative description; file/code remains the realization escape hatch. At minimum allow description as a body while reactor: declare produced side effects (events and executed commands) #34 lands.
  2. Treat file uniformly as attachable realization metadata on any construct that supports it, and state in the grammar documentation that a document must be expressible — and meaningful — with zero file references. Hand-authored documents precede code and gain file lines as slices are implemented; generated documents arrive with them pre-attached. Same language, two directions.
  3. Apply the principle to new constructs by default — the reducer/computed-read-model constructs proposed in Read models without a declarative projection: reducers and computed views are undeclarable #39, the custom-constraint gap noted in Validation language: conditional rules, cross-property operands, and state-based business rules #32, and anything future: declarative meaning first, code pointer optional.

Context

Found while validating a generated 5,348-line document from a production Arc application: the constructs that lean on file are exactly the ones a reader cannot understand from the document alone. Related: #32, #34, #39.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions