@ghostry/fabricator 0.0.2 → 0.0.3

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 (37) hide show
  1. package/README.md +18 -6
  2. package/dist/esm/Adapter/Core.js +3 -3
  3. package/dist/esm/Enumeration/Enumerate.js +16 -13
  4. package/dist/esm/Error/index.js +8 -8
  5. package/dist/esm/Fabricator/Constructor.js +12 -14
  6. package/dist/esm/Harnessing/Core.js +30 -0
  7. package/dist/esm/Harnessing/Salt.js +12 -0
  8. package/dist/esm/Harnessing/Types.js +1 -0
  9. package/dist/esm/Instance/Core.js +17 -24
  10. package/dist/esm/Primitive/recursive/Fabricator.js +1 -1
  11. package/dist/esm/Random/index.js +24 -79
  12. package/dist/esm/adapting.js +2 -0
  13. package/dist/esm/harnessing.js +1 -0
  14. package/dist/esm/index.js +1 -2
  15. package/dist/esm/internal.js +1 -2
  16. package/dist/types/Adapter/Core.d.ts +1 -1
  17. package/dist/types/Adapter/Types.d.ts +1 -1
  18. package/dist/types/Enumeration/Enumerate.d.ts +17 -15
  19. package/dist/types/Error/index.d.ts +15 -19
  20. package/dist/types/Fabricator/Constructor.d.ts +4 -4
  21. package/dist/types/Harnessing/Core.d.ts +43 -0
  22. package/dist/types/Harnessing/Salt.d.ts +31 -0
  23. package/dist/types/Harnessing/Types.d.ts +79 -0
  24. package/dist/types/Instance/Core.d.ts +14 -31
  25. package/dist/types/Instance/Types.d.ts +35 -41
  26. package/dist/types/Primitive/opaque/Registry.d.ts +1 -1
  27. package/dist/types/Primitive/recursive/Fabricator.d.ts +8 -8
  28. package/dist/types/Random/Types.d.ts +97 -217
  29. package/dist/types/Random/index.d.ts +30 -48
  30. package/dist/types/Types.d.ts +3 -3
  31. package/dist/types/adapting.d.ts +32 -0
  32. package/dist/types/harnessing.d.ts +30 -0
  33. package/dist/types/index.d.ts +40 -75
  34. package/dist/types/internal.d.ts +5 -23
  35. package/package.json +23 -3
  36. package/dist/esm/Random/CallSite.js +0 -70
  37. package/dist/types/Random/CallSite.d.ts +0 -78
@@ -37,25 +37,14 @@ export type Algorithm = (seed: string) => NumberGenerator;
37
37
  *
38
38
  * Slots, in encoded order:
39
39
  *
40
- * - `seed` — the _instance's_ seed, normalized to its parts
41
- * ({@link RandomSource.seed}), not anything derived per leaf.
40
+ * - `salt` — the _instance's_ salt, normalized to its parts
41
+ * ({@link RandomSource.salt}), not anything derived per leaf.
42
42
  * - `clock` — this construction's resolved "now," epoch milliseconds
