@reventlessdev/reventless-spec 3.0.0-alpha.115 → 3.0.0-alpha.116

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.116 (2026-08-16)
7
+
8
+ ### Features
9
+
10
+ * **ppx:** declare a command's lifecycle edge once, as [@transition](https://github.com/transition) ([dd35130](https://github.com/ReventlessDev/reventless-core/commit/dd3513014f14b71879ee21263c6755d3c3d95096))
11
+
12
+
6
13
  # 3.0.0-alpha.115 (2026-08-16)
7
14
 
8
15
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-spec",
3
- "version": "3.0.0-alpha.115",
3
+ "version": "3.0.0-alpha.116",
4
4
  "description": "Specifications for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -8,7 +8,7 @@ each slice (variant names + `*Id`-shaped fields), never an `S.t` schema and neve
8
8
  a tag-metadata flag. That is precisely what we are replacing — so both the runtime
9
9
  (building shapes from `S.t` schemas, via `DcbTag.sliceShapeFromSchemas`) and the
10
10
  VS Code tooling (building shapes from parsed `.res` source) can feed the same
11
- `infer`. See `docs/plans/dcb-tag-scope-inference.md` § "Phase 1 design".
11
+ `infer`. See `docs/plans/done/dcb-tag-scope-inference.md` § "Phase 1 design".
12
12
 
13
13
  The three rules (over the representation):
14
14
 
