@you-agent-factory/factory-emulator 0.0.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.
- package/LICENSE.md +3 -0
- package/README.md +286 -0
- package/generated/factory-emulator-scenario.schema.json +191 -0
- package/generated/factory.schema.json +2606 -0
- package/package.json +44 -0
- package/src/contracts.ts +41 -0
- package/src/data-error.js +21 -0
- package/src/data-only.js +208 -0
- package/src/emulator.js +195 -0
- package/src/emulator.ts +86 -0
- package/src/examples.js +86 -0
- package/src/examples.ts +11 -0
- package/src/generated/factory-schema.d.ts +3 -0
- package/src/generated/factory-schema.js +5 -0
- package/src/generated/scenario-schema.d.ts +4 -0
- package/src/generated/scenario-schema.js +6 -0
- package/src/generated/scenario.ts +103 -0
- package/src/identity.js +55 -0
- package/src/index.js +34 -0
- package/src/index.ts +102 -0
- package/src/limits.js +125 -0
- package/src/parser.js +113 -0
- package/src/parser.ts +56 -0
- package/src/scheduler.js +374 -0
- package/src/semantics.js +354 -0
- package/src/semantics.ts +38 -0
- package/src/session.js +1201 -0
- package/src/session.ts +324 -0
- package/src/sinks.js +118 -0
- package/src/sinks.ts +56 -0
- package/src/support.js +334 -0
- package/src/support.ts +15 -0
- package/src/virtual-time.js +36 -0
package/LICENSE.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# `@you-agent-factory/factory-emulator`
|
|
2
|
+
|
|
3
|
+
This package publishes the stable v1 JSON Schema and generated TypeScript
|
|
4
|
+
contract for deterministic Factory-emulator scenarios. The schema is available
|
|
5
|
+
as raw JSON from `@you-agent-factory/factory-emulator/schema`; the root module
|
|
6
|
+
exports `scenarioSchema` and `SUPPORTED_SCENARIO_VERSION`.
|
|
7
|
+
|
|
8
|
+
Every scenario declares a version, id, deterministic seed, UTC `startAt`,
|
|
9
|
+
ordered rules, and explicit unmatched behavior. Rules use finite scripted
|
|
10
|
+
outcomes with explicit exhaustion behavior. Initial submissions and lineage
|
|
11
|
+
cursors are structurally represented here; the parser validates the scenario
|
|
12
|
+
shape and supported Factory execution subset before emulation begins.
|
|
13
|
+
|
|
14
|
+
`activityLabel` is optional, limited to 120 characters, and only represents
|
|
15
|
+
transient emulator activity. It is never canonical Factory event content.
|
|
16
|
+
|
|
17
|
+
The schema under `contracts/factory-emulator/` is authored source. Run
|
|
18
|
+
`npm run generate` from this package to regenerate its committed schema and
|
|
19
|
+
TypeScript artifacts. The TypeScript declarations are derived from the schema's
|
|
20
|
+
properties, required fields, references, variants, and documented runtime
|
|
21
|
+
constraints rather than a separately authored type template. Run
|
|
22
|
+
`make generate-emulator` to verify they are current; when it reports drift,
|
|
23
|
+
regenerate them and commit the resulting artifacts.
|
|
24
|
+
|
|
25
|
+
## Parsing a scenario for browser emulation
|
|
26
|
+
|
|
27
|
+
`parseEmulatorScenario(scenario, factory)` is a pure preflight boundary. It
|
|
28
|
+
validates the complete canonical Factory JSON Schema before applying the
|
|
29
|
+
emulator's narrower capability policy, so accepted definitions can be emitted
|
|
30
|
+
in canonical bootstrap events without contract drift. The package carries a
|
|
31
|
+
generated byte-for-byte copy of the canonical Factory schema for this runtime
|
|
32
|
+
validation; `make generate-emulator` checks that copy for freshness.
|
|
33
|
+
The parser returns either the typed authored scenario and supported Factory
|
|
34
|
+
definition, or structured diagnostics with a stable JSON Pointer `path`,
|
|
35
|
+
`code`, `message`, and `expectation`. It never starts emulator activity or
|
|
36
|
+
creates Factory events.
|
|
37
|
+
|
|
38
|
+
The v1 emulator accepts static Petri Factory topology only. It rejects
|
|
39
|
+
JavaScript orchestration, configured Factory resources or guards, and cron,
|
|
40
|
+
repeater, or poller workstation scheduling before emulation starts. This keeps
|
|
41
|
+
scripted browser behavior deterministic while the runtime support subset grows.
|
|
42
|
+
|
|
43
|
+
## Rule semantics
|
|
44
|
+
|
|
45
|
+
Rules are evaluated in authored order; `selectEmulatorRule` returns the first
|
|
46
|
+
matching rule and no later rule can change that result. Parsing rejects a later
|
|
47
|
+
rule only when an earlier rule provably covers its supported domain, including a
|
|
48
|
+
known initial-submission id covered by an earlier work-type rule. It deliberately
|
|
49
|
+
does not report uncertain overlap as shadowing.
|
|
50
|
+
|
|
51
|
+
`resolveEmulatorScenarioResult(scenario, submission, invocationIndex)` is a
|
|
52
|
+
pure helper for a zero-based invocation count of the selected rule. It returns a
|
|
53
|
+
scripted outcome while one is available, repeats the final outcome only for
|
|
54
|
+
`repeatLast`, delegates only `useUnmatchedBehavior` exhaustion to the explicit
|
|
55
|
+
unmatched behavior, and otherwise returns the explicit exhaustion rejection.
|
|
56
|
+
|
|
57
|
+
Initial submission ids and rule ids must be unique. Initial submissions and
|
|
58
|
+
work-type matchers must name Factory work types. Lineage cursors may target one
|
|
59
|
+
known initial submission or one earlier `complete` scripted outcome; missing,
|
|
60
|
+
forward, cyclic, and incompatible targets are rejected with diagnostics before
|
|
61
|
+
emulation begins.
|
|
62
|
+
|
|
63
|
+
## Inspecting support and using examples
|
|
64
|
+
|
|
65
|
+
`inspectEmulatorSupport()` returns the stable machine-readable v1 capability
|
|
66
|
+
report. It covers the accepted static Factory subset, explicitly unsupported
|
|
67
|
+
Factory behavior, matchers, outcomes, lineage cursors, exhaustion and unmatched
|
|
68
|
+
options, initial-submission constraints, and `activityLabel` limits. The parser
|
|
69
|
+
uses that same Factory support policy, so the report cannot advertise execution
|
|
70
|
+
capabilities that parsing rejects.
|
|
71
|
+
|
|
72
|
+
`emulatorScenarioExamples` exports a minimal scenario and a multi-rule scenario.
|
|
73
|
+
The latter shows ordered priority matching, initial submissions, a scripted
|
|
74
|
+
lineage cursor, finite exhaustion, explicit unmatched rejection, and transient
|
|
75
|
+
`activityLabel` metadata. Both examples are validated through the public parser.
|
|
76
|
+
|
|
77
|
+
## Event sink and logical tick runtime
|
|
78
|
+
|
|
79
|
+
`@you-agent-factory/factory-emulator` provides the transport-neutral,
|
|
80
|
+
caller-owned `FactoryEventSink` contract used by Factory emulator hosts.
|
|
81
|
+
|
|
82
|
+
`write` accepts one ordered canonical `FactoryEventBatch` asynchronously. Its
|
|
83
|
+
only successful receipt means every event in the supplied order was accepted;
|
|
84
|
+
partial success must reject. `close` is a separate asynchronous operation and
|
|
85
|
+
does not implicitly accept a pending write. The values crossing the contract
|
|
86
|
+
are data-only, structured-cloneable Factory event and receipt shapes, making
|
|
87
|
+
the contract suitable for a future worker or process boundary.
|
|
88
|
+
|
|
89
|
+
`createMemoryFactoryEventSink({ maxEvents })` retains only the newest complete
|
|
90
|
+
batches that fit its event limit. `createFactoryRecordingSink({ sessionId,
|
|
91
|
+
maxEvents })` produces one finite recording for that session. Both helpers
|
|
92
|
+
structured-clone accepted batches and returned history, reject writes after
|
|
93
|
+
`close`, and preserve each batch atomically when a recording would exceed its
|
|
94
|
+
event bound.
|
|
95
|
+
|
|
96
|
+
This package intentionally does not own replay history or depend on browser
|
|
97
|
+
timers, React, Zustand, dashboard state, or transport code.
|
|
98
|
+
|
|
99
|
+
`@you-agent-factory/client` is a peer dependency because it supplies the
|
|
100
|
+
canonical Factory event and recording types. Consumers install both published
|
|
101
|
+
packages; the emulator package does not embed a checkout-relative dependency.
|
|
102
|
+
The peer range remains unconstrained while this dependency is type-only and no
|
|
103
|
+
minimum compatible client release has been established.
|
|
104
|
+
|
|
105
|
+
`createFactoryEmulator({ initialState, calculateTick, sink })` provides the
|
|
106
|
+
small logical-tick boundary used by an emulator host. It calculates a complete
|
|
107
|
+
batch from a detached committed-state snapshot, waits for `sink.write`, and
|
|
108
|
+
only then commits the calculated next state. A concurrent `advance` rejects
|
|
109
|
+
while the write is unresolved, ensuring no later tick is calculated or
|
|
110
|
+
committed ahead of an unaccepted batch.
|
|
111
|
+
|
|
112
|
+
If a sink rejects a tick, the emulator retains that detached batch and its
|
|
113
|
+
calculated state as the only pending transaction. The next `advance` retries it
|
|
114
|
+
with the same IDs, timestamps, contents, and order; `reset` explicitly
|
|
115
|
+
discards it. `pending` and `status` expose detached recovery state and the last
|
|
116
|
+
write or close error. An idle emulator remains open. When configured with
|
|
117
|
+
`calculateClose`, `close` writes that caller-supplied terminal lifecycle batch,
|
|
118
|
+
waits for it to be accepted, and then closes the sink. A pending rejected tick
|
|
119
|
+
blocks close so canonical history cannot be skipped. A rejected terminal batch
|
|
120
|
+
is likewise retained unchanged for the next close attempt; after its acceptance
|
|
121
|
+
a failed sink close retries only `sink.close`, never the terminal write.
|
|
122
|
+
|
|
123
|
+
## Deterministic session start and reset
|
|
124
|
+
|
|
125
|
+
`createFactoryEmulatorSession({ factory, scenario, sink })` owns one long-lived
|
|
126
|
+
emulator lifecycle. `start()` revalidates the supported Factory and scenario
|
|
127
|
+
before activity, normalizes `startAt` to a UTC instant, then writes an ordered
|
|
128
|
+
topology/run bootstrap batch followed by one normalized initial-submission
|
|
129
|
+
batch. The returned state becomes visible only after those writes are accepted.
|
|
130
|
+
|
|
131
|
+
Session, request, trace, Work, token, dispatch, completion, and event identities are derived from canonical
|
|
132
|
+
Factory/scenario inputs, the scenario seed, authored submission coordinates,
|
|
133
|
+
authored lineage cursors, and logical sequence. Submitted token identities are
|
|
134
|
+
recorded in `WORK_REQUEST` Work tags. Dispatch completion metadata records both
|
|
135
|
+
the resolved lineage-token anchor and the resulting token identity, while the
|
|
136
|
+
bounded Work snapshot retains the current token identity. The derivation reads
|
|
137
|
+
no ambient time, randomness, locale, or process-global counter. Every startup
|
|
138
|
+
event is stamped at virtual elapsed time zero (`startAt` after UTC normalization).
|
|
139
|
+
|
|
140
|
+
`reset()` is available after a successful start. It clears runtime Work,
|
|
141
|
+
virtual elapsed time, counters, and rule cursors and returns the session to
|
|
142
|
+
`pre-start` without writing an event. Starting again with the same immutable
|
|
143
|
+
configuration reproduces the original event bytes and committed snapshot;
|
|
144
|
+
changing the seed creates a different deterministic identity stream.
|
|
145
|
+
|
|
146
|
+
While started, `submit(work)` and `submit([work, ...])` accept the same
|
|
147
|
+
`id`, `workType`, and optional data-only `input` shape as scenario initial
|
|
148
|
+
submissions. The complete submission is detached and validated before the sink
|
|
149
|
+
is called. One accepted batch adds all of its Work in caller order; any invalid
|
|
150
|
+
member rejects the command without events, counter changes, or committed Work.
|
|
151
|
+
Request, trace, Work, and event identities include stable command coordinates,
|
|
152
|
+
so repeated sessions reproduce the same submission stream without relying on
|
|
153
|
+
ambient counters.
|
|
154
|
+
|
|
155
|
+
Scripted `complete` and `reject` outcomes may set a non-negative integer
|
|
156
|
+
`durationMs`; omission means zero virtual milliseconds. `advanceToNext()`
|
|
157
|
+
commits exactly one scheduler batch: ready Work starts at the current virtual
|
|
158
|
+
instant, while the next step jumps to the earliest deadline and completes all
|
|
159
|
+
dispatches due there in stable Work order. `advanceBy(durationMs)` processes
|
|
160
|
+
each eligible batch through its inclusive target and, when Work remains open,
|
|
161
|
+
ends exactly at that virtual instant. Waiting intervals move the virtual clock
|
|
162
|
+
without synthetic events, while a fully idle session returns an event-free
|
|
163
|
+
no-op receipt and stays open.
|
|
164
|
+
|
|
165
|
+
All advancement timestamps are derived from normalized scenario `startAt` plus
|
|
166
|
+
integer virtual elapsed milliseconds. The session creates no timers and owns no
|
|
167
|
+
playback speed, pause, visibility, or replay-selection state.
|
|
168
|
+
|
|
169
|
+
`status()` derives execution state from session facts. A started session with
|
|
170
|
+
ready Work reports `ready`; one with no unfinished Work remains open and reports
|
|
171
|
+
`idle`; unmatched unfinished Work configured to be ignored reports `waiting`.
|
|
172
|
+
During an accepted submission write it reports `active`, while `state()`
|
|
173
|
+
continues to expose only the prior committed snapshot. Once the sink accepts
|
|
174
|
+
the batch, the new Work becomes visible and the session reports `ready` or
|
|
175
|
+
`waiting` from its executable scenario facts.
|
|
176
|
+
|
|
177
|
+
Every status value also reports the current virtual instant, cumulative
|
|
178
|
+
completed-dispatch, event, and virtual-time usage with configured limits, and a
|
|
179
|
+
bounded summary of any rejected sink transaction. Error details are plain data,
|
|
180
|
+
including sink operation/message or execution-pause diagnostics. Status never
|
|
181
|
+
contains canonical event history, playback controls, timers, visibility state,
|
|
182
|
+
or framework-owned objects.
|
|
183
|
+
|
|
184
|
+
Configuration and command inputs are validated before runtime ownership and
|
|
185
|
+
must contain only plain objects, dense arrays, `null`, booleans, strings, and
|
|
186
|
+
finite numbers. Structured-cloneable class instances such as `Date`, `Map`,
|
|
187
|
+
`Set`, typed arrays, and regular expressions are rejected as configuration or
|
|
188
|
+
submission errors instead of entering scripted outputs, state, retries, or
|
|
189
|
+
events. Every receipt, status, pending batch, and state snapshot is a fresh
|
|
190
|
+
structured-cloneable data value. Mutating any returned value cannot alter
|
|
191
|
+
committed state or a later retry. The session retains current execution facts
|
|
192
|
+
and at most one bounded recovery transaction; accepted canonical batch history
|
|
193
|
+
belongs exclusively to the caller-owned sink.
|
|
194
|
+
|
|
195
|
+
Every session command follows the same calculate/write/commit boundary. If a
|
|
196
|
+
logical batch is rejected, `state()` and virtual time remain at the last
|
|
197
|
+
accepted transition, `status()` reports `error`, and `pending()` returns a
|
|
198
|
+
detached copy of the rejected batch. Only the same command with the same input
|
|
199
|
+
may retry that transaction; the retained event values and calculated next
|
|
200
|
+
state are reused without recalculation. `reset()` is the sole command that may
|
|
201
|
+
discard an open rejected transaction.
|
|
202
|
+
|
|
203
|
+
`close()` is explicit and terminal. It writes one deterministic `RUN_RESPONSE`
|
|
204
|
+
batch at the current virtual instant, commits the closed lifecycle only after
|
|
205
|
+
that batch is accepted, and then awaits `sink.close()`. A terminal write
|
|
206
|
+
rejection retries the same event. If only `sink.close()` rejects, the next
|
|
207
|
+
`close()` retries that operation without writing the terminal event again.
|
|
208
|
+
Non-close commands cannot bypass either recovery state, and all state-changing
|
|
209
|
+
commands reject after a successful close.
|
|
210
|
+
|
|
211
|
+
## Deterministic execution limits
|
|
212
|
+
|
|
213
|
+
Sessions enforce cumulative execution limits before a calculated batch reaches
|
|
214
|
+
the sink. Defaults are 1,000 completed dispatches, 10,000 canonical events, and
|
|
215
|
+
3,600,000 virtual milliseconds (one virtual hour). At one virtual instant, at
|
|
216
|
+
most 1,000 scheduler batches may run without virtual-time progress; crossing
|
|
217
|
+
that deterministic threshold is reported as a zero-duration cycle. Finite
|
|
218
|
+
zero-duration chains at or below the threshold still complete normally.
|
|
219
|
+
|
|
220
|
+
Callers may pass `limits` to `createFactoryEmulatorSession`. The limits object
|
|
221
|
+
must satisfy the same plain-data ownership boundary as Factory and scenario
|
|
222
|
+
configuration: class instances, custom or null prototypes, accessors, and
|
|
223
|
+
cycles are rejected before any property is read or sink activity occurs. The
|
|
224
|
+
accepted input is detached at construction, so later caller mutation cannot
|
|
225
|
+
change execution policy. Every supplied value must be a positive safe integer
|
|
226
|
+
and no greater than the exported
|
|
227
|
+
`FACTORY_EMULATOR_LIMIT_HARD_CAPS`. `maxEvents` has a minimum of 2 because the
|
|
228
|
+
mandatory bootstrap atomically emits `INITIAL_STRUCTURE_REQUEST` and
|
|
229
|
+
`RUN_REQUEST`; smaller configurations fail before sink activity. The defaults
|
|
230
|
+
and hard caps are exported as
|
|
231
|
+
`DEFAULT_FACTORY_EMULATOR_LIMITS` and `FACTORY_EMULATOR_LIMIT_HARD_CAPS`:
|
|
232
|
+
|
|
233
|
+
| Limit | Minimum | Default | Hard cap |
|
|
234
|
+
| --- | ---: | ---: | ---: |
|
|
235
|
+
| `maxCompletedDispatches` | 1 | 1,000 | 100,000 |
|
|
236
|
+
| `maxEvents` | 2 | 10,000 | 1,000,000 |
|
|
237
|
+
| `maxVirtualElapsedMs` | 1 | 3,600,000 | 31,536,000,000 |
|
|
238
|
+
| `maxZeroDurationBatches` | 1 | 1,000 | 100,000 |
|
|
239
|
+
| `maxSynchronousBatches` | 1 | 100 | 10,000 |
|
|
240
|
+
| `maxSynchronousWorkItems` | 1 | 100 | 10,000 |
|
|
241
|
+
|
|
242
|
+
Invalid policy fails at session construction, before bootstrap activity. All
|
|
243
|
+
kernel-produced command errors are detached plain-data values with `name`,
|
|
244
|
+
`message`, `code`, and family-specific diagnostic fields, so their complete
|
|
245
|
+
contract survives `structuredClone` across worker and process boundaries.
|
|
246
|
+
Caller-owned sink failures are propagated unchanged and are also projected as
|
|
247
|
+
plain data through `status()`, with non-string or unprintable rejection messages
|
|
248
|
+
normalized to safe strings. A batch that would exceed a cumulative limit is
|
|
249
|
+
not written or committed.
|
|
250
|
+
Instead, the command rejects with `FactoryEmulatorExecutionPausedError`, and
|
|
251
|
+
`status()` reports `error` with a detached `budget-exceeded` or
|
|
252
|
+
`zero-duration-cycle` diagnostic containing the limit name, configured and
|
|
253
|
+
observed values, and current virtual instant. Existing Work remains in its last
|
|
254
|
+
valid phase; the kernel never fabricates failed Work to represent a pause.
|
|
255
|
+
|
|
256
|
+
Before an atomic scheduler batch is materialized, the session examines at most
|
|
257
|
+
`maxSynchronousWorkItems` retained Work values and then yields with an explicit
|
|
258
|
+
plain-data inspection continuation. That inspection returns the exact candidate
|
|
259
|
+
indexes and lineage lookup consumed by pure calculation, so calculation does
|
|
260
|
+
not rescan retained Work. Replacement materialization and detached command-state
|
|
261
|
+
construction traverse retained Work with the same yield cadence instead of
|
|
262
|
+
performing whole-state clones. The inspection counts at most one eligible Work
|
|
263
|
+
beyond the limit. An oversized ready or due set pauses with a
|
|
264
|
+
`synchronous-work-limit` diagnostic before dispatch/completion events or
|
|
265
|
+
calculated next state are built. Initial and interactive submission batches use
|
|
266
|
+
the same ceiling. Their array cardinality is checked before any member is
|
|
267
|
+
validated or copied; oversized initial input fails session construction and an
|
|
268
|
+
oversized interactive command pauses without sink, state, or pending-transaction
|
|
269
|
+
residue. Cardinality inspection reads the array's own data descriptor inside an
|
|
270
|
+
exception-safe boundary, so throwing, revoked, or otherwise uninspectable proxy
|
|
271
|
+
inputs reject as detached command errors instead of leaking host exceptions.
|
|
272
|
+
Configuration and command detachment failures are normalized through the same
|
|
273
|
+
plain-data error boundary. The shared data-only validator uses an iterative
|
|
274
|
+
traversal capped at 10,000 nodes and 100 levels before cloning, so a single
|
|
275
|
+
deeply nested Work input cannot overflow the host stack or introduce an
|
|
276
|
+
unbounded calculation batch.
|
|
277
|
+
|
|
278
|
+
After each `maxSynchronousBatches` scheduler calculations, a long command awaits
|
|
279
|
+
a host task boundary. The default uses the runtime task queue without a wall
|
|
280
|
+
timer; hosts may inject `yieldControl` to own worker/process scheduling. Event
|
|
281
|
+
order is unchanged, and the original command stays serialized until it finishes
|
|
282
|
+
or pauses.
|
|
283
|
+
`reset()` clears the pause and all usage counters, reproducing the same boundary
|
|
284
|
+
for the same inputs. `close()` remains available after a safety pause and may
|
|
285
|
+
write its single terminal lifecycle event even when the execution event budget
|
|
286
|
+
is exhausted, ensuring the caller-owned sink can always be released.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://you-agent-factory.dev/schemas/factory-emulator/scenario/v1",
|
|
4
|
+
"title": "Factory Emulator Scenario v1",
|
|
5
|
+
"description": "A deterministic, authored scenario for a Factory emulator. activityLabel is transient emulator metadata and is never canonical Factory event content.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["version", "id", "seed", "startAt", "rules", "unmatchedBehavior"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"version": { "const": "you-agent-factory.emulator.scenario.v1" },
|
|
11
|
+
"id": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
12
|
+
"seed": { "type": "string", "minLength": 1, "maxLength": 256 },
|
|
13
|
+
"startAt": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"format": "date-time",
|
|
16
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(?:\\.[0-9]+)?Z$"
|
|
17
|
+
},
|
|
18
|
+
"initialSubmissions": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": { "$ref": "#/$defs/initialSubmission" }
|
|
21
|
+
},
|
|
22
|
+
"rules": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"items": { "$ref": "#/$defs/rule" }
|
|
25
|
+
},
|
|
26
|
+
"unmatchedBehavior": { "$ref": "#/$defs/unmatchedBehavior" },
|
|
27
|
+
"activityLabel": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"minLength": 1,
|
|
30
|
+
"maxLength": 120,
|
|
31
|
+
"description": "Bounded transient emulator activity metadata. It is never a canonical Factory event field."
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"$defs": {
|
|
35
|
+
"initialSubmission": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"additionalProperties": false,
|
|
38
|
+
"required": ["id", "workType"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"id": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
41
|
+
"workType": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
42
|
+
"input": { "type": "object", "additionalProperties": true }
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"rule": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["id", "match", "outcomes", "exhaustionBehavior"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
51
|
+
"match": { "$ref": "#/$defs/matcher" },
|
|
52
|
+
"outcomes": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"minItems": 1,
|
|
55
|
+
"items": { "$ref": "#/$defs/outcome" }
|
|
56
|
+
},
|
|
57
|
+
"exhaustionBehavior": { "$ref": "#/$defs/exhaustionBehavior" }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"matcher": {
|
|
61
|
+
"oneOf": [
|
|
62
|
+
{
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"required": ["kind"],
|
|
66
|
+
"properties": { "kind": { "const": "all" } }
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"required": ["kind", "workType"],
|
|
72
|
+
"properties": {
|
|
73
|
+
"kind": { "const": "workType" },
|
|
74
|
+
"workType": { "type": "string", "minLength": 1, "maxLength": 128 }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"additionalProperties": false,
|
|
80
|
+
"required": ["kind", "submissionId"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"kind": { "const": "submissionId" },
|
|
83
|
+
"submissionId": { "type": "string", "minLength": 1, "maxLength": 128 }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"outcome": {
|
|
89
|
+
"oneOf": [
|
|
90
|
+
{
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"required": ["kind"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"kind": { "const": "complete" },
|
|
96
|
+
"durationMs": {
|
|
97
|
+
"type": "integer",
|
|
98
|
+
"minimum": 0,
|
|
99
|
+
"maximum": 9007199254740991,
|
|
100
|
+
"description": "Deterministic virtual execution duration in milliseconds. Defaults to zero."
|
|
101
|
+
},
|
|
102
|
+
"output": { "type": "object", "additionalProperties": true },
|
|
103
|
+
"lineageCursor": { "$ref": "#/$defs/lineageCursor" }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": false,
|
|
109
|
+
"required": ["kind", "reason"],
|
|
110
|
+
"properties": {
|
|
111
|
+
"kind": { "const": "reject" },
|
|
112
|
+
"durationMs": {
|
|
113
|
+
"type": "integer",
|
|
114
|
+
"minimum": 0,
|
|
115
|
+
"maximum": 9007199254740991,
|
|
116
|
+
"description": "Deterministic virtual execution duration in milliseconds. Defaults to zero."
|
|
117
|
+
},
|
|
118
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"lineageCursor": {
|
|
124
|
+
"oneOf": [
|
|
125
|
+
{
|
|
126
|
+
"type": "object",
|
|
127
|
+
"additionalProperties": false,
|
|
128
|
+
"required": ["kind", "submissionId"],
|
|
129
|
+
"properties": {
|
|
130
|
+
"kind": { "const": "initialSubmission" },
|
|
131
|
+
"submissionId": { "type": "string", "minLength": 1, "maxLength": 128 }
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["kind", "ruleId", "outcomeIndex"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"kind": { "const": "scriptedOutcome" },
|
|
140
|
+
"ruleId": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
141
|
+
"outcomeIndex": { "type": "integer", "minimum": 0 }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"exhaustionBehavior": {
|
|
147
|
+
"oneOf": [
|
|
148
|
+
{
|
|
149
|
+
"type": "object",
|
|
150
|
+
"additionalProperties": false,
|
|
151
|
+
"required": ["kind"],
|
|
152
|
+
"properties": { "kind": { "const": "repeatLast" } }
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"type": "object",
|
|
156
|
+
"additionalProperties": false,
|
|
157
|
+
"required": ["kind"],
|
|
158
|
+
"properties": { "kind": { "const": "useUnmatchedBehavior" } }
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"type": "object",
|
|
162
|
+
"additionalProperties": false,
|
|
163
|
+
"required": ["kind", "reason"],
|
|
164
|
+
"properties": {
|
|
165
|
+
"kind": { "const": "reject" },
|
|
166
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
"unmatchedBehavior": {
|
|
172
|
+
"oneOf": [
|
|
173
|
+
{
|
|
174
|
+
"type": "object",
|
|
175
|
+
"additionalProperties": false,
|
|
176
|
+
"required": ["kind"],
|
|
177
|
+
"properties": { "kind": { "const": "ignore" } }
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"type": "object",
|
|
181
|
+
"additionalProperties": false,
|
|
182
|
+
"required": ["kind", "reason"],
|
|
183
|
+
"properties": {
|
|
184
|
+
"kind": { "const": "reject" },
|
|
185
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|