@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
@@ -45,25 +45,6 @@ export declare namespace FabricatorError {
45
45
  */
46
46
  limit: unknown);
47
47
  }
48
- /**
49
- * `initialize({ attribution: { kind: "rooted", root } })` when `root` is not
50
- * an absolute path or a `file://` URL. A relative root can never prefix a
51
- * resolved caller file, so `relativize` would leave every file unchanged —
52
- * the option would look configured while silently doing nothing. Thrown
53
- * eagerly at `initialize()`, not deferred to wherever that would first become
54
- * observable.
55
- */
56
- class InvalidAttributionRootError extends FabricatorError {
57
- /**
58
- * The rejected root, as given.
59
- */
60
- readonly root: string;
61
- constructor(
62
- /**
63
- * The rejected root, as given.
64
- */
65
- root: string);
66
- }
67
48
  /**
68
49
  * A `self` placeholder resolved with no `T.recursive` expanding around it —
69
50
  * only reachable by holding a `self` reference outside the `T.recursive(...)`
@@ -556,4 +537,19 @@ export declare namespace FabricatorError {
556
537
  class SynchronousStackError extends FabricatorError {
557
538
  constructor();
558
539
  }
540
+ /**
541
+ * The `fabricator` provider of `integration(instance)`
542
+ * (`@ghostry/fabricator/harnessing`) was called outside that integration's
543
+ * own `around`.
544
+ *
545
+ * The provider hands back the per-test scope `around` just entered, so there
546
+ * is no scope for it to return anywhere else. `@ghostry/harness` never does
547
+ * this — it runs each provider inside its integration's `around` — so this
548
+ * means a composer that breaks the contract. Raised rather than returning the
549
+ * base instance, which would draw plausible data from the wrong configuration
550
+ * with no signal.
551
+ */
552
+ class HarnessingProviderError extends FabricatorError {
553
+ constructor();
554
+ }
559
555
  }
@@ -11,9 +11,9 @@ import { type AsFabricator } from "./Types";
11
11
  * `function` that explicitly returns an object, so `new construct(schema)`
12
12
  * behaves identically to `construct(schema)` — a `new` call's returned object
13
13
  * always replaces the freshly-created `this`. The construct signature lets
14
- * callers spell `new T.Fabricator(schema)` — or `new Fabricator(schema, { seed
15
- * })` to pin this one build to an explicit seed, independent of the file it's
16
- * constructed in (see `construct()` for what `options.seed` does).
14
+ * callers spell `new T.Fabricator(schema)` — or `new Fabricator(schema, { salt
15
+ * })` to pin this one build's salt slot, leaving every other slot to resolve as
16
+ * usual (see `construct()` for what `options.salt` does).
17
17
  */
