@orkestrel/scaffold 0.0.66 → 0.0.68

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 (74) hide show
  1. package/dist/bin/main.js +67 -44
  2. package/dist/bin/main.js.map +1 -1
  3. package/dist/host/agents/templates/brief.md +9 -0
  4. package/dist/host/claude/agents/orkestrel.md +8 -8
  5. package/dist/host/claude/rules/names.md +15 -0
  6. package/dist/host/claude/rules/tests.md +33 -4
  7. package/dist/host/claude/rules/workspace.md +14 -2
  8. package/dist/host/dotfiles/prettierignore +3 -0
  9. package/dist/host/guides/README.md +65 -0
  10. package/dist/host/guides/abort.md +169 -0
  11. package/dist/host/guides/agent.md +1509 -0
  12. package/dist/host/guides/brief.md +1266 -0
  13. package/dist/host/guides/browser.md +2200 -0
  14. package/dist/host/guides/budget.md +196 -0
  15. package/dist/host/guides/codec.md +519 -0
  16. package/dist/host/guides/console.md +785 -0
  17. package/dist/host/guides/contract.md +1193 -0
  18. package/dist/host/guides/csv.md +541 -0
  19. package/dist/host/guides/database.md +2518 -0
  20. package/dist/host/guides/emitter.md +233 -0
  21. package/dist/host/guides/form.md +1791 -0
  22. package/dist/host/guides/html.md +717 -0
  23. package/dist/host/guides/indexeddb.md +505 -0
  24. package/dist/host/guides/interpret.md +1029 -0
  25. package/dist/host/guides/lsp.md +515 -0
  26. package/dist/host/guides/markdown.md +964 -0
  27. package/dist/host/guides/mcp.md +5554 -0
  28. package/dist/host/guides/middleware.md +927 -0
  29. package/dist/host/guides/msg.md +440 -0
  30. package/dist/host/guides/ndjson.md +120 -0
  31. package/dist/host/guides/ollama.md +380 -0
  32. package/dist/host/guides/pool.md +280 -0
  33. package/dist/host/guides/probe.md +1210 -0
  34. package/dist/host/guides/process.md +1620 -0
  35. package/dist/host/guides/program.md +1110 -0
  36. package/dist/host/guides/qualifier.md +854 -0
  37. package/dist/host/guides/queue.md +370 -0
  38. package/dist/host/guides/rater.md +330 -0
  39. package/dist/host/guides/reason.md +1122 -0
  40. package/dist/host/guides/relation.md +373 -0
  41. package/dist/host/guides/router.md +753 -0
  42. package/dist/host/guides/scaffold.md +192 -31
  43. package/dist/host/guides/sea.md +383 -0
  44. package/dist/host/guides/server.md +752 -0
  45. package/dist/host/guides/sqlite.md +330 -0
  46. package/dist/host/guides/sse.md +187 -0
  47. package/dist/host/guides/supervisor.md +4890 -0
  48. package/dist/host/guides/table.md +1556 -0
  49. package/dist/host/guides/template.md +280 -0
  50. package/dist/host/guides/terminal.md +1145 -0
  51. package/dist/host/guides/test.md +2969 -0
  52. package/dist/host/guides/timeout.md +252 -0
  53. package/dist/host/guides/tool.md +311 -0
  54. package/dist/host/guides/toolbox.md +1038 -0
  55. package/dist/host/guides/websocket.md +282 -0
  56. package/dist/host/guides/worker.md +615 -0
  57. package/dist/host/guides/workflow.md +1507 -0
  58. package/dist/host/guides/workspace.md +595 -0
  59. package/dist/host/manifest.json +1218 -10
  60. package/dist/host/tests/policy.test.ts +279 -2
  61. package/dist/host/tests/setupPolicy.ts +437 -6
  62. package/dist/src/core/index.cjs +44 -22
  63. package/dist/src/core/index.cjs.map +1 -1
  64. package/dist/src/core/index.d.cts +33 -9
  65. package/dist/src/core/index.d.ts +33 -9
  66. package/dist/src/core/index.js +43 -23
  67. package/dist/src/core/index.js.map +1 -1
  68. package/dist/src/server/index.cjs +1750 -1567
  69. package/dist/src/server/index.cjs.map +1 -1
  70. package/dist/src/server/index.d.cts +106 -24
  71. package/dist/src/server/index.d.ts +106 -24
  72. package/dist/src/server/index.js +1751 -1570
  73. package/dist/src/server/index.js.map +1 -1
  74. package/package.json +9 -9
