@cratis/pi 7.105.1 → 7.107.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +1 -0
  2. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +6 -5
  3. package/package/corpus/harnesses/copilot/instructions/review-reports.instructions.md +6 -0
  4. package/package/corpus/product-sync.json +3 -3
  5. package/package/corpus/prompts/ship-changes.prompt.md +16 -3
  6. package/package/corpus/rules/issue-assignment.md +1 -0
  7. package/package/corpus/rules/profiles.md +1 -0
  8. package/package/corpus/rules/pull-requests.md +6 -5
  9. package/package/corpus/rules/review-reports.md +6 -0
  10. package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +1 -1
  11. package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +4 -2
  12. package/package/corpus/skills/cratis-code-review/SKILL.md +3 -0
  13. package/package/corpus/skills/cratis-code-review/verification.json +2 -1
  14. package/package/corpus/skills/cratis-engineering-ci-gates/LICENSE +2 -0
  15. package/package/corpus/skills/cratis-engineering-ci-gates/SKILL.md +172 -0
  16. package/package/corpus/skills/cratis-engineering-issue-hygiene/LICENSE +2 -0
  17. package/package/corpus/skills/cratis-engineering-issue-hygiene/SKILL.md +184 -0
  18. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +3 -1
  19. package/package/corpus/skills/cratis-engineering-release-trains/LICENSE +2 -0
  20. package/package/corpus/skills/cratis-engineering-release-trains/SKILL.md +191 -0
  21. package/package/corpus/skills/cratis-engineering-release-trains/verification.json +20 -0
  22. package/package/corpus/skills/cratis-engineering-review-rounds/LICENSE +2 -0
  23. package/package/corpus/skills/cratis-engineering-review-rounds/SKILL.md +120 -0
  24. package/package/corpus/skills/cratis-engineering-review-rounds/verification.json +16 -0
  25. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/public-events-and-direction.md +8 -1
  26. package/package/corpus/skills/cratis-screenplay-automations-and-translations/verification.json +4 -0
  27. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/capture-map-and-example.md +79 -0
  28. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/verification.json +8 -0
  29. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +12 -0
  30. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +15 -0
  31. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +1 -0
  32. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +4652 -869
  33. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  34. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +6 -0
  35. package/package/corpus/skills/run-tests/NOTICE +1 -0
  36. package/package/corpus/skills/run-tests/SKILL.md +5 -3
  37. package/package/profile-catalog.json +4 -0
  38. package/package.json +1 -1
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: cratis-engineering-release-trains
3
+ description: Group related deliveries into one release candidate, fold superseded pull requests, and apply a ship bar before publishing the assembled change. Use when asked to group finished branches, join an open PR, fold superseded PRs, size a candidate, or decide whether the ship bar is met. Not for waiting on checks (use cratis-engineering-ci-gates), planning review rounds (use cratis-engineering-review-rounds), or optimizing workflow performance (use cratis-ci-pipeline-performance).
4
+ license: LICENSE
5
+ compatibility: Requires git and the GitHub CLI (gh).
6
+ ---
7
+
8
+ <!-- Copyright (c) Cratis. All rights reserved. -->
9
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
10
+
11
+ # One assembled candidate, one release
12
+
13
+ A **candidate** is the branch assembling deliveries intended to ship together.
14
+ A repository includes its main checkout and all its worktrees. Consider their
15
+ concurrent work together, not as separate releases merely because it has
16
+ separate branches. One person or session assembles the candidate.
17
+
18
+ ## Authority and routing
19
+
20
+ Read [capability-is-not-authority.md](../../rules/capability-is-not-authority.md)
21
+ and the [ship-changes prompt](../../prompts/ship-changes.prompt.md) before any
22
+ external effect. A user's ship request authorizes its ordinary shipping steps;
23
+ loading this skill does not turn an implementation-only request into shipping.
24
+ Without that request, prepare the grouping and report the proposed next action.
25
+
26
+ Read [pull-requests.md](../../rules/pull-requests.md) for release intent, split
27
+ criteria, release notes, issue dispositions, and the human checkpoint for a
28
+ major release. A major release is never merged by an agent: a human confirms
29
+ and merges it. Agent work stops at preparing the PR, even after confirmation.
30
+ Read [git-commits.md](../../rules/git-commits.md) before assembling
31
+ branches. Preserve commits: never squash, rebase, amend, or force-push.
32
+
33
+ Use `cratis-engineering-consolidation-guard` when folding existing PRs to prove
34
+ nothing was dropped. Use `cratis-engineering-ci-gates` for gate selection and
35
+ run handling, and `cratis-engineering-review-rounds` for proportionate review.
36
+
37
+ ## Choose the candidate before creating a PR
38
+
39
+ 1. Inspect the repository's worktrees, finished branches, and open PRs:
40
+
41
+ ```bash
42
+ git worktree list
43
+ gh pr list --state open --json number,headRefName,title,author
44
+ ```
45
+
46
+ 2. Group related, ready deliveries under one candidate and one PR. Check with
47
+ the person assembling an existing candidate before changing it. Independent
48
+ work branches start from `origin/main`; work that depends on an unmerged
49
+ candidate may start from that candidate's latest commit (see Replace waits
50
+ with local work). Ongoing work keeps its branch.
51
+ Do not edit another session's checkout or include its uncommitted work.
52
+ 3. Prefer joining a related open PR that is still accepting deliveries, has no
53
+ checks running, and is not being merged by another session. Agree on its
54
+ writer, merge `origin/main` into its branch, then merge the deliveries and
55
+ extend its release note. Do not open a competing PR while it is being cut.
56
+ 4. If no candidate exists, create a branch from current `origin/main` and merge
57
+ ready delivery branches with merge commits. Keep each logical change in its
58
+ own commits. Return a conflicting or failing delivery for correction rather
59
+ than guessing its intent in the assembled branch.
60
+ 5. Keep one candidate per repository by default. Apply the split criteria in
61
+ `pull-requests.md` for unrelated work, different risk, or an urgent fix. Name
62
+ the exception in the reviewer comment; a major awaiting human confirmation
63
+ must not silently hold unrelated safe work indefinitely.
64
+
65
+ Minimal assembly, after agreeing on the included deliveries:
66
+
67
+ ```bash
68
+ git fetch origin
69
+ git switch -c release-candidate origin/main
70
+ git merge --no-ff delivery-a
71
+ git merge --no-ff delivery-b
72
+ ```
73
+
74
+ Use a new branch name if `release-candidate` already exists. This example does
75
+ not authorize publication. Run the assembled gates before the shipping push.
76
+
77
+ ## Fold superseded PRs promptly
78
+
79
+ Once a fold is decided within the authorized shipping scope, stop pushing to
80
+ its old branch. Close the superseded PR with a one-line reason:
81
+ `Folded into <candidate branch or PR>`; use `Will be folded into <candidate>`
82
+ when assembly is still pending. Do not wait for the candidate's push to retire
83
+ a PR that is already known to be superseded.
84
+
85
+ Move its delivered release-note bullets into the candidate's release note,
86
+ following `pull-requests.md`; retain only issues actually delivered by the diff.
87
+ Before consolidation, check release intent and publication effects and apply
88
+ `cratis-engineering-consolidation-guard`.
89
+
90
+ Identify the exact queued or in-progress runs for the superseded head. Cancel
91
+ only runs started by this session's own superseded pushes. Never cancel a
92
+ release, publish, or deploy run, or another session's watched merge. Leave
93
+ others running and report them. Follow `cratis-engineering-ci-gates` for the
94
+ cancellation checks; folding a PR is not blanket cancellation authority.
95
+
96
+ ## Size by readiness, then freeze
97
+
98
+ Before the final gate, list in-flight deliveries and their expected readiness.
99
+ Hold the cut for work expected ready within about one gate duration, so the
100
+ assembled gate runs once on the larger set. Cut without work further out or
101
+ blocked on a design decision, consumer proof, or another repository.
102
+
103
+ After the cut, nothing joins. Late deliveries go into the next candidate.
104
+ Corrections needed to make the frozen candidate pass are not new deliveries;
105
+ rerun the affected required gates for that changed code state.
106
+
107
+ Record the cut and readiness estimates in one line in the reviewer comment,
108
+ not the release note: `Cut with A and B; C waits for consumer proof.` Keep local
109
+ coordination records under `.ai-work/`, never in public release text.
110
+
111
+ ## Replace waits with local work
112
+
113
+ Most waits are removable. The build queue is the only legitimate one; while
114
+ queued, do the next independent piece of work.
115
+
116
+ - Base work on a committed local candidate instead of waiting for it to reach
117
+ main, and say which candidate commit it is based on when delivering.
118
+ - Prove against locally built packages instead of waiting for a release; see
119
+ [cratis-engineering-local-cross-repo-verification](../cratis-engineering-local-cross-repo-verification/SKILL.md).
120
+ Only the final version pin waits for the release.
121
+ - Drop an item that has been stuck for about two hours rather than holding the
122
+ candidate; it joins the next one.
123
+ - Cut a candidate at least every few hours with whatever is green.
124
+
125
+ ## Apply the ship bar
126
+
127
+ Check these six conditions. If one is missing, stop and report it instead of
128
+ making a speculative shipping push. Recheck the merge conditions after CI.
129
+
130
+ 1. **Cause and design understood.** The change solves the named problem using
131
+ established conventions. Product questions are resolved, not guessed.
132
+ 2. **Behavior proved.** Changed behavior has specifications, or an explicit
133
+ reason why they do not apply. The assembled local gate is green. Required
134
+ integration coverage follows repository policy and must pass before merge;
135
+ name anything that cannot run locally rather than calling it a local pass.
136
+ 3. **Whole change reviewed.** The candidate has a completed review without
137
+ Blockers or missing required evidence. Targeted delivery reviews alone do
138
+ not satisfy this condition.
139
+ 4. **Release decision settled.** Release intent follows `pull-requests.md`.
140
+ For a major release, require explicit human confirmation and human merge.
141
+ An agent never merges it; preparing the PR does not answer that checkpoint.
142
+ 5. **Conversation reread.** Re-read the issues and PR, including comments and
143
+ requested changes, before pushing and again immediately before merging.
144
+ Resolve unanswered objections rather than treating green checks as consent.
145
+ 6. **Main overlap checked.** Fetch main before merging. Inspect changes since
146
+ the tested head on the candidate's changed paths, for example
147
+ `git log <ci-sha>..origin/main -- <changed-paths>`. If main overlaps, merge it
148
+ into the candidate and rerun the required gates and CI before merge.
149
+
150
+ ## Push deliberately and finish
151
+
152
+ Batch local commits and review corrections into one meaningful shipping push.
153
+ After feedback, fix the full set, rerun the required gates, and push once.
154
+ Never push a lone merge of main as a save point or push just to discover whether
155
+ untested code passes.
156
+
157
+ Never put a CI skip token (`[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]`)
158
+ in a PR title or commit message. The merge commit inherits the PR title, so a
159
+ skip token can prevent every check from running on main. Remove such tokens
160
+ before creating or editing the PR; never rewrite an existing commit to do it.
161
+ If a committed token cannot be corrected without rewriting history, stop and
162
+ report the unsafe message rather than pushing it.
163
+
164
+ Use the ship-changes prompt for PR creation, notes, merge, issue disposition,
165
+ and cleanup. Non-major releases use a merge commit; never squash or rebase.
166
+ A human confirms and merges every major release. In repositories
167
+ using release-action, delivered `(#n)` references close at release, not by hand;
168
+ follow `pull-requests.md` for other cases rather than inventing a closing step.
169
+
170
+ Do not enable auto-merge. Wait using `cratis-engineering-ci-gates`. If checks
171
+ outlast the session, leave a handoff under `.ai-work/` per
172
+ [local-work-artifacts.md](../../rules/local-work-artifacts.md), with valid
173
+ preconditions, candidate and tested SHAs, PR, exact pending checks, and the next
174
+ steps. The next session must recheck the ship bar, not blindly merge on green.
175
+
176
+ ## What breaks
177
+
178
+ - **One PR per delivery:** duplicate gates and fragmented releases replace an
179
+ assembled check of the actual shipped change.
180
+ - **A growing frozen candidate:** late work invalidates the gate and cut.
181
+ - **Green means permitted:** checks neither resolve objections nor approve a
182
+ major release. The user's request and owning rules still govern effects.
183
+
184
+ ## How it is proven
185
+
186
+ Run the repository's exact assembled gate and inspect its successful exit.
187
+ Run `gh pr checks <pr>` before merge: required checks must pass for the tested
188
+ head. Confirm the whole-change review, fresh discussion, and main-overlap check.
189
+ For release notes, execute the repository's `cratis-check-pr.mjs` command from
190
+ `pull-requests.md`; a zero exit is the pass signal. No checklist replaces those
191
+ behavioral and CI signals.
@@ -0,0 +1,20 @@
1
+ {
2
+ "skill": "cratis-engineering-release-trains",
3
+ "input": "Group related deliveries, freeze the candidate, and apply the ship bar without bypassing human merge or CI.",
4
+ "fixtures": [],
5
+ "assertions": [
6
+ { "kind": "skill-contains", "value": "One assembled candidate, one release" },
7
+ { "kind": "skill-contains", "value": "After the cut, nothing joins." },
8
+ { "kind": "skill-contains", "value": "The build queue is the only legitimate one" },
9
+ { "kind": "skill-contains", "value": "only runs started by this session's own superseded pushes" },
10
+ { "kind": "skill-contains", "value": "A major release is never merged by an agent: a human confirms" },
11
+ { "kind": "skill-contains", "value": "in a PR title or commit message" },
12
+ { "kind": "skill-contains", "value": "[skip ci]" },
13
+ { "kind": "skill-contains", "value": "[ci skip]" },
14
+ { "kind": "skill-contains", "value": "[no ci]" },
15
+ { "kind": "skill-contains", "value": "[skip actions]" },
16
+ { "kind": "skill-contains", "value": "never squash or rebase" },
17
+ { "kind": "skill-contains", "value": "../../rules/pull-requests.md" },
18
+ { "kind": "skill-contains", "value": "../../prompts/ship-changes.prompt.md" }
19
+ ]
20
+ }
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: cratis-engineering-review-rounds
3
+ description: Plan proportionate review rounds, distinguish blocking from advisory findings, and carry prior evidence into a delta round with a firm stopping point. Use when choosing a review round, handling blocking or advisory feedback, requesting a delta since the last reviewed SHA, or stopping recurring blockers. Not for review criteria (use cratis-code-review), grouping a release candidate (use cratis-engineering-release-trains), waiting on checks (use cratis-engineering-ci-gates), or a repeated regression class (use cratis-engineering-regression-cluster).
4
+ license: LICENSE
5
+ compatibility: Requires git and the GitHub CLI (gh).
6
+ ---
7
+
8
+ <!-- Copyright (c) Cratis. All rights reserved. -->
9
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
10
+
11
+ # Review the change, then its corrections
12
+
13
+ Read [review-reports.md](../../rules/review-reports.md) before choosing reviewers
14
+ or reporting findings. Its report shape, verdicts, scope limits, and reviewer
15
+ independence apply to every round. This skill schedules reviews; it does not
16
+ replace the criteria in `cratis-code-review` or specialist review skills.
17
+
18
+ **Blocking** means a must-fix finding in **Blockers**, yielding **Changes
19
+ requested**. **Advisory** means a non-blocking finding in **Suggestions**. An
20
+ advisory preference is not a merge gate. Missing required evidence yields
21
+ **Incomplete**, not approval; retain that gap until it is resolved.
22
+
23
+ ## Budget the review
24
+
25
+ - Run one quick round per delivery. A second is warranted only after a blocker,
26
+ not to seek reassurance or eliminate suggestions.
27
+ - Run one whole-change review per PR on the assembled change. Quick delivery
28
+ rounds do not replace it. Start whole-change inspection in parallel with the
29
+ gate when possible, but keep it provisional: required gates must pass before
30
+ an approval report is finalized. Do not launch duplicate gates for review.
31
+ - Use ordinary depth by default. Deep review needs one named risk class:
32
+ **security**, **algorithmic**, **concurrency**, or **cross-cutting**, plus a
33
+ one-line justification tied to the changed behavior. Data-loss exposure or
34
+ irreversible migrations may justify cross-cutting review; merely wanting
35
+ extra confidence does not.
36
+ - Prove migrations and deployment-sensitive behavior by running the migration
37
+ on representative local data and exercising the relevant old/new behavior.
38
+ Deeper inspection is not execution evidence. Follow repository test policy.
39
+
40
+ ## First whole-change round
41
+
42
+ 1. Fix the target scope and committed base and head SHAs. Name changed surfaces,
43
+ expected behavior, required checks, and any specific risk before starting.
44
+ Use `git rev-parse <base>` and `git rev-parse HEAD` to resolve full SHAs.
45
+ 2. Apply reviewer independence from `review-reports.md`: use a different
46
+ provider family where selectable. Where it is not selectable, declare
47
+ `single-provider` in the report header and on the Not examined line. A
48
+ provider/tool error makes the review Incomplete; fall back once as that
49
+ rule directs, rather than manufacturing a verdict.
50
+ 3. Review the whole diff using the applicable criteria and real gate results.
51
+ Record round 1 with its base/head and retain the complete report unchanged.
52
+ Keep local review records under `.ai-work/`; public reviewer notes follow
53
+ [pull-requests.md](../../rules/pull-requests.md), never the release note.
54
+ 4. Fix confirmed Blockers together. Dismiss a candidate only with evidence and
55
+ a reason, not by silently deleting it. Correct required evidence gaps before
56
+ seeking approval. Cheap advisory fixes may join this correction pass.
57
+
58
+ ## Delta rounds
59
+
60
+ A delta round follows a whole-change review and reviews from the last reviewed
61
+ SHA, not from an arbitrary base. Carry the prior Blockers, unresolved evidence
62
+ gaps, Suggestions, and Dismissed findings with their reasons. Supply the round
63
+ number, prior report, original base, last reviewed SHA, and new head explicitly.
64
+
65
+ For example, after correcting a blocker from round 1:
66
+
67
+ ```text
68
+ Round: 2 (delta)
69
+ Original base: <full base SHA>
70
+ Since: <full head SHA reviewed in round 1>
71
+ Head: <full corrected head SHA>
72
+ Prior: <complete round 1 report, including dismissals and scope limits>
73
+ Scope: inspect the correction diff and verify disposition of prior findings
74
+ ```
75
+
76
+ Inspect the correction diff with `git diff <last-reviewed-sha>..<new-head-sha>`.
77
+ Recheck earlier blockers against the correction and its specifications. Preserve
78
+ unresolved findings and limits; a narrow delta cannot certify surfaces that
79
+ were never examined. Reuse earlier approval only for the exact committed SHAs
80
+ and examined scope, never for a dirty tree or a changed head.
81
+
82
+ Do not start a follow-up round for advisory findings alone. Fix them only when
83
+ cheap in an existing correction pass; otherwise leave them as Suggestions.
84
+ Never file an issue merely to dispose of advisory feedback. A distinct defect
85
+ needs its own evidence and the authority rules, not automatic issue creation.
86
+
87
+ ## Stop instead of looping
88
+
89
+ Cap review at **3 rounds per work item**, normally fewer. Keep delivery and
90
+ whole-change round counts explicit; renaming the target does not reset a work
91
+ item's cap. If blockers recur, stop the fix/review loop. Make one structural
92
+ change addressing the failure class or ask the user about the approach. Use
93
+ `cratis-engineering-regression-cluster` when repeated instances share a surface.
94
+ A structural change does not authorize an automatic fourth round or waive any
95
+ required review; report the remaining blocker or required decision.
96
+
97
+ ## What breaks
98
+
99
+ - **A whole-change restart after every correction:** repeats work while losing
100
+ the earlier blocker list and dismissals. Use a delta with the prior report.
101
+ - **Advisory becomes blocking:** a preference causes needless edits, extra
102
+ rounds, or unwanted issues. Preserve the shared report vocabulary.
103
+ - **Deep by habit:** extra review displaces running the behavior without a
104
+ named risk. State the risk or use ordinary depth.
105
+ - **Green by absence:** a reviewer failure or missing required proof is
106
+ Incomplete, not a successful review with no findings.
107
+
108
+ ## How it is proven
109
+
110
+ Run the repository's required gates and behavioral specifications for the
111
+ correction; successful exits are required evidence, not review substitutes.
112
+ Use the delta command above to confirm scope and verify that each earlier
113
+ finding has a disposition with evidence. The report includes Blockers,
114
+ Suggestions, Dismissed (with reason), Verdict, and Not examined, per the shared
115
+ rule. No Blockers and complete required evidence permit approval; suggestions
116
+ alone permit Approved with suggestions.
117
+
118
+ For PR descriptions and release notes, run the deterministic
119
+ `cratis-check-pr.mjs` command from `pull-requests.md` and require a zero exit.
120
+ Do not spend a review round on checks that script owns.
@@ -0,0 +1,16 @@
1
+ {
2
+ "skill": "cratis-engineering-review-rounds",
3
+ "input": "Plan a delta round after a blocker without restarting whole-change review or filing advisory findings.",
4
+ "fixtures": [],
5
+ "assertions": [
6
+ { "kind": "skill-contains", "value": "../../rules/review-reports.md" },
7
+ { "kind": "skill-contains", "value": "Run one quick round per delivery" },
8
+ { "kind": "skill-contains", "value": "Run one whole-change review per PR" },
9
+ { "kind": "skill-contains", "value": "SHA, not from an arbitrary base" },
10
+ { "kind": "skill-contains", "value": "Prior: <complete round 1 report, including dismissals and scope limits>" },
11
+ { "kind": "skill-contains", "value": "3 rounds per work item" },
12
+ { "kind": "skill-contains", "value": "Never file an issue merely to dispose of advisory feedback" },
13
+ { "kind": "skill-contains", "value": "single-provider" },
14
+ { "kind": "skill-contains", "value": "**cross-cutting**" }
15
+ ]
16
+ }
@@ -113,7 +113,7 @@ module Integration
113
113
  source events