43
43
  * (`Instance/Types.ts`'s `Config.clock`). Second, not after the per-leaf
44
- * slots: blast radius matches `seed` — both are instance-level and perturb
45
- * every leaf, unlike `file`/`path`/`kind`/`ordinal`, which narrow to one
46
- * leaf. Never `undefined` (unlike `file`/`ordinal`): clock is always a
47
- * concrete instant before any leaf dispatches (`RandomSource`'s
48
- * `Options.clock`).
49
- * - `root` — how `file` and `ordinal` were resolved ({@link RootKind}). Sits
50
- * immediately before `file` because that is what it explains. Distinguishes
51
- * the three situations that all produce `file: undefined` (`{ kind: "none" }`
52
- * attributed, an unattributed seeded construction, a counted recursive
53
- * expansion), so a captured trace can be replayed faithfully via `new
54
- * Fabricator(schema, trace)`.
55
- * - `file` — the file this node's _construction_ (not the node) was attributed
56
- * to, relative to the instance's {@link Attribution} root (absolute only if
57
- * outside that root). `undefined` under `"counted"` / `"unattributed"`, or
58
- * `"attributed"` with `{ kind: "none" }` — {@link RootKind} says which.
44
+ * slots: blast radius matches `salt` — both are instance-level and perturb
45
+ * every leaf, unlike `path`/`kind`/`ordinal`, which narrow to one leaf. Never
46
+ * `undefined`: clock is always a concrete instant before any leaf dispatches
47
+ * (`RandomSource`'s `Options.clock`).
59
48
  * - `path` — structural position within the construction: field name, tuple slot,
60
49
  * choice option, one segment per nesting level (`Constructor.ts`'s `make`).
61
50
  * Distinguishes two leaves of the same kind in one construction. Stable under
@@ -63,50 +52,55 @@ export type Algorithm = (seed: string) => NumberGenerator;
63
52
  * identifies it.
64
53
  * - `kind` — schema kind the node was constructed as. Redundant given a unique
65
54
  * `path`, but changing a field's kind must change its data.
66
- * - `ordinal` — which construction among those sharing this `file` this node
67
- * belongs to. `undefined` for `"unattributed"`, already unique by its forked
68
- * seed.
55
+ * - `ordinal` — which construction on this source this node belongs to: the next
56
+ * value of the source's one counter, or a pinned value
57
+ * (`ConstructorOptions.ordinal`), which is how a replay avoids advancing that
58
+ * counter. `null` for a build that deliberately takes no ordinal — a
59
+ * `combinatorial`/`coverage` rebuild. `null`, not absent: a pin counts when
60
+ * it is defined, so only a defined "no ordinal" survives being replayed.
69
61
  */
70
62
  export type Trace = {
71
- readonly seed: ReadonlyArray<string>;
63
+ readonly salt: ReadonlyArray<string>;
72
64
  readonly clock: number;
73
- readonly root: RootKind;
74
- readonly file: string | undefined;
75
65
  readonly path: ReadonlyArray<string>;
76
66
  readonly kind: string;
77
- readonly ordinal: number | undefined;
67
+ readonly ordinal: number | null;
78
68
  };
79
69
  /**
80
70
  * Caller-supplied overrides for the construction-owned {@link Trace} slots
81
- * {@link RandomSource.toRoot} resolves. `seed` is not among them: it is the
82
- * {@link RandomSource}'s own identity (forked via {@link ConstructorOptions.seed}
83
- * when replaying), not something `toRoot` substitutes. `path`/`kind` are
84
- * per-node and applied in `construct()`, not here.
71
+ * {@link RandomSource.toRoot} resolves. `path`/`kind` are the only slots absent:
72
+ * they are per-node and applied in `construct()`, not here.
85
73
  *
86
- * Definedness, not `in`: `root` is present exactly when a trace is being
87
- * replayed and is never `undefined` on a real {@link Trace}.
74
+ * `salt` is a pin like the rest — it substitutes into that trace slot and does
75
+ * nothing else. It does not fork, so it neither resets nor sidesteps this
76
+ * source's construction counter: a salted build takes the next ordinal exactly
77
+ * as an unsalted one does. A caller who wants an isolated source, with its own
78
+ * counters, forks — that is what `fork`/`wrap` are for. Already normalized to
79
+ * parts here, since {@link Trace} carries the array form.
80
+ *
81
+ * Definedness, not `in`: a defined `ordinal` — a number, or `null` for "no
82
+ * ordinal" — is taken verbatim and does not advance the counter. That is all a
83
+ * replay needs, since every real {@link Trace} carries a defined ordinal.
88
84
  */
89
85
  export type RootPins = {
86
+ salt?: ReadonlyArray<string> | undefined;
90
87
  clock?: number | undefined;
91
- root?: RootKind | undefined;
92
- file?: string | undefined;
93
- ordinal?: number | undefined;
88
+ ordinal?: number | null | undefined;
94
89
  };
95
90
  /**
96
- * A construction's root: every {@link Trace} slot a {@link RootKind} resolution
97
- * fixes, before a leaf supplies its own `path`/`kind`. `RandomSource.toRoot`
98
- * resolves this once per construction; callers spread it into a full
99
- * {@link Trace} per leaf and hand that to `toStreamFromTrace`. One stack walk,
100
- * one construction-ordinal bump — reused across every leaf that construction
101
- * dispatches.
91
+ * A construction's root: every {@link Trace} slot a construction fixes, before a
92
+ * leaf supplies its own `path`/`kind`. `RandomSource.toRoot` resolves this once
93
+ * per construction; callers spread it into a full {@link Trace} per leaf and
94
+ * hand that to `toStreamFromTrace`. One construction-ordinal bump is reused
95
+ * across every leaf that construction dispatches.
102
96
  */
103
97
  export type ConstructionTrace = Omit<Trace, "path" | "kind">;
104
98
  /**
105
99
  * What a producer is told about the fabrication it is running inside. One
106
100
  * object, not a positional list: this is the only channel a producer has, and a
107
101
  * future addition must not change every kind's `.as(...)` arity. Curated, not
108
- * the whole instance `Config` — a producer has no business reading `seed` or
109
- * `attribution`, and `random` already carries this leaf's own derived seed.
102
+ * the whole instance `Config` — a producer has no business reading `salt`, and
103
+ * `random` already carries this leaf's own derived seed.
110
104
  */
111
105
  export type ProduceContext = {
112
106
  /** This leaf's own seeded stream, keyed by its structural path. */
@@ -115,7 +109,7 @@ export type ProduceContext = {
115
109
  * This construction's resolved "now," epoch milliseconds — the active `wrap`
116
110
  * frame's `Config.clock` if one is active, else the instance's
117
111
  * (`Instance/Types.ts`'s `Config.clock`). Defaults to an instant derived from
118
- * the instance's seed, not `Date.now()`, so a producer that reads it replays
112
+ * the instance's salt, not `Date.now()`, so a producer that reads it replays
119
113
  * like one that only reads `random`. A number, not a `Date`: the instant is
120
114
  * fixed once resolved, and a `Date` handed to every producer would be a
121
115
  * shared mutable — the same footgun `T.always([])` sharing one array
@@ -125,238 +119,124 @@ export type ProduceContext = {
125
119
  };
126
120
  /**
127
121
  * A kind's opaque custom producer — `.as(produce)` — given a
128
- * {@link ProduceContext} so its output replays under a seed like every other
122
+ * {@link ProduceContext} so its output replays under a salt like every other
129
123
  * primitive's draws. A zero-argument function (`() => $T`) is still assignable,
130
124
  * so every existing `.as(() => ...)` call compiles.
131
125
  */
132
126
  export type Produce<$T> = (context: ProduceContext) => $T;
133
127
  /**
134
- * How one _construction_ (a single `new Fabricator(...)` call) is rooted,
135
- * before any of its leaves are dispatched — resolved once, not per leaf, at
136
- * `Constructor.ts`'s `construct()`. Every leaf then derives its stream from
137
- * this root plus its own structural path, so inserting or reordering a sibling
138
- * field can never shift another field onto a different stream.
139
- *
140
- * Each variant is a decision about the two {@link Trace} slots a construction
141
- * owns — `file` and `ordinal` — and nothing else:
142
- *
143
- * | variant | `file` | `ordinal` |
144
- * | ---------------- | ----------------------- | ---------------------- |
145
- * | `"attributed"` | resolved from the stack | next ordinal for it |
146
- * | `"counted"` | `undefined` | next file-less ordinal |
147
- * | `"unattributed"` | `undefined` | `undefined` |
148
- *
149
- * `"attributed"` walks the live call stack once (`resolveCallerFile()`) and
150
- * relativizes it under the instance's `Attribution` root — or, under `{ kind:
151
- * "none" }`, resolves no file — then assigns the next ordinal for that file.
152
- * Two constructions in the same file diverge by default; a lone construction
153
- * stays reproducible across however many times its file is imported or re-run.
154
- * `ConstructorOptions.file` without `root` pins that file and draws the next
155
- * ordinal for it (the wrapping- integration case). A replay (`pins.root` given)
156
- * takes `file` and `ordinal` verbatim, including `undefined`.
157
- * `test/fixtures/checkout-a`/`checkout-b` stand in for two checkouts using real
158
- * frames instead.
159
- *
160
- * `"counted"` indexes without attributing. Under `{ kind: "none" }` an
161
- * `"attributed"` scope resolves to precisely this, and the two share the one
162
- * file-less bucket — reachable only if both kinds of scope were opened on a
163
- * single source, which nothing does. `"counted"` is not a variant you choose
164
- * when building — it is recorded on a node's {@link Trace} (and replayed) for
165
- * expansions inside `T.recursive`, whose private fork uses it so each lazy
166
- * expansion gets an ordinal (see `recursive/Fabricator.ts`). An identity that
167
- * isn't a stack frame but should still vary with the instance's seed is
168
- * `ConstructorOptions.seed`'s layered form (`{@link Layered}`, via
169
- * `layer(...)`) — see `ConstructorOptions`.
170
- *
171
- * `"unattributed"` fixes neither slot — used only by a source already isolated
172
- * for one construction (an explicitly seeded `new Fabricator(schema, { seed
173
- * })`, which forks a new `RandomSource` for that one build). A layered seed
174
- * (`{@link Layered}`, via `layer(...)`) still opens this same scope: composing
175
- * onto a base seed is a statement about _what_ the fork's seed is, not how the
176
- * fork itself should be rooted.
177
- *
178
- * A plain string union, not a discriminant object: none of the three variants
179
- * carries data of its own. Caller-supplied overrides go through
180
- * {@link RootPins} on {@link RandomSource.toRoot}, not through this union. A `{
181
- * kind: RootKind }` wrapper would invite a field an object shape can carry and
182
- * a switch can silently ignore.
183
- */
184
- export type RootKind = "attributed" | "counted" | "unattributed";
185
- /**
186
- * A seed as a caller supplies it: one string, or several — several lets a
128
+ * A salt as a caller supplies it: one string, or several — several lets a
187
129
  * caller compose independent parts (user id, session id, scenario label)
188
130
  * without joining them first. Always normalized internally to
189
- * `ReadonlyArray<string>` (`toRandomSource`'s `normalizeSeed`); a single string
131
+ * `ReadonlyArray<string>` (`toRandomSource`'s `normalizeSalt`); a single string
190
132
  * is the one-element case.
191
133
  */
192
- export type Seed = string | ReadonlyArray<string>;
134
+ export type Salt = string | ReadonlyArray<string>;
193
135
  /**
194
- * A {@link Seed} tagged as composing onto whatever base is in effect, rather
195
- * than replacing it — what `layer(seed)` (`Random/index.ts`) produces. Tagged
136
+ * A {@link Salt} tagged as composing onto whatever base is in effect, rather
137
+ * than replacing it — what `layer(salt)` (`Random/index.ts`) produces. Tagged
196
138
  * with `[Layer]` exactly as `replace()` (`Utility/Core.ts`) tags a merge
197
139
  * operand with `[Replace]`, so a caller never names the symbol and no ordinary
198
- * `Seed` — string or array — can be mistaken for one.
140
+ * `Salt` — string or array — can be mistaken for one.
199
141
  */
200
142
  export type Layered = {
201
- readonly [Layer]: Seed;
143
+ readonly [Layer]: Salt;
202
144
  };
203
145
  /**
204
- * How an instance normalizes a construction's resolved file before it becomes
205
- * part of that construction's root set once via `initialize({ attribution
206
- * })`.
207
- *
208
- * `"rooted"` expresses every file relative to `root`, so a checkout at a
209
- * different absolute path on a different machine derives the same seeds. `root`
210
- * accepts an absolute path or a `file://` URL (e.g. `new URL("..",
211
- * import.meta.url).href`, which needs no `node:path`), and is a normalization
212
- * parameter only — it never enters the hashed material, so moving the root
213
- * without moving the files under it changes nothing. A file outside `root` is
214
- * expressed with a leading `..` run rather than left absolute, so it stays
215
- * stable too, as long as both locations move together under the same checkout
216
- * (see `relativize`, `Random/CallSite.ts`).
217
- *
218
- * `"call site"`, the default, is `"rooted"` at the directory of whichever file
219
- * called `initialize()` — resolved once, at that call, from the live stack. Two
220
- * `initialize()` calls in different files that share a seed and happen to
221
- * produce the same file's-worth of relative paths (a symmetric monorepo layout
222
- * — this repo's `pkg/fabricator` and `pkg/fabricator-adapter-typebox-v0` test
223
- * suites) will collide; use `"rooted"` at a shared repository root instead.
224
- *
225
- * `"none"` attributes nothing: every construction in the instance draws its
226
- * root from one shared, file-less counter. Maximally portable — no path can
227
- * influence a seed — at the cost of every construction sharing one counter, so
228
- * adding, removing, or reordering a _construction_ anywhere in the instance
229
- * shifts every later one. Individual fields within one construction are
230
- * unaffected: they're keyed by structural path, not dispatch order.
231
- */
232
- export type Attribution = {
233
- kind: "rooted";
234
- root: string;
235
- } | {
236
- kind: "call site";
237
- } | {
238
- kind: "none";
239
- };
240
- /**
241
- * {@link Attribution} after `"call site"` has been resolved against the live
242
- * stack and `root` normalized — what actually drives construction-root
243
- * resolution. This, not the caller-facing `Attribution`, is what
244
- * `RandomSource.fork` threads through: re-resolving `"call site"` inside a fork
245
- * would read the stack at whatever moment the fork happens to run (an
246
- * explicitly seeded build, an enumeration's rebuild) and root the child
247
- * somewhere unrelated to the instance that spawned it.
248
- */
249
- export type ResolvedAttribution = {
250
- kind: "rooted";
251
- root: string;
252
- } | {
253
- kind: "none";
254
- };
255
- /**
256
- * `clock` is required, unlike `seed`/`algorithm`/`attribution` — by the time a
257
- * `RandomSource` is built, both the wall-clock default and the `"seeded"`
258
- * policy (`Instance/Types.ts`'s `Config.clock`) have already been resolved to a
146
+ * `clock` is required, unlike `salt`/`algorithm` by the time a `RandomSource`
147
+ * is built, both the wall-clock default and the `"derived"` policy
148
+ * (`Instance/Types.ts`'s `Config.clock`) have already been resolved to a
259
149
  * concrete epoch-millisecond instant (`Instance/Core.ts`'s `resolveClock`), so
260
150
  * `toRandomSource` has no default left to supply.
261
151
  */
262
152
  export type Options = {
263
- seed?: Seed | undefined;
153
+ salt?: Salt | undefined;
264
154
  algorithm?: Algorithm | undefined;
265
- attribution?: Attribution | undefined;
266
155
  clock: number;
267
156
  };
268
157
  /**
269
158
  * `new Fabricator(schema, options)`'s own option shape — not `Options`.
270
159
  * {@link Trace} is assignable to this (every slot optional here, required
271
- * there, and `file`/`ordinal` are `T | undefined` on both so `{ ...trace }`
272
- * typechecks under `exactOptionalPropertyTypes`), which is what makes `new
273
- * Fabricator(schema, trace)` a legal replay.
274
- *
275
- * A bare `seed` is a statement about _attribution_: it forks an isolated
276
- * `RandomSource` from exactly that value, sidestepping both the default
277
- * call-site logic and the instance's own seed. The same seed reproduces the
278
- * same result regardless of which file it's constructed from, which instance
279
- * built it, or how that instance was itself seeded — useful for a fixture that
280
- * should never change no matter how the surrounding run is reseeded.
281
- *
282
- * `seed: layer(...)` (via `layer()`, `Random/index.ts`) is the same fork, but
283
- * composed onto the instance's own seed (`[...instance.seed, ...seed]`) instead
284
- * of replacing it the construction still varies when the instance is
285
- * reseeded, which the bare form does not (see {@link RootKind}'s `"counted"`
286
- * paragraph). This is `fork`/`wrap`'s own `Overlay.seed` mechanism one level
287
- * down: the instance itself is the base, so no separate instance is needed just
288
- * to pin an identity that should still track the instance's seed.
289
- *
290
- * `clock` / `root` / `file` / `ordinal` pin the construction-owned
291
- * {@link Trace} slots {@link RandomSource.toRoot} would otherwise resolve.
292
- * Definedness, not `in`: `root` given means this is a replay (`file` and
293
- * `ordinal` taken verbatim, `undefined` included, no stack walk and no counter
294
- * bump). `root` absent but `file` given pins that file and draws `ordinal` from
295
- * _that file's_ counter — the wrapping-integration case. Neither given resolves
296
- * as an ordinary construction. A seeded construction is not, by default, asking
297
- * for a different "now"; a replayed trace whose `clock` is present explicitly
298
- * is.
160
+ * there), which is what makes `new Fabricator(schema, trace)` a legal replay.
161
+ *
162
+ * Every field here pins one {@link Trace} slot, `salt` included it is not a
163
+ * special case, and it does not fork. A bare `salt` replaces the instance's own
164
+ * for this build; `salt: layer(...)` (via `layer()`, `Random/index.ts`)
165
+ * composes onto whichever base is in effect (`[...instance.salt, ...salt]`), so
166
+ * the construction still varies when the instance is re-salted, which the bare
167
+ * form does not. That is `fork`/`wrap`'s own `Overlay.salt` parity, one level
168
+ * down.
169
+ *
170
+ * Pinning a salt says nothing about anything else. The build takes the next
171
+ * ordinal on its source and inherits the instance's clock, exactly as an
172
+ * unsalted build does so it shifts, and is shifted by, neighbouring
173
+ * constructions like any other. Two same-salt builds therefore diverge.
174
+ *
175
+ * `clock` / `ordinal` pin the construction-owned {@link Trace} slots
176
+ * {@link RandomSource.toRoot} would otherwise resolve. Definedness, not `in`: a
177
+ * given `ordinal` a number, or `null` for "no ordinal" — is taken verbatim
178
+ * with no counter bump, which is all a replay needs; without it, the
179
+ * construction takes the source counter's next value. A salted construction is
180
+ * not, by default, asking for a different "now"; a replayed trace whose `clock`
181
+ * is present explicitly is.
299
182
  *
300
183
  * `path` is the base structural path `make` extends for descendants, so
301
184
  * replaying a nested node's trace reproduces its subtree at the positions it
302
185
  * originally occupied. `kind`, when a string, must match `schema`'s own
303
186
  * `[Kind]` or `construct()` throws `TraceKindMismatchError`.
304
187
  *
305
- * No per-build algorithm override: it complicates root resolution for a
306
- * capability nobody asked for, unlike `seed`, which is a real statement about
307
- * attribution. Only `initialize({ seed, algorithm })` — instance-wide, via
308
- * `Options` — sets the algorithm.
188
+ * No per-build algorithm override: unlike `salt`, the algorithm is not a trace
189
+ * slot. Only `initialize({ salt, algorithm })` instance-wide, via `Options`
190
+ * sets it.
309
191
  */
310
192
  export type ConstructorOptions = {
311
- seed?: Seed | Layered | undefined;
193
+ salt?: Salt | Layered | undefined;
312
194
  clock?: number | undefined;
313
- root?: RootKind | undefined;
314
- file?: string | undefined;
315
195
  path?: ReadonlyArray<string> | undefined;
316
196
  kind?: string | undefined;
317
- ordinal?: number | undefined;
197
+ ordinal?: number | null | undefined;
318
198
  };
319
199
  /**
320
200
  * An isolated source of randomness: everything a single `initialize()` instance
321
201
  * needs to derive private, reproducible seeds for the fabricators it builds.
322
- * Each instance owns its own seed, builder, and per-construction counters —
202
+ * Each instance owns its own salt, builder, and per-construction counters —
323
203
  * nothing here is shared module-level state, so independently initialized
324
204
  * instances (e.g. parallel tests) can never perturb each other.
325
205
  */
326
206
  export type RandomSource = {
327
207
  /**
328
- * Resolve one construction's root see {@link RootKind}. Called once per `new
329
- * Fabricator(...)` (or per lazy expansion of a `T.recursive` schema, each of
330
- * which resolves its own root on a private forked source), never per leaf:
331
- * the returned {@link ConstructionTrace} is what every leaf beneath it
208
+ * Resolve one construction's root: this source's own `salt`/`clock` and the
209
+ * next construction ordinal, each overridable by {@link RootPins}. Called once
210
+ * per `new Fabricator(...)` (or per lazy expansion of a `T.recursive` schema,
211
+ * each of which resolves its own root on a private forked source), never per
212
+ * leaf: the returned {@link ConstructionTrace} is what every leaf beneath it
332
213
  * completes into a full {@link Trace} and hands to `toStreamFromTrace`. One
333
- * stack walk and construction-ordinal bump serves the whole construction.
214
+ * construction-ordinal bump serves the whole construction.
334
215
  */
335
- toRoot(kind: RootKind, pins?: RootPins): ConstructionTrace;
216
+ toRoot(pins?: RootPins): ConstructionTrace;
336
217
  /**
337
218
  * The algorithm this source (and every fork of it) hashes with. Stream
338
219
  * derivation is _not_ a member: it depends on no per-source state, so it is
339
220
  * the free function `toStreamFromTrace(algorithm, trace)`. `toRoot` is the
340
- * only stateful member (per-file ordinal counters).
221
+ * only stateful member (the construction counter).
341
222
  */
342
223
  readonly algorithm: Algorithm;
343
224
  /**
344
- * The seed this instance currently derives every stream from, normalized to
225
+ * The salt this instance currently derives every stream from, normalized to
345
226
  * its parts — a single string becomes a one-element array. Always an array so
346
- * a caller reading it back (e.g. `initialize({ seed: instance.seed })`)
347
- * round-trips through the same `Seed`-accepting surface it came from.
227
+ * a caller reading it back (e.g. `initialize({ salt: instance.salt })`)
228
+ * round-trips through the same `Salt`-accepting surface it came from.
348
229
  */
349
- readonly seed: ReadonlyArray<string>;
230
+ readonly salt: ReadonlyArray<string>;
350
231
  /**
351
- * Create a new, fully isolated `RandomSource` — its own private per-file
352
- * construction counters, sharing only the algorithm — seeded independently
353
- * from this one. For a build whose randomness must stay entirely
354
- * self-contained (an explicitly seeded `new Fabricator(schema, { seed })`, or
355
- * `T.recursive`, whose expansion count is data-dependent, unlike every other
356
- * kind's fixed, schema-determined dispatch count): forking means its internal
357
- * draws can never perturb, or be perturbed by, anything else built from the
358
- * same `initialize()` instance, no matter how many times or how deeply it
359
- * expands.
232
+ * Create a new, fully isolated `RandomSource` — its own private construction
233
+ * counters, sharing only the algorithm — salted independently from this one.
234
+ * For a build whose randomness must stay entirely self-contained
235
+ * (`T.recursive`, whose expansion count is data-dependent, unlike every other
236
+ * kind's fixed, schema-determined dispatch count; and `coverage`'s
237
+ * permutation stream): forking means its internal draws can never perturb, or
238
+ * be perturbed by, anything else built from the same `initialize()` instance,
239
+ * no matter how many times or how deeply it expands.
360
240
  */
361
- fork(seed: Seed): RandomSource;
241
+ fork(salt: Salt): RandomSource;
362
242
  };
@@ -1,79 +1,61 @@
1
- import type { Algorithm, Attribution, Layered, NumberGenerator, Options, RandomSource, ResolvedAttribution, Seed, Stream, Trace } from "./Types";
1
+ import type { Algorithm, Layered, NumberGenerator, Options, RandomSource, Salt, Stream, Trace } from "./Types";
2
2
  /**
3
- * Build the library's built-in PRNG from a seed. The same seed always yields
4
- * the same stream. Seeds may be numbers or strings; both are stringified and
5
- * hashed to fully seed sfc32's state.
3
+ * Build the library's built-in PRNG from a seed the genuine article, not a
4
+ * caller-supplied {@link Salt}: by the time anything reaches here the salt is
5
+ * one slot of an `encode`d {@link Trace}, and this string is that whole
6
+ * encoding. The same seed always yields the same stream, and `cyrb128` hashes
7
+ * it to fully seed sfc32's 128 bits of state.
6
8
  */
7
9
  export declare function defaultAlgorithm(seed: string): NumberGenerator;
8
10
  /**
9
- * Mint a fresh seed value — a uint32 label. Not used as `initialize()`'s
10
- * default (an omitted seed is empty; wall-clock `clock` is the default
11
+ * Mint a fresh salt value — a uint32 label. Not used as `initialize()`'s
12
+ * default (an omitted salt is empty; wall-clock `clock` is the default
11
13
  * entropy); kept for callers that want a generated mixer, and for tests that
12
14
  * need one.
13
15
  */
14
- export declare function randomSeed(): string;
16
+ export declare function randomSalt(): string;
15
17
  /**
16
- * Derive the explicit `"seeded"` clock — an epoch-millisecond instant, drawn
18
+ * Derive the explicit `"derived"` clock — an epoch-millisecond instant, drawn
17
19
  * across the full representable `Date` span — from an instance's own
18
- * `algorithm`/`seed`. The unconfigured default is wall-clock time
19
- * (`Instance/Core.ts`'s `overlay`); this is the opt-in that makes `seed` alone
20
+ * `algorithm`/`salt`. The unconfigured default is wall-clock time
21
+ * (`Instance/Core.ts`'s `overlay`); this is the opt-in that makes `salt` alone
20
22
  * the reproducibility unit, at the cost of an implausible "now". A throwaway
21
- * two-element encoding (`JSON.stringify([seed, "clock"])`), _not_ routed
23
+ * two-element encoding (`JSON.stringify([salt, "clock"])`), _not_ routed
22
24
  * through `RandomSource`/`Trace`: after the clock is folded into stream
23
25
  * derivation, a forked source's own stream derivation requires a clock, so
24
26
  * deriving the clock from a fork would be circular. Kept below that layer,
25
27
  * which also keeps this collision-free with every leaf's `encode(trace)` — that
26
- * encoding is always seven elements, this is always two, and the two can never
28
+ * encoding is always five elements, this is always two, and the two can never
27
29
  * produce the same JSON array. `Math.trunc`ed because a `Date`'s precision is
28
30
  * whole milliseconds.
29
31
  */
30
- export declare function deriveClock(algorithm: Algorithm, seed: ReadonlyArray<string>): number;
32
+ export declare function deriveClock(algorithm: Algorithm, salt: ReadonlyArray<string>): number;
31
33
  /**
32
34
  * Collapse a {@link Trace} into one string to hash — and, since
33
35
  * `toStreamFromTrace` hashes exactly this output, the _definition_ of that
34
36
  * leaf's stream seed. Concatenating fields with a delimiter would collide when
35
- * a path/kind/seed part contains that delimiter (`file="a b", kind="c"` vs
36
- * `file="a", kind="b c"`) silently: two leaves that should draw independently
37
- * would share one stream. `JSON.stringify` as an array makes every field's and
38
- * slot's boundaries unambiguous regardless of content or nesting depth.
39
- * `undefined` (`file`, `ordinal`) is the right "this slot doesn't apply" rather
40
- * than a sentinel string: `JSON.stringify` writes it as `null` in an array
41
- * position, one unambiguous value, with no chance of colliding with a real file
42
- * path or index.
37
+ * a path/kind/salt part contains that delimiter silently: two leaves that
38
+ * should draw independently would share one stream. `JSON.stringify` as an
39
+ * array makes every field's and slot's boundaries unambiguous regardless of
40
+ * content or nesting depth.
43
41
  */
44
42
  export declare function encode(trace: Trace): string;
45
43
  /**
46
- * Normalize a caller-supplied {@link Seed} to its parts: a single string becomes
47
- * a one-element array, an array passes through unchanged, and a missing seed is
48
- * empty — unless {@link envSeed} supplies one. No generated fallback: an omitted
49
- * seed is not a second source of entropy beside the instance clock.
44
+ * Normalize a caller-supplied {@link Salt} to its parts: a single string becomes
45
+ * a one-element array, an array passes through unchanged, and a missing salt is
46
+ * empty — unless {@link envSalt} supplies one. No generated fallback: an omitted
47
+ * salt is not a second source of entropy beside the instance clock.
50
48
  */
51
- export declare function normalizeSeed(seed: Seed | undefined): ReadonlyArray<string>;
49
+ export declare function normalizeSalt(salt: Salt | undefined): ReadonlyArray<string>;
52
50
  /**
53
- * Tag a seed as composing onto whatever base is in effect, rather than
54
- * replacing it — the reading a bare `seed` has everywhere else in this library.
51
+ * Tag a salt as composing onto whatever base is in effect, rather than
52
+ * replacing it — the reading a bare `salt` has everywhere else in this library.
55
53
  * Mirrors `replace()`'s `[Replace]` tagging: the `[Layer]` directive is read
56
- * (and, at every level that accepts one, consumed) by whoever resolves the seed
54
+ * (and, at every level that accepts one, consumed) by whoever resolves the salt
57
55
  * against its base, so a caller never names the symbol.
58
56
  */
59
- export declare function layer(seed: Seed): Layered;
57
+ export declare function layer(salt: Salt): Layered;
60
58
  export declare function isLayered(value: unknown): value is Layered;
61
- /**
62
- * Collapse a caller-facing {@link Attribution} to the
63
- * {@link ResolvedAttribution} the stream machinery uses. `"call site"` must
64
- * resolve _here_, and only here: `resolveCallerFile()` reads the live stack,
65
- * and `toRandomSource` runs synchronously inside `initialize()`, so this is the
66
- * one moment the first external frame genuinely is the file that called
67
- * `initialize()`. Resolving lazily — on first construction, or again inside
68
- * `fork` — would capture whichever file happened to call `new Fabricator(...)`,
69
- * or whichever internal mechanism happened to trigger a fork.
70
- *
71
- * A directory, not the file itself, becomes the root: rooting at the file would
72
- * relativize that one file to `""` while every sibling still carried a full
73
- * relative path from a directory one level up, an arbitrary asymmetry with no
74
- * reason to prefer it.
75
- */
76
- export declare function resolveAttribution(attribution: Attribution | undefined): ResolvedAttribution;
77
59
  export declare function toStream(algorithm: Algorithm, seed: string): Stream;
78
60
  /**
79
61
  * A leaf's stream: `toStream(algorithm, encode(trace))`. This is the
@@ -86,13 +68,13 @@ export declare function toStream(algorithm: Algorithm, seed: string): Stream;
86
68
  * {@link deriveClock} cannot route through this: a {@link Trace} carries
87
69
  * `clock`, and `deriveClock` is what produces it. That circularity is why
88
70
  * `deriveClock` stays below the `RandomSource`/`Trace` layer, with a
89
- * two-element encoding that can never collide with `encode`'s seven.
71
+ * two-element encoding that can never collide with `encode`'s five.
90
72
  */
91
73
  export declare function toStreamFromTrace(algorithm: Algorithm, trace: Trace): Stream;
92
74
  /**
93
75
  * Create a fresh, self-contained {@link RandomSource} — the randomness state a
94
76
  * single `initialize()` instance owns for its lifetime. `options.clock` is
95
- * baked in here, once, as a plain number — the `"seeded"` policy is already
77
+ * baked in here, once, as a plain number — the `"derived"` policy is already
96
78
  * resolved by the caller (`Instance/Core.ts`'s `resolveClock`) before a source
97
79
  * is ever built, so every root this source resolves carries the identical
98
80
  * instant, and `fork` threads it forward unchanged.
@@ -6,11 +6,11 @@ export declare const Produces: unique symbol;
6
6
  export declare const Replace: unique symbol;
7
7
  export declare const Fixed: unique symbol;
8
8
  /**
9
- * Tags a `Seed` as composing onto whatever base is in effect, rather than
10
- * replacing it — the reading a bare `seed` has everywhere else in this library.
9
+ * Tags a `Salt` as composing onto whatever base is in effect, rather than
10
+ * replacing it — the reading a bare `salt` has everywhere else in this library.
11
11
  * `layer()` (`Random/index.ts`) is the only producer; a caller never names this
12
12
  * symbol, mirroring `[Replace]`. Unlike every other symbol in this file, it
13
- * tags a config value (a `Seed`), not a Schema or Fabricator — see
13
+ * tags a config value (a `Salt`), not a Schema or Fabricator — see
14
14
  * `Random/Types.ts`'s `Layered`.
15
15
  */
16
16
  export declare const Layer: unique symbol;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The `@ghostry/fabricator/adapting` package export — what implementing a
3
+ * schema adapter (e.g. `@ghostry/fabricator-adapter-typebox-v0`) is built from.
4
+ * Named for the activity, not the noun (`Adapter` is one export among several
5
+ * here) — the same pattern `@ghostry/fabricator/harnessing` follows for
6
+ * supplying a test-framework integration.
7
+ *
8
+ * Deliberately separate from the `.` export: `.` is for using fabricator,
9
+ * `./internal` is the structural-walking tools an adapter needs (`Kind`,
10
+ * `Meta`, `Primitive`, `Buildable`), and this is the contract an adapter
11
+ * declares and drives. `Adapting` — the parameter type of every kind's
12
+ * `.adapt(adapter, produce)` producer — stays on `.` instead, despite the name
13
+ * overlap with this module: calling `.adapt()` is an ordinary caller's
14
+ * business, not an adapter author's, the same reason `Stream`/`ProduceContext`
15
+ * live there for `.as(produce)`.
16
+ *
17
+ * This package names no external schema library and depends on none: every
18
+ * mapping, and every dependency it needs, belongs to the adapter.
19
+ *
20
+ * @module
21
+ */
22
+ export { walk } from "./Adapter/Core";
23
+ /**
24
+ * `Adapter`/`Recurse` are what an adapter declares; `AdaptationsOf` is how it
25
+ * reads what a Schema declared at the type level, keyed by its own `key`.
26
+ */
27
+ export type { Adaptations, AdaptationsOf, Adapter, Recurse, } from "./Adapter/Types";
28
+ /**
29
+ * What `[Adaptation]` holds at runtime — a per-adapter map of overrides, read
30
+ * only by an adapter.
31
+ */
32
+ export { Adaptation } from "./Types";
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The `@ghostry/fabricator/harnessing` package export — what supplying a
3
+ * `@ghostry/harness` integration is built from. Named for the activity, the
4
+ * same pattern `@ghostry/fabricator/adapting` follows.
5
+ *
6
+ * Deliberately separate from the `.` export: `.` is for using fabricator,
7
+ * `./adapting` is implementing a schema adapter, `./internal` is the
8
+ * structural-walking tools an adapter needs, and this is the contract a
9
+ * test-framework wrapping library drives. Fabricator declares no dependency and
10
+ * no peer on `@ghostry/harness`; the types here describe the part of that
11
+ * package's contract this integration uses, satisfied structurally, so neither
12
+ * depends on the other.
13
+ *
14
+ * @module
15
+ */
16
+ /**
17
+ * Decorate an existing `Instance` as a `@ghostry/harness` integration — `{
18
+ * name, provides, around }`. Takes an instance rather than minting one: the
19
+ * caller owns `initialize(...)` (and in particular the suite-wide `clock`), and
20
+ * this only wraps each test body in that instance's per-identity `wrap`.
21
+ */
22
+ export { integration } from "./Harnessing/Core";
23
+ /**
24
+ * `Identity` is what identifies one registered test or suite; `Integration` is
25
+ * the `{ name, provides, around }` shape `integration(instance)` returns —
26
+ * `provides` is a `Provides<$Context>`, one `Provider` per context key;
27
+ * `FabricatorTestContext` is the `{ fabricator }` slice of the test context
28
+ * this integration contributes.
29
+ */
30
+ export type { FabricatorTestContext, Identity, Integration, Provider, Provides, } from "./Harnessing/Types";