Captures
Captures convert external data into events — change data capture as a first-class construct. The body of a capture block is written in the Change Data Capture Language (CDL) — an embedded sub-grammar the Screenplay parser delegates to (see Sub-language Pluggability). Captures live inside Translate slices.
Syntax
Section titled “Syntax”capture <Name> <CDL grammar>Example
Section titled “Example”capture LegacyInvoiceCapture source api api LegacyInvoicingApi route /invoices poll 5m key id map status = status translate "utkast" => draft "sendt" => sent "betalt" => paid "kansellert" => cancelled split contactName by "," firstName lastName append InvoiceStatusChanged when status invoiceId = $.id status = $.status changedAt = $context.occurred append InvoicePaidFromSent when status from "sent" to "paid" invoiceId = $.id paidAt = $context.occurred children lineItems identified by lineNumber map productName = name append InvoiceLineItemAdded when added invoiceId = $.id lineNumber = $.lineNumber quantity = $.quantity unitPrice = $.unitPrice append InvoiceLineItemRemoved when removed invoiceId = $.id lineNumber = $.lineNumber nested billingContact map contactName = name append BillingContactUpdated when email invoiceId = $.id email = $.emailCapturing from public events
Section titled “Capturing from public events”An inbound Translate slice turns the public events of another application into private events of its own. The capture reads them with source events, and the captured item is the incoming event’s content:
slice Translate TrackShipments direction inbound event OrderShipped orderId String capture ShipmentTracking source events from ShipmentDispatched from ShipmentDelivered key orderId append OrderShipped when status from "pending" to "dispatched" orderId = $.orderIdOne capture reads one origin: all its from events must have the exact same origin string (PLAY0687); split events from different origins into separate captures. Every from event must be a public event with an origin, an append event must be a private event of this application, and source events belongs only to an explicitly inbound slice (PLAY0610, PLAY0612, PLAY0616, PLAY0619, PLAY0620). The form selects ESM v9 and binds to an executable capture over events. The reference evaluator has no outside records to present to such a capture, so a when capture specification over events reports a typed Unsupported outcome instead of passing or failing. Rename follows a from line; see the diagnostics for the full list.
The CDL vocabulary at a glance
Section titled “The CDL vocabulary at a glance”| Construct | Meaning |
|---|---|
source events | Reads the public events of another application instead of an external system; each from <Event> line names one consumed event. |
source api / source webhook / source message | Where the captured data comes from, with source-specific settings (api/route/poll for api, path for webhook, topic for message). |
key <property> | Which source property identifies an instance. |
map | Maps, splits and translates source values before events are appended. |
<property> = <source> | Renames a source value onto a property, or assigns a `template` built from source values. |
translate | Maps source values to Screenplay values ("utkast" => draft). |
split <source> by "<separator>" | Splits one source value into several target properties. |
append <EventType> | Appends an event when the source changes, guarded by a when trigger. |
tag <value> | Attaches a tag to the appended event — a static identifier or string, or a $context. expression. |
when <property> | Appends when the named property changes. |
when <property> or <property> / when <property> and <property> | Appends when any (or) or all (and) of the named properties change. |
when <property> from <value> to <value> | Appends when the named property transitions between two specific values. |
when `<expression>` | Appends when a raw template-literal expression evaluates to true. |
when added / when removed | Appends when an item appears in / disappears from the source. |
children <collection> identified by <key> | Captures changes in a child collection, with its own optional map. |
nested <property> | Captures changes to a single nullable child object, with its own optional map. |
$.<property> | A value from the current source item. |
$context.occurred | The capture timestamp. |
In the executable semantic model
Section titled “In the executable semantic model”Captures bind to the executable semantic model as ESM v6 (decision 0022).
The reference evaluator is handed records - given capture and when capture in a specification -
and never contacts a source, which stays realization metadata. For each record:
mapoperations apply in order, each to the record as the ones before it left it. A fieldmapdoes not touch passes through unchanged.- A condition compares the mapped record with the mapped record the capture last saw for the same
key. A field the earlier record lacked has changed when the new one has it, so a first record has changed in every field it carries.when status from "sent" to "paid"compares mapped values. when `<expression>`holds a small portable grammar: fields, string, number, boolean andnullliterals,==,!=,<,<=,>,>=,&&,||,!and parentheses. Ordering compares numbers only.$.<field>reads the item being evaluated - the record, a child or the nested record - and falls back to the enclosing record when the item lacks the field.$context.occurredis the scenario’sgiven clock.- Everything is appended to the event source the record’s
keynames. Its type is the one the event’s commands give it, and text when no command produces the event. - The record’s own appends run first, then each
childrencollection’s - current children in order, then the removed ones in their earlier order - then eachnestedrecord’s.
The reference checks record shapes, event-source keys and child identities (including duplicates) before appending anything. After those preconditions pass, it evaluates each reached append in order, enforces its constraints, projects it and settles its reactions before evaluating the next capture effect. The first rejection or Unsupported stops the scenario. Facts and projections from earlier accepted appends remain; the failed append adds neither. A later unsupported mapping or guard cannot mask an earlier constraint rejection. This is not a capture-wide transaction; invoked commands keep their own atomicity.
given capture supplies immutable last-seen input for one specification. Running the specification does not
store a new last-seen record or acknowledge an external source, on success or failure. Supply the baseline
explicitly in each subsequent specification. Retained prefix facts do not imply successful source processing
or acknowledgement. A present object or collection used as a scalar mapping is Unsupported, not a missing
value or a passing then error.
A capture without a key, or a condition outside the grammar above, does not bind (PLAY0268).
Full CDL grammar
Section titled “Full CDL grammar”The authoritative CDL grammar - including the split, nested and richer when forms above - is published as the Capture Declaration Language grammar, mirroring how the Projection Declaration Language grammar documents PDL.