114
114
  from ShipmentDispatched
115
115
  from ShipmentDelivered
116
- key orderId
116
+ key orderId is event source
117
117
  append OrderDispatched
118
118
  when added
119
119
  carrier = $.carrier
@@ -163,6 +163,13 @@ must be required on every `from` event (PLAY0700); `$eventSourceId` and other co
163
163
  keys are refused. An empty or whitespace-only text key fails execution, even in a
164
164
  given before the action; non-text/non-numeric keys are Unsupported.
165
165
 
166
+ The example declares `is event source` because the producer sources every event by
167
+ `orderId`.
168
+ Requires Screenplay 4.242.0 and ESM v33. A fixture `for` must then equal the key;
169
+ without `for`, it takes the key. Unmarked captures stay unchanged. Other
170
+ sources or non-single-property keys report PLAY0809, with no automatic repair. Read
171
+ [event-source keys](../../cratis-screenplay-captures-and-reactions/references/capture-map-and-example.md#keying-by-the-event-source).
172
+
166
173
  Givens fold in authored order without appending. Each event overlays its top-level
167
174
  properties onto state for that typed key: absent properties retain earlier values;
168
175
  objects/lists replace whole values. First sight is `added` only, unchanged overlays
@@ -8,6 +8,10 @@
8
8
  { "kind": "skill-contains", "value": "then OrderShipped", "file": "references/public-events-and-direction.md" },
9
9
  { "kind": "skill-contains", "value": "typed Unsupported", "file": "references/public-events-and-direction.md" },
10
10
  { "kind": "play-compiles" },
11
+ { "kind": "skill-contains", "value": "key orderId is event source", "file": "references/public-events-and-direction.md" },
12
+ { "kind": "skill-contains", "value": "Requires Screenplay 4.242.0 and ESM v33", "file": "references/public-events-and-direction.md" },
13
+ { "kind": "skill-contains", "value": "PLAY0809, with no automatic repair", "file": "references/public-events-and-direction.md" },
14
+ { "kind": "skill-contains", "value": "Unmarked captures stay unchanged", "file": "references/public-events-and-direction.md" },
11
15
  { "kind": "skill-contains", "value": "`[ExecuteCommandsAsSystem(\"<role>\")]`" },
12
16
  { "kind": "skill-contains", "value": "ESM v10" },
13
17
  { "kind": "skill-contains", "value": "STAGE-ESM-024" },
@@ -1,5 +1,11 @@
1
1
  # Capture map and example
2
2
 
3
+ ## Contents
4
+
5
+ - Capture excerpt
6
+ - Capture `map`
7
+ - Keying by the event source
8
+
3
9
  ## Capture excerpt
4
10
 
5
11
  ```screenplay excerpt
@@ -57,6 +63,11 @@ reference is handed records (`given capture`, `when capture`) and never contacts
57
63
  (PLAY0700). Events append to the event source the key names, and
58
64
  `$context.occurred` is supplied by the scenario's `given clock`.
59
65
 
66
+ For a producer that sources every event by this key, declare
67
+ `key <property> is event source` (ESM v33, Screenplay 4.242.0).
68
+ See [Keying by the event source](#keying-by-the-event-source) below for the promise, fixture `for`
69
+ checks and the PLAY0809 restriction to single-property `source events` keys.
70
+
60
71
  An event's external origin is declared on the `event` itself with `event X from "<origin>"` (ESM v9);
61
72
  outside records still enter through a `capture` in a `Translate` slice
62
73
  (`cratis-screenplay-automations-and-translations` `references/public-events-and-direction.md`).
@@ -87,3 +98,71 @@ compile error. Split it into two `append` blocks.
87
98
 
88
99
  **`children <collection> identified by <path>`** and **`nested <path>`** each take
89
100
  an optional `map` and any number of `append` blocks.
101
+
102
+ ## Keying by the event source
103
+
104
+ Requires Screenplay 4.242.0 or later (`screenplay --version`). The marker selects
105
+ ESM v33 and serializes `keyIsEventSource` beside `sourceEvents`. A capture without
106
+ it keeps its earlier behavior, version and bytes.
107
+
108
+ Declare `key <property> is event source` only when the producer sources **every**
109
+ captured event by that property's value. This is a promise about the foreign
110
+ stream, not a request to move an event to another source. It lets a renderer that
111
+ admits v33 narrow an inbox history read by event source id. Binding and reference
112
+ execution do not prove the renderer or deployed observer realizes that promise.
113
+
114
+ Only a `source events` capture with a single property key may declare the marker.
115
+ Other capture sources or key shapes report PLAY0809, an error with no automatic
116
+ repair. The key must still be required on every `from` event (PLAY0700); the marker
117
+ does not permit `$eventSourceId` as the key expression.
118
+
119
+ ### Typed fixtures
120
+
121
+ - An explicit fixture `for` must equal the key. A mismatch rejects execution with
122
+ a contract rejection naming the capture, event and both values. Do not turn it
123
+ into an accepted `then no events` scenario.
124
+ - A fixture without `for` takes the key as its source **before** projections and
125
+ reactions see it, so `$eventSourceId` is the key.
126
+ - The check also runs while establishing givens, including a world with no action.
127
+ - Without the marker, an optional foreign fixture `for` stays opaque non-empty
128
+ text, independent of the capture key. Do not add the marker just to fix a fixture.
129
+
130
+ This complete model uses a producer that sources dispatches by `orderId`:
131
+
132
+ ```screenplay
133
+ module Shipping
134
+ feature Tracking
135
+ slice Translate ReceiveDispatches
136
+ direction inbound
137
+ event ParcelDispatched from "carrier"
138
+ orderId String
139
+ event DispatchRecorded
140
+ orderId String
141
+ capture DispatchFeed
142
+ source events
143
+ from ParcelDispatched
144
+ key orderId is event source
145
+ append DispatchRecorded
146
+ when added
147
+ orderId = $.orderId
148
+ specification RecordingADispatch
149
+ when append ParcelDispatched
150
+ for "order-42"
151
+ orderId = "order-42"
152
+ then DispatchRecorded
153
+ for "order-42"
154
+ orderId = "order-42"
155
+ specification TakingTheKeyAsSource
156
+ when append ParcelDispatched
157
+ orderId = "order-42"
158
+ then DispatchRecorded
159
+ for "order-42"
160
+ orderId = "order-42"
161
+ ```
162
+
163
+ Changing the first fixture's `for` to `"other-order"` rejects the run; it is not a
164
+ new stream to accept silently. Test that rejection and the given-only mismatch
165
+ through evaluator outcomes as well as the two successful source forms.
166
+
167
+ Authority: Screenplay [captures](https://github.com/Cratis/Screenplay/blob/main/Documentation/screenplay/captures.md#keying-by-the-event-source)
168
+ and [capture grammar](https://github.com/Cratis/Screenplay/blob/main/Documentation/screenplay/captures/grammar.md).
@@ -5,6 +5,14 @@
5
5
  "assertions": [
6
6
  { "kind": "skill-contains", "value": "unrouted facts never match" },
7
7
  { "kind": "skill-contains", "value": "source events" },
8
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "PLAY0809, an error" },
9
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "ESM v33" },
10
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "key orderId is event source" },
11
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "`keyIsEventSource` beside `sourceEvents`" },
12
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "earlier behavior, version and bytes" },
13
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "An explicit fixture `for` must equal the key" },
14
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "A fixture without `for` takes the key as its source" },
15
+ { "kind": "skill-contains", "file": "references/capture-map-and-example.md", "value": "givens, including a world with no action" },
8
16
  { "kind": "play-compiles" },
9
17
  {
10
18
  "kind": "skill-contains",
@@ -8,6 +8,7 @@
8
8
  - Exact numeric source mode
9
9
  - Clause order inside a command (canonical)
10
10
  - Slice contents (typical)
11
+ - Event-source capture keys (ESM v33)
11
12
  - `$context.` paths (command `produces`)
12
13
  - `$eventContext.` (projections)
13
14
  - PDL quick reference (most forms are compiled in `pdl-example.md` or `cheat-sheet-example.md`; `remove via join` and `$eventContext.occurred` are not)
@@ -139,6 +140,17 @@ description, properties, `reads`, `authorize`, `validate`, `produces`/`handler`,
139
140
  - `slice Translate <Behaviour>`: capture and/or translator reaction + both vocabularies' events.
140
141
  - Declare each event once, in the slice that produces it; reference it by name elsewhere.
141
142
 
143
+ ## Event-source capture keys (ESM v33)
144
+
145
+ For inbound `source events` captures only, a single-property
146
+ `key <property> is event source` promises every incoming event is sourced by that
147
+ key (Screenplay 4.242.0; serializes `keyIsEventSource` beside `sourceEvents`).
148
+ Other sources/key shapes report PLAY0809, with no automatic repair. Explicit typed
149
+ fixture `for` must equal the key; omission takes the key before projections/reactions,
150
+ including givens without an action. Unmarked captures keep earlier semantics.
151
+ An admitting renderer may narrow history reads by event source id; binding is not target evidence.
152
+ Read [event-source keys](../../cratis-screenplay-captures-and-reactions/references/capture-map-and-example.md#keying-by-the-event-source) for the complete example.
153
+
142
154
  ## `$context.` paths (command `produces`)
143
155
  `occurred`, `tenant`, `command.<p>`, `arguments.<p>`, `causedBy.subject|name|userName`,
144
156
  `causation.type`, `identity.id|name|userName|isAuthenticated|roles|claims.<n>`.
@@ -5,6 +5,7 @@
5
5
  - Warnings that hide defects (always validate with `--warnings-as-errors`)
6
6
  - Source reference and identifier checks
7
7
  - Public events and translation direction
8
+ - Event-source capture keys
8
9
  - Explicit enum member numbers
9
10
  - Reserved stored names and event pins
10
11
  - Named keys, production routes and observer filters
@@ -97,6 +98,20 @@ Requires Screenplay 4.176.0 or later for PLAY0694; older compilers leave the
97
98
  legacy directionless co-location unchecked. Full capture execution and ordering:
98
99
  automations-and-translations `references/public-events-and-direction.md`.
99
100
 
101
+ ## Event-source capture keys
102
+
103
+ Requires Screenplay 4.242.0 or later (`screenplay --version`); the marker selects ESM v33.
104
+
105
+ | Code | Severity | Meaning / fix |
106
+ | --- | --- | --- |
107
+ | PLAY0809 | E | `key <property> is event source` outside a single-property `source events` capture key. Declare it only when every captured event is sourced by that property. Other sources or key shapes are errors, with no automatic repair. |
108
+
109
+ Marked typed fixtures reject an explicit `for` that differs from the key. Without
110
+ `for`, the fixture takes the key before projections/reactions. The contract checks
111
+ givens too, even without an action. This execution rejection is not PLAY0809 and
112
+ not a successful `then no events` outcome. Unmarked captures retain prior semantics.
113
+ Read captures-and-reactions [event-source keys](../../cratis-screenplay-captures-and-reactions/references/capture-map-and-example.md#keying-by-the-event-source).
114
+
100
115
  ## Explicit enum member numbers
101
116
 
102
117
  Source errors; the pins bind as ESM v12:
@@ -19,6 +19,7 @@ exact language/semantic pairs; binding, reference execution and rendering are se
19
19
  | v29 | `decimals <= N`; `add`/`subtract` by `a * b`; a concept mapped to another concept over the same primitive (decision 0098) | Decimal-places rule on a Decimal concept or property; the exact decimal product; the conversion is admitted only when the target declares no rule or compliance the source does not, never for enums, composites or optional into required | v29 refused until Stage admits it |
20
20
  | v30 | A command `produces ... for <required scalar property>` (several event sources); a specification `given generated <Command>.<property> = <value>` (decision 0098) | Several sources in one accepted command; pinned generated values for reaction-invoked commands, taken in authored order | v30 refused until Stage admits it |
21
21
  | v31 | A policy `require anonymous` for a public command or query | A deliberately public surface; the policy is the whole effective authorization | v31 refused until Stage admits it |
22
+ | v33 | `key <property> is event source` on a single-property `source events` capture (Screenplay 4.242.0; PLAY0809) | Serializes `keyIsEventSource` beside `sourceEvents`. Promises every incoming event is sourced by that key; explicit fixture `for` must equal it, while omission takes the key before projections/reactions. Checks also run on givens without an action. Unmarked captures keep earlier behavior/version/bytes | An admitting renderer may narrow history reads by event source id; binding alone does not prove target realization |
22
23
 
23
24
  Constructs of decision 0098 with no executable-model content need no version: application-level toolbar buttons in the layout's `navigation topbar` region (`button <id> title "..." slice <Slice>` with an optional indented `authorize <Policy>`), a command specification that states the public event its outbound Translate slice publishes (no more false `PLAY0285`), and a capture over events that copies a list (`lines = $.lines`) or fans out with `children lines identified by sku`. Check `screenplay --version` against the release that admitted v29 and v30 before relying on them.
24
25