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

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,25 @@
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.115 (2026-08-16)
7
+
8
+ ### Features
9
+
10
+ * **core:** let [@retired](https://github.com/retired) name a lifecycle state, not only a boolean ([6bb346b](https://github.com/ReventlessDev/reventless-core/commit/6bb346b4f6a5f33826fc24537953482a76067177))
11
+ * **core:** mark the state that retires a row, and allow more than one ([cb1461f](https://github.com/ReventlessDev/reventless-core/commit/cb1461f024d3ca3b53fd9c8b010a054e3fcc4555))
12
+ * **core:** publish queryableDef.retiredField from the [@retired](https://github.com/retired) annotation ([b44436a](https://github.com/ReventlessDev/reventless-core/commit/b44436a997b6c4ff0531f0b07d793cc858eef94a))
13
+ * **spec:** [@retired](https://github.com/retired) state-field annotation and its schema emission ([2d8234b](https://github.com/ReventlessDev/reventless-core/commit/2d8234b6b3dd8f479031a67eb5b4b47b5c0c2ff9))
14
+ * **spec:** classify a caller against a view's retirement flag ([5031ce5](https://github.com/ReventlessDev/reventless-core/commit/5031ce573ce56d2407888c7777274e5580c4fb51))
15
+
16
+
17
+ # 3.0.0-alpha.114 (2026-08-15)
18
+
19
+ **Note:** Version bump only for package @reventlessdev/reventless-spec
20
+
21
+
22
+
23
+
24
+
6
25
  # 3.0.0-alpha.113 (2026-08-14)
7
26
 
8
27
  **Note:** Version bump only for package @reventlessdev/reventless-spec
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-spec",
3
- "version": "3.0.0-alpha.113",
3
+ "version": "3.0.0-alpha.115",
4
4
  "description": "Specifications for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "sury": "11.0.0-alpha.4",
22
22
  "sury-ppx": "11.0.0-alpha.2",
23
23
  "yaml": "^2.8.3",
24
- "@reventlessdev/rescript-node": "2.0.0-alpha.6"
24
+ "@reventlessdev/rescript-node": "2.0.0-alpha.7"
25
25
  },
26
26
  "devDependencies": {
27
27
  "rescript": "12.3.0",
@@ -212,15 +212,17 @@ type Platform_ReadSideDef {
212
212
  idFieldSource: String
213
213
  labelField: String!
214
214
  labelFieldSource: String
215
+ lifecycleField: String
215
216
  linkedWriteSide: [String!]!
216
217
  name: String!
217
218
  ownerField: String
218
219
  queryField: String!
219
220
  requiredAccess: [String!]
221
+ retiredField: String
222
+ retiredValues: [String!]
220
223
  schema: String!
221
224
  searchableFields: [String!]!
222
225
  singleQueryField: String
223
- statusField: String
224
226
  visibility: String
225
227
  }
226
228
 
@@ -290,7 +292,7 @@ type Query {
290
292
  Platform_ComponentDefinitions: [Platform_ComponentDefinitionEntry!]!
291
293
  Platform_Plugin(id: ID!): Platform_Plugin
292
294
  Platform_PluginStructures: [Platform_PluginStructureEntry!]!
293
- Platform_Plugins(after: String, before: String, filter: Platform_PluginFilter, first: Int, last: Int): Platform_PluginConnection!
295
+ Platform_Plugins(after: String, before: String, filter: Platform_PluginFilter, first: Int, includeRetired: Boolean, last: Int): Platform_PluginConnection!
294
296
  Platform_PluginsByIds(ids: [String!]!): [Platform_Plugin!]!
295
297
  Platform_UIFragments: [Platform_UIFragmentEntry!]!
296
298
  }
@@ -170,14 +170,15 @@ type commandDef = {
170
170
  mutationField: string,
171
171
  references: array<fieldReference>,
172
172
  /**
173
- Status values under which this command is meaningful. `None` means the command
173
+ Lifecycle states under which this command is meaningful. `None` means the command
174
174
  is always available (back-compat default). `Some([…])` lets AutoUI hide the
175
- command on rows whose status field is not in the set — see `queryableDef.statusField`
176
- for how the row's status is located. `Some([])` is the defensive "never show" form.
175
+ command on rows whose lifecycle field is not in the set — see
176
+ `queryableDef.lifecycleField` for how the row's state is located. `Some([])` is
177
+ the defensive "never show" form.
177
178
  */
178
179
  allowedStates: @s.matches(stringArrayOptionSchema) option<array<string>>,
179
180
  /**
180
- The single status value this command's handler writes — the command's *to*
181
+ The single lifecycle state this command's handler writes — the command's *to*
181
182
  state, sibling of `allowedStates`' *from* set. Source: the
182
183
  `@targetState("Shipped")` command-variant annotation. `None` (absent
183
184
  annotation) is the back-compat default: AutoUI's board resolver then falls
@@ -262,17 +263,17 @@ type queryableDef = {
262
263
  `None` means not stated — defs persisted before this field existed, and
263
264
  hand-rolled defs that decline to say. Distinct from `Some("fallback")`, which
264
265
  is this side stating that it looked. js_nullable for the same JSON-safety
265
- reason as `statusField`.
266
+ reason as `lifecycleField`.
266
267
  */
267
268
  labelFieldSource: @s.matches(stringOptionSchema) option<string>,
268
269
  /**
269
- Name of the state field whose value identifies the row's lifecycle status, used
270
- by AutoUI together with `commandDef.allowedStates` to filter the per-row command
271
- menu. Resolution order (codegen): (1) field annotated `@status`; (2) a field
272
- literally named `"status"`; (3) `None`. Spec authors that hand-roll a
273
- `queryableDef` set this explicitly.
270
+ Name of the state field whose value identifies the row's lifecycle, used by
271
+ AutoUI together with `commandDef.allowedStates` to filter the per-row command
272
+ menu. Resolution order (codegen): (1) field annotated `@lifecycle`; (2) a field
273
+ literally named `"lifecycle"` whose shape is an enum; (3) `None`. Spec authors
274
+ that hand-roll a `queryableDef` set this explicitly.
274
275
  */
275
- statusField: @s.matches(stringOptionSchema) option<string>,
276
+ lifecycleField: @s.matches(stringOptionSchema) option<string>,
276
277
  /**
277
278
  Name of the state field that ties a row to the principal owning it (`@owner`),
278
279
  when the view declares one. Two consequences for a client: reads of this view
@@ -285,6 +286,44 @@ type queryableDef = {
285
286
  */
286
287
  ownerField: @s.matches(stringOptionSchema) option<string>,
287
288
  /**
289
+ Name of the boolean state field that withdraws a row from ordinary reads
290
+ (`@retired`), when the view declares one. Reads of this view exclude rows whose
291
+ flag is true for callers outside `OwnerScope.elevatedGroups`, on the list door
292
+ and the single-entity door alike; an exempt caller reaches them by asking for
293
+ them.
294
+
295
+ Derived from the annotation and from nothing else — deliberately no fallback to
296
+ a conventionally-named boolean, unlike `lifecycleField`. A field named `archived`
297
+ that nobody annotated must not start hiding rows the day this ships, and the
298
+ cost of guessing wrong here is data disappearing rather than a menu filtering
299
+ oddly.
300
+
301
+ The label the flag reads as is not here. It travels on the state schema, which
302
+ every consumer of this def already holds, and a second copy is a second thing
303
+ to keep in step.
304
+ */
305
+ retiredField: @s.matches(stringOptionSchema) option<string>,
306
+ /**
307
+ The states a row is retired *in*, when the view declares the state form of
308
+ `@retired` — `Some(["Archived", "Discontinued"])` beside
309
+ `retiredField: Some("shelfStatus")`. `None` is the boolean form, where the
310
+ excluded value is always `true` and naming it would be a field that can only
311
+ hold one thing.
312
+
313
+ A set: a lifecycle may be withdrawn by more than one state, which exclude
314
+ identically and differ only in the way back. Retired iff the field's value is in
315
+ it, and one member is the ordinary case rather than a special one.
316
+
317
+ Published beside the field rather than left for a consumer to re-derive from the
318
+ state schema: a client holding this def holds the whole predicate, and two places
319
+ deriving one comparison is how they come to disagree about it.
320
+
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
323
+ vocabulary a command's stance is already written in.
324
+ */
325
+ retiredValues: @s.matches(stringArrayOptionSchema) option<array<string>>,
326
+ /**
288
327
  Component visibility hint (`@@reventless.visibility`). `Some("Internal")` marks a
289
328
  ReadModel / StateViewSlice that the deployed AutoUI hides from its menu, drill-down
290
329
  pages, web event graph and cross-plugin edges. `None` (absent) means Public. Internal
@@ -323,7 +362,7 @@ type queryableDef = {
323
362
 
324
363
  `None` means not stated — defs persisted before this field existed, and
325
364
  hand-rolled defs that decline to say; a consumer falls back to its own
326
- derivation there. js_nullable for the same JSON-safety reason as `statusField`.
365
+ derivation there. js_nullable for the same JSON-safety reason as `lifecycleField`.
327
366
  */
328
367
  singleQueryField: @s.matches(stringOptionSchema) option<string>,
329
368
  /**
@@ -334,7 +373,7 @@ type queryableDef = {
334
373
  `None` means unresolved: a state with several `*Id` fields and no name match,
335
374
  or with none at all. Such a component gets no key-derived filter or sort until
336
375
  its spec declares `@id`. Also `None` on defs persisted before this field
337
- existed. js_nullable for the same JSON-safety reason as `statusField`.
376
+ existed. js_nullable for the same JSON-safety reason as `lifecycleField`.
338
377
  */
339
378
  idField: @s.matches(stringOptionSchema) option<string>,
340
379
  /**
@@ -118,8 +118,10 @@ let queryableDefSchema = S.schema(s => ({
118
118
  labelField: s.m(S.string),
119
119
  searchableFields: s.m(S.array(S.string)),
120
120
  labelFieldSource: s.m(stringOptionSchema),
121
- statusField: s.m(stringOptionSchema),
121
+ lifecycleField: s.m(stringOptionSchema),
122
122
  ownerField: s.m(stringOptionSchema),
123
+ retiredField: s.m(stringOptionSchema),
124
+ retiredValues: s.m(stringArrayOptionSchema),
123
125
  visibility: s.m(stringOptionSchema),
124
126
  chapter: s.m(stringOptionSchema),
125
127
  singleQueryField: s.m(stringOptionSchema),
@@ -5,7 +5,7 @@ Spec describing the structural annotations declared on the fields of an
5
5
  `@compositeId`, `@subId`, `@compositeSubId`, `@index`), a visibility
6
6
  annotation (`@hidden`, `@summary`), a hierarchical-rendering annotation
7
7
  (`@drillTarget`, `@collapsed`), a server-query opt-in annotation
8
- (`@scan`, `@scanSort`), a UI-list annotation (`@status`, `@groupBy`), or a
8
+ (`@scan`, `@scanSort`), a UI-list annotation (`@lifecycle`, `@groupBy`), or a
9
9
  type-level live-updates annotation (`@live` on the `state` declaration).
10
10
  Downstream consumers (UI, MCP, codegen) read the
11
11
  spec to surface field roles in JSON Schema as `x-reventless-*` extension
@@ -34,6 +34,54 @@ KPI label, or `""` to let the UI derive one from the field name.
34
34
  */
35
35
  type metricSpec = {aggregate: string, label: string}
36
36
 
37
+ /**
38
+ The field declared `@retired`, and how a consumer should title it.
39
+
40
+ `field` names what withdraws the row from ordinary use — a deactivated customer,
41
+ an archived category. `label` is what that state is called ("Archived"), or `""`
42
+ to let a consumer derive one from the field name. `showWhenFalse` asks a consumer
43
+ to surface the flag in its negative state too; the default is false, because a
44
+ caller who is not exempt from the narrowing never receives a retired row and would
45
+ otherwise see the same negative marker on every record they can read.
46
+
47
+ `value` is what decides which of the two forms this is:
48
+
49
+ - `None` — the **boolean** form. The row is retired when the field is `true`. The
50
+ right shape for a record whose retirement genuinely is a flag: a `Products` view
51
+ with an `archived` boolean and no lifecycle should not have to invent a
52
+ two-valued enum.
53
+ - `Some(v)` — the **state** form. The row is retired when the field equals `v`,
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 —
57
+ because retirement is finally expressible in the vocabulary that stance is
58
+ already written in.
59
+
60
+ The narrowing itself is not described here. This spec carries what the field
61
+ *means*; who still sees a retired row is one deployment-wide rule
62
+ (`OwnerScope.elevatedGroups`), resolved where the query is answered.
63
+ */
64
+ type retiredSpec = {
65
+ field: string,
66
+ label: string,
67
+ showWhenFalse: bool,
68
+ /**
69
+ The states that withdraw the row, or `None` for the boolean form.
70
+
71
+ A **set**, because a lifecycle may end in more than one way — a product is
72
+ withdrawn `Archived` or `Discontinued`, by different routes and with different
73
+ ways back — and one field carries all of them. Retired iff the field's value is
74
+ in the set; a single-element set is the ordinary case rather than a special one.
75
+
76
+ The `option` is the **form discriminator** and is load-bearing. `None` is the
77
+ boolean form, where the row is retired when the field is `true`. Flattened to a
78
+ bare array, `[]` would mean both "boolean form" and "state form naming no
79
+ states", and every consumer's boolean-form handling — the column suppression
80
+ most visibly — would stop firing on a value that looks merely empty.
81
+ */
82
+ values: option<array<string>>,
83
+ }
84
+
37
85
  type stateAnnotationSpec = {
38
86
  ids: array<string>,
39
87
  compositeIds: array<string>,
@@ -64,13 +112,16 @@ type stateAnnotationSpec = {
64
112
  */
65
113
  metric: array<(string, metricSpec)>,
66
114
  /**
67
- Field annotated `@status` on the state record (PPX-emitted). `Some(name)`
68
- when one such annotation exists; the PPX errors on duplicate `@status`
69
- annotations within the same record. Codegen consumes this to populate
70
- `queryableDef.statusField` (with a fallback to a field literally named
71
- `"status"` when this annotation is absent).
115
+ 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
+ from and a state diagram renders. `Some(name)` when one such annotation
118
+ exists; the PPX errors on duplicate `@lifecycle` annotations within the same
119
+ record. Codegen consumes this to populate `queryableDef.lifecycleField`, and
120
+ falls back to a field literally named `"lifecycle"` whose shape is an enum
121
+ when this annotation is absent — so a record whose field can honestly be
122
+ called `lifecycle` declares one without ceremony.
72
123
  */
73
- status: option<string>,
124
+ lifecycle: option<string>,
74
125
  /**
75
126
  Field annotated `@groupBy` on the state record (PPX-emitted). `Some(name)`
76
127
  when one such annotation exists; the PPX errors on duplicate `@groupBy`
@@ -96,6 +147,22 @@ type stateAnnotationSpec = {
96
147
  control is offered (`true`) or hidden (`false`) for the view.
97
148
  */
98
149
  live: option<bool>,
150
+ /**
151
+ Field annotated `@retired` on the state record (PPX-emitted). `Some(spec)` when
152
+ one such annotation exists; the PPX errors on duplicates and on a non-boolean
153
+ field. `SuryToJsonSchema.deriveObjectSchema` emits `x-reventless-retired:
154
+ {label?, showWhenFalse}` on the named field.
155
+
156
+ `option<retiredSpec>` rather than an array: at most one per record. Two
157
+ retirement flags are not a stricter rule but an unanswered one — the read
158
+ predicate would have to guess whether they conjoin or disjoin, and the query
159
+ layer narrows on a single field.
160
+
161
+ Both the boolean and the state form ride this one key. `x-reventless-retired`
162
+ carries `value` only in the state form, on the same omit-rather-than-write-empty
163
+ rule `label` already follows.
164
+ */
165
+ retired: option<retiredSpec>,
99
166
  }
100
167
 
101
168
  /** Sury metadata ID used to attach a `stateAnnotationSpec` to a state schema. */
@@ -225,3 +225,108 @@ let scopeOf = (decision: decision): option<(string, string)> =>
225
225
  | ScopeTo(field, required) => Some((field, required))
226
226
  | Unscoped | RefuseOwned => None
227
227
  }
228
+
229
+ /**
230
+ What `@retired` does to one read of one view.
231
+
232
+ Deliberately in this module rather than beside the annotation. Owner scoping and
233
+ retirement narrowing are two rules over the same question — which rows does this
234
+ caller get — and they resolve the caller with the same `resolve`, against the
235
+ same deployment-wide `elevatedGroups`. Written apart, they could disagree about
236
+ who an operator is, and the disagreement would be invisible until a caller
237
+ elevated for one rule turned out to be scoped by the other.
238
+
239
+ `ExcludeRetired` carries the whole predicate — the field and, for the state form
240
+ of `@retired`, every state that retires the row. `values: None` is the boolean
241
+ form, where the excluded value is always `true`; naming it there would be a
242
+ parameter that can only hold one thing, and a parameter a call site can pass
243
+ wrongly.
244
+
245
+ Both halves travel together for the reason the pair exists at all: a field
246
+ without its values is half a comparison, and an adapter left to fetch the other
247
+ half from the schema is an adapter that can disagree with the one next to it
248
+ about which rows a caller may see.
249
+ */
250
+ type retiredScope = {
251
+ field: string,
252
+ values: option<array<string>>,
253
+ }
254
+
255
+ type retiredDecision =
256
+ | RetiredVisible
257
+ | ExcludeRetired(retiredScope)
258
+
259
+ /**
260
+ Combine a view's declared retirement flag with the caller behind the request.
261
+
262
+ `~asked` is the caller's `includeRetired` request, honoured only where the
263
+ caller was going to see those rows anyway. Reading it before classifying would
264
+ make the argument the decision rather than a request.
265
+
266
+ `Unidentified` excludes rather than refuses, which is where this parts company
267
+ with `decide`. An owner-scoped read of an unidentified caller has no value to
268
+ match, so scoping it would be indistinguishable from an empty view and a refusal
269
+ says more. Retirement has no such value — the predicate is the same for every
270
+ non-exempt caller — so the fail-closed action is simply the narrow read.
271
+ */
272
+ let decideRetired = (
273
+ identity: Identity.t,
274
+ ~retiredField: option<string>,
275
+ ~retiredValues: option<array<string>>=?,
276
+ ~asked: bool=false,
277
+ ~elevated: array<string>=elevatedGroups(),
278
+ ): retiredDecision =>
279
+ switch retiredField {
280
+ | None => RetiredVisible
281
+ | Some(field) =>
282
+ let scope = {field, values: retiredValues}
283
+ switch resolve(identity, ~elevated) {
284
+ | System | Elevated(_) => asked ? RetiredVisible : ExcludeRetired(scope)
285
+ | Owned(_) | Unidentified(_) => ExcludeRetired(scope)
286
+ }
287
+ }
288
+
289
+ /**
290
+ The field a read excludes on, or `None` when it excludes nothing.
291
+
292
+ Note that an exempt caller who did not ask still gets `Some`: retired rows are
293
+ withheld from everyone by default, and elevation buys the ability to ask for
294
+ them rather than a standing exemption. An archive that is always underfoot is
295
+ not an archive.
296
+ */
297
+ let retiredScopeOf = (decision: retiredDecision): option<retiredScope> =>
298
+ switch decision {
299
+ | ExcludeRetired(scope) => Some(scope)
300
+ | RetiredVisible => None
301
+ }
302
+
303
+ /**
304
+ Whether a row's value in the retirement field is a retiring one.
305
+
306
+ The single place the two forms differ, so every reader asks one question rather
307
+ than branching on the form itself. The state form is a membership test: a
308
+ lifecycle may be withdrawn by several states, and they exclude identically —
309
+ what differs between them is the way back, which commands express and this does
310
+ not need to know.
311
+
312
+ `None` — the field absent from the row — answers false in both, which is the
313
+ mirror image of the owner rule and lands the opposite way for the same reason: an
314
+ owner-scoped read excludes a row that states no owner, because such a row belongs
315
+ to nobody in particular, while a retirement read KEEPS a row that states no flag,
316
+ because absent means not retired. That is what a row written before the
317
+ annotation existed is, and excluding those would empty the view the day the
318
+ annotation lands.
319
+
320
+ A state form naming no states excludes nothing, which is the same reading one
321
+ step further: no state has been declared to withdraw a row, so no row is.
322
+ */
323
+ let isRetiredValue = (scope: retiredScope, cell: option<JSON.t>): bool =>
324
+ switch (scope.values, cell) {
325
+ | (_, None) => false
326
+ | (None, Some(v)) => v->JSON.Decode.bool->Option.getOr(false)
327
+ | (Some(states), Some(v)) =>
328
+ switch v->JSON.Decode.string {
329
+ | None => false
330
+ | Some(s) => states->Array.includes(s)
331
+ }
332
+ }
@@ -1,5 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
3
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
5
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
5
6
  import * as Identity$Reventless from "./Identity.res.mjs";
@@ -155,6 +156,70 @@ function scopeOf(decision) {
155
156
  }
156
157
  }
157
158
 
159
+ function decideRetired(identity, retiredField, retiredValues, askedOpt, elevatedOpt) {
160
+ let asked = askedOpt !== undefined ? askedOpt : false;
161
+ let elevated = elevatedOpt !== undefined ? elevatedOpt : elevatedGroups();
162
+ if (retiredField === undefined) {
163
+ return "RetiredVisible";
164
+ }
165
+ let scope = {
166
+ field: retiredField,
167
+ values: retiredValues
168
+ };
169
+ let match = resolve(identity, elevated);
170
+ if (typeof match !== "object") {
171
+ if (asked) {
172
+ return "RetiredVisible";
173
+ } else {
174
+ return {
175
+ TAG: "ExcludeRetired",
176
+ _0: scope
177
+ };
178
+ }
179
+ }
180
+ switch (match.TAG) {
181
+ case "Elevated" :
182
+ if (asked) {
183
+ return "RetiredVisible";
184
+ } else {
185
+ return {
186
+ TAG: "ExcludeRetired",
187
+ _0: scope
188
+ };
189
+ }
190
+ case "Owned" :
191
+ case "Unidentified" :
192
+ return {
193
+ TAG: "ExcludeRetired",
194
+ _0: scope
195
+ };
196
+ }
197
+ }
198
+
199
+ function retiredScopeOf(decision) {
200
+ if (typeof decision !== "object") {
201
+ return;
202
+ } else {
203
+ return decision._0;
204
+ }
205
+ }
206
+
207
+ function isRetiredValue(scope, cell) {
208
+ let match = scope.values;
209
+ if (cell === undefined) {
210
+ return false;
211
+ }
212
+ if (match === undefined) {
213
+ return Stdlib_Option.getOr(Stdlib_JSON.Decode.bool(cell), false);
214
+ }
215
+ let s = Stdlib_JSON.Decode.string(cell);
216
+ if (s !== undefined) {
217
+ return match.includes(s);
218
+ } else {
219
+ return false;
220
+ }
221
+ }
222
+
158
223
  export {
159
224
  isJsString,
160
225
  systemProviders,
@@ -169,5 +234,8 @@ export {
169
234
  isExempt,
170
235
  decide,
171
236
  scopeOf,
237
+ decideRetired,
238
+ retiredScopeOf,
239
+ isRetiredValue,
172
240
  }
173
241
  /* Identity-Reventless Not a pure module */