18
18
  export type Constructor = {
19
19
  new <const $Schema extends Buildable>(schema: $Schema, options?: ConstructorOptions): AsFabricator<$Schema>;
@@ -23,7 +23,7 @@ export type Constructor = {
23
23
  * internal `convert(schema: any)` — and the precisely-typed `construct()`
24
24
  * boundary around it, both closed over a single instance's `source` so every
25
25
  * fabricator this `construct()` produces draws from that instance's own
26
- * seed/streams and never another instance's.
26
+ * salt/streams and never another instance's.
27
27
  *
28
28
  * `stack` is the instance's own lineage-wide ambient stack
29
29
  * (`Instance/Core.ts`'s `toStack()`) — passed straight through to
@@ -0,0 +1,43 @@
1
+ import type { Instance } from "../Instance/Types";
2
+ import type { PlainObject } from "../Utility/Types";
3
+ import type { FabricatorTestContext, Integration } from "./Types";
4
+ /**
5
+ * Decorate an existing `Instance` as a `@ghostry/harness` integration.
6
+ * `around(identity, body)` is `instance.wrap({ salt: layer(saltFor(identity))
7
+ * })` — one line of real work. Construction ordinals therefore restart per test
8
+ * (each `wrap` re-instantiates), which is what makes `.only`, filters, shards,
9
+ * and `.concurrent` unable to shift a neighbor's data. That per-test
10
+ * partitioning is also why the salt needs no file in it; see `saltFor`
11
+ * (`Harnessing/Salt.ts`).
12
+ *
13
+ * `around`, not `setup`: the ambient frame has to enclose the body, and only
14
+ * `around` does. Its `finally` running at the call boundary rather than at test
15
+ * settlement costs nothing here — there is no teardown, and the
16
+ * `AsyncLocalStorage` carrier keeps the frame alive across the body's `await`s
17
+ * regardless of when `wrap` returns. On the synchronous carrier an async body
18
+ * still raises `SynchronousStackError` from `wrap`. Declaring no `setup` also
19
+ * keeps `@ghostry/harness` on its uninstrumented path, where a synchronous
20
+ * assertion failure is reported at the user's own line.
21
+ *
22
+ * `provides.fabricator` hands back the scope `wrap` gave its block, not the
23
+ * base instance, so `context.fabricator.salt` is the per-test salt and
24
+ * `.fork()` forks from the test's configuration. The two calls meet through
25
+ * `scope`: set just before `body()`, read by the provider, restored in a
26
+ * `finally`. That is safe under `.concurrent` because `@ghostry/harness` runs a
27
+ * provider synchronously inside its own integration's `around` — no other test
28
+ * can enter between the write and the read, and the context object already
29
+ * holds the scope by the body's first `await`. Restoring rather than clearing
30
+ * keeps a nested `around` from dropping its parent's scope. A provider reached
31
+ * with no scope is a composer breaking that contract, and raises
32
+ * `HarnessingProviderError` rather than quietly providing the base instance.
33
+ *
34
+ * Nothing here reads `instance.context`. The integration is a pure function of
35
+ * the `Identity` it is handed and the instance it decorates, and never sets
36
+ * `clock`. A pinned `Date` (the recommended setup) and the wall-clock default
37
+ * are already concrete numbers by the time `overlay()` sees them, so they
38
+ * inherit through every `wrap` unchanged: salt varies per test, "now" does not.
39
+ * `clock: "derived"` is left alone on purpose — that policy's documented
40
+ * meaning is that the salt _is_ the reproducibility unit, so per-test clocks
41
+ * are the request honored, not a bug to override.
42
+ */
43
+ export declare function integration<$Registry extends PlainObject>(instance: Instance<$Registry>): Integration<FabricatorTestContext<$Registry>>;
@@ -0,0 +1,31 @@
1
+ import type { Identity } from "./Types";
2
+ /**
3
+ * The salt `integration` layers onto the instance for one `Identity`.
4
+ *
5
+ * [ <kind>, ...<describe names>, <name>, <row?> ]
6
+ *
7
+ * **No file, deliberately.** Every test body runs inside its own
8
+ * `instance.wrap`, which builds a fresh `RandomSource` with a fresh
9
+ * construction counter, so constructions are already partitioned per test.
10
+ * Identity comes from a path, never from an execution counter or a location
11
+ * that moves when a file does.
12
+ *
13
+ * The accepted cost: two tests with the same `kind`, describe path, and name in
14
+ * _different files_ share a salt and therefore draw the same data. Each is
15
+ * still deterministic. That is the same trade already made in dropping
16
+ * duplicate-path detection, and the fix is the ordinary one — give them
17
+ * distinguishable names.
18
+ *
19
+ * `kind` leads. Without it, an empty-named test collides with its enclosing
20
+ * suite scope: `path` never carries a leaf's own name, only its describes, and
21
+ * `name` is `""` for both a `"suite"` identity (by design — see `Identity`) and
22
+ * any test a user happens to name `""`, so at the same `path` the two arrays
23
+ * would otherwise be identical. `kind` does not disambiguate two suite
24
+ * identities that share a `path` (a `beforeAll` and an `afterAll` in one
25
+ * `describe`, say) — that collision is intentional, a suite's setup and
26
+ * teardown sharing one deterministic scope, and a caller who wants otherwise
27
+ * already has `instance.wrap(...)` inside the hook body.
28
+ *
29
+ * The row is appended only for `.each`.
30
+ */
31
+ export declare function saltFor(identity: Identity): ReadonlyArray<string>;
@@ -0,0 +1,79 @@
1
+ import type { Instance } from "../Instance/Types";
2
+ import type { PlainObject } from "../Utility/Types";
3
+ /**
4
+ * What identifies one registered test or suite — the material a salt is derived
5
+ * from. Named to match how this codebase already talks about the concept:
6
+ * fabricator's own reproducibility guide reaches for `layer(...)` for "a tenant
7
+ * id, a test's own name" — this is that identity, structured.
8
+ *
9
+ * Declared here rather than imported from `@ghostry/harness`, so neither
10
+ * package depends on the other — the same arrangement `Adapter`/`walk` already
11
+ * uses for schema adapters. Satisfied structurally.
12
+ *
13
+ * **Carries no file, deliberately.** Nothing here identifies where the test was
14
+ * registered, which is what lets `@ghostry/harness` skip stack walking entirely
15
+ * — see `saltFor` (`Harnessing/Salt.ts`) for why the file turned out to be
16
+ * redundant against per-test `wrap` partitioning. The consequence for the
17
+ * contract: an integration that genuinely needs the registering file cannot get
18
+ * it from here, and adding it back means solving the frame-skip problem for
19
+ * every wrapper between the user's `it(...)` and the integration. Worth
20
+ * revisiting only against a real requirement, not speculatively.
21
+ */
22
+ export type Identity = {
23
+ /**
24
+ * Disambiguates an empty-named test from its enclosing suite scope — `name`
25
+ * is `""` for both, and `path` never carries a leaf's own name. Two suite
26
+ * identities that share a `path` (`beforeAll` and `afterAll` in one
27
+ * `describe`) are not disambiguated by this: that collision is intentional
28
+ * (see `saltFor`, `Harnessing/Salt.ts`).
29
+ */
30
+ readonly kind: "test" | "suite";
31
+ /** Enclosing describe names, outer → inner. */
32
+ readonly path: ReadonlyArray<string>;
33
+ /** The test name; empty for a suite-scoped callback. */
34
+ readonly name: string;
35
+ /** `.each` row index (0-based), `undefined` when the test is not from `.each`. */
36
+ readonly row: number | undefined;
37
+ };
38
+ /**
39
+ * One context key's value, as a function of the test's `Identity` rather than a
40
+ * fixed value.
41
+ */
42
+ export type Provider<$Value> = (identity: Identity) => $Value;
43
+ /**
44
+ * The keys an integration contributes, and how each is produced. Homomorphic
45
+ * over `$Context`, so the context an integration contributes is read back out
46
+ * of this object's shape with no separate key declaration to keep in sync.
47
+ */
48
+ export type Provides<$Context extends object> = {
49
+ readonly [$Key in keyof $Context]: Provider<$Context[$Key]>;
50
+ };
51
+ /**
52
+ * What `integration(instance)` is, as `@ghostry/harness`'s `initialize` sees
53
+ * it. The subset of that package's contract this integration actually uses, not
54
+ * a copy of all of it: `@ghostry/harness` also accepts an optional `setup`,
55
+ * which fabricator has no teardown to put in, and an object lacking an optional
56
+ * member still satisfies the contract structurally. `around` is required here,
57
+ * though optional there, because this integration always declares it.
58
+ *
59
+ * `provides` is the _only_ source of context keys; `initialize` rejects a
60
+ * collision across integrations by reading `Object.keys(provides)`. Each
61
+ * provider runs inside its integration's `around`. `around` is generic in its
62
+ * return and must return the body's value unchanged: that is what makes async
63
+ * work and what lets frames nest.
64
+ */
65
+ export type Integration<$Context extends object> = {
66
+ readonly name: string;
67
+ readonly provides: Provides<$Context>;
68
+ around<$Return>(identity: Identity, body: () => $Return): $Return;
69
+ };
70
+ /**
71
+ * The slice of the test context `integration(instance)` contributes — one key,
72
+ * `fabricator`, holding the per-test scoped `Instance`. The same instance is
73
+ * also ambient for the body's duration (`instance.wrap`), so a body that
74
+ * ignores this and uses the caller's own `instance` still sees the per-test
75
+ * salt.
76
+ */
77
+ export type FabricatorTestContext<$Registry extends PlainObject = PlainObject> = {
78
+ readonly fabricator: Instance<$Registry>;
79
+ };
@@ -11,36 +11,19 @@ export declare const DEFAULT_COMBINATORIAL_LIMIT = 1024;
11
11
  /**
12
12
  * The single place a `Config` inherits from a base — `initialize` lays its own
13
13
  * config over an empty `{}` base (nothing to inherit, so every field falls
14
- * through to a hardcoded default: an empty seed, wall-clock `clock`, the
15
- * built-in algorithm, `resolveAttribution(undefined)`'s `"call site"`
16
- * resolution, the default registry, the default combinatorial limit), and
17
- * `fork` lays its overlay over the instance it was called on (a full,
14
+ * through to a hardcoded default: an empty salt, wall-clock `clock`, the
15
+ * built-in algorithm, the default registry, the default combinatorial limit),
16
+ * and `fork` lays its overlay over the instance it was called on (a full,
18
17
  * already-resolved `Config`, so every field has a real value to fall back to).
19
18
  * `base` is typed `Partial<Config<PlainObject>>` rather than `Config`
20
19
  * specifically so both calls go through the same function.
21
20
  *
22
- * `seed` composes onto the base rather than replacing it only when tagged with
23
- * `layer(...)` (`{@link isLayered}`) — a bare `seed` (the ordinary meaning
21
+ * `salt` composes onto the base rather than replacing it only when tagged with
22
+ * `layer(...)` (`{@link isLayered}`) — a bare `salt` (the ordinary meaning
24
23
  * everywhere else in this library) replaces the base's outright, and an omitted
25
- * `seed` inherits the base's unchanged (or, at the root, an empty mixer via
26
- * `normalizeSeed(undefined)`, unless an env var supplies one). Wall-clock
27
- * `clock` is the default entropy; `seed` is an optional mixer.
28
- *
29
- * `attribution` resolves through `resolveAttribution` at most once per call,
30
- * and only when it's actually needed:
31
- *
32
- * - an explicit `over.attribution` always wins (resolved fresh, so `fork({
33
- * attribution: { kind: "call site" } })` roots at _that_ call);
34
- * - otherwise an already-resolved `base.attribution` is reused as-is — never
35
- * re-resolved, which keeps a fork from silently re-rooting `"call site"` at
36
- * wherever `fork()` itself happens to be called (`resolveCallerFile()` skips
37
- * this library's own frames, so calling it from here still lands on the
38
- * user's call site either way);
39
- * - only when neither is available (the root case, `base.attribution` absent)
40
- * does this fall back to resolving the `"call site"` default. That also keeps
41
- * `initialize({ attribution: { kind: "none" } })` — or any other explicit
42
- * override — from paying for a stack walk whose result would be immediately
43
- * discarded.
24
+ * `salt` inherits the base's unchanged (or, at the root, an empty mixer via
25
+ * `normalizeSalt(undefined)`, unless an env var supplies one). Wall-clock
26
+ * `clock` is the default entropy; `salt` is an optional mixer.
44
27
  *
45
28
  * `algorithm`/`types`: wholesale replacement when given, matching how
46
29
  * `initialize({ types })` already behaves — no deep merge;
@@ -49,13 +32,13 @@ export declare const DEFAULT_COMBINATORIAL_LIMIT = 1024;
49
32
  * inherited, or defaulted), so a bad limit fails at `fork()`/`initialize()`
50
33
  * time rather than at first use. `clock` follows the given → inherited →
51
34
  * default shape `algorithm` does, but stays _unresolved_ only for the explicit
52
- * `"seeded"` sentinel: an explicit `Date` and the unconfigured wall-clock
35
+ * `"derived"` sentinel: an explicit `Date` and the unconfigured wall-clock
53
36
  * default are stored as epoch milliseconds (a stated instant, inherited as-is
54
- * from then on), while `"seeded"` is left as the sentinel rather than collapsed
55
- * to a number, so `resolveClock` can re-derive it from whichever `seed` is
56
- * actually in effect at read time. An omitted `clock` on a `fork`/`wrap` whose
57
- * seed changed therefore keeps the parent's instant unless that parent was
58
- * itself `"seeded"`.
37
+ * from then on), while `"derived"` is left as the sentinel rather than
38
+ * collapsed to a number, so `resolveClock` can re-derive it from whichever
39
+ * `salt` is actually in effect at read time. An omitted `clock` on a
40
+ * `fork`/`wrap` whose salt changed therefore keeps the parent's instant unless
41
+ * that parent was itself `"derived"`.
59
42
  */
60
43
  export declare function overlay<$Registry extends PlainObject>(base: Partial<Config<PlainObject>>, over: Overlay<$Registry>): Config<$Registry>;
61
44
  /**
@@ -1,56 +1,51 @@
1
1
  import type { Enumerable, Limits } from "../Enumeration/Types";
2
2
  import type { Constructor } from "../Fabricator/Constructor";
3
- import type { Algorithm, Attribution, Layered, RandomSource, Seed } from "../Random/Types";
3
+ import type { Algorithm, Layered, RandomSource, Salt } from "../Random/Types";
4
4
  import type { PlainObject } from "../Utility/Types";
5
5
  /**
6
6
  * A fully resolved instance configuration — every field present, nothing left
7
7
  * to default. `Overlay` is what `fork` accepts; `overlay()`
8
8
  * (`Instance/Core.ts`) is the only thing producing a complete `Config`.
9
9
  *
10
- * Two fields are declared at their caller-facing type but always hold their
11
- * resolved form once `overlay()` has run: `seed` is `Seed` because that is what
12
- * a caller may supply, but always holds the normalized array (`Instance.seed`
13
- * is the authoritative read); `attribution` is `Attribution` for the same
14
- * reason but always holds a `ResolvedAttribution`, a subtype. `clock` is
15
- * different from both: unlike `seed`/`attribution`, it holds _either_ a
16
- * resolved instant (epoch milliseconds) or the unresolved `"seeded"` policy
17
- * never collapsed to a number by `overlay()` when `"seeded"`, because that
18
- * policy must re-derive whenever the seed it composes changes (a `fork({ seed:
19
- * layer(...) })`). The unconfigured default is a wall- clock number, inherited
20
- * as-is like an explicit `Date`. `resolveClock` (`Instance/Core.ts`) is the one
21
- * place that resolves `"seeded"` to a number, called fresh wherever the clock
22
- * actually matters (`instantiate`, the `context.clock` getter) rather than once
23
- * here.
10
+ * `salt` is declared at its caller-facing `Salt` type but always holds the
11
+ * normalized array once `overlay()` has run (`Instance.salt` is the
12
+ * authoritative read). `clock` holds _either_ a resolved instant (epoch
13
+ * milliseconds) or the unresolved `"derived"` policy never collapsed to a
14
+ * number by `overlay()` when `"derived"`, because that policy must re-derive
15
+ * whenever the salt it composes changes (a `fork({ salt: layer(...) })`). The
16
+ * unconfigured default is a wall- clock number, inherited as-is like an
17
+ * explicit `Date`. `resolveClock` (`Instance/Core.ts`) is the one place that
18
+ * resolves `"derived"` to a number, called fresh wherever the clock actually
19
+ * matters (`instantiate`, the `context.clock` getter) rather than once here.
24
20
  */
25
21
  export type Config<$Registry extends PlainObject> = {
26
- readonly seed: Seed;
22
+ readonly salt: Salt;
27
23
  readonly algorithm: Algorithm;
28
- readonly attribution: Attribution;
29
24
  readonly types: $Registry;
30
25
  readonly limits: Limits;
31
- readonly clock: number | "seeded";
26
+ readonly clock: number | "derived";
32
27
  };
33
28
  /**
34
29
  * What `fork` accepts — a `Config` to lay over a base, every field optional.
35
- * Identical to `Partial<Config>` but for `seed`, which additionally accepts a
36
- * {@link Layered}: a bare `Seed` replaces the base's seed outright (what `seed`
37
- * means everywhere else in this library), `layer(seed)` appends onto it
38
- * (`[...base.seed, ...seed]`) — the shape a wrapping integration wants, and
30
+ * Identical to `Partial<Config>` but for `salt`, which additionally accepts a
31
+ * {@link Layered}: a bare `Salt` replaces the base's salt outright (what `salt`
32
+ * means everywhere else in this library), `layer(salt)` appends onto it
33
+ * (`[...base.salt, ...salt]`) — the shape a wrapping integration wants, and
39
34
  * what `ConstructorOptions`' layered form is for a single construction.
40
- * Omitting `seed` inherits the base's unchanged. `clock` similarly accepts the
41
- * caller-facing `Date | "seeded"` rather than `Config`'s own resolved `number |
42
- * "seeded"`, so a caller can hand in a literal instant without converting it to
43
- * epoch milliseconds themselves. `"seeded"` is the explicit opt-in that derives
44
- * "now" from the instance seed; omitting `clock` at the root captures
35
+ * Omitting `salt` inherits the base's unchanged. `clock` similarly accepts the
36
+ * caller-facing `Date | "derived"` rather than `Config`'s own resolved `number
37
+ * | "derived"`, so a caller can hand in a literal instant without converting it
38
+ * to epoch milliseconds themselves. `"derived"` is the explicit opt-in that
39
+ * derives "now" from the instance salt; omitting `clock` at the root captures
45
40
  * wall-clock time instead.
46
41
  *
47
- * `initialize`'s own parameter keeps a plain `seed?: Seed`, so passing
42
+ * `initialize`'s own parameter keeps a plain `salt?: Salt`, so passing
48
43
  * `layer(...)` there is a compile error: there is no base to layer onto at the
49
44
  * root.
50
45
  */
51
- export type Overlay<$Registry extends PlainObject> = Partial<Omit<Config<$Registry>, "seed" | "clock">> & {
52
- readonly seed?: Seed | Layered;
53
- readonly clock?: Date | "seeded" | undefined;
46
+ export type Overlay<$Registry extends PlainObject> = Partial<Omit<Config<$Registry>, "salt" | "clock">> & {
47
+ readonly salt?: Salt | Layered;
48
+ readonly clock?: Date | "derived" | undefined;
54
49
  };
55
50
  /**
56
51
  * One active `wrap` — its resolved config plus the single `RandomSource` every
@@ -100,24 +95,23 @@ export type Stack = {
100
95
  * in effect."
101
96
  */
102
97
  export type Context = {
103
- readonly seed: ReadonlyArray<string>;
98
+ readonly salt: ReadonlyArray<string>;
104
99
  readonly algorithm: Algorithm;
105
- readonly attribution: Attribution;
106
100
  readonly clock: number;
107
101
  };
108
102
  /**
109
103
  * A single initialized library instance: the registry it was given, and a
110
- * `construct()` bound to its own isolated randomness — its own seed, builder,
111
- * and per-file overrides/streams, held internally and never shared with any
104
+ * `construct()` bound to its own isolated randomness — its own salt, builder,
105
+ * and construction counter/streams, held internally and never shared with any
112
106
  * other `initialize()` call. Independently initialized instances (e.g. parallel
113
107
  * tests) can never perturb each other.
114
108
  */
115
- export interface Instance<$Registry extends PlainObject> extends Pick<RandomSource, "seed"> {
109
+ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSource, "salt"> {
116
110
  /** The registry of type definers this instance was initialized with. */
117
111
  readonly T: $Registry;
118
112
  /**
119
113
  * Turn a Schema built from `T` into a live Fabricator, deriving fresh
120
- * randomness from this instance's own seed for whichever leaves actually need
114
+ * randomness from this instance's own salt for whichever leaves actually need
121
115
  * it.
122
116
  */
123
117
  Fabricator: Constructor;
@@ -138,8 +132,8 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
138
132
  coverage: Enumerable;
139
133
  /**
140
134
  * Derive a new instance laid over this one: anything the overlay names
141
- * overrides, anything it omits inherits. A bare `seed` replaces this
142
- * instance's seed; `seed: layer(...)` appends onto it. A peer of an
135
+ * overrides, anything it omits inherits. A bare `salt` replaces this
136
+ * instance's salt; `salt: layer(...)` appends onto it. A peer of an
143
137
  * `initialize()` return value in every respect, including its own `fork`.
144
138
  */
145
139
  fork<const $ForkRegistry extends PlainObject = $Registry>(overlay?: Overlay<$ForkRegistry>): Instance<$ForkRegistry>;
@@ -154,8 +148,8 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
154
148
  * configuration again, not the wrap's.
155
149
  *
156
150
  * A nested `wrap` lays over whichever frame is currently active, not over the
157
- * instance it was called on — so `overlay.seed: layer(...)` accumulates with
158
- * nesting depth while a bare `seed` still replaces outright, discarding every
151
+ * instance it was called on — so `overlay.salt: layer(...)` accumulates with
152
+ * nesting depth while a bare `salt` still replaces outright, discarding every
159
153
  * enclosing layer.
160
154
  */
161
155
  wrap<$Return, const $WrapRegistry extends PlainObject = $Registry>(overlay: Overlay<$WrapRegistry>, block: (scope: Instance<$WrapRegistry>) => $Return): $Return;
@@ -6,7 +6,7 @@ import { Schema } from "./Schema";
6
6
  * `T.opaque((random) => new Map<string, number>())` needs no annotation.
7
7
  *
8
8
  * `produce` receives this schema's own seeded stream, so an opaque value still
9
- * replays from a seed; see `Types.ts`'s `Produce`. No bare form and no `.as()`
9
+ * replays from a salt; see `Types.ts`'s `Produce`. No bare form and no `.as()`
10
10
  * — `produce` is the whole schema.
11
11
  */
12
12
  export default function <$T>(produce: Produce<$T>): Schema<$T>;
@@ -29,13 +29,13 @@ export type Fabricator<$Schema extends {
29
29
  * sibling expansions at the same depth (an `array` of three `self` children
30
30
  * calls `fabricateAt` three times on one shared element Fabricator; the schema
31
31
  * does not tell them apart). Each expansion gets its own _root_: `forkSource`
32
- * mints an isolated `RandomSource` seeded from this node's draw, and each
33
- * `fabricateAt` opens a `"counted"` scope on it (`Random/Types.ts`'s `RootKind`
34
- * recorded on each expansion's `trace`, not chosen at `ConstructorOptions`).
35
- * The private source's construction counter orders expansions; nothing to
36
- * increment here. Isolation also keeps this node's data-dependent draws from
37
- * perturbing (or being perturbed by) an unrelated Fabricator from the same
38
- * `initialize()` instance.
32
+ * mints an isolated `RandomSource` salted from this node's draw, and each
33
+ * `fabricateAt` resolves an ordinary construction root on it
34
+ * (`RandomSource.toRoot`), recorded on each expansion's `trace`. The private
35
+ * source's construction counter orders expansions; nothing to increment here.
36
+ * Isolation also keeps this node's data-dependent draws from perturbing (or
37
+ * being perturbed by) an unrelated Fabricator from the same `initialize()`
38
+ * instance.
39
39
  *
40
40
  * Each `self` gets its own independently-dispatched expansion — calling
41
41
  * `context.self` twice (two array slots) is two `fabricateAt` calls, each with
@@ -43,4 +43,4 @@ export type Fabricator<$Schema extends {
43
43
  * shared-element one. Sibling tree branches therefore draw independently, not a
44
44
  * correlated shared sequence.
45
45
  */
46
- export declare function Fabricator<$Body>(context: FabricatorContext<Schema<$Body>>, forkSource: (seed: string) => RandomSource, make: (schema: unknown, path: ReadonlyArray<string>, context: ConstructionContext) => NaiveFabricator<unknown>): Fabricator<Schema<$Body>>;
46
+ export declare function Fabricator<$Body>(context: FabricatorContext<Schema<$Body>>, forkSource: (salt: string) => RandomSource, make: (schema: unknown, path: ReadonlyArray<string>, context: ConstructionContext) => NaiveFabricator<unknown>): Fabricator<Schema<$Body>>;