@directive-run/knowledge 0.2.0 → 0.4.2

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 (54) hide show
  1. package/README.md +3 -3
  2. package/ai/ai-adapters.md +7 -7
  3. package/ai/ai-agents-streaming.md +8 -8
  4. package/ai/ai-budget-resilience.md +5 -5
  5. package/ai/ai-communication.md +1 -1
  6. package/ai/ai-guardrails-memory.md +7 -7
  7. package/ai/ai-mcp-rag.md +5 -5
  8. package/ai/ai-multi-agent.md +14 -14
  9. package/ai/ai-orchestrator.md +8 -8
  10. package/ai/ai-security.md +2 -2
  11. package/ai/ai-tasks.md +9 -9
  12. package/ai/ai-testing-evals.md +2 -2
  13. package/core/anti-patterns.md +39 -39
  14. package/core/constraints.md +15 -15
  15. package/core/core-patterns.md +9 -9
  16. package/core/error-boundaries.md +7 -7
  17. package/core/multi-module.md +16 -16
  18. package/core/naming.md +21 -21
  19. package/core/plugins.md +14 -14
  20. package/core/react-adapter.md +13 -13
  21. package/core/resolvers.md +14 -14
  22. package/core/schema-types.md +22 -22
  23. package/core/system-api.md +16 -16
  24. package/core/testing.md +5 -5
  25. package/core/time-travel.md +20 -20
  26. package/dist/index.cjs +6 -105
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.js +7 -97
  29. package/dist/index.js.map +1 -1
  30. package/examples/ab-testing.ts +18 -90
  31. package/examples/ai-checkpoint.ts +68 -87
  32. package/examples/ai-guardrails.ts +20 -70
  33. package/examples/auth-flow.ts +2 -2
  34. package/examples/batch-resolver.ts +19 -59
  35. package/examples/contact-form.ts +220 -69
  36. package/examples/counter.ts +77 -95
  37. package/examples/dashboard-loader.ts +37 -55
  38. package/examples/debounce-constraints.ts +0 -2
  39. package/examples/dynamic-modules.ts +17 -20
  40. package/examples/error-boundaries.ts +30 -81
  41. package/examples/newsletter.ts +22 -49
  42. package/examples/notifications.ts +24 -23
  43. package/examples/optimistic-updates.ts +36 -41
  44. package/examples/pagination.ts +2 -2
  45. package/examples/permissions.ts +22 -32
  46. package/examples/provider-routing.ts +26 -83
  47. package/examples/shopping-cart.ts +8 -8
  48. package/examples/sudoku.ts +55 -62
  49. package/examples/theme-locale.ts +4 -7
  50. package/examples/time-machine.ts +12 -90
  51. package/examples/topic-guard.ts +30 -38
  52. package/examples/url-sync.ts +8 -8
  53. package/examples/websocket.ts +5 -5
  54. package/package.json +3 -3
package/core/naming.md CHANGED
@@ -33,7 +33,7 @@ Fulfillment logic?
33
33
  The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** -- the object emitted by a constraint's `require` property.
34
34
 
35
35
  ```typescript
36
- // CORRECT req is a requirement
36
+ // CORRECT req is a requirement
37
37
  resolvers: {
38
38
  fetchUser: {
39
39
  requirement: "FETCH_USER",
@@ -47,7 +47,7 @@ resolvers: {
47
47
  },
48
48
  },
49
49
 
50
- // WRONG never use "request" or "r"
50
+ // WRONG never use "request" or "r"
51
51
  resolve: async (request, context) => { /* ... */ },
52
52
  resolve: async (r, context) => { /* ... */ },
53
53
  ```
@@ -62,7 +62,7 @@ resolve: async (req, context) => {
62
62
  context.snapshot(); // facts snapshot
63
63
  },
64
64
 
65
- // WRONG never abbreviate to ctx
65
+ // WRONG never abbreviate to ctx
66
66
  resolve: async (req, ctx) => { /* ... */ },