@@ -53,7 +53,7 @@ module type Spec = {
53
53
 
54
54
  /** Optional display name of the foreign system this anti-corruption slice receives
55
55
  from (e.g. `"SupplierFeed"`). Drives the **external box** drawn outside the plugin
56
- in the Event Graph / Context Map (see docs/plans/translation-external-boxes.md).
56
+ in the Event Graph / Context Map.
57
57
  Auto-injected by `@@reventless.spec` defaulting to `None` — set it to name the box. */
58
58
  let externalSystem: option<string>
59
59
 
@@ -103,7 +103,7 @@ module type Spec = {
103
103
 
104
104
  /** Optional display name of the foreign system this anti-corruption slice publishes
105
105
  to (e.g. `"EmailService"`). Drives the **external box** drawn outside the plugin
106
- in the Event Graph / Context Map (see docs/plans/translation-external-boxes.md).
106
+ in the Event Graph / Context Map.
107
107
  Auto-injected by `@@reventless.spec` defaulting to `None` — set it to name the box. */
108
108
  let externalSystem: option<string>
109
109
  }
@@ -180,11 +180,12 @@ type commandDef = {
180
180
  /**
181
181
  The single lifecycle state this command's handler writes — the command's *to*
182
182
  state, sibling of `allowedStates`' *from* set. Source: the
183
- `@targetState("Shipped")` command-variant annotation. `None` (absent
184
- annotation) is the back-compat default: AutoUI's board resolver then falls
185
- back to its name-stem heuristic. `Some("Shipped")` lets the resolver move a
186
- row by a declared transition instead of a guess. js_nullable for JSON safety,
187
- same as `allowedStates`.
183
+ target of the `@transition(([Placed]) => Shipped)` command-variant annotation.
184
+ `Some("Shipped")` lets a resolver move a row by a declared transition instead
185
+ of a guess. `None` means no target was declared — and note that this is two
186
+ different statements depending on `allowedStates`: with a from-set present it
187
+ is the command declaring it does not move the row, and with none it is simply
188
+ an unannotated command. js_nullable for JSON safety, same as `allowedStates`.
188
189
  */
189
190
  targetState: @s.matches(stringOptionSchema) option<string>,
190
191
  /**
@@ -318,8 +319,8 @@ type queryableDef = {
318
319
  state schema: a client holding this def holds the whole predicate, and two places
319
320
  deriving one comparison is how they come to disagree about it.
320
321
 
321
- The state form is also what lets `@allowedStates` answer command applicability
322
- when retired, with no annotation beyond the two — retirement expressed in the
322
+ The state form is also what lets a command's `@transition` answer applicability
323
+ when retired, with no annotation beyond the one — retirement expressed in the
323
324
  vocabulary a command's stance is already written in.
324
325
  */
325
326
  retiredValues: @s.matches(stringArrayOptionSchema) option<array<string>>,
@@ -1,5 +1,5 @@
1
1
  // Per-aggregate persisted-snapshot configuration
2
- // (docs/plans/aggregate-snapshotting.md).
2
+ // (docs/plans/done/aggregate-snapshotting.md).
3
3
  //
4
4
  // Snapshotting is opt-in and lives on the Behavior module (where `state` is
5
5
  // defined): `Behavior.T.snapshot = None` (the default, auto-injected by
@@ -52,8 +52,9 @@ otherwise see the same negative marker on every record they can read.
52
52
  two-valued enum.
53
53
  - `Some(v)` — the **state** form. The row is retired when the field equals `v`,
54
54
  and the field is the record's `@lifecycle` field. One field then carries the
55
- fact once instead of twice, and `@allowedStates([Deactivated])` on the way-back
56
- command is enough to make a generated menu offer it there and nowhere else —
55
+ fact once instead of twice, and `@transition(([Deactivated]) => Active)` on the
56
+ way-back command is enough to make a generated menu offer it there and nowhere
57
+ else —
57
58
  because retirement is finally expressible in the vocabulary that stance is
58
59
  already written in.
59
60
 
@@ -113,7 +114,7 @@ type stateAnnotationSpec = {
113
114
  metric: array<(string, metricSpec)>,
114
115
  /**
115
116
  Field annotated `@lifecycle` on the state record (PPX-emitted) — the enum a
116
- command's `@allowedStates` is written in terms of, a board draws its columns
117
+ command's `@transition` is written in terms of, a board draws its columns
117
118
  from and a state diagram renders. `Some(name)` when one such annotation
118
119
  exists; the PPX errors on duplicate `@lifecycle` annotations within the same
119
120
  record. Codegen consumes this to populate `queryableDef.lifecycleField`, and
@@ -29,7 +29,7 @@ let folderToComponentType = ComponentKind.folderToKind
29
29
  // `None`. Uses the single-source `ComponentKind.isKindFolder`, so a chapter read
30
30
  // here (build time, disk) agrees with the authoring tool's identical heuristic and
31
31
  // with a chapter reflected off the deployed plugin structure. See
32
- // docs/plans/deployed-chapter-grouping.md.
32
+ // docs/plans/done/deployed-chapter-grouping.md.
33
33
  let chapterOf = (relPath: string): option<string> => {
34
34
  let segments = relPath->String.split("/")
35
35
  // Need at least one directory segment before the filename.
@@ -72,7 +72,7 @@ module type T = {
72
72
  */
73
73
  let decide: (state, Spec.command) => result<array<Spec.event>, Spec.error>
74
74
 
75
- /** Persisted-snapshot configuration (docs/plans/aggregate-snapshotting.md).
75
+ /** Persisted-snapshot configuration (docs/plans/done/aggregate-snapshotting.md).
76
76
  `None` — the default, auto-injected by `@@reventless.behavior` — keeps
77
77
  full replay; `Some({interval, stateSchema})` writes a keep-one snapshot
78
78
  every `interval` events and seeds cold replays from the latest one.
@@ -162,7 +162,7 @@ type commandJson = {
162
162
  // (clones via a JSON round-trip; never re-encodes through the schema), is idempotent on
163
163
  // valid data, and falls back to the ORIGINAL error when the fill doesn't resolve the
164
164
  // failure — so genuine corruption still surfaces.
165
- // See docs/plans/platform-infrastructure-in-plugin-list.md (durable fix option 2).
165
+ // See docs/plans/done/platform-infrastructure-in-plugin-list.md (durable fix option 2).
166
166
  //
167
167
  // The scalar arm is the odd one out and is deliberately noisy. Every other fill is
168
168
  // *derived* — the schema states what an absent value means, and the fill supplies exactly