@directive-run/core 1.4.0 → 1.6.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/dist/adapter-utils.cjs +1 -1
- package/dist/adapter-utils.d.cts +1 -1
- package/dist/adapter-utils.d.ts +1 -1
- package/dist/adapter-utils.js +1 -1
- package/dist/{chunk-FK7BD7XT.js → chunk-EH2Q754B.js} +3 -3
- package/dist/chunk-EH2Q754B.js.map +1 -0
- package/dist/chunk-EOLY64E6.cjs +3 -0
- package/dist/chunk-EOLY64E6.cjs.map +1 -0
- package/dist/chunk-K3KVGWLP.cjs +3 -0
- package/dist/chunk-K3KVGWLP.cjs.map +1 -0
- package/dist/chunk-OVNPYGYJ.js +3 -0
- package/dist/chunk-OVNPYGYJ.js.map +1 -0
- package/dist/chunk-QOK7CHOW.js +16 -0
- package/dist/chunk-QOK7CHOW.js.map +1 -0
- package/dist/{chunk-DDUARSUH.cjs → chunk-S3CFYDIB.cjs} +3 -3
- package/dist/chunk-S3CFYDIB.cjs.map +1 -0
- package/dist/chunk-T4ZO4IYL.cjs +16 -0
- package/dist/chunk-T4ZO4IYL.cjs.map +1 -0
- package/dist/chunk-T6IJUWYR.js +3 -0
- package/dist/chunk-T6IJUWYR.js.map +1 -0
- package/dist/{helpers-BUY1lYCX.d.cts → helpers-BwAThjnJ.d.ts} +12 -2
- package/dist/{helpers-D6LcRum7.d.ts → helpers-CG27mEGG.d.cts} +12 -2
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +413 -5
- package/dist/index.d.ts +413 -5
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +1 -1
- package/dist/internals.d.cts +86 -40
- package/dist/internals.d.ts +86 -40
- package/dist/internals.js +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.d.cts +11 -8
- package/dist/plugins/index.d.ts +11 -8
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/{plugins-Dy1C8GtT.d.cts → plugins-DvrsPhzx.d.cts} +471 -68
- package/dist/{plugins-Dy1C8GtT.d.ts → plugins-DvrsPhzx.d.ts} +471 -68
- package/dist/system-5BSCMT63.cjs +2 -0
- package/dist/{system-2THXJBFM.cjs.map → system-5BSCMT63.cjs.map} +1 -1
- package/dist/system-DMJ6XEJ7.js +2 -0
- package/dist/{system-JIO36ALC.js.map → system-DMJ6XEJ7.js.map} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4CMO5OVZ.js +0 -3
- package/dist/chunk-4CMO5OVZ.js.map +0 -1
- package/dist/chunk-BEJ6ICA7.cjs +0 -3
- package/dist/chunk-BEJ6ICA7.cjs.map +0 -1
- package/dist/chunk-DDUARSUH.cjs.map +0 -1
- package/dist/chunk-E2WETPLH.js +0 -3
- package/dist/chunk-E2WETPLH.js.map +0 -1
- package/dist/chunk-FK7BD7XT.js.map +0 -1
- package/dist/chunk-LFMRWCIG.js +0 -16
- package/dist/chunk-LFMRWCIG.js.map +0 -1
- package/dist/chunk-TUS5WDVE.cjs +0 -3
- package/dist/chunk-TUS5WDVE.cjs.map +0 -1
- package/dist/chunk-VSHSYVSY.cjs +0 -16
- package/dist/chunk-VSHSYVSY.cjs.map +0 -1
- package/dist/system-2THXJBFM.cjs +0 -2
- package/dist/system-JIO36ALC.js +0 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,408 @@
|
|
|
1
|
-
import { S as SchemaType, D as DefinitionMeta, M as ModuleSchema,
|
|
2
|
-
export { A as AnySystem, B as BatchConfig,
|
|
3
|
-
export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-
|
|
1
|
+
import { P as PatchSpec, C as ClauseResult, F as FactTemplate, a as FactPredicate, S as SchemaType, D as DefinitionMeta, M as ModuleSchema, b as Facts, T as TypedDerivationsDef, c as TypedEventsDef, E as EffectsDef, d as TypedConstraintsDef, e as TypedResolversDef, f as ModuleHooks, g as CrossModuleDeps, h as CrossModuleDerivationsDef, i as CrossModuleEffectsDef, j as CrossModuleConstraintsDef, k as ModuleDef, l as CreateSystemOptionsSingle, m as SingleModuleSystem, n as ModulesMap, o as CreateSystemOptionsNamed, N as NamespacedSystem, p as Plugin, q as TraceOption, r as ErrorBoundaryConfig, R as RequirementWithId, s as Requirement, t as RequirementKeyFn } from './plugins-DvrsPhzx.cjs';
|
|
2
|
+
export { A as AnySystem, B as BatchConfig, u as DirectiveError, v as DistributableSnapshot, w as DistributableSnapshotOptions, x as DynamicConstraintDef, y as DynamicEffectDef, z as DynamicResolverDef, G as FactsSnapshot, H as HistoryAPI, I as HistoryOption, J as HistoryState, K as InferDerivations, L as InferEvents, O as InferFacts, Q as InferRequirementTypes, U as InferRequirements, V as InferSchemaType, W as InferSelectorState, X as KeySelector, Y as MetaAccessor, Z as MetaMatch, _ as ObservationEvent, $ as OperatorObject, a0 as PatchValue, a1 as PayloadRef, a2 as PredicateClause, a3 as PredicateCombinator, a4 as PredicateCombinatorKey, a5 as PredicateObject, a6 as PredicateOp, a7 as RetryPolicy, a8 as Schema, a9 as Snapshot, aa as System, ab as SystemConfig, ac as SystemInspection, ad as SystemMode, ae as SystemSnapshot, af as TraceEntry, ag as isNamespacedSystem, ah as isSingleModuleSystem } from './plugins-DvrsPhzx.cjs';
|
|
3
|
+
export { D as DerivationDefWithMeta, t as typedConstraint, a as typedResolver } from './helpers-CG27mEGG.cjs';
|
|
4
4
|
export { D as DistributableSnapshotLike, S as SignedSnapshot, a as SnapshotDiff, b as SnapshotDiffEntry, d as diffSnapshots, i as isSignedSnapshot, c as isSnapshotExpired, s as shallowEqual, e as signSnapshot, v as validateSnapshot, f as verifySnapshotSignature } from './utils-BnQajqPu.cjs';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Runtime for data-configuration predicates and templates.
|
|
8
|
+
*
|
|
9
|
+
* Pure module — imports only its own types. Reads facts through whatever
|
|
10
|
+
* object it is handed (the reactive `Facts` proxy in production, a plain
|
|
11
|
+
* snapshot in tests), so it never depends on the engine, store, or tracking.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** A readable scope — the `Facts` proxy and a plain snapshot both satisfy it. */
|
|
15
|
+
type Scope = Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* True when `v` is a data-form spec (predicate object/array) rather than a
|
|
18
|
+
* function. Excludes class instances (Date, RegExp, Map, Set, Promise, etc.)
|
|
19
|
+
* — only plain `{}` literals and arrays of plain clause shapes qualify.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* isPredicate({ phase: "red" }); // true
|
|
24
|
+
* isPredicate((f) => f.phase === "red"); // false
|
|
25
|
+
* isPredicate([{ fact: "phase", op: "$eq", value: "red" }]); // true
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare function isPredicate(v: unknown): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* True when `v` is a {@link FactTemplate} (`{ $template: string }`).
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* isTemplate({ $template: "Hi ${name}" }); // true
|
|
35
|
+
* isTemplate({ $set: { name: "x" } }); // false
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare function isTemplate(v: unknown): v is FactTemplate;
|
|
39
|
+
/**
|
|
40
|
+
* Throw when a predicate spec contains an operand that cannot survive a
|
|
41
|
+
* JSON round-trip — i.e. that would silently mis-evaluate if the spec was
|
|
42
|
+
* loaded from `JSON.parse`.
|
|
43
|
+
*
|
|
44
|
+
* Three failure classes are detected:
|
|
45
|
+
*
|
|
46
|
+
* - **Lost `RegExp` operand.** A `$matches` operand that is not a
|
|
47
|
+
* `RegExp` instance. `JSON.parse` reconstructs a serialized regex as
|
|
48
|
+
* `{}`, so a `$matches` clause with an empty-object operand is the
|
|
49
|
+
* signature of a regex that did not survive serialization. Reify it
|
|
50
|
+
* with `new RegExp(pattern, flags)` before installing the predicate.
|
|
51
|
+
* - **`bigint` operand.** `JSON.stringify` throws on `bigint`, so a
|
|
52
|
+
* `bigint` operand cannot have been produced by a JSON pipeline and
|
|
53
|
+
* cannot be persisted by one either.
|
|
54
|
+
* - **`Set` / `Map` operand.** Both serialize to `{}` and lose all
|
|
55
|
+
* members; a predicate carrying one is not JSON-safe.
|
|
56
|
+
*
|
|
57
|
+
* This is an opt-in helper — the engine does not call it automatically.
|
|
58
|
+
* Users who load predicates from JSON should call it after `JSON.parse`
|
|
59
|
+
* to fail loud rather than silently mis-evaluate. See the
|
|
60
|
+
* "Serialization" section of RFC-0004.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* validatePredicate({ phase: { $matches: {} } });
|
|
65
|
+
* // throws — empty object where a RegExp is required
|
|
66
|
+
*
|
|
67
|
+
* validatePredicate({ phase: "red", elapsed: { $gte: 30 } });
|
|
68
|
+
* // ok — JSON-clean operands
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare function validatePredicate(spec: unknown, path?: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Evaluate a {@link FactPredicate} against a fact scope. `prev` (a previous
|
|
74
|
+
* snapshot) is consulted only by the `$changed` operator.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* evaluatePredicate({ phase: "red", elapsed: { $gte: 30 } }, { phase: "red", elapsed: 45 });
|
|
79
|
+
* // → true
|
|
80
|
+
* evaluatePredicate({ $any: [{ phase: "red" }, { phase: "yellow" }] }, { phase: "green" });
|
|
81
|
+
* // → false
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function evaluatePredicate(spec: unknown, facts: Scope, prev?: Scope, depth?: number): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Evaluate a predicate and return a per-clause breakdown — the data feed for
|
|
87
|
+
* devtools, `system.explain()`, and `directive explain`.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* evaluatePredicateExplained(
|
|
92
|
+
* { phase: "red", elapsed: { $gte: 30 } },
|
|
93
|
+
* { phase: "red", elapsed: 20 },
|
|
94
|
+
* );
|
|
95
|
+
* // → [
|
|
96
|
+
* // { path: "phase", op: "$eq", expected: "red", actual: "red", pass: true },
|
|
97
|
+
* // { path: "elapsed", op: "$gte", expected: 30, actual: 20, pass: false },
|
|
98
|
+
* // ]
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
declare function evaluatePredicateExplained(spec: unknown, facts: Scope, prev?: Scope, pathPrefix?: string): ClauseResult[];
|
|
102
|
+
/**
|
|
103
|
+
* Memoize a predicate as a reusable evaluation closure.
|
|
104
|
+
*
|
|
105
|
+
* The returned function accepts any `facts` scope (the reactive proxy in
|
|
106
|
+
* production, a plain object in tests) plus an optional `prev` snapshot for
|
|
107
|
+
* `$changed`. The closure is cached **by predicate identity** in a
|
|
108
|
+
* `WeakMap`, so passing the same `predicate` reference repeatedly is
|
|
109
|
+
* allocation-free; cleanup is automatic once the predicate is no longer
|
|
110
|
+
* reachable.
|
|
111
|
+
*
|
|
112
|
+
* Note: no actual compilation happens — the returned closure re-walks the
|
|
113
|
+
* spec on every call via `evaluatePredicate`. The name reflects what the
|
|
114
|
+
* function does (closure memoization keyed by predicate identity), not a
|
|
115
|
+
* bytecode/AST compile step.
|
|
116
|
+
*
|
|
117
|
+
* Intended for advanced users who want a stable function reference per
|
|
118
|
+
* predicate (custom devtools, batched analyses). Regular module code does
|
|
119
|
+
* not need to call this — the engine wraps data-form `when` / `on` specs
|
|
120
|
+
* automatically at registration.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const predicate = { phase: "red", elapsed: { $gte: 30 } };
|
|
125
|
+
* const check = memoizePredicate(predicate);
|
|
126
|
+
* check({ phase: "red", elapsed: 45 }); // → true
|
|
127
|
+
* check({ phase: "red", elapsed: 5 }); // → false
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
declare function memoizePredicate(predicate: object): (facts: Scope, prev?: Scope) => boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Collect the fact keys a predicate references. Used for static analysis,
|
|
133
|
+
* devtools, and effect `on` dependency wiring. Nested predicates contribute
|
|
134
|
+
* dotted keys (`auth.token`).
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* extractDeps({ phase: "red", elapsed: { $gte: 30 } });
|
|
139
|
+
* // → Set { "phase", "elapsed" }
|
|
140
|
+
* extractDeps({ self: { phase: "red" }, auth: { token: { $exists: true } } });
|
|
141
|
+
* // → Set { "self.phase", "auth.token" }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
declare function extractDeps(spec: unknown, prefix?: string): Set<string>;
|
|
145
|
+
/**
|
|
146
|
+
* Interpolate a {@link FactTemplate} against a scope. Single-pass character
|
|
147
|
+
* scanner: `${ident}` interpolates `scope[ident]`; `$${` emits a literal
|
|
148
|
+
* `${`; unknown keys dev-warn and yield an empty string.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* evaluateTemplate({ $template: "Hi ${name}!" }, { name: "Ada" });
|
|
153
|
+
* // → "Hi Ada!"
|
|
154
|
+
* evaluateTemplate({ $template: "$${price}" }, {});
|
|
155
|
+
* // → "${price}"
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
declare function evaluateTemplate(spec: FactTemplate, scope: Scope): string;
|
|
159
|
+
/**
|
|
160
|
+
* Collect the placeholder keys referenced by a template. The static-analysis
|
|
161
|
+
* counterpart to {@link extractDeps} — useful for devtools, codegen, and
|
|
162
|
+
* "which facts does this template read" inspections. Only valid identifier
|
|
163
|
+
* placeholders are collected; malformed ones are ignored.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* extractTemplateKeys({ $template: "${firstName} ${lastName}" });
|
|
168
|
+
* // → Set { "firstName", "lastName" }
|
|
169
|
+
* extractTemplateKeys({ $template: "$${literal}" });
|
|
170
|
+
* // → Set {} (escaped — not a placeholder)
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function extractTemplateKeys(spec: FactTemplate): Set<string>;
|
|
174
|
+
/**
|
|
175
|
+
* Build a stable dedup key by selecting fields from a requirement payload.
|
|
176
|
+
* Order-as-declared; values are stable-stringified (keys sorted recursively)
|
|
177
|
+
* so two payloads with the same fields in different orders dedupe to the
|
|
178
|
+
* same key.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* evaluateKeySelector(["url", "method"], { url: "/a", method: "GET" });
|
|
183
|
+
* // → '"/a"|"GET"'
|
|
184
|
+
* evaluateKeySelector(["id"], { id: 42 });
|
|
185
|
+
* // → '42'
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
declare function evaluateKeySelector(selector: readonly string[], source: Record<string, unknown>): string;
|
|
189
|
+
/**
|
|
190
|
+
* Apply a {@link PatchSpec} — assign facts from literals, payload copies
|
|
191
|
+
* (`$ref`), or interpolated strings (`$template`). Mutates through the passed
|
|
192
|
+
* `facts` proxy so change-tracking and downstream invalidation fire.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* const spec = {
|
|
197
|
+
* $set: {
|
|
198
|
+
* active: true,
|
|
199
|
+
* userId: { $ref: "id" },
|
|
200
|
+
* label: { $template: "user ${name}" },
|
|
201
|
+
* },
|
|
202
|
+
* };
|
|
203
|
+
* applyPatch(spec, facts, { id: "u_1", name: "Ada" });
|
|
204
|
+
* // facts.active = true; facts.userId = "u_1"; facts.label = "user Ada"
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
declare function applyPatch(spec: PatchSpec<Record<string, unknown>, Record<string, unknown>>, facts: Record<string, unknown>, payload: Record<string, unknown>): void;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Predicate backtest — rule-change impact.
|
|
211
|
+
*
|
|
212
|
+
* Given a recorded sequence of fact-state frames and a proposed replacement
|
|
213
|
+
* for a constraint's `when` predicate, re-score the frames against BOTH the
|
|
214
|
+
* original and the proposed predicate and produce a backtest report: how
|
|
215
|
+
* many frames each matched, plus the per-frame diff (frames that newly
|
|
216
|
+
* match / no longer match). It answers "how many recorded frames would the
|
|
217
|
+
* proposed rule have matched differently" against real recorded history.
|
|
218
|
+
*
|
|
219
|
+
* This is a *static* backtest, not a behavioral simulation — the engine is
|
|
220
|
+
* not re-run. Recorded frames are re-scored against a new predicate; the
|
|
221
|
+
* resulting requirements, resolvers, and downstream fact changes are NOT
|
|
222
|
+
* modeled. Treat the numbers as a divergence scan, not a forecast.
|
|
223
|
+
*
|
|
224
|
+
* Pure module — imports only the predicate runtime. No engine, store, or
|
|
225
|
+
* tracking dependency. Replay walks frames in order; for `$changed`-style
|
|
226
|
+
* predicates each frame is evaluated against the previous frame's facts.
|
|
227
|
+
*/
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Upper bound on the number of frames a single {@link replayUnder} call will
|
|
231
|
+
* process. A history file is held entirely in memory; an unbounded array is a
|
|
232
|
+
* denial-of-service surface. A history larger than this should be split or
|
|
233
|
+
* down-sampled before replay.
|
|
234
|
+
*/
|
|
235
|
+
declare const MAX_REPLAY_FRAMES = 1000000;
|
|
236
|
+
/** One recorded fact-state frame. */
|
|
237
|
+
interface ReplayFrame<F = Record<string, unknown>> {
|
|
238
|
+
/** Stable identifier — a snapshot id, an index, a session key. */
|
|
239
|
+
id: string | number;
|
|
240
|
+
/** Optional wall-clock time (ms epoch). */
|
|
241
|
+
timestamp?: number;
|
|
242
|
+
/** The fact state at this frame. */
|
|
243
|
+
facts: F;
|
|
244
|
+
}
|
|
245
|
+
interface ReplayUnderOptions<F = Record<string, unknown>> {
|
|
246
|
+
/** Recorded frames, chronological order. */
|
|
247
|
+
frames: readonly ReplayFrame<F>[];
|
|
248
|
+
/** The constraint's current `when` predicate (the baseline). */
|
|
249
|
+
original: FactPredicate<F>;
|
|
250
|
+
/** The proposed replacement `when` predicate. */
|
|
251
|
+
proposed: FactPredicate<F>;
|
|
252
|
+
/** Max diff samples to attach per bucket (default 20). */
|
|
253
|
+
maxSamples?: number;
|
|
254
|
+
/**
|
|
255
|
+
* A fact key identifying the entity a frame belongs to (e.g. `"userId"`,
|
|
256
|
+
* `"sessionId"`). When set, the report also reports distinct-entity counts
|
|
257
|
+
* — how many unique entities matched, not just how many frames. Without it
|
|
258
|
+
* the unit is frames: one fact snapshot, not one user or session.
|
|
259
|
+
*/
|
|
260
|
+
entityKey?: string;
|
|
261
|
+
}
|
|
262
|
+
/** A frame where the original and proposed predicate disagree. */
|
|
263
|
+
interface ReplayDiffSample {
|
|
264
|
+
frameId: string | number;
|
|
265
|
+
timestamp?: number;
|
|
266
|
+
/** The fact state at this frame. */
|
|
267
|
+
facts: Record<string, unknown>;
|
|
268
|
+
/** Per-clause breakdown under the original predicate. */
|
|
269
|
+
originalExplain: ClauseResult[];
|
|
270
|
+
/** Per-clause breakdown under the proposed predicate. */
|
|
271
|
+
proposedExplain: ClauseResult[];
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* The outcome of replaying a recorded history under two predicates — a
|
|
275
|
+
* static backtest of a proposed rule change, not a behavioral simulation.
|
|
276
|
+
*/
|
|
277
|
+
interface PredicateBacktestReport {
|
|
278
|
+
/** Total frames evaluated. */
|
|
279
|
+
framesEvaluated: number;
|
|
280
|
+
/**
|
|
281
|
+
* Frames where the original predicate matched (was true). `matchedEntities`
|
|
282
|
+
* is the count of distinct `entityKey` values among matched frames — only
|
|
283
|
+
* populated when {@link ReplayUnderOptions.entityKey} was supplied.
|
|
284
|
+
*/
|
|
285
|
+
original: {
|
|
286
|
+
matched: number;
|
|
287
|
+
matchedEntities?: number;
|
|
288
|
+
};
|
|
289
|
+
/** Frames where the proposed predicate matched. */
|
|
290
|
+
proposed: {
|
|
291
|
+
matched: number;
|
|
292
|
+
matchedEntities?: number;
|
|
293
|
+
};
|
|
294
|
+
/** proposed.matched - original.matched. */
|
|
295
|
+
delta: number;
|
|
296
|
+
/** Total count of frames that newly match (original false -> proposed true). */
|
|
297
|
+
newMatchCount: number;
|
|
298
|
+
/** Total count of frames that no longer match (original true -> proposed false). */
|
|
299
|
+
lostMatchCount: number;
|
|
300
|
+
/** Frames where original and proposed agree. */
|
|
301
|
+
unchanged: number;
|
|
302
|
+
/** Sampled new-match frames (capped at maxSamples), with clause explain. */
|
|
303
|
+
newMatches: ReplayDiffSample[];
|
|
304
|
+
/** Sampled lost-match frames (capped at maxSamples), with clause explain. */
|
|
305
|
+
lostMatches: ReplayDiffSample[];
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Normalize a parsed-from-JSON history value into a `ReplayFrame[]`.
|
|
309
|
+
*
|
|
310
|
+
* Accepts the three documented history shapes:
|
|
311
|
+
*
|
|
312
|
+
* 1. A bare array of frames: `[{ id, timestamp?, facts }, ...]`
|
|
313
|
+
* 2. An object wrapping them: `{ frames: [{ id, ..., facts }, ...] }`
|
|
314
|
+
* 3. A bare array of fact objects: `[{ phase: "red", ... }, ...]`
|
|
315
|
+
* — each element is wrapped as a frame.
|
|
316
|
+
*
|
|
317
|
+
* Frame ids are kept unambiguous: a frame that supplies its own `id` keeps
|
|
318
|
+
* it; a frame missing an `id` (and every bare-fact frame) gets an
|
|
319
|
+
* **index-derived** id prefixed with `#` (`"#0"`, `"#1"`, …) so a fallback
|
|
320
|
+
* id can never collide with an explicit numeric or string id in a mixed
|
|
321
|
+
* history. This is a pure helper — it **throws** a clear `Error` on bad
|
|
322
|
+
* input and never calls `process.exit`, so library users can catch it.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* toReplayFrames([{ id: "s1", facts: { phase: "red" } }]);
|
|
327
|
+
* // → [{ id: "s1", facts: { phase: "red" } }]
|
|
328
|
+
* toReplayFrames([{ phase: "red" }, { phase: "green" }]);
|
|
329
|
+
* // → [{ id: "#0", facts: { phase: "red" } }, { id: "#1", facts: { phase: "green" } }]
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
declare function toReplayFrames(raw: unknown): ReplayFrame[];
|
|
333
|
+
/**
|
|
334
|
+
* Convert a history-manager export (the JSON produced by
|
|
335
|
+
* `system.history.export()`) into a `ReplayFrame[]` ready for
|
|
336
|
+
* {@link replayUnder}.
|
|
337
|
+
*
|
|
338
|
+
* The history manager records a ring buffer of `{ id, timestamp, facts,
|
|
339
|
+
* trigger }` snapshots; `export()` wraps them as `{ version, snapshots,
|
|
340
|
+
* currentIndex }`. Each snapshot's `facts` is the fact state at that point,
|
|
341
|
+
* so the snapshot sequence is exactly a frame stream.
|
|
342
|
+
*
|
|
343
|
+
* Accepts either the parsed export object, the raw JSON string, or a bare
|
|
344
|
+
* array of snapshots. Throws a clear `Error` on bad input.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* const frames = framesFromHistory(system.history.export());
|
|
349
|
+
* const report = replayUnder({ frames, original, proposed });
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
declare function framesFromHistory(historyExport: unknown): ReplayFrame[];
|
|
353
|
+
/**
|
|
354
|
+
* Convert an array of `{ id, timestamp?, facts }` snapshots — e.g. the
|
|
355
|
+
* `snapshots` field of a history export, or an array assembled by pushing
|
|
356
|
+
* `system.getSnapshot()` on each reconcile — into a `ReplayFrame[]`.
|
|
357
|
+
*
|
|
358
|
+
* Throws a clear `Error` if the argument is not an array. Each snapshot is
|
|
359
|
+
* normalized through the same {@link toReplayFrames} id logic.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```ts
|
|
363
|
+
* const snapshots: typeof history[] = [];
|
|
364
|
+
* system.observe(() => snapshots.push(system.getSnapshot()));
|
|
365
|
+
* // ...later
|
|
366
|
+
* const frames = framesFromSnapshots(snapshots);
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
declare function framesFromSnapshots(snapshots: unknown): ReplayFrame[];
|
|
370
|
+
/**
|
|
371
|
+
* Replay a recorded fact-frame history through two predicates — the
|
|
372
|
+
* constraint's current `when` and a proposed replacement — and report how
|
|
373
|
+
* their match sets differ.
|
|
374
|
+
*
|
|
375
|
+
* This is a **predicate backtest**: the engine is not re-run. Each recorded
|
|
376
|
+
* frame is statically re-scored against both specs; the previous frame's
|
|
377
|
+
* facts are threaded as `prev` so a replayed effect-`on` predicate using
|
|
378
|
+
* `$changed` still works (for a constraint `when` it is harmless). The
|
|
379
|
+
* report counts matches under each spec and buckets the disagreements into
|
|
380
|
+
* new matches (original false, proposed true) and lost matches (original
|
|
381
|
+
* true, proposed false). Up to `maxSamples` diff frames per bucket carry a
|
|
382
|
+
* per-clause `evaluatePredicateExplained` breakdown for inspection.
|
|
383
|
+
*
|
|
384
|
+
* Both specs are validated up front — a malformed spec throws a clear
|
|
385
|
+
* `[Directive] replayUnder:` error identifying which spec failed, rather
|
|
386
|
+
* than letting a raw `evaluatePredicate` error escape mid-loop.
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```ts
|
|
390
|
+
* const report = replayUnder({
|
|
391
|
+
* frames: [
|
|
392
|
+
* { id: 0, facts: { phase: "red", elapsed: 10 } },
|
|
393
|
+
* { id: 1, facts: { phase: "red", elapsed: 35 } },
|
|
394
|
+
* ],
|
|
395
|
+
* original: { phase: "red" },
|
|
396
|
+
* proposed: { phase: "red", elapsed: { $gte: 30 } },
|
|
397
|
+
* });
|
|
398
|
+
* // report.original.matched === 2
|
|
399
|
+
* // report.proposed.matched === 1
|
|
400
|
+
* // report.delta === -1
|
|
401
|
+
* // report.lostMatchCount === 1
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
declare function replayUnder<F = Record<string, unknown>>(options: ReplayUnderOptions<F>): PredicateBacktestReport;
|
|
405
|
+
|
|
6
406
|
/** Brand symbol for branded types */
|
|
7
407
|
declare const Brand: unique symbol;
|
|
8
408
|
/** Branded type - adds a unique brand to a base type */
|
|
@@ -793,6 +1193,14 @@ declare function createSystemWithStatus<M extends ModuleSchema>(options: CreateS
|
|
|
793
1193
|
* - Requirement comparison and hashing
|
|
794
1194
|
*/
|
|
795
1195
|
|
|
1196
|
+
/**
|
|
1197
|
+
* Computes a stable identifier for a requirement, used for coalescing
|
|
1198
|
+
* duplicate fetches across the constraint graph.
|
|
1199
|
+
*
|
|
1200
|
+
* @param req - the requirement to identify
|
|
1201
|
+
* @param keyFn - optional custom key function; if omitted, a stableStringify-based default is used (memoized via WeakMap)
|
|
1202
|
+
* @returns the requirement's stable string ID
|
|
1203
|
+
*/
|
|
796
1204
|
declare function generateRequirementId(req: Requirement, keyFn?: RequirementKeyFn): string;
|
|
797
1205
|
/**
|
|
798
1206
|
* Create a typed requirement factory for a given requirement type string.
|
|
@@ -1141,7 +1549,7 @@ declare function resumeTimer(state: TimerFactState, nowMs: number): TimerFactSta
|
|
|
1141
1549
|
declare function resetTimer(): TimerFactState;
|
|
1142
1550
|
/**
|
|
1143
1551
|
* Transition: mark the timer completed. For countdown mode when
|
|
1144
|
-
* elapsed
|
|
1552
|
+
* elapsed reaches `ms`; for repeat mode when consumer wants to halt.
|
|
1145
1553
|
*/
|
|
1146
1554
|
declare function completeTimer(state: TimerFactState): TimerFactState;
|
|
1147
1555
|
/**
|
|
@@ -1255,4 +1663,4 @@ declare const Backoff: {
|
|
|
1255
1663
|
readonly Exponential: "exponential";
|
|
1256
1664
|
};
|
|
1257
1665
|
|
|
1258
|
-
export { Backoff, type Branded, type ChainableSchemaType, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, Facts, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, Plugin, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, forType, generateRequirementId, initialTimerState, isRequirementType, pauseTimer, realClock, registerRepeat, remainingMs, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, virtualClock };
|
|
1666
|
+
export { Backoff, type Branded, type ChainableSchemaType, ClauseResult, CreateSystemOptionsNamed, CreateSystemOptionsSingle, CrossModuleDeps, DefinitionMeta, ErrorBoundaryConfig, type ExtendedSchemaType, FactPredicate, FactTemplate, Facts, MAX_REPLAY_FRAMES, type ModuleConfig, type ModuleConfigWithDeps, ModuleDef, ModuleHooks, ModuleSchema, ModulesMap, NamespacedSystem, PatchSpec, Plugin, type PredicateBacktestReport, type ReplayDiffSample, type ReplayFrame, type ReplayUnderOptions, Requirement, RequirementSet, type RequirementTypeStatus, RequirementWithId, SchemaType, type SignalClock, SingleModuleSystem, type TimerFactOpts, type TimerFactState, TraceOption, applyPatch, completeTimer, createModule, createModuleFactory, createRequirementStatusPlugin, createStatusHook, createSystem, createSystemWithStatus, defaultClock, elapsedMs, evaluateKeySelector, evaluatePredicate, evaluatePredicateExplained, evaluateTemplate, extractDeps, extractTemplateKeys, forType, framesFromHistory, framesFromSnapshots, generateRequirementId, initialTimerState, isPredicate, isRequirementType, isTemplate, memoizePredicate, pauseTimer, realClock, registerRepeat, remainingMs, replayUnder, req, resetTimer, resumeTimer, startTimer, t, tickTimer, timerOps, toReplayFrames, validatePredicate, virtualClock };
|