67
67
  ```
68
68
 
@@ -88,10 +88,10 @@ constraints: {
88
88
  // Wait -- the above IS correct for one-line arrow expressions.
89
89
  // The brace rule applies to if/return blocks:
90
90
 
91
- // WRONG single-line if return
91
+ // WRONG single-line if return
92
92
  if (facts.user) return "ready";
93
93
 
94
- // CORRECT always use braces
94
+ // CORRECT always use braces
95
95
  if (facts.user) {
96
96
  return "ready";
97
97
  }
@@ -102,7 +102,7 @@ if (facts.user) {
102
102
  Add a blank line before `return` when there is code above it. Skip the blank line when `return` is the first statement in a block.
103
103
 
104
104
  ```typescript
105
- // CORRECT blank line before return when code precedes it
105
+ // CORRECT blank line before return when code precedes it
106
106
  function getStatus(facts) {
107
107
  const phase = facts.phase;
108
108
  const hasUser = facts.user !== null;
@@ -110,12 +110,12 @@ function getStatus(facts) {
110
110
  return phase === "ready" && hasUser;
111
111
  }
112
112
 
113
- // CORRECT no blank line when return is first statement
113
+ // CORRECT no blank line when return is first statement
114
114
  function isReady(facts) {
115
115
  return facts.phase === "ready";
116
116
  }
117
117
 
118
- // CORRECT blank line after brace-style return block
118
+ // CORRECT blank line after brace-style return block
119
119
  function process(facts) {
120
120
  if (!facts.ready) {
121
121
  return null;
@@ -126,7 +126,7 @@ function process(facts) {
126
126
  return result;
127
127
  }
128
128
 
129
- // WRONG no blank line before return after code
129
+ // WRONG no blank line before return after code
130
130
  function getStatus(facts) {
131
131
  const phase = facts.phase;
132
132
  return phase === "ready"; // Missing blank line
@@ -138,13 +138,13 @@ function getStatus(facts) {
138
138
  Never put properties or statements on a single line inside braces. Always expand to one item per line with proper indentation. This applies everywhere: schema definitions, init functions, events, effects, requirement types, and any other object or block.
139
139
 
140
140
  ```typescript
141
- // WRONG properties crammed on one line
141
+ // WRONG properties crammed on one line
142
142
  schema: {
143
143
  facts: { phase: t.string(), count: t.number() },
144
144
  requirements: { FETCH_USER: { id: t.string() }, RESET: {} },
145
145
  },
146
146
 
147
- // CORRECT one property per line, always expanded
147
+ // CORRECT one property per line, always expanded
148
148
  schema: {
149
149
  facts: {
150
150
  phase: t.string(),
@@ -158,10 +158,10 @@ schema: {
158
158
  },
159
159
  },
160
160
 
161
- // WRONG statements crammed on one line
161
+ // WRONG statements crammed on one line
162
162
  init: (facts) => { facts.phase = "idle"; facts.count = 0; },
163
163
 
164
- // CORRECT one statement per line
164
+ // CORRECT one statement per line
165
165
  init: (facts) => {
166
166
  facts.phase = "idle";
167
167
  facts.count = 0;
@@ -181,12 +181,12 @@ events: {
181
181
 
182
182
  Single-expression arrows (no braces) are fine on one line. Empty objects `{}` are fine inline.
183
183
  ```typescript
184
- // OK single expression, no braces
184
+ // OK single expression, no braces
185
185
  derive: {
186
186
  isReady: (facts) => facts.phase === "ready",
187
187
  },
188
188
 
189
- // OK empty object
189
+ // OK empty object
190
190
  RESET: {},
191
191
  ```
192
192
 
@@ -205,7 +205,7 @@ constraints: {
205
205
  },
206
206
  },
207
207
 
208
- // WRONG bare facts.* in multi-module context
208
+ // WRONG bare facts.* in multi-module context
209
209
  constraints: {
210
210
  loadWhenAuth: {
211
211
  when: (facts) => facts.isAuthenticated && !facts.loaded,
@@ -217,13 +217,13 @@ constraints: {
217
217
  ### System-Level Access Uses Dot Notation
218
218
 
219
219
  ```typescript
220
- // CORRECT dot notation through namespace proxy
220
+ // CORRECT dot notation through namespace proxy
221
221
  system.facts.auth.token;
222
222
  system.facts.cart.items;
223
223
  system.derive.auth.isLoggedIn;
224
224
  system.events.auth.login({ token: "..." });
225
225
 
226
- // WRONG bracket notation with internal separator
226
+ // WRONG bracket notation with internal separator
227
227
  system.facts["auth::token"];
228
228
  system.facts["auth_token"];
229
229
  ```
@@ -235,11 +235,11 @@ system.facts["auth_token"];
235
235
  The schema provides all types. Do not add `as` casts when reading facts or derivations from the system.
236
236
 
237
237
  ```typescript
238
- // CORRECT schema provides the type
238
+ // CORRECT schema provides the type
239
239
  const profile = system.facts.profile;
240
240
  const isReady = system.derive.isReady;
241
241
 
242
- // WRONG unnecessary cast
242
+ // WRONG unnecessary cast
243
243
  const profile = system.facts.profile as UserProfile;
244
244
  const isReady = system.derive.isReady as boolean;
245
245
  ```
@@ -249,7 +249,7 @@ const isReady = system.derive.isReady as boolean;
249
249
  Type assertions are only valid in schema definition using the `{} as {}` pattern:
250
250
 
251
251
  ```typescript
252
- // CORRECT cast in schema definition
252
+ // CORRECT cast in schema definition
253
253
  schema: {
254
254
  facts: {} as { profile: UserProfile; settings: AppSettings },
255
255
  derivations: {} as { displayName: string },
package/core/plugins.md CHANGED
@@ -46,13 +46,13 @@ Logs state changes, requirements, and resolutions to the console.
46
46
  ```typescript
47
47
  import { loggingPlugin } from "@directive-run/core/plugins";
48
48
 
49
- // Default logs facts changes and resolver start/complete
49
+ // Default logs facts changes and resolver start/complete
50
50
  loggingPlugin()
51
51
 
52
- // Verbose logs everything including derivation recomputation and constraint evaluation
52
+ // Verbose logs everything including derivation recomputation and constraint evaluation
53
53
  loggingPlugin({ verbose: true })
54
54
 
55
- // Custom filter only log specific events
55
+ // Custom filter only log specific events
56
56
  loggingPlugin({
57
57
  filter: (event) => {
58
58
  // Only log resolver events
@@ -97,7 +97,7 @@ persistencePlugin({
97
97
  storage: localStorage,
98
98
  })
99
99
 
100
- // sessionStorage cleared when tab closes
100
+ // sessionStorage cleared when tab closes
101
101
  persistencePlugin({
102
102
  key: "session-state",
103
103
  storage: sessionStorage,
@@ -113,7 +113,7 @@ persistencePlugin({
113
113
  },
114
114
  })
115
115
 
116
- // Selective persistence only persist certain facts
116
+ // Selective persistence only persist certain facts
117
117
  persistencePlugin({
118
118
  key: "my-app",
119
119
  storage: localStorage,
@@ -122,7 +122,7 @@ persistencePlugin({
122
122
  exclude: ["tempData", "sessionId"], // Everything except these
123
123
  })
124
124
 
125
- // Versioning handle schema changes
125
+ // Versioning handle schema changes
126
126
  persistencePlugin({
127
127
  key: "my-app",
128
128
  storage: localStorage,
@@ -267,13 +267,13 @@ const system = createSystem({
267
267
  ### Enabling devtools in production
268
268
 
269
269
  ```typescript
270
- // WRONG devtools overhead in production
270
+ // WRONG devtools overhead in production
271
271
  const system = createSystem({
272
272
  module: myModule,
273
273
  plugins: [devtoolsPlugin()],
274
274
  });
275
275
 
276
- // CORRECT conditional on environment
276
+ // CORRECT conditional on environment
277
277
  const plugins = [];
278
278
  if (process.env.NODE_ENV === "development") {
279
279
  plugins.push(devtoolsPlugin());
@@ -289,13 +289,13 @@ const system = createSystem({
289
289
  ### Persistence without versioning
290
290
 
291
291
  ```typescript
292
- // WRONG schema changes break existing users
292
+ // WRONG schema changes break existing users
293
293
  persistencePlugin({
294
294
  key: "app-state",
295
295
  storage: localStorage,
296
296
  })
297
297
 
298
- // CORRECT version and migrate
298
+ // CORRECT version and migrate
299
299
  persistencePlugin({
300
300
  key: "app-state",
301
301
  storage: localStorage,
@@ -307,7 +307,7 @@ persistencePlugin({
307
307
  ### Plugin order matters
308
308
 
309
309
  ```typescript
310
- // WRONG logging misses events from persistence restore
310
+ // WRONG logging misses events from persistence restore
311
311
  const system = createSystem({
312
312
  module: myModule,
313
313
  plugins: [
@@ -316,7 +316,7 @@ const system = createSystem({
316
316
  ],
317
317
  });
318
318
 
319
- // CORRECT logging first to capture everything
319
+ // CORRECT logging first to capture everything
320
320
  const system = createSystem({
321
321
  module: myModule,
322
322
  plugins: [
@@ -329,13 +329,13 @@ const system = createSystem({
329
329
  ### Persisting sensitive or transient data
330
330
 
331
331
  ```typescript
332
- // WRONG persists auth tokens and loading state
332
+ // WRONG persists auth tokens and loading state
333
333
  persistencePlugin({
334
334
  key: "app",
335
335
  storage: localStorage,
336
336
  })
337
337
 
338
- // CORRECT exclude sensitive and transient facts
338
+ // CORRECT exclude sensitive and transient facts
339
339
  persistencePlugin({
340
340
  key: "app",
341
341
  storage: localStorage,
@@ -18,7 +18,7 @@ What are you building?
18
18
  Create the system outside of React. Components subscribe to it.
19
19
 
20
20
  ```typescript
21
- // system.ts created once, imported anywhere
21
+ // system.ts created once, imported anywhere
22
22
  import { createSystem } from "@directive-run/core";
23
23
  import { counterModule } from "./counter-module";
24
24
 
@@ -31,7 +31,7 @@ import { useSelector, useEvent } from "@directive-run/react";
31
31
  import { system } from "./system";
32
32
 
33
33
  function Counter() {
34
- // Subscribe to derived state re-renders only when value changes
34
+ // Subscribe to derived state re-renders only when value changes
35
35
  const count = useSelector(system, (s) => s.facts.count);
36
36
  const doubled = useSelector(system, (s) => s.derive.doubled);
37
37
 
@@ -174,10 +174,10 @@ function Dashboard() {
174
174
  ## CRITICAL: Hooks That DO NOT Exist
175
175
 
176
176
  ```typescript
177
- // WRONG useDirective() does not exist. This is a common hallucination.
177
+ // WRONG useDirective() does not exist. This is a common hallucination.
178
178
  const { facts, derive, events } = useDirective(system);
179
179
 
180
- // CORRECT use useSelector for state, useEvent for actions
180
+ // CORRECT use useSelector for state, useEvent for actions
181
181
  const count = useSelector(system, (s) => s.facts.count);
182
182
  const events = useEvent(system);
183
183
  ```
@@ -187,7 +187,7 @@ const events = useEvent(system);
187
187
  ### Creating the system inside a component without useSystem
188
188
 
189
189
  ```typescript
190
- // WRONG creates a new system on every render
190
+ // WRONG creates a new system on every render
191
191
  function Counter() {
192
192
  const system = createSystem({ module: counterModule }); // New system each render!
193
193
  const count = useSelector(system, (s) => s.facts.count);
@@ -195,7 +195,7 @@ function Counter() {
195
195
  return <div>{count}</div>;
196
196
  }
197
197
 
198
- // CORRECT create outside the component
198
+ // CORRECT create outside the component
199
199
  const system = createSystem({ module: counterModule });
200
200
 
201
201
  function Counter() {
@@ -204,7 +204,7 @@ function Counter() {
204
204
  return <div>{count}</div>;
205
205
  }
206
206
 
207
- // ALSO CORRECT useSystem manages lifecycle
207
+ // ALSO CORRECT useSystem manages lifecycle
208
208
  function Counter() {
209
209
  const system = useSystem({ module: counterModule });
210
210
  const count = useSelector(system, (s) => s.facts.count);
@@ -216,10 +216,10 @@ function Counter() {
216
216
  ### Selecting too much state (causes unnecessary re-renders)
217
217
 
218
218
  ```typescript
219
- // WRONG re-renders on ANY fact change
219
+ // WRONG re-renders on ANY fact change
220
220
  const allFacts = useSelector(system, (s) => s.facts);
221
221
 
222
- // CORRECT select only what you need
222
+ // CORRECT select only what you need
223
223
  const name = useSelector(system, (s) => s.facts.userName);
224
224
  const count = useSelector(system, (s) => s.facts.count);
225
225
  ```
@@ -227,7 +227,7 @@ const count = useSelector(system, (s) => s.facts.count);
227
227
  ### Mutating facts directly in event handlers
228
228
 
229
229
  ```typescript
230
- // WRONG bypass the event system
230
+ // WRONG bypass the event system
231
231
  function Counter() {
232
232
  const count = useSelector(system, (s) => s.facts.count);
233
233
 
@@ -238,7 +238,7 @@ function Counter() {
238
238
  );
239
239
  }
240
240
 
241
- // CORRECT use events for intent-driven mutations
241
+ // CORRECT use events for intent-driven mutations
242
242
  function Counter() {
243
243
  const count = useSelector(system, (s) => s.facts.count);
244
244
  const events = useEvent(system);
@@ -254,9 +254,9 @@ function Counter() {
254
254
  ### Casting values from useSelector
255
255
 
256
256
  ```typescript
257
- // WRONG unnecessary type casting
257
+ // WRONG unnecessary type casting
258
258
  const profile = useSelector(system, (s) => s.facts.profile as UserProfile);
259
259
 
260
- // CORRECT types are inferred from the module schema
260
+ // CORRECT types are inferred from the module schema
261
261
  const profile = useSelector(system, (s) => s.facts.profile);
262
262
  ```
package/core/resolvers.md CHANGED
@@ -16,7 +16,7 @@ Is the work async (API calls, timers)?
16
16
  │ ├── Yes → Add batch config to group them
17
17
  │ └── No → Single resolve is fine
18
18
 
19
- └── No → Reconsider maybe this is an event handler or derivation
19
+ └── No → Reconsider maybe this is an event handler or derivation
20
20
  ```
21
21
 
22
22
  ## Basic Resolver
@@ -27,12 +27,12 @@ resolvers: {
27
27
  // Which requirement type this resolver handles
28
28
  requirement: "FETCH_USER",
29
29
 
30
- // Async function req is the requirement, context has facts + signal
30
+ // Async function req is the requirement, context has facts + signal
31
31
  resolve: async (req, context) => {
32
32
  const res = await fetch(`/api/users/${req.userId}`);
33
33
  const user = await res.json();
34
34
 
35
- // Mutate facts to store results resolvers return void
35
+ // Mutate facts to store results resolvers return void
36
36
  context.facts.user = user;
37
37
  context.facts.phase = "loaded";
38
38
  },
@@ -46,13 +46,13 @@ The `context` object provides:
46
46
 
47
47
  ```typescript
48
48
  resolve: async (req, context) => {
49
- // context.facts mutable proxy to the module's facts
49
+ // context.facts mutable proxy to the module's facts
50
50
  context.facts.status = "loading";
51
51
 
52
- // context.signal AbortSignal, cancelled when system stops or requirement removed
52
+ // context.signal AbortSignal, cancelled when system stops or requirement removed
53
53
  const res = await fetch("/api/data", { signal: context.signal });
54
54
 
55
- // context.snapshot() read-only snapshot for before/after comparisons
55
+ // context.snapshot() read-only snapshot for before/after comparisons
56
56
  const before = context.snapshot();
57
57
  context.facts.count += 1;
58
58
  const after = context.snapshot();
@@ -69,7 +69,7 @@ resolvers: {
69
69
  fetchUser: {
70
70
  requirement: "FETCH_USER",
71
71
 
72
- // Custom key only one inflight resolver per userId
72
+ // Custom key only one inflight resolver per userId
73
73
  key: (req) => `fetch-user-${req.userId}`,
74
74
 
75
75
  resolve: async (req, context) => {
@@ -270,14 +270,14 @@ const explanation = system.explain("req-123");
270
270
  ### Returning data from resolve
271
271
 
272
272
  ```typescript
273
- // WRONG return value is ignored
273
+ // WRONG return value is ignored
274
274
  resolve: async (req, context) => {
275
275
  const user = await fetchUser(req.userId);
276
276
 
277
277
  return user; // Ignored!
278
278
  },
279
279
 
280
- // CORRECT mutate context.facts
280
+ // CORRECT mutate context.facts
281
281
  resolve: async (req, context) => {
282
282
  const user = await fetchUser(req.userId);
283
283
  context.facts.user = user;
@@ -297,7 +297,7 @@ resolve: async (req, context) => { /* ... */ },
297
297
  ### Checking conditions in resolve (constraint's job)
298
298
 
299
299
  ```typescript
300
- // WRONG condition checking belongs in constraint's when()
300
+ // WRONG condition checking belongs in constraint's when()
301
301
  resolve: async (req, context) => {
302
302
  if (!context.facts.isAuthenticated) {
303
303
  return;
@@ -305,7 +305,7 @@ resolve: async (req, context) => {
305
305
  // ...
306
306
  },
307
307
 
308
- // CORRECT let constraints handle conditions
308
+ // CORRECT let constraints handle conditions
309
309
  // The resolver only runs when a requirement is emitted
310
310
  resolve: async (req, context) => {
311
311
  const data = await fetch("/api/data");
@@ -316,7 +316,7 @@ resolve: async (req, context) => {
316
316
  ### Forgetting error handling
317
317
 
318
318
  ```typescript
319
- // WRONG unhandled errors with no recovery
319
+ // WRONG unhandled errors with no recovery
320
320
  resolvers: {
321
321
  fetch: {
322
322
  requirement: "FETCH",
@@ -327,7 +327,7 @@ resolvers: {
327
327
  },
328
328
  },
329
329
 
330
- // CORRECT retry policy + error handling
330
+ // CORRECT retry policy + error handling
331
331
  resolvers: {
332
332
  fetch: {
333
333
  requirement: "FETCH",
@@ -346,7 +346,7 @@ resolvers: {
346
346
  ### Missing settle() after start()
347
347
 
348
348
  ```typescript
349
- // WRONG reading facts before resolvers finish
349
+ // WRONG reading facts before resolvers finish
350
350
  system.start();
351
351
  console.log(system.facts.data); // Likely null
352
352
 
@@ -32,7 +32,7 @@ const myModule = createModule("example", {
32
32
  // Basic string
33
33
  name: t.string(),
34
34
 
35
- // String literal union full type safety
35
+ // String literal union full type safety
36
36
  phase: t.string<"idle" | "loading" | "done">(),
37
37
 
38
38
  // Number with validation
@@ -85,11 +85,11 @@ schema: {
85
85
  ```typescript
86
86
  schema: {
87
87
  facts: {
88
- // Enum string literal union from values
88
+ // Enum string literal union from values
89
89
  status: t.enum("pending", "active", "archived"),
90
90
  // TypeScript type: "pending" | "active" | "archived"
91
91
 
92
- // Literal exact match
92
+ // Literal exact match
93
93
  version: t.literal(2),
94
94
  mode: t.literal("strict"),
95
95
  enabled: t.literal(true),
@@ -102,13 +102,13 @@ schema: {
102
102
  ```typescript
103
103
  schema: {
104
104
  facts: {
105
- // Nullable T | null
105
+ // Nullable T | null
106
106
  selectedItem: t.nullable(t.string()),
107
107
 
108
- // Optional T | undefined
108
+ // Optional T | undefined
109
109
  nickname: t.optional(t.string()),
110
110
 
111
- // Union combine types
111
+ // Union combine types
112
112
  result: t.union(t.string(), t.number()),
113
113
 
114
114
  // Nullable via object generic (also valid)
@@ -122,28 +122,28 @@ schema: {
122
122
  ```typescript
123
123
  schema: {
124
124
  facts: {
125
- // Default value used if init doesn't set it
125
+ // Default value used if init doesn't set it
126
126
  theme: t.string<"light" | "dark">().default("light"),
127
127
 
128
- // Custom validation runs in dev mode
128
+ // Custom validation runs in dev mode
129
129
  email: t.string().validate((val) => val.includes("@")),
130
130
 
131
- // Transform on set runs when fact is mutated
131
+ // Transform on set runs when fact is mutated
132
132
  slug: t.string().transform((val) => val.toLowerCase().replace(/\s+/g, "-")),
133
133
 
134
- // Branded type nominal typing
134
+ // Branded type nominal typing
135
135
  userId: t.string().brand<"UserId">(),
136
136
 
137
- // Description for docs and devtools
137
+ // Description for docs and devtools
138
138
  retryCount: t.number().describe("Number of failed attempts"),
139
139
 
140
- // Refinement predicate with error message
140
+ // Refinement predicate with error message
141
141
  port: t.number().refine(
142
142
  (n) => n >= 1 && n <= 65535,
143
143
  "Port must be between 1 and 65535",
144
144
  ),
145
145
 
146
- // Chaining combine multiple modifiers
146
+ // Chaining combine multiple modifiers
147
147
  score: t.number()
148
148
  .min(0)
149
149
  .max(100)
@@ -193,43 +193,43 @@ schema: {
193
193
  These are common AI hallucinations. Do not use them.
194
194
 
195
195
  ```typescript
196
- // WRONG t.map() does not exist
196
+ // WRONG t.map() does not exist
197
197
  items: t.map<string, number>(),
198
198
  // CORRECT
199
199
  items: t.object<Map<string, number>>(),
200
200
 
201
- // WRONG t.set() does not exist
201
+ // WRONG t.set() does not exist
202
202
  tags: t.set<string>(),
203
203
  // CORRECT
204
204
  tags: t.object<Set<string>>(),
205
205
 
206
- // WRONG t.date() does not exist
206
+ // WRONG t.date() does not exist
207
207
  createdAt: t.date(),
208
208
  // CORRECT
209
209
  createdAt: t.object<Date>(),
210
210
  // OR use timestamps
211
211
  createdAt: t.number(), // Unix ms
212
212
 
213
- // WRONG t.tuple() does not exist
213
+ // WRONG t.tuple() does not exist
214
214
  coords: t.tuple<[number, number]>(),
215
215
  // CORRECT
216
216
  coords: t.array<[number, number]>(),
217
217
 
218
- // WRONG t.record() does not exist
218
+ // WRONG t.record() does not exist
219
219
  scores: t.record<string, number>(),
220
220
  // CORRECT
221
221
  scores: t.object<Record<string, number>>(),
222
222
 
223
- // WRONG t.promise() does not exist (facts are synchronous)
223
+ // WRONG t.promise() does not exist (facts are synchronous)
224
224
  result: t.promise<string>(),
225
225
 
226
- // WRONG t.any() does not exist
226
+ // WRONG t.any() does not exist
227
227
  data: t.any(),
228
228
  // CORRECT
229
229
  data: t.object<unknown>(),
230
230
 
231
- // WRONG t.void() does not exist (not a fact type)
232
- // WRONG t.function() does not exist (functions are not serializable)
231
+ // WRONG t.void() does not exist (not a fact type)
232
+ // WRONG t.function() does not exist (functions are not serializable)
233
233
  ```
234
234
 
235
235
  ## Type Assertion Alternative