@@ -0,0 +1,1193 @@
1
+ # Contract
2
+
3
+ > The zero-dependency contract toolkit — runtime type guards, guard combinators,
4
+ > coerce-and-extract parsers, and a shape DSL that compiles one declaration into a JSON
5
+ > Schema, a guard, a parser, a strict audit, a parse report, and a generator, every one of
6
+ > them derived from a single owned snapshot of that declaration.
7
+
8
+ Validation is where untrusted data — an HTTP body, a parsed JSON blob, a tool argument — crosses into typed code. This module is that crossing: guards turn `unknown` into a narrowed `T` without leaking a hostile input's throw, while parsers return a typed value or `undefined` for readable invalid input. Here a **reader** is a public operation whose documented result depends on inspecting a caller-owned container, and an **advertised read** is the exact property, key, element, iteration, or reflection that operation says it observes. REQUIRED readers refuse an incomplete advertised read with a coded `ContractError`; unreadability never becomes their absence or accept-anything answer. Total guards instead answer `false`; optional lookup/coercion readers (`enumerableKeys`, `resolveField`, `parseArray`, `parseEnum`, and the `parse*Field` family) deliberately answer `undefined`. Schema inversion widens readable unsupported, depth-exhausted, or cyclic nodes to `rawShape({})`, but a traversal that fails is refused as unreadable rather than widened. **READABLE** therefore means every advertised read for the operation being discussed completes; **STABLE** means those observable reads also keep the same answers across separate calls. The module deliberately ships **flat primitives** instead of a full schema framework — every guard is a one-argument total function and parsers coerce-or-bail rather than collect errors. The `parseJSON` / `parseJSONAs` text boundary stays lazy by default; `isJSONValue`, `parseJSONValue`, `cloneJSONValue`, and the record-root `cloneJSONRecord` are explicit deep whole-tree operations. Recursive contracts remain opt-in through the shape DSL, where the tree is finite and developer-authored. Its source is [`src/core`](../src/core), surfaced through the `@src/core` barrel.
9
+
10
+ ## Surface
11
+
12
+ A guard is the `Guard<T>` type from [`types.ts`](../src/core/types.ts):
13
+
14
+ ```ts
15
+ type Guard<T> = (value: unknown) => value is T
16
+ ```
17
+
18
+ Every guard takes one `unknown`, returns a `boolean` TypeScript reads as a type predicate, and **never throws** — a value that doesn't fit is `false`, even on adversarial input (cycles, hostile prototypes). Totality is universal (`.claude/rules/patterns.md` § Validation and contracts), so any guard is safe to call on anything at any trust boundary. **Purity is not.** It holds for every guard this module builds out of its own reads, and it cannot hold for any combinator that runs YOUR code inside the guard body. The rule: **any combinator that runs code you supplied inherits whatever that code does** — whether you hand it a callback directly, as `whereOf`, `lazyOf` and `transformOf` do, or hand it a guard it composes. If you passed it, its behaviour is yours. Such a guard is exactly as pure and as order-independent as the callback you hand it: a stateful predicate that counts its own calls answers `true` and then `false` for the SAME argument, and one that appends to a log leaves the write behind. Containment keeps it total either way; what it cannot keep is "function of its argument alone". Hand pure callbacks if you want the whole family's guarantee, and read "in any order" as a promise the guards this module builds from its own reads make.
19
+
20
+ Sibling families, each with its own job:
21
+
22
+ - **Validators** (`is*`) answer "_is_ this value a `T`?" — a boolean predicate that narrows in place. No coercion, no transform.
23
+ - **Combinators** (`*Of`) build a fresh `Guard<…>` out of existing guards (and accept any bare `(value: unknown) => boolean` predicate), so a complex guard is composed, never hand-written.
24
+ - **Parsers** (`parse*`) answer "give me a `T` _or_ `undefined`" for readable input — they coerce (`'36'` → `36`) and return the typed value or `undefined`. `parseRecord` and `parseJSONValue` throw the shared coded read refusal when traversal fails, so a caller can distinguish invalidity from unreadability. Each parser forms a **sound** pair with the guard for its output type (`.claude/rules/patterns.md` § Validation and contracts): a guard-valid readable input is returned unchanged, and every non-`undefined` output satisfies that guard, so you can parse-then-trust.
25
+
26
+ The `*Field` parsers read a (possibly nested) record field through a `FieldPath` (`string | readonly string[]`, in [`src/core/types.ts`](../src/core/types.ts)) — a single string is **one** key (no dot-splitting); an array descends own properties of nested objects/arrays through the `resolveField` core helper. The root must satisfy `isRecord`, and inherited properties are rejected at every segment. This is deliberate: a field reader receives a record, so accepting a root the module's record guard rejects or a value visible only through its prototype would contradict that contract; arrays remain supported as nested containers because indexed path segments are their own properties. The `whereOf` / `lazyOf` / `transformOf` combinators run caller-supplied callbacks _inside_ a guard body; they contain any throw through the core `attempt` helper, so even a guard that runs your code stays total and returns `false` rather than propagating.
27
+
28
+ In a guard table a `Shape` cell holds the type the guard narrows to.
29
+
30
+ ### Primitive & null-ish guards
31
+
32
+ | Guard | Kind | Shape | Summary |
33
+ | ---------------------- | -------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
34
+ | `isNull` | function | `null` | Determines whether a value is `null`. |
35
+ | `isUndefined` | function | `undefined` | Determines whether a value is `undefined`. |
36
+ | `isDefined` | function | `T` | Determines whether a value is defined (neither `null` nor `undefined`). |
37
+ | `isString` | function | `string` | Determines whether a value is a string. |
38
+ | `isNumber` | function | `number` | Determines whether a value is a number. |
39
+ | `isFiniteNumber` | function | `number` | Determines whether a value is a finite number (excludes `NaN` and `±Infinity`). |
40
+ | `isInteger` | function | `number` | Determines whether a value is a finite integer (excludes `NaN`, `±Infinity`, and fractional numbers). |
41
+ | `isNonNegativeNumber` | function | `number` | Determines whether a value is a finite primitive number at or above positive zero. |
42
+ | `isNonNegativeInteger` | function | `number` | Determines whether a value is a non-negative finite primitive integer. |
43
+ | `isBoolean` | function | `boolean` | Determines whether a value is a boolean. |
44
+ | `isLiteralValue` | function | `LiteralValue` | Determines whether a value belongs to the string, number, or boolean literal domain. |
45
+ | `isTrue` | function | `true` | Determines whether a value is exactly `true`. |
46
+ | `isFalse` | function | `false` | Determines whether a value is exactly `false`. |
47
+ | `isBigInt` | function | `bigint` | Determines whether a value is a bigint. |
48
+ | `isSymbol` | function | `symbol` | Determines whether a value is a symbol. |
49
+ | `isNullableString` | function | `string \| null` | Determines whether a value is a string or `null`. |
50
+ | `isNullableNumber` | function | `number \| null` | Determines whether a value is a number or `null` (the number may be `NaN` / `±Infinity`). |
51
+ | `isNullableBoolean` | function | `boolean \| null` | Determines whether a value is a boolean or `null`. |
52
+
53
+ ### Structural & collection guards
54
+
55
+ | Guard | Kind | Shape | Summary |
56
+ | --------------------- | -------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
57
+ | `isObject` | function | `object` | Determines whether a value is a non-null object. |
58
+ | `isRecord` | function | `Record<string, unknown>` | Determines whether a value is a plain record (object literal or null-prototype), not an array or class instance. |
59
+ | `isMap` | function | `ReadonlyMap<K, V>` | Determines whether a value is a `Map`. |
60
+ | `isSet` | function | `ReadonlySet<T>` | Determines whether a value is a `Set`. |
61
+ | `isWeakMap` | function | `WeakMap<object, unknown>` | Determines whether a value is a `WeakMap`. |
62
+ | `isWeakSet` | function | `WeakSet<object>` | Determines whether a value is a `WeakSet`. |
63
+ | `isDate` | function | `Date` | Determines whether a value is a `Date`. |
64
+ | `isRegExp` | function | `RegExp` | Determines whether a value is a `RegExp`. |
65
+ | `isError` | function | `Error` | Determines whether a value is an `Error`. |
66
+ | `isPromise` | function | `Promise<T>` | Determines whether a value is a native `Promise` (use `isPromiseLike` for any thenable). |
67
+ | `isPromiseLike` | function | `PromiseLike<T>` | Determines whether a value is promise-like — an object exposing callable `then`, `catch`, and `finally` methods. |
68
+ | `isIterable` | function | `Iterable<T>` | Determines whether a value implements the iterable protocol (`Symbol.iterator`). |
69
+ | `isAsyncIterable` | function | `AsyncIterable<T>` | Determines whether a value implements the async iterable protocol (`Symbol.asyncIterator`). |
70
+ | `isArrayBuffer` | function | `ArrayBuffer` | Determines whether a value is an `ArrayBuffer`. |
71
+ | `isSharedArrayBuffer` | function | `SharedArrayBuffer` | Determines whether a value is a `SharedArrayBuffer`. |
72
+
73
+ #### Recognizing a plain record
74
+
75
+ `isRecord` must recognize a plain object from another realm — a `vm.Context`, an iframe, a worker — whose `Object.prototype` is a different object from this realm's. It therefore identifies a foreign `Object.prototype` by the own members every conformant realm puts on it (`constructor`, `hasOwnProperty`, `isPrototypeOf`, `propertyIsEnumerable`, `toLocaleString`, `toString`, `valueOf`), each read through its own descriptor so no accessor on a hostile prototype runs, and each required to be an own data property whose value is a function.
76
+
77
+ That is a structural test rather than a provenance one, and the residual is exactly this: a prototype forged to carry the mandated names as function-valued own data properties passes, while a prototype carrying the same names with no values is refused. A class prototype merely reparented to `null` fails, and so do `Date` and an ordinary class instance. The pass buys acceptance at brand-governed doors and nothing after it — every ownership engine builds a frozen plain record from captured data, so no class instance, class behavior, or forged prototype survives into a snapshot.
78
+
79
+ ### Array & typed-array guards
80
+
81
+ | Guard | Kind | Shape | Summary |
82
+ | --------------------- | -------- | ------------------- | ----------------------------------------------------------------------------------- |
83
+ | `isArray` | function | `readonly T[]` | Determines whether a value is an array. |
84
+ | `isDataView` | function | `DataView` | Determines whether a value is a `DataView`. |
85
+ | `isArrayBufferView` | function | `ArrayBufferView` | Determines whether a value is an `ArrayBufferView` (any typed array or `DataView`). |
86
+ | `isInt8Array` | function | `Int8Array` | Determines whether a value is an `Int8Array`. |
87
+ | `isUint8Array` | function | `Uint8Array` | Determines whether a value is a `Uint8Array`. |
88
+ | `isUint8ClampedArray` | function | `Uint8ClampedArray` | Determines whether a value is a `Uint8ClampedArray`. |
89
+ | `isInt16Array` | function | `Int16Array` | Determines whether a value is an `Int16Array`. |
90
+ | `isUint16Array` | function | `Uint16Array` | Determines whether a value is a `Uint16Array`. |
91
+ | `isInt32Array` | function | `Int32Array` | Determines whether a value is an `Int32Array`. |
92
+ | `isUint32Array` | function | `Uint32Array` | Determines whether a value is a `Uint32Array`. |
93
+ | `isFloat32Array` | function | `Float32Array` | Determines whether a value is a `Float32Array`. |
94
+ | `isFloat64Array` | function | `Float64Array` | Determines whether a value is a `Float64Array`. |
95
+ | `isBigInt64Array` | function | `BigInt64Array` | Determines whether a value is a `BigInt64Array`. |
96
+ | `isBigUint64Array` | function | `BigUint64Array` | Determines whether a value is a `BigUint64Array`. |
97
+
98
+ ### Emptiness guards
99
+
100
+ | Guard | Kind | Shape | Summary |
101
+ | ------------------ | -------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
102
+ | `isEmptyString` | function | `''` | Determines whether a value is the empty string `''`. |
103
+ | `isEmptyArray` | function | `readonly []` | Determines whether a value is an empty array. |
104
+ | `isEmptyObject` | function | `Record<string \| symbol, never>` | Determines whether a value is an empty plain object — no OWN keys at all, of any kind: string or symbol, enumerable or not. |
105
+ | `isEmptyMap` | function | `ReadonlyMap<never, never>` | Determines whether a value is an empty `Map`. |
106
+ | `isEmptySet` | function | `ReadonlySet<never>` | Determines whether a value is an empty `Set`. |
107
+ | `isNonEmptyString` | function | `string` | Determines whether a value is a non-empty string (at least one character). |
108
+ | `isNonEmptyArray` | function | `readonly [T, ...T[]]` | Determines whether a value is a non-empty array (at least one element). |
109
+ | `isNonEmptyObject` | function | `Record<string \| symbol, unknown>` | Determines whether a value is a non-empty plain object — at least one own key of any kind: string or symbol, enumerable or not. |
110
+ | `isNonEmptyMap` | function | `ReadonlyMap<K, V>` | Determines whether a value is a non-empty `Map` (at least one entry). |
111
+ | `isNonEmptySet` | function | `ReadonlySet<T>` | Determines whether a value is a non-empty `Set` (at least one element). |
112
+
113
+ ### Function & constructor guards
114
+
115
+ | Guard | Kind | Shape | Summary |
116
+ | -------------------------- | -------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
117
+ | `isFunction` | function | `AnyFunction` | Determines whether a value is callable. |
118
+ | `isZeroArg` | function | `ZeroArgFunction` | Determines whether a value is a function that declares zero parameters (`Function.length === 0`). |
119
+ | `isAsyncFunction` | function | `AnyAsyncFunction` | Determines whether a value is a native `async function`. |
120
+ | `isGeneratorFunction` | function | `(...args: unknown[]) => Generator<unknown, unknown, unknown>` | Determines whether a value is a generator function (`function*`). |
121
+ | `isAsyncGeneratorFunction` | function | `(...args: unknown[]) => AsyncGenerator<unknown, unknown, unknown>` | Determines whether a value is an async generator function (`async function*`). |
122
+ | `isZeroArgAsync` | function | `ZeroArgAsyncFunction` | Determines whether a value is a zero-argument async function. |
123
+ | `isZeroArgGenerator` | function | `() => Generator<unknown, unknown, unknown>` | Determines whether a value is a zero-argument generator function. |
124
+ | `isZeroArgAsyncGenerator` | function | `() => AsyncGenerator<unknown, unknown, unknown>` | Determines whether a value is a zero-argument async generator function. |
125
+ | `isConstructor` | function | `AnyConstructor` | Determines whether a value can be used as a `new`-target constructor. |
126
+ | `isInstance` | function | `InstanceType<C>` | Determines whether a value is an instance of a constructor, contained against a throwing `instanceof` check. |
127
+
128
+ ### Combinators
129
+
130
+ Each combinator builds a fresh guard out of guards you already hold. There is no
131
+ `iterableOf`; guard a `Set`, a `Map`, or an array with `setOf`, `mapOf`, or `arrayOf`.
132
+
133
+ | Combinator | Kind | Summary |
134
+ | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
135
+ | `arrayOf` | function | Builds a guard that accepts DENSE arrays whose every element satisfies `elementGuard`. |
136
+ | `tupleOf` | function | Builds a guard that accepts fixed-arity DENSE tuples, testing each index with the corresponding guard. |
137
+ | `setOf` | function | Builds a guard that accepts `Set` instances whose every element satisfies `elementGuard`. |
138
+ | `mapOf` | function | Builds a guard that accepts `Map` instances where every key satisfies `keyGuard` and every value satisfies `valueGuard`. |
139
+ | `recordOf` | function | Builds a guard that accepts plain records matching a guard shape. |
140
+ | `objectOf` | function | Builds a guard that accepts non-array objects matching an open guard shape. |
141
+ | `literalOf` | function | Builds a guard that accepts a provided literal primitive using SameValueZero comparison. |
142
+ | `instanceOf` | function | Builds a guard that accepts instances of the provided constructor. |
143
+ | `enumOf` | function | Builds a guard from a native `enum` or any object whose values are strings or numbers. |
144
+ | `keyOf` | function | Builds a guard that accepts values that are own keys of the provided object. |
145
+ | `pickOf` | function | Builds a new guard shape by keeping only the listed keys — the structural equivalent of `Pick<T, K>`. Produces a shape for `recordOf`, not a guard. |
146
+ | `omitOf` | function | Builds a new guard shape by removing the listed keys — the structural equivalent of `Omit<T, K>`. Produces a shape for `recordOf`, not a guard. |
147
+ | `andOf` | function | Combines `left` and `right` with logical AND — passes only when both pass. |
148
+ | `orOf` | function | Combines `left` and `right` with logical OR — passes when at least one passes. Prefer `unionOf` for a wider set of variants. |
149
+ | `notOf` | function | Negates a guard or predicate — passes when `guard` returns `false`. |
150
+ | `complementOf` | function | Builds a guard for `Exclude<TBase, TExcluded>` — accepts values that pass `base` but not `excluded`. |
151
+ | `unionOf` | function | Builds a guard that accepts values matching at least one of the provided guards — the variadic form of `orOf`. |
152
+ | `intersectionOf` | function | Builds a guard that accepts values matching ALL of the provided guards — the variadic form of `andOf`. |
153
+ | `whereOf` | function | Refines a base guard with an additional predicate that runs only when the base passes. |
154
+ | `lazyOf` | function | Defers guard creation until first use by calling `thunk()` on every invocation. |
155
+ | `transformOf` | function | Builds a guard that passes when the base passes AND the projection of the value satisfies the target guard. Still narrows to `T` (the base type) — the target check is a validity constraint on a derived view, not a type transformation. |
156
+ | `nullableOf` | function | Extends a guard to also allow `null`. |
157
+ | `optionalOf` | function | Extends a guard to also allow `undefined` — the optional counterpart of `nullableOf`. |
158
+ | `boundsOf` | function | Builds a guard that accepts finite numbers within an inclusive `[min, max]` range. |
159
+ | `matchOf` | function | Builds a guard that accepts strings matching a regular expression. |
160
+ | `stringOf` | function | Builds a guard that accepts strings satisfying optional length and pattern refinements — `min` / `max` length and a `pattern`. |
161
+
162
+ The bound the combinators carry is not itself a combinator, and its `Value` cell holds
163
+ the constant's own literal:
164
+
165
+ | Bound | Kind | Value | Summary |
166
+ | ------------------- | ----- | ----- | ----------------------------------------------------------------------------- |
167
+ | `GUARD_DEPTH_LIMIT` | const | `512` | Caps the active recursion or JSON container depth for runtime guards, frozen. |
168
+
169
+ ### Parsers
170
+
171
+ **Coercion policy.** Number and string coerce into each other bidirectionally by design: `parseNumber` accepts a numeric string (`'42'` → `42`) and `parseString` accepts a finite number, stringifying it (`42` → `'42'`) — use `isString` / `isFiniteNumber` directly when you need strict rejection with no coercion. Boolean is a coercion **sink only**, never a source: `parseBoolean` accepts `'true'` / `'false'` / `'1'` / `'0'` / `1` / `0` and coerces them TO a boolean, but `parseNumber` and `parseString` both reject booleans outright — a boolean never coerces into a number or string. `'1'` meaning "the number one" and `'1'` meaning "true" are different domains; only the boolean parser treats the numeric/string forms as booleans.
172
+
173
+ | Parser | Kind | Summary |
174
+ | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
175
+ | `parseString` | function | Parses an unknown value to a string. |
176
+ | `parseNumber` | function | Parses an unknown value to a finite number. |
177
+ | `parseInteger` | function | Parses an unknown value to a finite integer. |
178
+ | `parseBoolean` | function | Parses an unknown value to a boolean. |
179
+ | `parseRecord` | function | Parses an unknown value to a plain record — the input reference, never cloned. |
180
+ | `parseArray` | function | Parses an unknown value to an array — the input reference, never cloned — optionally guarding every element. |
181
+ | `parseEnum` | function | Parses an unknown value as one of the allowed literal primitives. |
182
+ | `parseNull` | function | Parses an unknown value to `null`. |
183
+ | `parseJSONValue` | function | Parses an unknown value to a cycle-safe JSON value — the input reference, never cloned. |
184
+ | `parseStringField` | function | Reads and parses a string field from a record by key or nested key path. |
185
+ | `parseNumberField` | function | Reads and parses a finite-number field from a record by key or nested key path. |
186
+ | `parseIntegerField` | function | Reads and parses a finite-integer field from a record by key or nested key path. |
187
+ | `parseBooleanField` | function | Reads and parses a boolean field from a record by key or nested key path. |
188
+ | `parseRecordField` | function | Reads and parses a nested record field from a record by key or nested key path. |
189
+ | `parseArrayField` | function | Reads and parses an array field from a record by key or nested key path, optionally guarding elements. |
190
+ | `parseEnumField` | function | Reads and parses an enum field from a record by key or nested key path. |
191
+ | `parseNullField` | function | Reads and parses a `null` field from a record by key or nested key path. |
192
+ | `parseJSONValueField` | function | Reads and parses a JSON-value field from a record by key or nested key path. |
193
+
194
+ ### JSON
195
+
196
+ The safe JSON surface keeps text parsing lazy: `parseJSON` returns `unknown`, while `parseJSONAs` walks only the guard shape supplied by its caller. `isJSONValue` and `parseJSONValue` are shipped explicit deep whole-tree gates; `isBoundedJSONValue` adds the fixed resource boundary, and `isBoundedJSONRecord` adds the record-root invariant. `JSONRecord` and `cloneJSONRecord` provide the record-root ownership contract required by metadata and persistence consumers, while `cloneJSONValue` owns any JSON root. A dedicated `JSONArray` alias, broad deep `isJSONObject` / `isJSONSchema` validators, and the ~50-field `JSONSchemaDefinition` remain deliberately omitted. Compose narrower shapes from the combinators and read a parsed blob field-by-field with the `parse*Field` readers when whole-tree work is unnecessary.
197
+
198
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
199
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
200
+ literal with a union's arms escaped as `\|`. A function row's `Shape` cell holds its signature, and a
201
+ guard row's the type it narrows to.
202
+
203
+ | API | Kind | Shape | Summary |
204
+ | --------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
205
+ | `isJSONPrimitive` | function | `JSONPrimitive` | Determines whether a value is a primitive JSON value. |
206
+ | `isJSONValue` | function | `JSONValue` | Determines whether a value is a cycle-safe JSON value. |
207
+ | `isBoundedJSONValue` | function | `JSONValue` | Determines whether a value is JSON-valid within the fixed container-depth limit. |
208
+ | `isBoundedJSONRecord` | function | `JSONRecord` | Determines whether a value is a depth-bounded JSON record. |
209
+ | `parseJSON` | function | `(value: string) => unknown` | Parses a JSON string, returning `undefined` instead of throwing. |
210
+ | `parseJSONAs` | function | `<T>(value: string, guard: Guard<T>) => T \| undefined` | Parses a JSON string and validates the result against a guard. |
211
+ | `JSON_SCHEMA_TYPES` | const | `readonly JSONSchemaType[]` | Lists the seven standard JSON Schema `type` names, frozen. |
212
+ | `JSONPrimitive` | type | `string \| number \| boolean \| null` | Represents a primitive JSON value — the flat leaf of any JSON document. |
213
+ | `JSONRecord` | type | `{ readonly [key: string]: JSONValue }` | Represents a readonly string-keyed JSON object record. |
214
+ | `JSONValue` | type | `JSONPrimitive \| readonly JSONValue[] \| JSONRecord` | Represents a recursive JSON value — primitives, arrays, and object records. |
215
+ | `JSONSchemaType` | type | `'null' \| 'boolean' \| 'object' \| 'array' \| 'number' \| 'integer' \| 'string'` | Lists the seven standard JSON Schema `type` names. |
216
+ | `JSONSchema` | interface | `{ type?, description?, enum?, minLength?, maxLength?, pattern?, format?, minimum?, maximum?, minItems?, maxItems?, items?, properties?, required?, additionalProperties?, anyOf?, oneOf? }` | Represents a JSON Schema fragment — the supported keyword vocabulary the contract compiler emits and `RawShape` validates before embedding. |
217
+ | `SchemaFormat` | type | `'date-time' \| 'date' \| 'time' \| 'uuid' \| 'email' \| 'uri'` | Lists the closed set of string formats `stringToFormat` recognizes. |
218
+
219
+ ### Helper
220
+
221
+ | Constant | Kind | Summary |
222
+ | ---------------------- | ----- | --------------------------------------------------------------------------------------------- |
223
+ | `CONTRACT_ERROR_BRAND` | const | Holds the registry-global key used to recognize `ContractError` values across package copies. |
224
+
225
+ | Helper | Kind | Summary |
226
+ | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
227
+ | `attempt` | function | Invokes a callback once and synchronously captures its exact outcome as a `Result`. |
228
+ | `INTRINSICS` | const | Captures every host operation this package dispatches through, while this module evaluates. |
229
+ | `contain` | function | Runs a public door's whole body and publishes only this package's error class. |
230
+ | `appendEntries` | function | Appends every element of one array onto another, by index. |
231
+ | `limitEntries` | function | Takes at most `limit` leading elements of an array, by index. |
232
+ | `compareValues` | function | Orders two primitive keys or indices ascending. |
233
+ | `sortValues` | function | Orders primitive keys or indices deterministically, on an owned copy, through the captured sort. |
234
+ | `pathOf` | function | Builds a diagnostic path from an existing path and further segments, without dispatching through array iteration. |
235
+ | `readValue` | function | Reads a value through the shared containment boundary or refuses it with the contract module's uniform read diagnostic. |
236
+ | `readArrayEntries` | function | Snapshots an array through its reflected own-index population. |
237
+ | `readGuardShape` | function | Snapshots a guard shape and its optional-key mode for a shape combinator. |
238
+ | `holds` | function | Invokes a predicate through the sanctioned never-throw boundary. |
239
+ | `enumerableKeys` | function | Snapshots an object's own enumerable string keys through a total boundary. |
240
+ | `readOptions` | function | Validates and snapshots a shape-builder options record through every reflective operation the builder relies on. |
241
+ | `drawRandom` | function | Draws and validates one generator random sample. |
242
+ | `enumerableSymbolCount` | function | Counts the enumerable own-symbol keys on a value. |
243
+ | `matchesJSONValue` | function | Matches an unknown value against the recursive JSON value structure. |
244
+ | `matchesRecordBrand` | function | Determines whether a value carries the plain-record brand, raising a hostile prototype observation instead of answering it. |
245
+ | `matchesJSONDepth` | function | Determines whether a readable value stays within the fixed JSON container-depth limit. |
246
+ | `resolveField` | function | Resolves a (possibly nested) field value from a record by a key or key path. |
247
+ | `seededRandom` | function | Builds a deterministic pseudo-random source seeded from a single number. |
248
+ | `schemaToParameters` | function | Narrows a compiled `JSONSchema` down to the open `Readonly<Record<string, unknown>>` shape tool definitions advertise as `parameters` — through the `isRecord` boundary guard, never an assertion, as `.claude/rules/patterns.md` § Validation and contracts requires. |
249
+ | `schemaToObject` | function | Wraps a non-object `JSONSchema` root in a single-property object schema, so an inferred primitive/array/union schema can flow into `schemaToParameters` as an MCP-compatible `inputSchema`. |
250
+ | `collectMembers` | function | Collects an array's entries into a membership collection this package owns. |
251
+ | `matchesMember` | function | Determines whether a value is a member of a collected vocabulary, by SameValueZero. |
252
+ | `admitMember` | function | Collects one more member into a vocabulary that grows as a walk proceeds. |
253
+ | `matchesVisited` | function | Determines whether an object is already on a traversal's active path. |
254
+ | `admitVisited` | function | Records an object as entered on a traversal's active path. |
255
+ | `omitVisited` | function | Records an object as exited from a traversal's active path. |
256
+ | `retainDepth` | function | Records one node's answer at one remaining-depth allowance in a shared memo. |
257
+ | `collectEntries` | function | Builds the collector a captured `forEach` sweep appends through. |
258
+ | `readSetEntries` | function | Snapshots the genuine contents of a caller's `Set` without running an iterator. |
259
+ | `readMapEntries` | function | Snapshots the genuine entries of a caller's `Map` without running an iterator. |
260
+ | `matchesPattern` | function | Determines whether a string is in the language of a pattern this package owns. |
261
+ | `readPatternSource` | function | Reads a regular expression's source text through the captured accessor. |
262
+ | `readPatternFlags` | function | Reads a regular expression's flag text through the captured accessor. |
263
+ | `readPattern` | function | Rebuilds a caller's regular expression as a stateless pattern this package owns. |
264
+ | `ownPattern` | function | Rebuilds a declaration's regular expression as a stateless pattern this package owns, and refuses an unreadable one under the reader's own name. |
265
+ | `pinMembers` | function | Pins every own member of a class prototype as a non-configurable member — non-writable too when it is a data property — and verify the pin took. |
266
+ | `refuseExpansion` | function | Refuses a validated declaration whose compiled expansion exceeds `COMPILE_NODE_LIMIT`. |
267
+
268
+ `matchesJSONDepth` is deliberately depth-only: active cycles terminate successfully at the depth layer but remain invalid JSON, honest sparse holes add no child depth but fail the dense `isJSONValue` contract, and readable exotics pass as leaves but fail JSON validity. `isBoundedJSONValue` therefore performs two total sequential observations — fixed depth first, then the existing JSON guard — rather than promising an atomic snapshot of caller-owned state. It validates but does not own; use `cloneJSONValue` / `cloneJSONRecord` when an independent frozen snapshot is required. The fixed cap is package safety mechanism, not configurable product policy: byte budgets, key budgets, configured wire depth, unsafe-name rejection, descriptor policy, and application-specific limits remain with their consuming package.
269
+
270
+ ### Membership
271
+
272
+ Membership is the answer a validation package exists to be right about, and it is asked through MODULE BINDINGS rather than through any property. `Set` is the right data structure for SameValueZero membership and the wrong dispatch surface: a caller who writes `Set.prototype.has = () => true` changed what `contract.is`, `literalOf`, `enumOf` and `parseEnum` ANSWERED — no throw, no diagnostic, a wrong yes. Moving those reads onto the `has` method of an exported class reproduces the defect verbatim, because every public class method is dispatched through a prototype every consumer can reach. Relocating an answer onto a reachable member moves the defect rather than removing it. This package instead asks through a module-scope function, which the specification makes immutable to every importer, over an operation `INTRINSICS` captured while it evaluated.
273
+
274
+ So `matchesMember` / `admitMember` / `collectMembers` own literal, enum and key membership; `matchesVisited` / `admitVisited` / `omitVisited` own cycle and visitation membership; `matchesPattern` / `readPattern` / `readPatternSource` / `readPatternFlags` own pattern membership; and `readSetEntries` / `readMapEntries` read a caller's own `Set` / `Map` through the captured `forEach` rather than through a replaceable iterator. Collection construction is by INDEX rather than from an iterable, because `new Set(values)` reads `Symbol.iterator` off the argument and `add` off the instance — two replaceable dispatches added to remove one.
275
+
276
+ The scope claim, stated so it can be checked rather than trusted: **no membership answer this package publishes — literal, enum, pattern, set, map, intersection, record key, declared key, or schema keyword — is decided by a property lookup on any object a caller can reach.** The standing proof is `tests/src/core/integration.test.ts`, which sweeps every membership door against every lying host member, against both accessors of `RegExp.prototype`, and against every writable prototype member of every value this package exports as a constructor. That last population is not empty: an earlier sentence here said it was "empty, because each of those classes pins its prototype while it is defined", which ran a true claim about the CLASSES together with a false one about the population. The rule draws from every exported callable, and an ordinary exported FUNCTION's `.prototype.constructor` is writable and always will be — so the corpus is one row per exported plain function and zero rows per exported class. The sweep asserts what it always asserted, that no door consults any of them. The suite pins the corpus's composition against the barrel rather than against a remembered number: every exported plain function contributes exactly one row, every row is a `.prototype.constructor`, and no exported class contributes any. A count stated here drifted for a round after further functions were exported, which is why no number stands here.
277
+
278
+ What that claim does NOT cover is named rather than left to be discovered: the load-order precondition below, and a caller who replaces a door's own method and then calls that door, which is their arrangement rather than this package's defect.
279
+
280
+ ### Threat model
281
+
282
+ Stated as a LIMIT, because a security claim that names no boundary is not checkable.
283
+
284
+ **This package does not defend against an adversary who can modify shared intrinsics in its own realm.** A caller who can assign `String.prototype.trim`, `Object.freeze`, or `Set.prototype.has` is already running arbitrary code in the same realm as this package and can replace the package outright — swap the module, wrap every export, or answer the verification read that any self-check performs. Defending is impossible in principle rather than merely unimplemented, and it is the assumption every comparable validation library makes. The same argument covers the load-order precondition above: a module that evaluates first chooses what `INTRINSICS` captures, and nothing inside the package can reach code that ran before the package existed.
285
+
286
+ The hardening that exists for that adversary anyway — `contain`, `INTRINSICS`, the module-scope membership functions, `pinMembers`, the indexed publication walks — **stays, raises attacker cost, and is not claimed to be complete.** Its sweeps in `tests/src/core/integration.test.ts` are regression guards over work already paid for, not acceptance gates: a newly discovered intrinsic vector is recorded as a boundary case rather than treated as a release blocker.
287
+
288
+ What IS guaranteed, with honest intrinsics and hostile DATA:
289
+
290
+ - **Guards are total.** Every `is*` and every combinator-built guard answers a `boolean` for any input — a throwing getter, a revoked or trap-throwing `Proxy`, a cycle, a 200,000-deep graph, a foreign realm, an exotic host — and never propagates a throw.
291
+ - **Published snapshots are frozen and faithful.** A builder freezes what it returns and copies what you hand it; `cloneShape` / `cloneSchema` / `cloneJSONValue` publish deeply frozen graphs that retain no caller reference, and a snapshot that cannot be faithful refuses instead of normalizing.
292
+ - **`is`, `parse`, `audit` and `explain` agree.** No input is certified clean by one door and refused by another: the laws in Domains hold for readable, stably-read values, and where a door must perform a read that can fail, every door that answers about the same value performs it.
293
+ - **Hostile data is refused with a coded `ContractError`.** Cycles, excessive depth, exotic objects, foreign realms, revoked proxies, throwing accessors and unstable reads reach a coded refusal or a documented non-match, never a raw host error and never an unbounded walk.
294
+ - **A shared reference costs one visit, a published bound, or nothing at all.** `COMPILE_DEPTH_LIMIT`, `GUARD_DEPTH_LIMIT`, `FAULT_LIMIT`, `INFER_DEPTH_LIMIT`, `INFER_BREADTH_LIMIT`, `CLONE_NODE_LIMIT` and `COMPILE_NODE_LIMIT` are the published bounds, and where a bound is the wrong instrument the walk carries an identity memo instead. Sharing arrives on BOTH sides and both are answered: `COMPILE_NODE_LIMIT` caps what a shared-child DECLARATION expands into (see Compilers), and `is`, `audit` and `explain` answer a shared-reference VALUE in one visit per (compiled node, object) pair however many paths reach that object. Both halves are needed: without the value-side memo an ordinary graph with several references per level — a few hundred bytes, no attacker, shared references are normal data — costs node reads exponential in its depth. A faulted node is re-walked at its new path, because a fault carries one, and stays bounded by `FAULT_LIMIT`. `cloneJSONValue` and `parse` deliberately still expand and each says so here: `cloneJSONValue` duplicates an alias by contract and caps that at `CLONE_NODE_LIMIT`, and `parse` materializes a tree — see the line below. The claim is about those doors, not about a guard a caller composes: nesting `arrayOf` twenty levels deep builds a walker of your own, and it pays per path.
295
+
296
+ What is NOT guaranteed, beyond the realm assumption above: a value whose observable reads CHANGE between two calls can leave any two-call law unsatisfied (see Domains), `Date` and `undefined` fall outside the round-trip law, and `schemaToShape`'s memo is ancestor-context-sensitive across graphs (see its row). Two more follow from the memo above and are named rather than left to be discovered. `parse` returns a TREE, so it pays for the tree its input expands into: eighteen shared arrays parse into 262,143 of them in about 370 ms, where `is`, `audit` and `explain` answer the same value in under a millisecond and `cloneJSONValue` refuses that exact graph at `CLONE_NODE_LIMIT`. That cost is the RESULT rather than the walk, which is why it carries no cap — a cap here would refuse a value the caller asked to be handed — so measure an untrusted graph's expansion before parsing it. And within ONE call, `is`, `audit` and `explain` read a given object once per compiled node rather than once per path, so a value whose reads change BETWEEN two reads of the same node can answer differently than it did when every path re-read it. Both are consequences of trading repeated reads for bounded work, and the trade is stated so it can be checked rather than discovered. A third limit belongs to the guards you compose YOURSELF: the memo above lives in a compiled artifact, so a chain you build by hand out of combinators — `arrayOf(arrayOf(...))` and its siblings — has no shared ledger between its independently constructed links and re-reads a shared object once per PATH. Measured: a depth-18 hand-composed chain over an 18-level shared graph answers in about 250 ms, growing fourfold every two levels, where the same value through `createContract` answers in under a millisecond. Compile the declaration when the value may share references; the compiled route is the one this bound covers.
297
+
298
+ ### Types
299
+
300
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
301
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
302
+ literal with a union's arms escaped as `\|`.
303
+
304
+ | Type | Kind | Shape | Summary |
305
+ | ------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
306
+ | `Failure` | interface | `{ success, error }` | Represents the discriminated failure branch of a `Result`. |
307
+ | `ArrayRead<T = unknown>` | interface | `{ entries, dense }` | Represents the owned result of reading one array through its reflected own-index lens. |
308
+ | `GuardShapeRead` | interface | `{ guards, names, optional, vocabulary }` | Represents the owned result of reading one guard shape and its optional-key mode. |
309
+ | `BoundsRead` | interface | `{ min?, max? }` | Represents a derived numeric bounds pair, either member absent. |
310
+ | `EntryCollectorFunction` | type | `(value: unknown, key: unknown) => void` | Represents the collector a captured `forEach` sweep invokes per entry. |
311
+ | `StringGuardOptions` | interface | `{ min?, max?, pattern? }` | Groups the options for the `stringOf` guard builder. |
312
+ | `FieldPath` | type | `string \| readonly string[]` | Addresses one field in a record: a single key, or an ordered list of keys to descend through nested objects. |
313
+ | `Guard` | type | `(value: unknown) => value is T` | Represents a runtime type guard: returns `true` when `value` satisfies `T` and narrows it. |
314
+ | `GuardType` | type | `G extends Guard<infer T> ? T : never` | Extracts the guarded type `T` from a `Guard<T>`. |
315
+ | `GuardsShape` | type | `Readonly<Record<string, Guard<unknown>>>` | Represents a mapping of string keys to guards. |
316
+ | `FromGuards` | type | `Readonly<{ [K in keyof G]: GuardType<G[K]> }>` | Resolves a `GuardsShape` to a readonly object type of its guarded property types. |
317
+ | `OptionalFromGuards` | type | `Readonly<{ [P in Exclude<keyof S, K[number]>]: FromGuards<S>[P] } & { [P in Extract<keyof S, K[number]>]?: FromGuards<S>[P] }>` | Mirrors `FromGuards`, but every key listed in `K` becomes a true optional member (`?`) rather than a required key widened with `\| undefined`. |
318
+ | `TupleFromGuards` | type | `Readonly<{ [K in keyof Ts]: GuardType<Ts[K]> }>` | Maps a tuple of element guards to a readonly tuple of their guarded types. |
319
+ | `UnionToIntersection` | type | `(U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never` | Converts a union type to an intersection type. |
320
+ | `IntersectionFromGuards` | type | `UnionToIntersection<GuardType<Gs[number]>>` | Intersects the types guarded by a tuple of guards — backs `intersectionOf`. |
321
+ | `Parser` | type | `(value: unknown) => T \| undefined` | Coerces an unknown value to `T`, or returns `undefined`. |
322
+ | `LiteralValue` | type | `string \| number \| boolean` | Represents a string, number, or boolean literal. |
323
+ | `Result` | type | `Success<T> \| Failure<E>` | Represents a discriminated union for operations that can succeed or fail without throwing. |
324
+ | `ReadValueOptions` | interface | `{ subject?, code?, context? }` | Represents optional diagnostic metadata for a required read. |
325
+ | `ContainOptions` | interface | `{ code?, context? }` | Represents optional diagnostic metadata for a public door's containment boundary. |
326
+ | `ShapeProperty` | interface | `{ key, child }` | Represents one captured property of an object shape, held as an ordered entry rather than as a `Map` pair. |
327
+ | `Success` | interface | `{ success, value }` | Represents the discriminated success branch of a `Result`. |
328
+ | `AnyConstructor` | type | `new (...args: unknown[]) => T` | Represents a constructor signature that produces instances of `T`. |
329
+ | `AnyFunction` | type | `(...args: unknown[]) => unknown` | Represents a function accepting any arguments and returning `unknown`. |
330
+ | `AnyAsyncFunction` | type | `(...args: unknown[]) => Promise<unknown>` | Represents an async function accepting any arguments and returning a `Promise`. |
331
+ | `ZeroArgFunction` | type | `() => unknown` | Represents a function accepting zero arguments and returning `unknown`. |
332
+ | `ZeroArgAsyncFunction` | type | `() => Promise<unknown>` | Represents an async function accepting zero arguments and returning a `Promise`. |
333
+
334
+ ### Classes
335
+
336
+ `ContractError` is documented in full under its own heading following this table.
337
+
338
+ | API | Kind | Summary |
339
+ | --------------- | ----- | -------------------------------------------------------------------------------------------- |
340
+ | `ContractError` | class | Carries a machine-readable contract category, optional context, and an exact optional cause. |
341
+
342
+ ### `ContractError`
343
+
344
+ `CONTRACT_ERROR_BRAND` is the registry-global symbol captured while `constants.ts` evaluates. The constructor stores the error itself under that key, and `isContractError` requires the descriptor value to be the value under inspection. That identity check keeps cross-copy recognition and refuses accidental property lookalikes and transparent wrappers: a proxy forwards a descriptor that stores its target, not the proxy. The registry makes the stamp forgeable by design. A complete `Error` subclass forgery with the exact name, a declared code, and its own identity stored under `Symbol.for('@orkestrel/contract.error')` passes recognition. The brand is therefore a cross-copy recognition marker, not proof that this package constructed the value.
345
+
346
+ The one error class thrown across this module — an `Error` subclass carrying a machine-readable `code`, optional structured `context`, and an exact optional `cause`, from [`errors.ts`](../src/core/errors.ts). Omitting `cause` creates no own cause property; supplying `cause: undefined` creates an own property whose value is exactly `undefined`; every other cause retains its identity. Both optional options are read as OWN properties and ownership is established before the value is read at all, so an inherited `cause` or `context` counts as omission: an unqualified read of an absent option would leave the container and land on `Object.prototype`, which any caller can write, and would let that caller decide what a refusal an engine authored carries. `code` is required by the options type, so an internal literal always carries it own; a caller who hands in a container that INHERITS `code` still gets the inherited value, because the type promised a value rather than an own property, and that caller is choosing what its own error carries. `name` is fixed to `'ContractError'`; `code` and `context` are readonly. The constructor stamps the global own-property brand `Symbol.for('@orkestrel/contract.error')`. `isContractError` requires that brand plus the native `Error` base, a prototype other than `Error.prototype`, the exact `ContractError` name, and a declared `ContractCode`. The global symbol registry makes recognition work across duplicate installations and ESM/CommonJS module copies at 0.0.13 or later. A copy earlier than 0.0.13 stamps no brand, so its errors remain outside the type. An ordinary `Error`, a plain object, or a partial property lookalike remains outside the type.
347
+
348
+ These refusal families may throw, and whenever they do they throw only this class: REQUIRED READS (`readValue` and the public inferer/helper/combinator/compiler readers layered over it — normally `structure` with `<reader>: <subject> could not be read`, while `RegExp` readers use `pattern`), shape CONSTRUCTION (every builder validates every runtime argument position before returning — `bound` / `range` / `empty` / `placement` / `pattern` / `literal` / `structure`), CLONING (`cloneJSONValue` / `cloneJSONRecord` for inexact JSON data, cycles, or hostile traversal; `cloneSchema` / `cloneShape` / `ownShape`, and `rawShape` through its snapshot — `clone` plus declaration-policy codes), VALIDATION (`validateShape` and `ShapeValidator` — `range` / `empty` / `placement` / `structure` / `literal` / `cycle` / `bound` / `pattern`), the COMPILATION gate (every `compile*` export plus `createContract` routes through that same `validateShape` — the same declaration-policy codes, plus `depth`), and GENERATION (`compileGenerator` on an unsatisfiable request — `generate`; `drawRandom` on a broken sample source — `random`). Every message opens with the reader that OWNS the rule it enforces, never the engine that happened to run it. A declaration rule belongs to the shared gate and reads `validateShape: …` wherever it is applied, including inside `ShapeCloner`, which enforces the same rules while capturing; `cloneShape: …` is reserved for the ownership rules the cloner itself owns — own data discriminants, inherited fields, accessors, read stability, unreadable property maps, and a failed snapshot; and `ShapeCloner.clone: …`, `SchemaCloner.clone: …`, `JSONCloner.clone: …` and `ShapeValidator.validate: …` name a refusal about the CALL rather than the declaration, such as reentry. One rule therefore has one diagnostic at each of those doors: `cloneShape`, `ownShape`, `validateShape`, `ShapeValidator`, every `compile*` export and `createContract` report the same malformed declaration with the same code and the same message, across every declaration-policy family the gate owns (`placement`, `range`, `bound`, `pattern`, `empty`, `literal`, `cycle`, `depth`, `structure`). That is a statement about those doors and those families, enforced by a sweep rather than asserted: it says nothing about a door outside the list. `createContract` observes its caller’s source twice — once as the declaration, once while cloning it — so a LIVE declaration that changes between those walks can be refused by ownership rather than by the gate, and each refusal names the boundary that owns the rule it broke. An error adopted by identity from another engine keeps the prefix that engine gave it. Hand-authored string declarations use the same unflagged-pattern policy as builders: a stable genuine `RegExp` carrying flags is a `pattern` refusal, and inline pattern constructs are the supported alternative. Total guards and optional readers use their non-throwing outcomes; `compileReporter` contains its diagnostic walk, while required `parse`/`audit` reads and schema inversion refuse traversal failure. Root ownership, including the frozen-state probe itself, is contained before standalone compilation begins: a revoked `Proxy`, throwing getter, or caller-thrown value becomes a coded `clone` / `structure` `ContractError`. Malformed containers, hostile proxies, and wrong primitives at any builder position become coded `ContractError` values. Every public door that can refuse runs its whole body through `contain`, which republishes anything that is not this class under the door's own name with the exact thrown value as `cause`; a door whose body cannot throw carries no boundary, because wrapping code that cannot fail misreports where the refusals are. A boundary placed per STATEMENT is only ever as complete as the last sweep, while a boundary at the door covers whatever the body reaches, enumerated or not. Its limits are named rather than promised away. A boundary covers a BODY, so it cannot reach a parameter-default initializer, which is evaluated in the function environment before the first statement runs: the one such default this package had (`compileGenerator`'s wall-clock seed) was moved into the contained body, and any future computed default belongs there too. And a boundary is not a fidelity guarantee: containment answers what a door may THROW, while what a door PUBLISHES under a redirect that lies instead of throwing is the separate job of `INTRINSICS`, the module-scope membership functions layered over it, and the indexed publication walks. Every such site is reached from the captured table — which is a claim a sweep checks, not a claim this sentence makes.
349
+
350
+ ```ts
351
+ import { ContractError, isContractError } from '@orkestrel/contract'
352
+
353
+ const error = new ContractError('Minimum exceeds maximum', {
354
+ code: 'range',
355
+ context: { path: ['properties', 'age'] },
356
+ })
357
+ isContractError(error) // true
358
+ ```
359
+
360
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
361
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
362
+ literal with a union's arms escaped as `\|`. A function row's `Shape` cell holds its signature, and a
363
+ guard row's the type it narrows to.
364
+
365
+ | API | Kind | Shape | Summary |
366
+ | ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
367
+ | `isContractError` | function | `ContractError` | Checks whether an unknown value is a `ContractError`. |
368
+ | `ContractCode` | type | `'bound' \| 'range' \| 'empty' \| 'placement' \| 'structure' \| 'literal' \| 'cycle' \| 'pattern' \| 'generate' \| 'random' \| 'clone' \| 'depth' \| 'expansion'` | Names the machine-readable category carried by a `ContractError`. |
369
+ | `CONTRACT_CODES` | const | `readonly ContractCode[]` | Lists every declared `ContractCode` refusal category, frozen. |
370
+ | `ContractErrorContext` | interface | `{ path?, shape?, limit?, received? }` | Represents the optional structured details carried by a `ContractError`. |
371
+ | `ContractErrorOptions` | interface | `{ code, context?, cause? }` | Represents the construction options for a `ContractError`. |
372
+
373
+ ### Cloners
374
+
375
+ `JSONCloner` is the public state-owning JSON engine. Its constructor only retains the source; the first `clone()` performs the iterative snapshot and settles once. A successful instance replays the exact same deeply frozen root without another source read, while a failed instance releases partial traversal working state and rethrows its exact class-owned `ContractError` without another read, retaining the source and exact error for replay. That terminal settlement is nonredirectable, which needs each of these: its ownership record and error construction dispatch only through intrinsics captured while the module evaluated, AND every optional diagnostic option is read as an own property, so a construction never consults a prototype chain the caller can write. Neither replacing an intrinsic after construction nor installing a `cause`, `context` or `path` accessor on `Object.prototype` can make the first call escape with a raw value or make the replay disagree with it — including when the caller arms the pollution from inside its own reflective trap, after the walk has begun. A redirected working-state member is contained instead, and settles as an ordinary owned refusal. Active reentry permanently poisons nested, outer, and later calls with one cause-free `JSONCloner.clone: JSON cloning may not be reentered` error (`clone`, `{ shape: 'json' }`), even when hostile source code catches the nested throw. Distinct instances are independent. `cloneJSONValue` constructs a fresh instance on every call, so every eager call re-observes its source and produces a distinct composite root or distinct diagnostic when identity is observable.
376
+
377
+ `SchemaCloner` is the corresponding public state-owning JSON Schema engine. Its inert constructor retains one schema graph; the first `clone()` performs an iterative identity-memoized snapshot and settles once. Success replays the exact deeply frozen root, preserving shared and cyclic edges; failure rethrows the exact class-owned `ContractError`. Both outcomes release traversal frames and the active memo through preconstructed replacement state before nonredirectable terminal publication, while retaining the source and exact terminal result. Nonredirectable carries the same requirements here, and the diagnostic `path` is read as an own property too, so a translated foreign failure reports no path rather than one a polluted prototype supplied. Active reentry permanently poisons nested, outer, and later calls with one cause-free `SchemaCloner.clone: schema cloning may not be reentered` error (`clone`, `{ shape: 'schema' }`), including when hostile source code catches the nested throw and continues. Enumeration refusal is cause-free; property-read refusal retains the exact thrown cause, including an explicit `undefined`; unexpected foreign failures are translated once. Only errors created by that instance replay as terminal errors. Distinct instances are independent, while `cloneSchema` constructs a fresh instance for every eager call.
378
+
379
+ `ShapeCloner` is the public state-owning contract-shape engine. Its source-only constructor is inert; the first `clone()` requires every node to satisfy the realm-neutral plain-record brand before discriminant observation, then iteratively captures and wires the graph, composes raw nodes through `SchemaCloner`, freezes the completed root, validates that exact root through `ShapeValidator`, and only then applies deferred source-fidelity refusal. Success and failure replay the exact terminal root or class-owned/adopted `ContractError` without rereading the source. Active reentry permanently poisons nested, outer, and later calls with one cause-free `ShapeCloner.clone: shape cloning may not be reentered` error (`clone`, `{ shape: 'shape' }`), including caught reentry. Only errors created by this instance or adopted directly from its schema cloner or validator may replay by identity; unexpected foreign failures become `cloneShape: failed to create an owned shape snapshot` with the exact cause. Terminal settlement releases graph-working state through preconstructed replacement state before nonredirectable terminal publication, while retaining the source and exact terminal result. Distinct instances are independent, while `cloneShape` constructs a fresh instance for every eager call.
380
+
381
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
382
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
383
+ literal with a union's arms escaped as `\|`. A class row's `Shape` cell holds the interface it
384
+ implements, or its constructor signature where it implements none.
385
+
386
+ | API | Kind | Shape | Summary |
387
+ | ----------------------- | --------- | ----------------------- | ------------------------------------------------------------------------- |
388
+ | `JSONCloner` | class | `JSONClonerInterface` | Owns the state of one exact JSON snapshot operation. |
389
+ | `JSONClonerInterface` | interface | `{} plus clone` | Settles one exact JSON snapshot of a retained source, then replays it. |
390
+ | `SchemaCloner` | class | `SchemaClonerInterface` | Owns the state of one JSON Schema snapshot operation. |
391
+ | `SchemaClonerInterface` | interface | `{} plus clone` | Settles one JSON Schema snapshot of a retained schema, then replays it. |
392
+ | `ShapeCloner` | class | `ShapeClonerInterface` | Owns the state of one contract-shape snapshot operation. |
393
+ | `ShapeClonerInterface` | interface | `{} plus clone` | Settles one contract-shape snapshot of a retained shape, then replays it. |
394
+
395
+ `cloneShape` is the fresh eager boundary over `ShapeCloner`: every call constructs a new class instance and invokes `clone()`, so separate calls re-observe the source and produce distinct composite roots or diagnostics when identity is observable.
396
+
397
+ `ownShape` returns a successful independent eager snapshot for both frozen and unfrozen sources. After failure it rethrows a non-`clone` `ContractError` or any failure for an unfrozen source. For a frozen source whose clone failure is `clone`-coded or foreign, it validates the source with a fresh `ShapeValidator`, prefers that validator's `ContractError` when present, and otherwise rethrows the original clone failure.
398
+
399
+ The machinery behind owned snapshots (see Shape builders, below) — from [`JSONCloner.ts`](../src/core/JSONCloner.ts), [`SchemaCloner.ts`](../src/core/SchemaCloner.ts), [`ShapeCloner.ts`](../src/core/ShapeCloner.ts), and the eager boundaries in [`cloners.ts`](../src/core/cloners.ts). The JSON cloner accepts only exact acyclic JSON data, rejects sparse or decorated arrays and non-data record properties without invoking accessors, and builds deeply frozen standard arrays plus null-prototype records. “Decorated” means the array own-key set contains anything other than intrinsic `length` and every canonical index, including an extra, substituted, symbol, hidden, or accessor key. Index writability and configurability are normalized rather than treated as JSON data, so frozen arrays and nonwritable data indices remain valid. Because JSON persistence is a tree, repeated noncyclic source aliases are duplicated into distinct equal output branches; active-path back-edges fail as cycles. `cloneJSONRecord` adds record-root validation over the same engine. `cloneSchema` preserves shared-child identity and closes cyclic schema edges onto its clone; `cloneShape` preserves sharing, carries one accepted declaration population into its clone, and runs the complete declaration gate on that carried clone before returning, so a cyclic shape is refused with the same `cycle` diagnosis as every other shape entry. A key literally named `__proto__` stays own data. Every hostile reflective operation is contained through the sanctioned total boundary, and so is every caller-reachable dispatch on the declaration gate's own path: `ShapeValidator.validate` and `validateShape` translate a failure they did not author into a coded `ContractError` carrying the exact thrown value, rather than rethrowing it verbatim. JSON reflection failures and schema enumeration failures remain cause-free. A schema property-read failure instead retains the exact thrown value as its cause, including an explicit `undefined`; caller-owned errors never become terminal errors by identity. Only the exact errors owned or explicitly adopted by an engine can replay by terminal identity.
400
+
401
+ | API | Kind | Summary |
402
+ | ------------------ | -------- | ---------------------------------------------------------------------------------------------- |
403
+ | `cloneJSONValue` | function | Deep-clones exact JSON data into an owned frozen snapshot. |
404
+ | `cloneJSONRecord` | function | Deep-clones an exact JSON object record into an owned frozen snapshot. |
405
+ | `cloneSchema` | function | Deep-clones a JSON Schema graph into an owned frozen snapshot. |
406
+ | `cloneShape` | function | Deep-clones a contract shape graph into an owned frozen snapshot. |
407
+ | `CLONE_NODE_LIMIT` | const | Caps at `262144` the number of nodes one JSON snapshot may produce, frozen. |
408
+ | `ownShape` | function | Takes ownership of a contract shape node as an independent `cloneShape` snapshot of its graph. |
409
+
410
+ This constructs a `JSONCloner` directly and clones a record through `cloneJSONRecord`, showing that each snapshot is independently owned.
411
+
412
+ ```ts
413
+ import type { JSONClonerInterface } from '@orkestrel/contract'
414
+ import { cloneJSONRecord, JSONCloner } from '@orkestrel/contract'
415
+
416
+ const settings = { enabled: true }
417
+ const cloner: JSONClonerInterface = new JSONCloner(settings) // no source read yet
418
+ const settingsClone = cloner.clone()
419
+ cloner.clone() === settingsClone // true — terminal success replays exactly
420
+
421
+ const clone = cloneJSONRecord({ primary: settings, fallback: settings })
422
+ clone.primary === clone.fallback // false — JSON tree branches are independently owned
423
+ Object.isFrozen(clone.primary) // true
424
+ ```
425
+
426
+ This constructs a `SchemaCloner` directly, showing that its `clone` replays a schema whose shared child keeps its graph identity.
427
+
428
+ ```ts
429
+ import type { JSONSchema, SchemaClonerInterface } from '@orkestrel/contract'
430
+ import { SchemaCloner } from '@orkestrel/contract'
431
+
432
+ const child: JSONSchema = { type: 'string' }
433
+ const schemaCloner: SchemaClonerInterface = new SchemaCloner({ anyOf: [child, child] })
434
+ const schema = schemaCloner.clone()
435
+ schema.anyOf?.[0] === schema.anyOf?.[1] // true — graph identity is preserved
436
+ schemaCloner.clone() === schema // true — terminal success replays exactly
437
+ ```
438
+
439
+ ### Shape builders
440
+
441
+ Declarative constructors for the `ContractShape` union (`src/core/shapers.ts`). The `deriveLengthBounds` and `deriveRangeBounds` rows sit in this section because schema inversion consumes them, and they live in `src/core/helpers.ts`: they build no shape, they reduce a keyword pair to a numeric bound. One shape compiles into a JSON Schema, a guard, a parser, a strict audit, a parse report, and a generator (see the compilers, below). Builders omit absent options from the produced shape object: an option left `undefined` is not present as a key, so `Object.keys`, `in` checks, and spreads see only the options actually provided.
442
+
443
+ **The snapshot-ownership model.** A builder freezes the node it returns and copies every collection you hand it — a `values` list, a `properties` map, a variant list, a `rawShape` fragment — while a `pattern` is captured and re-exposed as a fresh frozen `RegExp` per read, so editing your originals afterwards cannot reach the shape. `objectShape` enumerates a caller-owned property declaration once and carries that key/value snapshot. `cloneShape`, which must also validate a hand-authored graph, first requires every node to be a plain, null-prototype, or foreign-realm record before it reads the discriminant, then captures each declared field through own descriptors plus two agreeing reads before it builds the shell. Missing fields are carried as absent without a read; inherited fields and ordinary accessors are refused without invocation. The documented `pattern` accessor is the one exception, and its two frozen genuine-RegExp results must independently expose agreeing primitive-string `source` and `flags` pairs; no caller scalar object or conversion hook is retained. Structural children, literal values, variants, property maps, and raw-schema roots are then wired only from those captured references, never by rereading the source node. Property maps retain their separate stability mechanism: `cloneShape` compares exactly two caller enumerations and refuses second-population disagreement, while the first enumeration obtains every property child's own data descriptor and requires its value plus two reads to agree by identity. The complete declaration gate validates the carried cloned root; it does not repair or replace a captured population. Consequently, `createContract` reads a property entry exactly as often as `cloneShape` does — twice, and the two readings must agree — because it reaches the declaration the same way: there is no discarded pre-ownership walk, so there is no second caller population to disagree with the captured one. That single captured clone controls every artifact, an invalid captured population is refused by the gate that runs over the clone, and no third caller value read occurs. `ownShape` retains the already-performed `cloneShape` result for frozen and unfrozen inputs alike, so no caller-owned root or reference-bearing child is returned by identity. Thus a malformed value container, raw-schema child, discriminant, scalar, or structural slot cannot become plausible merely because copying would normalize it. A hand-authored `{ category: 'string', pattern }` node receives the same accessor-owned pattern snapshot as builder output and must likewise use an unflagged genuine local- or foreign-realm `RegExp`; inline constructs express the supported flag-like behavior. `createContract` takes its own `cloneShape` snapshot of the whole graph, so its `schema` / `is` / `parse` / `audit` / `explain` / `generate` are fixed at construction and cannot drift with a later edit to the shape you passed. The practical rule: build shapes with the builders, and treat a shape you assemble by hand as caller-owned until a compiler or `ownShape` has copied it.
444
+
445
+ | Builder | Kind | Summary |
446
+ | -------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
447
+ | `stringShape` | function | Builds a string `StringShape`. |
448
+ | `numberShape` | function | Builds a numeric `NumberShape`. |
449
+ | `integerShape` | function | Builds an integer `NumberShape` — forces `integer: true`. |
450
+ | `booleanShape` | function | Builds a `BooleanShape`. |
451
+ | `nullShape` | function | Builds a `NullShape`. |
452
+ | `literalShape` | function | Builds a literal shape from a fixed set of primitive values. |
453
+ | `arrayShape` | function | Builds an `ArrayShape` from an element shape. |
454
+ | `objectShape` | function | Builds an `ObjectShape` from a property map. |
455
+ | `recordShape` | function | Builds an open `ObjectShape` with no fixed properties — a dictionary. |
456
+ | `unionShape` | function | Builds a `UnionShape` from a list of variant shapes (`anyOf` in JSON Schema). |
457
+ | `oneOfShape` | function | Builds a `UnionShape` that emits `oneOf` (exactly one match) in JSON Schema. |
458
+ | `optionalShape` | function | Wraps a shape so it may be absent (`undefined`). |
459
+ | `nullableShape` | function | Wraps a shape so it may be `null`. |
460
+ | `jsonShape` | function | Builds a `JSONShape`. |
461
+ | `rawShape` | function | Builds a `RawShape` from a supported JSON Schema fragment. |
462
+ | `schemaToShape` | function | Converts a runtime `JSONSchema` value into a validating `ContractShape` — the inverse of `compileSchema`. Unlike direct `rawShape` construction, which rejects malformed supported-vocabulary keywords, this conversion is total and widens an inexpressible input to a valid raw `{}`. |
463
+ | `deriveLengthBounds` | function | Derives `min`/`max` shape bounds from a pair of non-negative-integer JSON Schema length keywords (`minLength`/`maxLength`, `minItems`/`maxItems`). |
464
+ | `deriveRangeBounds` | function | Derives `min`/`max` shape bounds from a pair of finite-number JSON Schema range keywords (`minimum`/`maximum`). |
465
+
466
+ Raw-schema validation is deliberately structural and vocabulary-domain validation, not a full JSON Schema solver. It checks that every keyword is supported, every keyword value has the declared runtime domain, arrays are dense and vocabularies unique where required, every member captured from a present `properties`, dense `anyOf`, or dense `oneOf` population is a plain record, patterns compile, and the graph stays acyclic and within the depth limit. Population is determined by membership, so a present member valued `undefined` is refused rather than erased as absence; omitted optional keywords, plus explicitly `undefined` `items` and `additionalProperties`, retain their absence behavior. It does not resolve cross-keyword contradictions such as `minLength: 5` with `maxLength: 1`, require each `required` name to appear in `properties`, enforce keyword/type coherence, compare `enum` members with `type`, or restrict `format` to a known vocabulary; those semantic interactions remain the responsibility of a full JSON Schema implementation.
467
+
468
+ `rawShape` first validates the caller-visible fragment, clones it exactly once, validates that exact owned clone, and returns that same frozen clone. A caller phase change that makes the captured population invalid is therefore refused; a valid captured population is the one published, and failures during the single clone retain the established `cloneSchema` diagnostic.
469
+
470
+ Direct declaration populations are dense data arrays too. A sparse literal is refused immediately with `validateShape: values must be a dense data array` at the container path `[…path, 'values']`; a sparse union is refused symmetrically with `validateShape: variants must be a dense data array` at `[…path, 'variants']`. Both are cause-free `structure` diagnostics, before any descriptor/stability walk. Raw `enum`, `required`, `anyOf`, and `oneOf` retain their existing dense-array vocabulary and apply it to the same bounded reflected snapshot.
471
+
472
+ `schemaToShape` is the sole entry point for the conversion. The walk behind it is interned, so the door's name is the only one a refusal ever carries and the caller reaches the host failure through one `cause`.
473
+
474
+ The precedence below assumes a readable node. A readable malformed keyword is ignored and widens according to the listed rule; a keyword access, enumeration, or recursive traversal that throws is not malformed schema vocabulary and is refused with `ContractError { code: 'structure', context: { shape: 'schema' } }`.
475
+
476
+ `schemaToShape`'s precedence, top-down at each node (every keyword read is type-guarded; a malformed keyword is IGNORED, not thrown): (1) `enum` (≥ 1 string/number/boolean entry) → `literalShape`. (2) `oneOf` (≥ 1 record entry) → `oneOfShape` over the recursed variants, PROVIDED the record-entry count is at or under `INFER_BREADTH_LIMIT`; over the cap, building a subset union would be strictly narrower than the schema's full union, so the node widens to `rawShape` instead of sampling a subset. (3) `anyOf` identically → `unionShape`, with the same over-cap widen-to-`rawShape` rule rather than a subset union. (4) `type: 'string'/'number'/'integer'/'boolean'/'null'` → the matching primitive shape, with `minLength`/`maxLength`/`minimum`/`maximum` bounds kept only when well-formed and non-contradictory (a malformed or `min > max` pair drops to unbounded — widening, never narrowing). (5) `type: 'array'` → `arrayShape`, recursing into a record-valued `items` (else `rawShape`), with `minItems`/`maxItems` bounds. (6) `type: 'object'` (or no `type`/`enum`/`oneOf`/`anyOf` but a record `properties`) → `objectShape`: a property not listed in `required` is wrapped `optionalShape`; `additionalProperties: false` closes, a record value recurses into it (`objectShape` validates extras against that shape directly — no widening needed), and `true` / ABSENT / anything malformed leaves it open (`true`) — absent matches JSON Schema's own default, and `valueToSchema` / `samplesToSchema` always emit the keyword explicitly, so an absent value only arises from a hand-written schema. When `properties` has MORE keys than `INFER_BREADTH_LIMIT`, the schema's own `additionalProperties` is OVERRIDDEN and forced open (`true`) regardless of `false` or a record value — a key dropped past the sampling cap was never checked against a closed or record-valued rest shape, so forcing the object open is the only sound widening — mirroring the inferers' own `truncated ? true : !closed` rule. (7) Everything else — `{}`, an unrecognized `type`, exhausted depth (`INFER_DEPTH_LIMIT`), or a cyclic re-encounter — widens to `rawShape` (NOT `jsonShape`: `{}` is JSON Schema’s accept-anything schema, and `rawShape` is its exact inverse — its guard accepts every defined value and it re-emits `{}` verbatim, whereas `jsonShape`’s `isJSONValue` guard would reject the exotic originals (`Map`, `Set`, a class instance, a function, `NaN`) whose inferred schema is exactly `{}`). A `WeakMap` memo (keyed by schema-node identity + remaining depth), mirroring the inferers, guards a shared-reference schema DAG against exponential re-conversion. **Its key does not carry the active-ancestor set, and that is observable**: a node first reached through a CYCLIC path is cached with the shape it widened to at the back-edge, and a later ACYCLIC path is served that cached shape instead of descending further. Two schemas differing only in which sibling holds the cyclic node therefore convert to different shapes. Every such difference is a WIDENING — an accept-anything `rawShape` — so no value is wrongly rejected and the round-trip law is unaffected; what it costs is determinism ACROSS graphs, not within one, since the same input always converts the same way. This is stated as a limit rather than repaired because both repairs (dropping the ancestor set, or threading a cycle-affected flag through three public signatures) change the published surface.
477
+
478
+ **Round-trip law:** for any READABLE value `v` — including `NaN`, `±Infinity`, a `Map`, a `Set`, a class instance, a function, a symbol, a bigint, and readable cyclic hosts — `compileGuard(schemaToShape(valueToSchema(v)))(v) === true`, with widening as the ONLY source of looseness, never narrowing. An unreadable host is refused before the law produces a schema. The law otherwise retains its three limits: JSON absence, `Date` serialization, and unstable reads between inference and validation. A widened node cannot be auto-generated: `createContract(schemaToShape(x)).generate()` throws when the conversion widened anywhere; its parser returns `undefined` for readable invalid input and propagates the shared coded refusal when a required read fails.
479
+
480
+ ```ts
481
+ import { samplesToSchema, schemaToShape, createContract } from '@orkestrel/contract'
482
+
483
+ const schema = samplesToSchema([
484
+ { id: 1, name: 'Ada' },
485
+ { id: 2, name: 'Grace' },
486
+ ])
487
+ const contract = createContract(schemaToShape(schema))
488
+ contract.parse({ id: 3, name: 'Alan' }) // { id: 3, name: 'Alan' }
489
+ contract.parse({ id: 'nope', name: 'x' }) // undefined
490
+ ```
491
+
492
+ ### Shape types
493
+
494
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
495
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
496
+ literal with a union's arms escaped as `\|`. A resolver whose value is a multi-branch
497
+ conditional carries none, and its `Summary` states what the resolution produces.
498
+
499
+ | Type | Kind | Shape | Summary |
500
+ | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
501
+ | `ContractShape` | type | `StringShape \| NumberShape \| BooleanShape \| NullShape \| LiteralShape \| ArrayShape \| ObjectShape \| UnionShape \| OptionalShape \| NullableShape \| JSONShape \| RawShape` | Describes a value declaratively — a declaration the shape builders build and the compilers turn into a guard, a parser, a JSON Schema, and a generator. |
502
+ | `StringShape` | interface | `{ category, min?, max?, pattern?, description? }` | Describes a string with optional length and pattern constraints. |
503
+ | `NumberShape` | interface | `{ category, min?, max?, integer?, description? }` | Describes a number with optional bounds; `integer` restricts to whole numbers. |
504
+ | `BooleanShape` | interface | `{ category, description? }` | Describes a boolean — accepts only `true` or `false`. |
505
+ | `NullShape` | interface | `{ category, description? }` | Describes a null value — accepts only `null`. |
506
+ | `LiteralShape` | interface | `{ category, values, description? }` | Describes a literal — accepts exactly one of a fixed set of primitive values. |
507
+ | `ArrayShape` | interface | `{ category, items, min?, max?, description? }` | Describes an array with an element shape and optional length bounds. |
508
+ | `ObjectShape` | interface | `{ category, properties, additionalProperties?, description? }` | Describes an object — a map of property names to child shapes. |
509
+ | `UnionShape` | interface | `{ category, variants, mode?, description? }` | Describes a union — accepts a value matching any one variant (first match wins). |
510
+ | `OptionalShape` | interface | `{ category, inner }` | Wraps an inner shape that may be absent (`undefined`). |
511
+ | `NullableShape` | interface | `{ category, inner }` | Wraps an inner shape that may be `null`. |
512
+ | `JSONShape` | interface | `{ category, description? }` | Describes a JSON passthrough — accepts any JSON value. |
513
+ | `RawShape` | interface | `{ category, schema }` | Describes a validated raw JSON Schema passthrough — embeds a supported schema fragment directly. |
514
+ | `Infer` | type | | Resolves the static TypeScript type a `ContractShape` describes. |
515
+ | `InferObject` | type | | Resolves `Infer` of an object shape's `properties` — the required keys, plus the `optional`-wrapped keys as optional members, plus the index-signature contribution of `additionalProperties` (see `InferIndex`). |
516
+ | `InferIndex` | type | | Computes the index-signature contribution of a pure record shape's `additionalProperties` — the `recordShape` case, where `properties` is empty. |
517
+ | `InferOpenIndex` | type | | Computes the index-signature contribution of a MIXED object shape's `additionalProperties` — one with both fixed `properties` and an open tail. |
518
+ | `InferMutable` | type | `{ -readonly [K in keyof Infer<S>]: Infer<S>[K] }` | Strips the TOP-LEVEL `readonly` modifiers from `Infer` (a shallow strip — nested object/array properties stay readonly) — for consumers writing the parsed value's own fields. |
519
+ | `InferUnion` | type | `V extends ReadonlyArray<infer U> ? (U extends ContractShape ? Infer<U> : never) : never` | Resolves `Infer` of a union shape's `variants` — the union of each variant's inferred type. |
520
+ | `StringShapeOptions` | interface | `{ min?, max?, pattern?, description? }` | Groups the options for `StringShape` (through `stringShape`). |
521
+ | `NumberShapeOptions` | interface | `{ min?, max?, integer?, description? }` | Groups the options for `NumberShape` (through `numberShape` / `integerShape`). |
522
+ | `BooleanShapeOptions` | interface | `{ description? }` | Groups the options for `BooleanShape` (through `booleanShape`). |
523
+ | `NullShapeOptions` | interface | `{ description? }` | Groups the options for `NullShape` (through `nullShape`). |
524
+ | `JSONShapeOptions` | interface | `{ description? }` | Groups the options for `JSONShape` (through `jsonShape`). |
525
+ | `LiteralShapeOptions` | interface | `{ description? }` | Groups the options for `LiteralShape` (through `literalShape`). |
526
+ | `ArrayShapeOptions` | interface | `{ min?, max?, description? }` | Groups the options for `ArrayShape` (through `arrayShape`). |
527
+ | `ObjectShapeOptions` | interface | `{ additionalProperties?, description? }` | Groups the options for `ObjectShape` (through `objectShape`). |
528
+ | `RecordShapeOptions` | interface | `{ description? }` | Groups the options for record shapes (through `recordShape`). |
529
+
530
+ ### Compilers
531
+
532
+ Turn one `ContractShape` into the six lockstep outputs — `schema` / `is` / `parse` / `audit` / `explain` / `generate` (`src/core/compilers.ts`). `createContract` is the one door in this section that returns an entity rather than a compiled projection, so it lives in `src/core/factories.ts` over the same engine. Two engines sit under those functions. `ShapeValidator` owns the sole stateful declaration walk; `validateShape` constructs a fresh validator as its eager function boundary, while `cloners.ts`, `ShapeCloner`, and the shape builders use the class directly so lower validation no longer imports the compiler module. `ContractCompiler` owns ownership, preparation, and the six artifact families; every function in this section is a real typed door over it that requests exactly the root it is named for, so asking for a guard never compiles a generator. LOCKSTEP here means DERIVED FROM ONE SNAPSHOT, not equal in what they accept: `createContract` compiles all six from a single owned copy of the declaration, so no later edit to the shape you passed can move one of them without the others. It does not mean the six accept the same values — deliberately, they do not (see Domains, below). The individual compilers return untyped runtime functions; `createContract` is the typed entry point — its `is` / `parse` / `generate` carry `Infer<S>` by inferring once, at the boundary (so the recursion stays cheap). `compileGuard` / `compileParser` / `compileReporter` / `compileAuditor` reuse the existing combinators and parsers rather than re-implementing them: `literalOf` IS the literal match at all four (one SameValueZero implementation, taking its vocabulary as an array), and each leaf's refinements (`min` / `max` / `pattern`) are read off the one shape node rather than restated per artifact — `compileGuard` and `compileParser` compose them through the **same** combinators (`stringOf` for a string's length and pattern, `boundsOf` for a number's value and an array's length), while `compileReporter` and `compileAuditor` check those same three against that same node inline, so each violated refinement can carry its own fault; the pattern test is the same flag-stripped owned `RegExp` in every artifact (`matchOf` for the two reports, the identical construction inside `stringOf` for the guard and parser). No artifact — not `compileGuard`, not `compileParser`, not `compileReporter`, not `compileAuditor` — holds a bound of its own to drift from the other three. What the four do NOT share is the leaf TYPE test: `compileGuard` and `compileAuditor` demand a `string`, `compileParser` and `compileReporter` accept whatever `parseString` coerces — which is where the two domains part company. Every entry point reaches the same declaration-rule set through validation or ownership, and `cloneShape` asks that claim of the carried cloned root after its node fields have completed descriptor/two-read capture and its property map has completed its separate enumeration and child-capture checks. The validator mirrors the ownership boundary by rejecting ordinary declared-field accessors before `Reflect.get`, while preserving the documented `pattern` exception. No entry can therefore launder a malformed property/variant/value container, discriminant, scalar accessor, vocabulary, raw-schema child, or structural child into a plausible contract. Every compiled object artifact — guard, parser, reporter, auditor, and the inference direction too — reads an object through the one `enumerableKeys` property view (own enumerable string keys, the set `JSON.stringify` serializes), so all of them see the SAME key set. What each does with an undeclared key in that set differs by design: for a CLOSED object `is` rejects the object, `audit` reports an `'extra'` fault at the key, `parse` drops the key WITHOUT reading it, `explain` says nothing about it, and `schema` forbids it with `additionalProperties: false`. For an OPEN one they all READ it, including under `additionalProperties: true` where nothing constrains the value: open means unconstrained, not unobserved, and the parser copies every such key into its result. Skipping that read on three of the four doors is how `is`, `audit` and `explain` all certified a value clean that `parse` then refused as unreadable.
533
+
534
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
535
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
536
+ literal with a union's arms escaped as `\|`. A function row's `Shape` cell holds its signature, and a
537
+ guard row's the type it narrows to. A class row's `Shape` cell holds the interface it
538
+ implements, or its constructor signature where it implements none.
539
+
540
+ | API | Kind | Shape | Summary |
541
+ | --------------------------- | --------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
542
+ | `ShapeValidator` | class | `ShapeValidatorInterface` | Validates one retained contract-shape source live on every call. |
543
+ | `ShapeValidatorInterface` | interface | `{ expansion } plus validate` | Validates one retained contract-shape source on demand. |
544
+ | `validateShape` | function | `(shape: ContractShape) => void` | Gates recursive compiler work on shape structure, depth, and cycles. |
545
+ | `compileGuard` | function | `<S extends ContractShape>(shape: S) => Guard<Infer<S>>` | Compiles a `ContractShape` into a runtime type guard. |
546
+ | `compileParser` | function | `<S extends ContractShape>(shape: S) => Parser<Infer<S>>` | Compiles a `ContractShape` into an input parser. |
547
+ | `compileSchema` | function | `(shape: ContractShape) => JSONSchema` | Compiles a `ContractShape` into a JSON Schema document. |
548
+ | `compileGenerator` | function | `<S extends ContractShape>(shape: S, random?: RandomFunction) => Infer<S>` | Compiles a `ContractShape` into a deterministic seed value. |
549
+ | `createContract` | function | `<S extends ContractShape>(shape: S) => ContractInterface<Infer<S>>` | Compiles a `ContractShape` into a `ContractInterface` — the lockstep outputs from one declaration, lockstep meaning derived from one owned snapshot rather than accepting the same values. |
550
+ | `ContractInterface` | interface | `{ schema, is } plus parse, audit, explain, generate` | Represents a compiled contract — the lockstep outputs derived from one shape. |
551
+ | `ContractCompiler` | class | `ContractCompilerInterface` | Owns one contract shape's artifacts and their bundle, compiled lazily. |
552
+ | `ContractCompilerInterface` | interface | `{ schema, guard, parser, auditor, reporter, generator, contract }` | Owns one contract shape's compiled artifacts plus their bundle, lazily. |
553
+ | `RandomFunction` | type | `() => number` | Represents a deterministic random source returning a value in `[0, 1)`. |
554
+ | `AuditorFunction` | type | `(value: unknown, path?: readonly string[]) => readonly AuditFault[]` | Represents a compiled strict-domain diagnostic — the shape of `compileAuditor` bound to one shape. |
555
+ | `ReporterFunction` | type | `(value: unknown, path?: readonly string[]) => readonly Fault[]` | Represents a compiled coercive-domain diagnostic — the shape of `compileReporter` bound to one shape. |
556
+ | `SeederFunction` | type | `(random?: RandomFunction) => T` | Represents a compiled seed-data source — the shape of `compileGenerator` bound to one shape. |
557
+ | `GENERATION_ATTEMPT_LIMIT` | const | `number` | Caps at `32` the number of candidate-generation attempts for a constrained generated value, frozen. |
558
+ | `COMPILE_DEPTH_LIMIT` | const | `number` | Caps at `512` the supported nesting depth of a compiled contract shape, frozen. |
559
+ | `COMPILE_NODE_LIMIT` | const | `number` | Caps at `16384` the number of nodes a compiled artifact may expand a shape into, frozen. |
560
+ | `PRESENCE_MASK_LIMIT` | const | `number` | Caps at `31` the number of object keys one compiled presence mask carries, frozen. |
561
+
562
+ `ContractCompilerInterface` declares no call-signature member, so it has no Methods table: its
563
+ whole surface is the readonly data properties — `schema` (a `JSONSchema`), `guard` (a
564
+ `Guard<Infer<S>>`), `parser` (a `Parser<Infer<S>>`), `auditor` (an `AuditorFunction`), `reporter`
565
+ (a `ReporterFunction`), `generator` (a `SeederFunction<Infer<S>>`), and `contract` (a
566
+ `ContractInterface<Infer<S>>`). `contract` is the frozen bundle whose own enumerable keys are
567
+ `schema`, `is`, `parse`, `audit`, `explain`, and `generate` in that order, each holding the exact
568
+ value the corresponding getter publishes — `contract.is` is exactly `compiler.guard`, by
569
+ identity rather than as a copy of it.
570
+
571
+ Compilation costs ONE ownership and ONE validation per call, not one per node. Every `compile*` entry and `createContract` construct a `ContractCompiler`, which owns the declaration once, validates that owned graph once, and indexes each unique node and structural edge once; the artifact families are postorder passes over that index. This is what replaced the arrangement where each recursive invocation re-ran `ownShape` AND `validateShape` over the subgraph it received — quadratic work for a linear declaration, and the reason a 129-node depth chain used to measure 6.3 ms of gate plus 7.9 ms of ownership and a 257-node chain 26.0 + 41.9 ms. A 30-alias depth-100 declaration now compiles a guard in 3 ms and a whole contract in 4 ms, against 640 ms and 1.87 s before. `createContract` precompiles every artifact, so `audit`, `explain` and `generate` re-walk and re-gate nothing on a later call either; `contract.audit` and `compileAuditor` are the same compiled function reached by different names. A compiled artifact is no longer a TREE either. Each family holds one entry per unique node and a parent points at its children, so a shared child is compiled once and the emitted schema preserves that sharing — which is why the cap boundary stopped being expensive: `createContract` over the two-edge-per-level DAG at the 16,383-node boundary now takes under a millisecond where it took 1,342 ms, because it compiles fourteen nodes rather than sixteen thousand. Cost tracks AUTHORED nodes and edges instead: measured here, a depth-100 chain and a 30-alias depth-100 staircase answer every door in 1–5 ms, and a flat 10,001-node object takes 52–68 ms per artifact and 110 ms for a whole contract. One level past the cap boundary — 32,767 emitted nodes over thirty-one authored ones — still refuses in about two milliseconds with code `expansion`, because the count is measured over the captured graph rather than by walking the expansion. What the cap now protects is the consumer's side of the artifacts rather than the compiler's: `generate` materializes the whole tree, and so does serializing the schema. The JSON cloner is capped for the opposite reason — it DUPLICATES a shared alias by contract rather than re-walking it: see `CLONE_NODE_LIMIT`. The `samplesToSchema` family is not on this list and was never meant to be reachable: its record path carried neither an ancestor set nor a memo, so an ordinary shared reference bought `k^depth` visits; it now memoizes a single-row slot on `(row, remaining depth)` exactly as the record branch of `valueToSchema` does. Everything above is the DECLARATION side, and for one release that was the only side measured. A compiled artifact applies each child artifact once per OCCURRENCE, which is right for a tree and wrong for a graph, so a value whose levels each held two references to one object was walked once per PATH: twenty-two shared arrays against a twenty-three-node chain of `arrayShape` — zero aliases in the declaration, every published limit satisfied — cost 524,286 node reads, 4.4 s for `is` and 8.4 s for `audit`, growing fourfold per two levels, while the same declaration over a TREE value answered instantly and `valueToSchema` answered the same graph in 4 ms because it already memoized. The verdict families now carry a per-CALL identity memo keyed by `(compiled node, value object)`, and the same value now costs thirty-six reads and under a millisecond. These details are exact rather than incidental. The guard reuses either answer while the auditor and reporter reuse only the CLEAN one, because a fault carries the path it was found at and emptiness carries nothing — a faulted node is re-walked and bounded by `FAULT_LIMIT` instead. Each node's memo is tagged with the call that filled it and nothing else releases it, so an answer never survives into a later call where the caller may have changed the value. And a leaf is not tracked at all: it descends into no child, so tracking one would buy nothing and would replace the package's own guards and parsers in the artifacts a leaf-rooted declaration publishes. `parse` is deliberately absent from that list, because its result IS the expansion; the threat model names what that costs.
572
+
573
+ String and array length bounds deliberately use the builders' FULL rule — every present bound is a non-negative safe integer — rather than merely checking finiteness. A finiteness-only gate would close the `NaN` / infinity bypass but still admit hand-authored negative, fractional, and unsafe-integer length keywords that no builder can produce and that are not valid JSON Schema length bounds. Matching the builders costs compatibility only for those already-malformed hand-authored shapes; it preserves every legitimate builder output and keeps guard, parser, audit, and schema semantics on one domain.
574
+
575
+ > A shape nesting a `rawShape` or a pattern-constrained `stringShape` still compiles cleanly (`compileSchema` / `compileGuard` / `compileParser` all succeed) — only `generate()` throws at CALL time, once it walks down into that leaf, because a `rawShape`'s embedded schema is arbitrary and a pattern the generator cannot satisfy has no auto-generatable sample.
576
+
577
+ The depth gate is why a pathological shape fails as a diagnosis rather than as a stack overflow — and it holds whether you reach the compilers through `createContract` or call one directly:
578
+
579
+ ```ts
580
+ import type { ContractShape } from '@orkestrel/contract'
581
+ import { arrayShape, compileGuard, stringShape, validateShape } from '@orkestrel/contract'
582
+
583
+ let deep: ContractShape = stringShape()
584
+ for (let level = 0; level < 600; level += 1) deep = { category: 'array', items: deep }
585
+
586
+ validateShape(deep) // throws a ContractError with code 'depth'
587
+ compileGuard(deep) // the same throw — every compile* entry fidelity-checks ownership, then gates
588
+ ```
589
+
590
+ Every builder validates every runtime argument position before freezing its result. At every options position, a primitive or readable array/class instance throws a `structure` `ContractError` saying that the builder's options must be a plain record. A failure while reading any option key that builder consumes, or while snapshotting the options record, routes through the shared constructor as `<builder>: options could not be read`; no failed read becomes an absent option. Each consumed option is read once and its one non-`undefined` answer is copied into the snapshot as own enumerable data, including inherited and non-enumerable answers; unrelated properties remain irrelevant. `{}` is accepted and constrains nothing. Invalid bounds use the total `preview` diagnostic, so even a hostile `Symbol.toPrimitive` receives the existing `bound` refusal instead of leaking its raw error. The wider construction gate also covers `description` domains, child-shape slots, finite/ranged bounds, non-empty dense unique literal/union vocabularies, integer-range satisfiability, optional placement, and `rawShape`'s recursive supported-schema vocabulary. A malformed builder call therefore throws a coded `ContractError` at construction instead of leaking a raw host error or returning a node that only a later compiler rejects. Hand-authored declarations remain checked at ownership and by `validateShape` before artifact recursion.
591
+
592
+ ```ts
593
+ import type { ContractShape } from '@orkestrel/contract'
594
+ import { compileGuard, objectShape } from '@orkestrel/contract'
595
+
596
+ const source: { readonly child: ContractShape } = JSON.parse('{}')
597
+ objectShape({ child: source.child }) // throws ContractError { code: 'structure', context: { path: ['properties', 'child'] } }
598
+ ```
599
+
600
+ ### Inferers
601
+
602
+ The **reverse** direction of `compileSchema` (`src/core/inferers.ts`): instead of emitting a `JSONSchema` from a developer-authored `ContractShape`, these infer a `JSONSchema` at runtime from an unknown/opaque value — a database row, a parsed endpoint payload — so an inferred schema can flow through the same `schemaToParameters` → `createTool` → MCP `inputSchema` bridge a hand-declared shape does. Unlike a shape tree (finite, developer-authored, never cyclic), a runtime value may be arbitrarily deep, wide, or self-referential, so every inferer here is bounded on three axes: a `WeakSet` ancestor set (cycle safety), a decrementing depth budget (`INFER_DEPTH_LIMIT` default), and a per-container sampling cap (`INFER_BREADTH_LIMIT` default) — never a type parameter, conditional type, mapped type, or overload. Readable unsupported values may widen where documented; a failed read throws the shared coded refusal instead of producing a schema.
603
+
604
+ One deliberate asymmetry with the compiled direction: an inferred schema is a PLAIN, MUTABLE result, not an owned frozen snapshot. `compileSchema` and `contract.schema` are frozen because they must stay in lockstep with a guard and parser compiled beside them; `valueToSchema` / `samplesToSchema` answer a question about one value and hand you the answer to edit — annotate a `description`, drop a column, merge two fragments. When you need the ownership guarantee, take it explicitly: `cloneSchema(schema)` for a frozen copy, `rawShape(schema)` to embed one in a shape, or `createContract(schemaToShape(schema))` for the full compiled bundle.
605
+
606
+ The canonicalization leaves (`canonicalStringify`, `encodeLeaf`) and the format-classification leaves (`classifyFormat`, `matchesISOInstant`) are listed here beside the inferers that consume them, and they live in `src/core/helpers.ts`: each is a pure encoding or classification leaf that emits no schema.
607
+
608
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
609
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
610
+ literal with a union's arms escaped as `\|`. A function row's `Shape` cell holds its signature, and a
611
+ guard row's the type it narrows to.
612
+
613
+ | API | Kind | Shape | Summary |
614
+ | ---------------------- | --------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
615
+ | `valueToSchema` | function | `(value: unknown, options?: ValueToSchemaOptions) => JSONSchema` | Infers a `JSONSchema` for one unknown value — the reverse direction of `compileSchema`. |
616
+ | `samplesToSchema` | function | `(samples: readonly unknown[], options?: ValueToSchemaOptions) => JSONSchema` | Infers a `JSONSchema` from a set of example values — the multi-example counterpart of `valueToSchema` (for example inferring one schema from several database rows). |
617
+ | `unifySchemas` | function | `(schemas: readonly JSONSchema[]) => JSONSchema` | Unifies a list of inferred `JSONSchema` fragments into one schema. |
618
+ | `canonicalStringify` | function | `(value: unknown) => string \| undefined` | Renders a value as a deterministic, key-sorted JSON string — or `undefined` when it has no faithful JSON encoding. |
619
+ | `encodeLeaf` | function | `(value: unknown) => string \| undefined` | Encodes one non-container value the way JSON encodes it, or `undefined` when JSON cannot encode it at all. |
620
+ | `buildSampleMemo` | function | `() => SampleMemo` | Builds one empty `SampleMemo` node. |
621
+ | `readSampleMemo` | function | `(memo: SampleMemo, reader: string) => SampleMemo` | Checks that a value really is a `SampleMemo` before a walk stores a published schema in it. |
622
+ | `inferPrimitiveEnum` | function | `(values: readonly unknown[], limit: number) => JSONSchema \| undefined` | Infers an `{ enum: [...] }` fragment for a low-cardinality, repeated primitive slot — the multi-sample-only counterpart to `stringToFormat` (`valueToSchema` never emits `enum`). |
623
+ | `stringToFormat` | function | `(value: string) => SchemaFormat \| undefined` | Classifies a string against the `SchemaFormat` vocabulary. |
624
+ | `classifyFormat` | function | `(value: string) => SchemaFormat \| undefined` | Classifies an already-bounded string against the pattern-only and calendar-checked `SchemaFormat` vocabulary. |
625
+ | `samplesToFormat` | function | `(values: readonly unknown[]) => SchemaFormat \| undefined` | Classifies a list of sample values against the `SchemaFormat` vocabulary, requiring unanimity. |
626
+ | `matchesISOInstant` | function | `(value: string) => boolean` | Checks whether a supported ISO-8601 date or date-time names a real instant. |
627
+ | `ValueToSchemaOptions` | interface | `{ limits?, closed?, format?, enum? }` | Groups the options for `valueToSchema` / `samplesToSchema`. |
628
+ | `ValueToSchemaLimits` | interface | `{ depth?, properties? }` | Holds the per-walk budgets `ValueToSchemaOptions` groups under `limits`. |
629
+ | `SampleMemo` | interface | `{ rows, schemas }` | Holds the per-walk memo the multi-sample walk behind `samplesToSchema` owns, keyed by the ORDERED identities of the rows a slot collected. |
630
+ | `sanitizeDepth` | function | `(value: number \| undefined) => number` | Resolves a caller's depth budget to one the traversal can actually survive. |
631
+ | `sanitizeBudget` | function | `(value: number \| undefined, fallback: number) => number` | Sanitizes a user-supplied inference budget (`limits.depth` / `limits.properties`) to a finite non-negative integer, selecting a valid fallback for anything else. |
632
+ | `INFER_DEPTH_LIMIT` | const | `number` | Caps at `32` the object/array nesting depth `valueToSchema` walks, frozen. |
633
+ | `INFER_BREADTH_LIMIT` | const | `number` | Caps by default at `256` the number of object properties / array elements `valueToSchema` samples per container, frozen. |
634
+ | `INFER_ENUM_LIMIT` | const | `number` | Caps by default at `12` the number of distinct values a multi-sample slot may hold before enum inference gives up and falls back to a bare `type`, frozen. |
635
+ | `FORMAT_MAX_LENGTH` | const | `number` | Caps at `128` the string length `stringToFormat` attempts to classify, frozen. |
636
+ | `FORMAT_PATTERNS` | const | `Readonly<Record<'uuid' \| 'email' \| 'uri', RegExp>>` | Holds the pure-regex matchers backing `stringToFormat`'s pattern-only formats (`uuid` / `email` / `uri`), frozen as data. |
637
+
638
+ Canonicalization classifies every non-null object at the read boundary before choosing a traversal. Arrays retain the dense indexed path; the shared realm-neutral `matchesRecordBrand` rule selects sorted own keys for ordinary, null-prototype, and foreign-realm plain records; every other readable exotic object — including a class whose prototype a caller reparented to `null` — keeps the existing `JSON.stringify` fallback. A failed prototype inspection is unreadable structure, reported as `canonicalStringify: value could not be read`.
639
+
640
+ > **MCP caveat.** A non-object root schema — `valueToSchema('hello')` infers `{ type: 'string' }` — is structurally accepted by `schemaToParameters` (any `JSONSchema` is a record), but MCP clients expect an object-shaped `inputSchema`. Wrap a non-object schema with `schemaToObject` (a single required `value` property) before advertising it as a tool's parameters.
641
+
642
+ ```ts
643
+ import { samplesToSchema, schemaToParameters, valueToSchema } from '@orkestrel/contract'
644
+
645
+ // One opaque row → a schema, ready for the schemaToParameters → createTool bridge.
646
+ const row = { id: 1, name: 'Ada', tags: ['admin', 'staff'] }
647
+ valueToSchema(row)
648
+ // { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' },
649
+ // tags: { type: 'array', items: { type: 'string' } } },
650
+ // required: ['id', 'name', 'tags'], additionalProperties: false }
651
+
652
+ // Several rows → a key is required only when every row has it.
653
+ samplesToSchema([{ id: 1 }, { id: 2, name: 'Ada' }])
654
+ // { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' } },
655
+ // required: ['id'], additionalProperties: false }
656
+
657
+ schemaToParameters(valueToSchema(row)) // the open record a tool advertises as `parameters`
658
+ ```
659
+
660
+ ### Reporting
661
+
662
+ One diagnostic for each artifact that answers yes-or-no. `compileReporter` is the counterpart of `compileParser`: instead of a coerced value it returns every structured `Fault` a value has against a shape — MIRROR-PARSE semantics, so it reuses the exact leaf parsers/guards `compileParser` uses and the soundness invariant `explain(v).length === 0 ⟺ parse(v) !== undefined` holds structurally for READABLE input (`explain` mirrors `parse`'s coercion leniency, not the stricter `is`). `compileAuditor` is the counterpart of `compileGuard`: instead of a `boolean` it returns every `AuditFault` a value has against the STRICT domain, reusing the leaf guards `compileGuard` uses, so `audit(v).length === 0 ⟺ is(v)`. Each report mirrors exactly one artifact, and neither mirrors both, because `is` and `parse` accept different values — which is the subject of the next section. Before either pair compiles, `validateShape` rejects structural and bound-domain malformations; the laws are evaluated only for a valid declaration. Both biconditionals span two separate calls, so both require STABLE reads; the parse biconditional additionally requires the read to succeed rather than raise its coded refusal (see Domains).
663
+
664
+ A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an
665
+ optional member and `plus` introducing its call-signature members, and a type alias's own type
666
+ literal with a union's arms escaped as `\|`. A function row's `Shape` cell holds its signature, and a
667
+ guard row's the type it narrows to.
668
+
669
+ | API | Kind | Shape | Summary |
670
+ | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
671
+ | `compileAuditor` | function | `(shape: ContractShape, value: unknown, path?: readonly string[]) => readonly AuditFault[]` | Audits a value against the strict acceptance domain of a `ContractShape`. |
672
+ | `compileReporter` | function | `(shape: ContractShape, value: unknown, path?: readonly string[]) => readonly Fault[]` | Compiles a `ContractShape` into a structured fault report for a value — the diagnostic counterpart of `compileGuard` / `compileParser`. |
673
+ | `buildStringFaults` | function | `(shape: StringShape, value: string, path: readonly string[], pattern?: RegExp) => readonly Fault[]` | Builds the refinement faults a string value has against a `StringShape`. |
674
+ | `buildNumberFaults` | function | `(shape: NumberShape, value: number, path: readonly string[]) => readonly Fault[]` | Builds the refinement faults a number value has against a `NumberShape`. |
675
+ | `buildArrayFaults` | function | `(shape: ArrayShape, length: number, path: readonly string[]) => readonly Fault[]` | Builds the length faults an array has against an `ArrayShape`. |
676
+ | `selectClosestFaults` | function | `<T extends AuditFault>(reports: ReadonlyArray<readonly T[]>) => readonly T[]` | Selects the report of the variant that came closest to matching. |
677
+ | `shapeToKind` | function | `(shape: ContractShape) => FaultKind` | Projects a `ContractShape` to the `FaultKind` it describes. |
678
+ | `preview` | function | `(value: unknown) => string` | Renders an unknown value as a short, safe, TOTAL string for a `Fault`'s `received` field. |
679
+ | `FAULT_LIMIT` | const | `number` | Caps at `64` the number of `Fault` / `AuditFault` entries a single `explain` or `audit` report ever returns, frozen. |
680
+ | `PREVIEW_LIMIT` | const | `number` | Caps at `64` the character length of a `preview`-rendered string, frozen. |
681
+ | `Fault` | type | `{ reason: 'type', path, expected, received } \| { reason: 'missing', path, expected } \| { reason: 'constraint', path, expected, constraint, limit?, received } \| { reason: 'variant', path, variants } \| { reason: 'oneOf', path, matched }` | Represents a single structured parse-failure diagnostic — one entry of an `ContractInterface.explain` report. |
682
+ | `ExtraFault` | interface | `{ reason, path }` | Represents a key present on a value that its closed object shape does not declare. |
683
+ | `AuditFault` | type | `Fault \| ExtraFault` | Covers every fault an audit reports — the parse faults plus undeclared keys. |
684
+ | `FaultKind` | type | `'string' \| 'number' \| 'integer' \| 'boolean' \| 'null' \| 'literal' \| 'array' \| 'object' \| 'union' \| 'json'` | Names the kind of value a `Fault` expected — the shape-projected counterpart of a `ContractShape`'s `category`. |
685
+ | `FaultConstraint` | type | `'min' \| 'max' \| 'pattern' \| 'integer'` | Names the refinement a `Fault` of reason `'constraint'` violates. |
686
+
687
+ #### How a union is audited and reported
688
+
689
+ An `anyOf` union stops at the FIRST variant that reports nothing, in declaration order, and runs no later variant plan. `is` and `parse` make the same stop at the first accepting variant, so `is`, `parse`, `audit` and `explain` agree on a value one variant accepts and a later one cannot read: a refusal a later variant would have raised, such as an object variant's prototype probe, is never reached.
690
+
691
+ An `anyOf` union with no matching variant reports one `'variant'` summary plus the closest variant's own faults — fewest faults, ties favouring the lowest index. A `oneOf` union runs every variant plan, because its verdict is the match count rather than the first acceptance, and reports `'oneOf'` with the raw guard-match count; a count of `0` also appends the closest variant's faults, and a count of `2` or more stands alone. A value a later `oneOf` variant cannot read therefore still reaches the same coded refusal.
692
+
693
+ Arrays report from the shared owned sparse snapshot: an owned hole retains its per-index fault, a hostile absent source index is never read, and a failed snapshot retains the root array type fault. The auditor stops once `FAULT_LIMIT` faults exist, so even a native-maximum sparse length performs no absent source-index reads.
694
+
695
+ #### Supplying a rebuilt pattern
696
+
697
+ `buildStringFaults` applies whatever pattern it is handed and never re-reads `shape.pattern`, so a supplied pattern decides the match, the `limit` text, and whether a pattern fault is reported at all. Supply the rebuild of this same shape's own pattern, built through `readPattern`, and the report matches the omitted form, `limit` text included, because `readPattern` preserves `source` exactly. A `g` or `y` pattern makes repeated answers for one value disagree, so do not supply one.
698
+
699
+ Stripping `g` and `y` is what makes a rebuild reusable: it carries no `lastIndex` an answer could move. `compileAuditor` and `compileReporter` therefore read the declaration's `pattern` accessor once while the plan is built and hand the rebuild down as the trailing argument, instead of minting a `RegExp` per answered value. Left to rebuild, the helper asks the shape's `pattern` accessor once for the presence test that decides whether a pattern was declared at all, and once more for the rebuild that decides the match.
700
+
701
+ A leaf that declares no refinement has no refinement question, so its compiled plan answers empty past the type test without entering the helper. The helper's whole body reads the caller's SHAPE, so it runs through the same `readValue` boundary `shapeToKind` uses. The compiled doors gate a non-`RegExp` `pattern` and a non-finite bound long before the helper sees them, so the package's own path never arrives off-domain — but the door is published, and a shape a `StringShape` annotation merely vouched for reaches it unchecked.
702
+
703
+ ### Domains
704
+
705
+ A compiled contract describes TWO sets of values, not one. `is` and `schema` describe the canonical domain — the values the declaration literally admits. `parse` is a map INTO that domain whose preimage is deliberately larger: it coerces `'36'` into `36` and drops a closed object's undeclared keys, so it accepts inputs `is` rejects and answers with a value `is` accepts. `explain` diagnoses the map; `audit` diagnoses the domain.
706
+
707
+ The laws that bind those domains:
708
+
709
+ ```text
710
+ audit(v).length === 0 ⟺ is(v)
711
+ explain(v).length === 0 ⟺ parse(v) !== undefined
712
+ parse(v) !== undefined ⟹ is(parse(v))
713
+ ```
714
+
715
+ Under the module-wide READABLE and STABLE definitions at the top of this guide, all three laws require stable reads, and the two parse laws additionally require readable input. Each relates two separate calls, and every call reads the value it is handed, so each holds for a value whose observable reads succeed and do not change between calls. A failed required read raises the shared coded refusal instead of producing the `undefined` result used for honest invalidity, and the read population is the same at every door: a read one door performs and another skips is a two-call law broken in one call, which is what an unread open-object extra and `parseRecord`'s eager whole-record probe each produced. A getter that answers `'allowed'` on its first read and `42` on its second, or a `Proxy` whose traps change behavior mid-flight, can leave `audit` empty and still fail `is` — the audit read one value and `is` read another. No law spanning two calls can promise otherwise, and no artifact re-reads a value to close the gap. `Object.freeze` alone does not establish those conditions because it is shallow and does not stabilize accessors. `explain`'s invariant carries both preconditions; `audit`'s carries stability for the identical two-call reason.
716
+
717
+ The ordering between the two reports follows from those three rather than standing as a fourth law: `audit(v).length === 0 ⟹ explain(v).length === 0`. Every value in the canonical domain is inside `parse`'s preimage, so a clean audit implies a clean explain; the converse fails for exactly the inputs `parse` had to work on. Reach for `audit` when you need to know what `parse` silently repaired, and for `explain` when you need to know why it gave up.
718
+
719
+ `parse` therefore is not the identity function on the values `is` already accepts. It differs in three ways:
720
+
721
+ - **Coercion.** `'36'` parses to `36` against an `integerShape`, and a string that trims to a declared literal parses to that literal. The input fails `is` and earns a `'type'` fault from `audit`; `explain` reports nothing, because nothing failed the parse.
722
+ - **Dropped extras.** A key a closed object shape does not declare is dropped from the parsed result. `is` rejects the object, `audit` reports one `'extra'` fault at the key, `schema` forbids it with `additionalProperties: false`, and `explain` stays silent — the parser repaired it, so there is nothing to explain.
723
+ - **A null-prototype copy.** The compiled object parser assembles its result on `Object.create(null)` and copies the declared keys into it, so `parse` returns a NEW null-prototype record and never the record you handed it — `contract.parse(v) !== v` holds even when `contract.is(v)` was already `true`. The copy satisfies `is` (`isRecord` accepts a `null` prototype directly) and is not frozen; the cloners build null-prototype records for the same reason — a key literally named `__proto__` has to land as own data instead of mutating a prototype. An array shape likewise returns a fresh standard array. A leaf returns its input by identity, and a union returns a guard-valid value unchanged — its identity pass runs before any coercion — so the rebuild belongs to the object and array branches, not to every `parse`.
724
+
725
+ ```ts
726
+ import { createContract, integerShape, objectShape } from '@orkestrel/contract'
727
+
728
+ const contract = createContract(objectShape({ age: integerShape() }))
729
+ const input = { age: 36 }
730
+
731
+ contract.is(input) // true — already in the canonical domain
732
+ contract.parse(input) === input // false — an object parse always rebuilds
733
+ Object.getPrototypeOf(contract.parse(input)) // null
734
+ ```
735
+
736
+ ## Methods
737
+
738
+ The public methods of each behavioral interface — one table per type, keyed by its backticked name, every call-signature member listed (its `readonly` data members, `schema` / `is`, stay in the Surface row above). `ContractInterface` has no implementing class: `createContract` builds it as a plain object whose shape conforms to the interface exactly, so the table below is its per-instance surface (`AGENTS.md`, Documentation contract).
739
+
740
+ #### `JSONClonerInterface`
741
+
742
+ | Method | Returns | Summary |
743
+ | ------- | ----------- | --------------------------------------------------------------- |
744
+ | `clone` | `JSONValue` | Clones the retained source into exact, deeply frozen JSON data. |
745
+
746
+ #### `SchemaClonerInterface`
747
+
748
+ | Method | Returns | Summary |
749
+ | ------- | ------------ | -------------------------------------------------------------------------- |
750
+ | `clone` | `JSONSchema` | Clones the retained schema into a deeply frozen identity-preserving graph. |
751
+
752
+ #### `ShapeClonerInterface`
753
+
754
+ | Method | Returns | Summary |
755
+ | ------- | --------------- | ------------------------------------------------------------------------- |
756
+ | `clone` | `ContractShape` | Clones the retained shape into a deeply frozen identity-preserving graph. |
757
+
758
+ This constructs a `ShapeCloner` directly, showing that its `clone` replays the same owned shape on a repeated call.
759
+
760
+ ```ts
761
+ import type { ShapeClonerInterface } from '@orkestrel/contract'
762
+ import { ShapeCloner, stringShape } from '@orkestrel/contract'
763
+
764
+ const shapeCloner: ShapeClonerInterface = new ShapeCloner(stringShape({ pattern: /^ready$/ }))
765
+ const owned = shapeCloner.clone()
766
+ shapeCloner.clone() === owned // true — terminal success replays exactly
767
+ ```
768
+
769
+ #### `ShapeValidatorInterface`
770
+
771
+ | Method | Returns | Summary |
772
+ | ---------- | ------- | ----------------------------------------- |
773
+ | `validate` | `void` | Validates the retained shape declaration. |
774
+
775
+ `ShapeValidatorInterface` also carries one readonly data property, `expansion`: the number of
776
+ nodes the last successful `validate()` found the retained declaration expands into, one per node
777
+ per incoming edge, and `undefined` both before the first successful pass and after a failed one,
778
+ because neither measured one. `validateShape` reads it to apply `COMPILE_NODE_LIMIT`, and
779
+ `refuseExpansion` refuses an absent measurement rather than reading it as a small count.
780
+
781
+ ##### Diagnostic precedence and reentry
782
+
783
+ Immediate depth outranks deferred structure, cycle, and domain diagnoses. Within a string declaration the fixed domain order is invalid `min`, invalid `max`, flagged pattern, then contradictory range.
784
+
785
+ Every nested and outer call inside an active pass shares the exact reentry poison object, which carries no own cause. Cleanup restores idle state, so a later independent call observes the source again. A failed pass, including a caught-reentry-poisoned outer pass, leaves `expansion` undefined, and a later successful pass replaces it.
786
+
787
+ The whole traversal is contained, and its cleanup builds its active-path set from an intrinsic captured at module evaluation, so no caller-reachable dispatch on the path can put a raw value through this door. A contained failure this class did not author is translated into `validateShape: shape reflection failed` (code `structure`, root path) carrying the exact thrown value as its cause.
788
+
789
+ #### `ContractInterface`
790
+
791
+ | Method | Returns | Summary |
792
+ | ---------- | ----------------------- | ------------------------------------------------------------------------ |
793
+ | `parse` | `T \| undefined` | Coerces a readable value to the contract's type, or returns `undefined`. |
794
+ | `audit` | `readonly AuditFault[]` | Reports every strict fault a value has against this contract. |
795
+ | `explain` | `readonly Fault[]` | Reports every structured parse fault a value has against this contract. |
796
+ | `generate` | `T` | Produces deterministic seed data for this contract. |
797
+
798
+ ## Contract
799
+
800
+ These invariants hold across `src/core` ↔ `contract.md`:
801
+
802
+ 1. **DOC ↔ SOURCE bijection.** Every `function` / `type` row in the `## Surface` tables is a real export of the contract source tree, and every contract-module export appears as a Surface row — exhaustive, both directions (`AGENTS.md`, Documentation contract). Adding, renaming, or removing a guard breaks the parity gate until the doc is reconciled.
803
+ 2. **Guards are total.** `.claude/rules/patterns.md` § Validation and contracts requires it: every guard takes one `unknown`, returns a `boolean` type predicate, and **never throws** — adversarial input yields `false`. The only deferral is `lazyOf`, whose thunk runs per call; `whereOf` / `lazyOf` / `transformOf` contain a callback throw as a non-match through the core `attempt` helper.
804
+ 3. **Parse ↔ guard soundness.** `.claude/rules/patterns.md` § Validation and contracts mandates it. On readable input, each standalone leaf parser (`parseString`, …) pairs with the guard for its **output type**: a guard-valid input is returned unchanged (by identity, never rejected), and every non-`undefined` output satisfies that type guard. Coercion of otherwise-invalid inputs is a bonus on top, not a violation; a failed required read is a coded refusal, not an `undefined` parse result. The **compiled** contract goes further: `compileParser` (and thus `createContract`'s `parse`) re-applies every leaf REFINEMENT after coercion through the same combinators (`stringOf` / `boundsOf`) `compileGuard` uses — so a non-`undefined` `contract.parse` always satisfies `contract.is`, refinements (`min` / `max` / `pattern`) included. That law is about parse's OUTPUT. Its readable INPUT domain is deliberately wider than `is` — a coercible leaf, a closed object's extra key — and no amount of shared machinery closes that gap, because it is the feature. What cannot drift is `compileGuard` and `compileParser`, both compiled from one snapshot; what differs, permanently, is the set each accepts (see Domains). `audit` is the report for the stricter of the two.
805
+ 4. **Types are the source of truth.** `Guard`, `Parser`, and the guard-shape types are declared in [`types.ts`](../src/core/types.ts) first; guards and parsers conform to them, never the reverse.
806
+ 5. **`createContract` validates before it compiles.** The declaration is owned once and that OWNED graph is validated once, before any artifact is built, and the same is true at every `compile*` entry — a malformed shape (a structural child that is not a shape, `min > max`, a non-finite number bound, an empty integer range, an empty literal/union, a literal shape holding a non-finite number value, an `optionalShape` placed anywhere but a direct object-property value, a structural cycle, or nesting past `COMPILE_DEPTH_LIMIT`) throws a coded `ContractError` immediately instead of silently producing a wrong guard, parser, schema, audit, report, or generator. `optionalShape` is legal in exactly one position: as the value of an object property. ONE population, one rule set: ownership refuses a malformed structural slot, scalar field, or bound rather than normalizing it, so the graph the gate judges is the graph the artifacts compile from — there is no earlier reading of the caller's live source that is validated and then thrown away.
807
+ 6. **DOC ↔ SOURCE method bijection.** Every behavioral interface's `## Methods` table lists exactly its public methods (call-signature members) — exhaustive, both directions — and each implementing class exposes the same public methods, no more (`AGENTS.md`, Documentation contract). A renamed / added / removed method breaks the gate until the table is reconciled.
808
+ 7. **Compilation owns its input.** A builder freezes what it produces, copies what you hand it, and re-exposes a `pattern` as a fresh frozen `RegExp` per read; every `compile*` entry point takes its argument through `ownShape`, which always returns an independent clone, and `createContract` snapshots unconditionally. Ownership refuses a non-record node before discriminant normalization and retains only primitive-string RegExp `source` / `flags` pairs. A shape you keep a reference to can never change what an already-compiled artifact does, and a compiled `schema` is deeply frozen — so the six outputs stay in lockstep with the declaration they came from, lockstep meaning derived from that one snapshot rather than agreeing on which values to accept.
809
+
810
+ The `parseJSON` / `parseJSONAs` text boundary is **lazy by default**: keep the result unknown, validate only a supplied shape, or read fields individually. Whole-tree work is explicit through the shipped `isJSONValue`, fixed-cap `isBoundedJSONValue` / `isBoundedJSONRecord`, `parseJSONValue`, `cloneJSONValue`, and record-root `cloneJSONRecord`; `JSONRecord` is the reusable record-root type. A dedicated `JSONArray` alias and broad deep JSON-Schema validators / `JSONSchemaDefinition` remain omitted; compose any narrower contract a consumer actually needs.
811
+
812
+ ## Patterns
813
+
814
+ ### Capturing synchronous outcomes losslessly
815
+
816
+ `attempt` records one synchronous callback invocation without interpreting the result. `Result<T>` resolves to `Result<T, unknown>` through the safe default, so the failure branch must be narrowed before member access. Domain boundaries can preserve that unknown value as an exact cause. Promises and thenables remain ordinary return values; handle their later settlement separately.
817
+
818
+ ```ts
819
+ import { attempt, ContractError } from '@orkestrel/contract'
820
+
821
+ const reason = Object.freeze({ category: 'offline' })
822
+ const failure = attempt(() => {
823
+ throw reason
824
+ })
825
+ if (!failure.success) {
826
+ const error = new ContractError('Read failed', { code: 'structure', cause: failure.error })
827
+ Object.is(error.cause, reason) // true
828
+ }
829
+
830
+ const promise = Promise.resolve(42)
831
+ const pending = attempt(() => promise)
832
+ pending.success && pending.value === promise // true — settlement was not observed
833
+ ```
834
+
835
+ ### Narrowing `unknown`
836
+
837
+ Guard a value against each candidate type in turn, narrowing it before use.
838
+
839
+ ```ts
840
+ import { isFiniteNumber, isRecord, isString } from '@orkestrel/contract'
841
+
842
+ function describe(value: unknown): string {
843
+ if (isString(value)) return value.toUpperCase() // value: string
844
+ if (isFiniteNumber(value)) return value.toFixed(2) // value: number (no NaN / Infinity)
845
+ if (isRecord(value)) return Object.keys(value).join(',') // value: Record<string, unknown>
846
+ return 'other'
847
+ }
848
+ ```
849
+
850
+ ### Composing with `recordOf` / `arrayOf` / `unionOf`
851
+
852
+ Build a complex guard out of leaf guards — never hand-roll the structural walk. `recordOf` is **exact** (extra keys fail), and the shape it took is reusable: `pickOf` / `omitOf` derive a related guard from it without restating fields.
853
+
854
+ ```ts
855
+ import {
856
+ arrayOf,
857
+ isNumber,
858
+ isString,
859
+ literalOf,
860
+ pickOf,
861
+ recordOf,
862
+ unionOf,
863
+ } from '@orkestrel/contract'
864
+
865
+ const userShape = {
866
+ id: isString,
867
+ age: isNumber,
868
+ role: literalOf('admin', 'member', 'guest'),
869
+ tags: arrayOf(isString),
870
+ }
871
+ const isUser = recordOf(userShape)
872
+ isUser({ id: 'u1', age: 36, role: 'admin', tags: [] }) // true
873
+ isUser({ id: 'u1', age: 36, role: 'admin', tags: [], extra: true }) // false (exact — no extra keys)
874
+
875
+ // Derive a narrower guard from the same shape — no field repetition.
876
+ const isUserRef = recordOf(pickOf(userShape, ['id', 'role'])) // Guard<{ id: string; role: 'admin' | … }>
877
+
878
+ const isId = unionOf(isString, isNumber) // Guard<string | number>
879
+ ```
880
+
881
+ ### Accepting foreign interface implementations with `objectOf`
882
+
883
+ Use `objectOf` for values returned through a foreign interface. It checks only the declared members, admits unknown members, and reads through the prototype chain. Arrays remain outside this object contract.
884
+
885
+ ```ts
886
+ import { isBoolean, objectOf } from '@orkestrel/contract'
887
+
888
+ class ForeignResult {
889
+ get conclusion(): boolean {
890
+ return true
891
+ }
892
+ }
893
+
894
+ const isResult = objectOf({ conclusion: isBoolean })
895
+ isResult(new ForeignResult()) // true
896
+ isResult({ conclusion: true, metadata: 'retained' }) // true
897
+ isResult([]) // false
898
+ ```
899
+
900
+ ### Recursive guards with `lazyOf`
901
+
902
+ `lazyOf` is the sanctioned recursion entry point — the thunk defers construction so a self-referential guard never references itself before it exists.
903
+
904
+ ```ts
905
+ import type { Guard } from '@orkestrel/contract'
906
+ import { arrayOf, isNumber, lazyOf, orOf } from '@orkestrel/contract'
907
+
908
+ // A number-tree: a number, or an array of trees.
909
+ const isNumberTree: Guard<unknown> = orOf(isNumber, arrayOf(lazyOf(() => isNumberTree)))
910
+ isNumberTree([1, [2, 3], 4]) // true
911
+ isNumberTree(['x']) // false
912
+ ```
913
+
914
+ ### Guards narrow, parsers coerce
915
+
916
+ A guard rejects a wrong-typed value outright, while a `*Field` parser reads a nested path and coerces it.
917
+
918
+ ```ts
919
+ import { isString, parseIntegerField, parseStringField } from '@orkestrel/contract'
920
+
921
+ isString(36) // false — a guard never converts
922
+
923
+ // `*Field` parsers resolve a nested path (a single string is ONE key, no dot-split).
924
+ const data = { user: { profile: { name: 'Ada', age: '36' } } }
925
+ parseStringField(data, ['user', 'profile', 'name']) // 'Ada'
926
+ parseIntegerField(data, ['user', 'profile', 'age']) // 36 (coerced from '36')
927
+ ```
928
+
929
+ ### Parsing JSON safely
930
+
931
+ The boundary is `parseJSONAs` (validate a known shape in one step) or `parseJSON` + the `parse*Field` readers (parse once, then pull only what you need — never walking the whole document).
932
+
933
+ ```ts
934
+ import {
935
+ arrayOf,
936
+ isString,
937
+ JSON_SCHEMA_TYPES,
938
+ parseEnumField,
939
+ parseJSON,
940
+ parseJSONAs,
941
+ parseRecord,
942
+ parseRecordField,
943
+ recordOf,
944
+ } from '@orkestrel/contract'
945
+
946
+ // 1. Validate a known shape — only the guard's shape is walked.
947
+ const isConfig = recordOf({ host: isString, tags: arrayOf(isString) })
948
+ parseJSONAs('{"host":"localhost","tags":["a"]}', isConfig) // { host: 'localhost', tags: ['a'] }
949
+ parseJSONAs('nope', isConfig) // undefined — never throws
950
+
951
+ // 2. Or parse once, then read fields lazily — no full-tree validation, including JSON Schema.
952
+ const blob = parseRecord(parseJSON('{"schema":{"type":"object","properties":{}}}'))
953
+ if (blob) {
954
+ parseEnumField(blob, ['schema', 'type'], JSON_SCHEMA_TYPES) // 'object' (a JSONSchemaType)
955
+ parseRecordField(blob, ['schema', 'properties']) // {} (a nested record), or undefined
956
+ }
957
+ ```
958
+
959
+ ### Checking structural JSON safely
960
+
961
+ `matchesJSONValue(entry, ancestors)` is the cycle-safe structural JSON predicate used internally by `isJSONValue`. Pass the `unknown` candidate as `entry` and the active parent path as `ancestors: WeakSet<object>`; readable input returns a `boolean`, while a failed direct traversal gets the shared coded refusal. `isJSONValue` owns the outer guard boundary that converts that refusal to `false`.
962
+
963
+ ```ts
964
+ import { matchesJSONValue } from '@orkestrel/contract'
965
+
966
+ matchesJSONValue({ nested: [1, 'x', null] }, new WeakSet()) // true
967
+ ```
968
+
969
+ ### Declaring a shape
970
+
971
+ Declare an object shape from the builders, then derive its static type with `Infer`.
972
+
973
+ ```ts
974
+ import type { Infer } from '@orkestrel/contract'
975
+ import {
976
+ arrayShape,
977
+ integerShape,
978
+ literalShape,
979
+ objectShape,
980
+ optionalShape,
981
+ stringShape,
982
+ } from '@orkestrel/contract'
983
+
984
+ const user = objectShape({
985
+ name: stringShape({ min: 1 }),
986
+ age: integerShape({ min: 0, max: 120 }),
987
+ role: literalShape(['admin', 'member', 'guest']),
988
+ tags: arrayShape(stringShape()),
989
+ bio: optionalShape(stringShape()), // may be absent
990
+ })
991
+
992
+ type User = Infer<typeof user>
993
+ // { readonly name: string; readonly age: number; readonly role: 'admin' | 'member' | 'guest';
994
+ // readonly tags: readonly string[]; readonly bio?: string }
995
+ ```
996
+
997
+ The compilers turn this one declaration into a JSON Schema, a guard, a parser, a strict audit, a parse report, and a generator — see the compilers section.
998
+
999
+ ### Validating a live shape source
1000
+
1001
+ `ShapeValidator` is useful when one retained caller-owned declaration must be checked more than once. Its constructor is inert; every `validate()` is a new observation, and within one call each unique node is observed exactly once however many positions it occupies. `validateShape(shape)` remains the equivalent one-shot eager function.
1002
+
1003
+ ```ts
1004
+ import type { ContractShape, ShapeValidatorInterface } from '@orkestrel/contract'
1005
+ import { ShapeValidator, validateShape } from '@orkestrel/contract'
1006
+
1007
+ const shape: ContractShape = { category: 'string', min: 1 }
1008
+ const validator: ShapeValidatorInterface = new ShapeValidator(shape) // no shape read yet
1009
+
1010
+ validator.validate() // live pass succeeds
1011
+ Reflect.set(shape, 'min', -1)
1012
+ validator.validate() // throws ContractError { code: 'bound' }
1013
+ Reflect.set(shape, 'min', 1)
1014
+ validator.validate() // fresh recovery pass succeeds
1015
+
1016
+ validateShape(shape) // constructs a fresh validator and validates eagerly
1017
+ ```
1018
+
1019
+ ### Compiling a contract
1020
+
1021
+ `createContract` is the typed entry point — one shape in, the six lockstep outputs out, on a single object.
1022
+
1023
+ ```ts
1024
+ import {
1025
+ createContract,
1026
+ integerShape,
1027
+ objectShape,
1028
+ seededRandom,
1029
+ stringShape,
1030
+ } from '@orkestrel/contract'
1031
+
1032
+ const user = createContract(objectShape({ name: stringShape({ min: 1 }), age: integerShape() }))
1033
+
1034
+ user.is({ name: 'Ada', age: 36 }) // true — a typed guard (narrows to Infer<typeof shape>)
1035
+ user.parse({ name: 'Ada', age: '36' }) // { name: 'Ada', age: 36 } — coerces, or undefined
1036
+ user.parse({ name: '', age: 36 }) // undefined — '' violates name min:1 (parse enforces refinements, like is)
1037
+ user.explain({ name: '', age: 36 }) // [{ reason: 'constraint', path: ['name'], expected: 'string', constraint: 'min', limit: 1, received: '""' }]
1038
+ user.schema // the owned, deeply frozen { type: 'object', properties: { … }, required: ['name', 'age'], additionalProperties: false }
1039
+ user.generate(seededRandom(42)) // reproducible seed data; omit the arg for a wall-clock-seeded source
1040
+ ```
1041
+
1042
+ ### Auditing an undeclared key
1043
+
1044
+ This audits a value against a closed object shape, showing that `parse` drops an undeclared key that `audit` still reports.
1045
+
1046
+ ```ts
1047
+ import { createContract, objectShape, stringShape } from '@orkestrel/contract'
1048
+
1049
+ const contract = createContract(objectShape({ id: stringShape() }))
1050
+ const value = { id: 'a', debug: true }
1051
+
1052
+ contract.is(value) // false
1053
+ contract.parse(value) // { id: 'a' }
1054
+ contract.audit(value) // [{ reason: 'extra', path: ['debug'] }]
1055
+ contract.explain(value) // []
1056
+ ```
1057
+
1058
+ Reach for `ContractCompiler` directly when you want ONE artifact, or
1059
+ want the declaration owned and validated once and then to pay for artifacts as
1060
+ you ask for them. `createContract` is that class with all six requested:
1061
+
1062
+ ```ts
1063
+ import type { ContractCompilerInterface } from '@orkestrel/contract'
1064
+ import { ContractCompiler, objectShape, stringShape } from '@orkestrel/contract'
1065
+
1066
+ const shape = objectShape({ id: stringShape({ min: 1 }) })
1067
+ const compiler: ContractCompilerInterface<typeof shape> = new ContractCompiler(shape)
1068
+ // Nothing has been read yet — construction observes the declaration not at all.
1069
+
1070
+ compiler.guard({ id: 'a' }) // true; the first read owns and validates, once
1071
+ compiler.guard === compiler.guard // true — every getter replays its exact artifact
1072
+ compiler.contract.is === compiler.guard // true — the bundle holds these exact values
1073
+ ```
1074
+
1075
+ One declaration; the schema, guard, parser, both reports, and the generator are all derived from one owned snapshot of it, so no later edit to the shape can move one of them without the others. Derived together is not the same as equal, though, and the block above is the proof: `is` rejects the undeclared key, `schema` forbids it, `audit` names it, `parse` drops it, and `explain` has nothing to say. See Domains for the three laws that hold between them.
1076
+
1077
+ When you want one artifact, hold the artifact rather than the compiler. A compiler releases its working set — the owned graph, the node index, the order, and every family plan — after every family exists, so a compiler read for one artifact and then kept holds all of it for as long as you keep the compiler. Each compiled artifact closes over the child entries its family needed while that family was built, so it answers on its own and outlives the compiler that produced it. The following block reads one guard and keeps no reference to the compiler behind it:
1078
+
1079
+ ```ts
1080
+ import { ContractCompiler, objectShape, stringShape } from '@orkestrel/contract'
1081
+
1082
+ // The compiler is never named: the guard is what leaves the expression, and the
1083
+ // compiler it came from is unreachable the moment that expression finishes.
1084
+ const isTicket = new ContractCompiler(objectShape({ id: stringShape({ min: 1 }) })).guard
1085
+
1086
+ isTicket({ id: 'T-1' }) // true — a compiled artifact carries its own plan
1087
+ isTicket({ id: '' }) // false — an empty id fails the min:1 refinement
1088
+ ```
1089
+
1090
+ `createContract` is written the same way, so a contract it returns holds its own values and no route back to the compiler that built them. Part of the declaration travels with those values: the `audit` and `explain` functions close over the owned leaf and array nodes whose bounds they report, and an array node carries the subgraph under its `items` field.
1091
+
1092
+ ### From an existing API/DB to an MCP tool
1093
+
1094
+ `samplesToSchema` with `format` and `enum` turned on infers a richer schema from a handful of rows than the bare defaults — string columns that unanimously look like dates/UUIDs/emails gain a `format` keyword, and low-cardinality repeated string/number columns gain an `enum` list, both of which flow VERBATIM to the model reading the tool's `inputSchema`. `schemaToObject` then guarantees an object root before `schemaToParameters` narrows it to the open record a tool advertises.
1095
+
1096
+ ```ts
1097
+ import { samplesToSchema, schemaToObject, schemaToParameters } from '@orkestrel/contract'
1098
+
1099
+ const rows = [
1100
+ {
1101
+ id: '550e8400-e29b-41d4-a716-446655440000',
1102
+ status: 'active',
1103
+ joined: '2024-01-15',
1104
+ },
1105
+ {
1106
+ id: 'c56a4180-65aa-42ec-a945-5fd21dec0538',
1107
+ status: 'inactive',
1108
+ joined: '2024-02-02',
1109
+ },
1110
+ {
1111
+ id: '9b2e8f14-3c7a-4d21-9f6e-2a1b8c4d5e6f',
1112
+ status: 'active',
1113
+ joined: '2024-03-10',
1114
+ },
1115
+ ]
1116
+
1117
+ const schema = samplesToSchema(rows, { format: true, enum: true })
1118
+ // { type: 'object', properties: {
1119
+ // id: { type: 'string', format: 'uuid' },
1120
+ // joined: { type: 'string', format: 'date' },
1121
+ // status: { enum: ['active', 'inactive'] } },
1122
+ // required: ['id', 'joined', 'status'], additionalProperties: false }
1123
+
1124
+ const parameters = schemaToParameters(schemaToObject(schema)) // already object-rooted — schemaToObject is a no-op here
1125
+ ```
1126
+
1127
+ Wiring this into an actual MCP tool crosses package boundaries: `@orkestrel/tool`'s `createTool` accepts the same `parameters` record this schema resolves to, and `@orkestrel/mcp` renames `parameters` → `inputSchema` with zero transform when it registers the tool — so whatever keywords `samplesToSchema` emits here (`format`, `enum`, `description`) reach the model reading the tool definition verbatim; there is no server-side stripping or reinterpretation. Three things to keep in mind before wiring real data through this path:
1128
+
1129
+ - **Pre-convert `bigint` fields.** `JSON.stringify` throws on a `bigint`, and `valueToSchema` / `samplesToSchema` themselves infer `{}` for a `bigint` leaf (it is not JSON-representable) — convert an ID or counter column to a `number` or a decimal `string` before sampling it, or the column infers as accept-anything instead of a typed leaf.
1130
+ - **A non-object root still needs `schemaToObject`.** Sampling a column of bare values (not rows) infers a non-object schema (`{ type: 'string' }`, an `enum`-only fragment, …); `schemaToObject` wraps it under a single required `value` key so the wrapped payload matches the shape a tool call actually sends — read the argument back out at `value`, not at the schema's own root.
1131
+ - **An inferred contract validates but does not generate.** `schema` / `is` / `audit` / `explain` remain available on an inferred shape, and `parse` returns `undefined` for readable invalid input while preserving the shared coded refusal for a failed required read. `generate()` throws a `generate` `ContractError` as soon as it walks into any node the conversion widened to `rawShape` — and widening is the normal case for inferred schemas (a `{}` fragment, an unrecognized `type`, an over-cap union, exhausted depth, a cyclic re-encounter). Treat an inferred contract as a validator; keep seed data on a hand-declared shape.
1132
+
1133
+ The inferred schema is not only an advertised `inputSchema` — `schemaToShape` turns it back into a `ContractShape`, so the SAME inference also gives the tool a runtime validator for incoming call arguments (`createContract(schemaToShape(schema)).parse(args)`), with no separate hand-written contract to keep in sync.
1134
+
1135
+ **Full loop — infer, validate, reject:**
1136
+
1137
+ ```ts
1138
+ import { samplesToSchema, schemaToShape, createContract } from '@orkestrel/contract'
1139
+
1140
+ const rows = [
1141
+ { id: 1, name: 'Ada', role: 'admin' },
1142
+ { id: 2, name: 'Grace', role: 'member' },
1143
+ ]
1144
+ const schema = samplesToSchema(rows)
1145
+ const contract = createContract(schemaToShape(schema))
1146
+
1147
+ contract.parse({ id: 3, name: 'Alan', role: 'guest' })
1148
+ // { id: 3, name: 'Alan', role: 'guest' } — in-shape, accepted
1149
+
1150
+ contract.parse({ id: 'nope', name: 'x', role: 'y' })
1151
+ // undefined — out-of-shape, rejected
1152
+
1153
+ contract.explain({ id: 'nope', name: 'x', role: 'y' })
1154
+ // [{ reason: 'type', path: ['id'], expected: 'integer', received: '"nope"' }]
1155
+ ```
1156
+
1157
+ ### Practices
1158
+
1159
+ - **Guards narrow, parsers coerce.** `isNumber('36')` is `false`. Need `'36'` → `36`? Use `parseNumber`.
1160
+ - **`isNumber` accepts `NaN`; reach for `isFiniteNumber`** (or `isInteger`) when `NaN` / `±Infinity` must be rejected.
1161
+ - **`isObject` is broad, `isRecord` is strict.** Arrays and ordinary class instances satisfy `isObject` but fail `isRecord` — use `isRecord` for plain config / JSON-style objects. `isRecord` is a structural brand, not a provenance check, so a class whose prototype has been forged into a realm prototype — with the seven mandated names carried as function-valued own data properties — passes it; see `matchesRecordBrand` for that residual and its exact cost.
1162
+ - **`recordOf` is exact.** Extra keys fail by default; declare optional keys with a key list or `true`, and derive related shapes with `pickOf` / `omitOf`.
1163
+ - **`objectOf` is open.** Use it for objects or callables a foreign interface returns when only the declared members belong to this package's check.
1164
+ - **Use `lazyOf` for self-referential guards** — never reference a guard inside its own definition without it.
1165
+ - **JSON text parsing is lazy by default.** Use `parseJSONAs` with a composed guard or read a `parseJSON` result field-by-field when that is sufficient. Choose `isJSONValue`, fixed-cap `isBoundedJSONValue` / `isBoundedJSONRecord`, `parseJSONValue`, `cloneJSONValue`, or record-root `cloneJSONRecord` only when an explicit deep whole-tree guard, bounded guard, parser, or owned snapshot is required. `JSONRecord` serves real record-root consumers; a dedicated `JSONArray` alias and broad deep JSON-Schema validation remain outside the surface.
1166
+
1167
+ ## Tests
1168
+
1169
+ - [`tests/guides.test.ts`](../tests/guides.test.ts) — the `## Surface` ↔ `src/core` bijection (value and type exports), the `## Methods` ↔ implementing-class bijection read from the real prototypes, and the equality gate: every `Summary` cell against its declaration's description paragraph, the titled `Compiling a contract` fence against the `@example` block of that title (pinned so the titled pair cannot be retired silently), and the README pitch against this guide's tagline. It also runs the flagship fences and asserts the values their comments claim.
1170
+ - [`tests/src/core/JSONCloner.test.ts`](../tests/src/core/JSONCloner.test.ts) — direct root-imported `JSONCloner`/interface contract: inert construction, exact prototype, terminal identity and zero rereads, failure working-set release, atomic settlement while every terminal-path intrinsic is redirected, caught/uncaught reentry poisoning, independent instances, eager parity, caller-error containment, graph/descriptor/order/freeze/mutation behavior, and iterative depth.
1171
+ - [`tests/src/core/SchemaCloner.test.ts`](../tests/src/core/SchemaCloner.test.ts) — direct root-imported `SchemaCloner`/interface contract: inert construction, exact prototype, terminal replay and zero rereads, caught/uncaught reentry precedence, independent instances, exact provenance and paths, enumerable-string observation, aliases/cycles, shells/order/freeze/depth, atomic settlement while every terminal-path intrinsic is redirected, and success/failure working-state release with a real collection control.
1172
+ - [`tests/src/core/cloners.test.ts`](../tests/src/core/cloners.test.ts) — eager JSON and schema behavior plus the shape function boundaries: fresh `cloneShape` roots/failures/source observation, overload/runtime and compact class parity, and genuine `ownShape` frozen-failure precedence and independent-success behavior.
1173
+ - [`tests/src/core/combinators.test.ts`](../tests/src/core/combinators.test.ts) — guard-combinator semantics, refinement composition, exact records/tuples, open-object and member-carrying-callable controls including the prototype-accessor proof, lazy recursion, thrown-value containment, dense array membership, genuine foreign-pattern ownership/flag stripping, and the unreadable-brand versus proxy/forgery diagnostic split.
1174
+ - [`tests/src/core/ContractCompiler.test.ts`](../tests/src/core/ContractCompiler.test.ts) — the lazy engine's own contract: the pinned getters, construction that observes nothing, per-root replay identity and the frozen bundle, one entry per unique node, terminal adoption/reentry poison, release, the shared-edge staircase and the bounded expansion refusal, and door-versus-getter agreement across every shape category.
1175
+ - [`tests/src/core/compilers.test.ts`](../tests/src/core/compilers.test.ts) — the `compile*` exports and `createContract`, including schema/guard/parser/generator behavior, the public depth boundary, strict auditor and coercive reporter fault semantics, hostile input containment, and contract wiring. It binds genuine foreign patterns through every compiler, exact captured property populations read twice (including refusal of an invalid captured population, and the absence of any further caller read), and the validator/cloner/compiler/contract forgery matrix. The explicit declaration matrix covers non-record roots and children, object-valued RegExp `source` / `flags`, present raw `undefined` populations, and flagged-pattern refusal, with plain/null-prototype/foreign records plus valid local/foreign/accessor patterns as controls; no generated message inventory or source pin participates.
1176
+ - [`tests/src/core/errors.test.ts`](../tests/src/core/errors.test.ts) — cross-copy `ContractError` recognition through distinct source-module instances, including transparent-wrapper, stripped-brand subclass, plain-error, complete self-branded forgery, and undeclared-code controls.
1177
+ - [`tests/src/core/factories.test.ts`](../tests/src/core/factories.test.ts) — the entity door `createContract` driven directly: an eager bundle whose roots are data properties carrying one artifact identity through destructuring and through a spread, the generic overload and the widened-`ContractShape` overload each answering at every root, a malformed declaration refused at the call itself with the authoring door's own diagnosis rather than a rewrap, and `is` agreeing with `compileGuard` over a corpus that exercises each verdict.
1178
+ - [`tests/src/core/helpers.test.ts`](../tests/src/core/helpers.test.ts) — helper behavior including `attempt`, reflected reads, fixed JSON-depth boundaries/aliases/cycles/sparse populations/hostile hosts, option capture, random/schema utilities, `preview`, and `shapeToKind`; it also owns `ContractError` construction, exhaustive `ContractCode` preservation, exact causes, and `isContractError` containment.
1179
+ - [`tests/src/core/SampleInferer.test.ts`](../tests/src/core/SampleInferer.test.ts) — the interned `SampleInferer` reached by relative source path: the ordered row-prefix memo served to a slot collecting the same rows in the same order and missed by slots whose rows arrive in a different order or at a different remaining depth, no memo carried across two walks over one row list, and the closed flag reaching the emitted opening.
1180
+ - [`tests/src/core/ValueInferer.test.ts`](../tests/src/core/ValueInferer.test.ts) — the interned `ValueInferer` reached by relative source path and driven with the depth and breadth budgets its door sanitizes away: a container root widened at every budget not above zero, a leaf root classified without consulting the budget, one level of descent on a fractional budget, descent past the cap the door imposes, and a negative breadth budget that samples no member and forces the record open.
1181
+ - [`tests/src/core/inferers.test.ts`](../tests/src/core/inferers.test.ts) — schema inference, unification, depth/breadth limits, deterministic sampling, readable widening, hostile traversal, sparse populations, and canonical serialization, including direct/public/consumer failed-prototype classification plus readable record/exotic controls.
1182
+ - [`tests/src/core/integration.test.ts`](../tests/src/core/integration.test.ts) — the one explicit layout exception: genuine public cross-module composition, seeded generation/guard/parser/schema round trips, and guard-combinator integration. Unit and type-carrier behavior remains in mirrored suites.
1183
+ - [`tests/src/core/parsers.test.ts`](../tests/src/core/parsers.test.ts) — coercion, field parsing, parse/guard soundness, reflected dense arrays, record/JSON boundaries, and coded unreadable-input refusal.
1184
+ - [`tests/src/core/SchemaShaper.test.ts`](../tests/src/core/SchemaShaper.test.ts) — the interned `SchemaShaper` reached by relative source path: a node two branches share converted exactly once and re-converted at a different remaining depth, a cyclic schema widened at the re-encountered node instead of recursed into, and an unreadable keyword's read failure escaping the walk carrying no door name of its own.
1185
+ - [`tests/src/core/ShapeCloner.test.ts`](../tests/src/core/ShapeCloner.test.ts) — canonical direct root-imported `ShapeCloner`/interface contract: inert source-only construction, exact prototype, terminal success/failure replay without rereads, caught/uncaught/replacement reentry poison, independent instances, exact error provenance and foreign containment, plain-record branding before discriminant observation, category/field/population observation and ordering, sharing/paths/optional placement, raw-schema composition, completed-root validation before deferred fidelity, primitive RegExp scalar ownership without coercion, freezing/mutation isolation, iterative depth refusal, atomic settlement while every terminal-path intrinsic is redirected, and symmetric terminal working-state release with a real three-reference collection control.
1186
+ - [`tests/src/core/shapers.test.ts`](../tests/src/core/shapers.test.ts) — builders and `Infer`/`InferMutable`, with explicit `BUILDER_CASES` option positions and public keys driving real plain/frozen/null-prototype and hostile get/has/descriptor/own-key/revoked controls. It also covers caller/post-clone raw-schema populations and diagnostic precedence, genuine foreign-pattern ownership and flag policy, inverse schema construction, and inference depth/breadth behavior without reading or parsing project source.
1187
+ - [`tests/src/core/ShapeValidator.test.ts`](../tests/src/core/ShapeValidator.test.ts) — direct public validator behavior: inert construction, repeatable live passes and reentry poison, precedence, depth/cycle handling, dense populations, raw-schema keywords, the present-`undefined` rule — an own raw-population member holding `undefined` is a present declaration rather than an absent one, so it is validated — and flagged-pattern observation/order/repair.
1188
+ - [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts) — primitive, non-negative numeric, structural, bounded-JSON, and JSON/record/RegExp guards; genuine `node:vm` record/RegExp values; depth-versus-validity and sequential-observation controls; zero-read duck/tag/accessor/proxy/revoked opposites; hostile-value totality; and parser/guard soundness corpora.
1189
+
1190
+ ## See also
1191
+
1192
+ - [`AGENTS.md`](../AGENTS.md) — the rules; see § Documentation contract. Guard totality and parse↔guard soundness are `.claude/rules/patterns.md` § Validation and contracts.
1193
+ - [`README.md`](README.md) — the guides index.