@directive-run/knowledge 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +50 -15
  2. package/ai/ai-adapters.md +7 -0
  3. package/ai/ai-agents-streaming.md +187 -149
  4. package/ai/ai-budget-resilience.md +305 -132
  5. package/ai/ai-communication.md +220 -197
  6. package/ai/ai-debug-observability.md +259 -173
  7. package/ai/ai-guardrails-memory.md +191 -153
  8. package/ai/ai-mcp-rag.md +204 -199
  9. package/ai/ai-multi-agent.md +254 -153
  10. package/ai/ai-orchestrator.md +353 -114
  11. package/ai/ai-security.md +287 -180
  12. package/ai/ai-tasks.md +8 -1
  13. package/ai/ai-testing-evals.md +363 -256
  14. package/core/anti-patterns.md +18 -2
  15. package/core/constraints.md +13 -2
  16. package/core/core-patterns.md +12 -0
  17. package/core/error-boundaries.md +8 -0
  18. package/core/history.md +7 -0
  19. package/core/multi-module.md +15 -3
  20. package/core/naming.md +128 -90
  21. package/core/plugins.md +7 -0
  22. package/core/react-adapter.md +256 -174
  23. package/core/resolvers.md +10 -0
  24. package/core/schema-types.md +8 -0
  25. package/core/system-api.md +10 -0
  26. package/core/testing.md +257 -143
  27. package/examples/checkers.ts +15 -16
  28. package/examples/contact-form.ts +2 -2
  29. package/examples/counter-react.ts +1 -1
  30. package/examples/counter-svelte.ts +1 -1
  31. package/examples/counter-vue.ts +1 -1
  32. package/examples/counter.ts +1 -1
  33. package/examples/data-triggers.ts +4 -4
  34. package/examples/feature-flags.ts +2 -2
  35. package/examples/form-wizard.ts +2 -2
  36. package/examples/newsletter.ts +2 -2
  37. package/examples/server.ts +2 -2
  38. package/examples/shopping-cart.ts +1 -1
  39. package/examples/topic-guard.ts +1 -1
  40. package/package.json +3 -3
  41. package/sitemap.md +17 -11
  42. package/examples/debounce-constraints.ts +0 -95
  43. package/examples/multi-module.ts +0 -58
@@ -1,5 +1,7 @@
1
1
  # Anti-Patterns
2
2
 
3
+ > Covers `@directive-run/core` and `@directive-run/react` — hallucination-prone API patterns to avoid.
4
+
3
5
  19 most common mistakes when generating Directive code, ranked by AI hallucination frequency. Every code generation MUST be checked against this list.
4
6
 
5
7
  ## 1. Unnecessary Type Casting on Facts/Derivations
@@ -113,11 +115,16 @@ createModule("timer", {
113
115
  ## 7. String-Based Event Dispatch
114
116
 
115
117
  ```typescript
116
- // WRONG – events are not dispatched by string
118
+ // WRONG – there is no two-argument string-keyed dispatch signature
117
119
  system.dispatch("login", { token: "abc" });
118
120
 
119
- // CORRECT – use the events accessor
121
+ // CORRECT – use the typed events accessor (preferred — autocomplete + payload typing)
120
122
  system.events.login({ token: "abc" });
123
+
124
+ // ALSO VALID – the single-arg object form of dispatch() is supported when you
125
+ // need to forward a programmatically-built event. Prefer the events accessor
126
+ // for normal code.
127
+ system.dispatch({ type: "login", token: "abc" });
121
128
  ```
122
129
 
123
130
  ## 8. Direct Array/Object Mutation
@@ -364,3 +371,12 @@ Before generating any Directive code, verify:
364
371
  8. Multi-module uses `facts.self.*` for own facts
365
372
  9. Imports from `@directive-run/core`, not deep paths
366
373
  10. `await system.settle()` after `system.start()`
374
+
375
+ ## See also
376
+
377
+ - [`naming.md`](./naming.md) — the strict canonical-term rules AND the alias map for cross-paradigm searches
378
+ - [`constraints.md`](./constraints.md) — the constraint shape these anti-patterns reference (`facts` not in scope inside static `require:`, etc.)
379
+ - [`resolvers.md`](./resolvers.md) — the resolver shape these anti-patterns reference (return `void`, mutate `context.facts`, `(req, context)` not `(req, ctx)`)
380
+ - [`schema-types.md`](./schema-types.md) — the `t.*()` builders that exist and the hallucinated ones (`t.map`, `t.set`, `t.promise`, `t.date`) that don't
381
+ - [`react-adapter.md`](./react-adapter.md) — the React hooks that exist and the hallucinated ones (`useEvent`, `useSystem`, `DirectiveProvider`) that don't
382
+ - [`error-boundaries.md`](./error-boundaries.md) — error-handling shapes AI assistants sometimes invent
@@ -1,5 +1,7 @@
1
1
  # Constraints
2
2
 
3
+ > Covers `@directive-run/core` — constraint definition: `when` / `require`, async constraints with `deps`, priority, data-form predicates.
4
+
3
5
  Constraints declare WHEN something is needed. They are the demand side of the constraint-resolver pattern. Constraints evaluate conditions against facts and emit requirements that resolvers fulfill.
4
6
 
5
7
  ## Decision Tree: "Should this be a constraint?"
@@ -22,8 +24,10 @@ constraints: {
22
24
  // when() returns boolean – evaluated on every fact change
23
25
  when: (facts) => facts.isAuthenticated && !facts.user,
24
26
 
25
- // require – the requirement to emit when condition is true
26
- require: { type: "FETCH_USER", userId: facts.userId },
27
+ // require – the requirement to emit when condition is true.
28
+ // Use the function form whenever you need to read facts
29
+ // facts is NOT in scope inside the static object form.
30
+ require: (facts) => ({ type: "FETCH_USER", userId: facts.userId }),
27
31
  },
28
32
  },
29
33
  ```
@@ -261,3 +265,10 @@ constraints: {
261
265
  "Whenever X changes, log it" → Effect
262
266
  "X is always facts.a + facts.b" → Derivation
263
267
  ```
268
+
269
+ ## See also
270
+
271
+ - [`resolvers.md`](./resolvers.md) — the other half of the constraint-resolver loop; the supply side that fulfills the requirements constraints emit
272
+ - [`core-patterns.md`](./core-patterns.md) — how constraints fit into the module shape alongside facts, derivations, events, and effects
273
+ - [`multi-module.md`](./multi-module.md) — `crossModuleDeps` for constraints that fire on facts owned by another module
274
+ - [`anti-patterns.md`](./anti-patterns.md) — the constraint-shaped mistakes AI assistants reliably make
@@ -1,5 +1,7 @@
1
1
  # Core Patterns
2
2
 
3
+ > Covers `@directive-run/core` — modules, facts, derivations, effects, events, and the constraint-resolver loop.
4
+
3
5
  How to think about building with Directive: modules, systems, and the constraint-resolver pattern.
4
6
 
5
7
  ## Decision Tree: "Where does this logic go?"
@@ -226,3 +228,13 @@ const typed = createModule("typed", {
226
228
  },
227
229
  });
228
230
  ```
231
+
232
+ ## See also
233
+
234
+ - [`constraints.md`](./constraints.md) — the demand side of the constraint-resolver loop
235
+ - [`resolvers.md`](./resolvers.md) — the supply side that fulfills requirements
236
+ - [`schema-types.md`](./schema-types.md) — the `t.*()` builders that define fact and derivation types
237
+ - [`multi-module.md`](./multi-module.md) — when a single module isn't enough
238
+ - [`system-api.md`](./system-api.md) — `createSystem` and the runtime instance once your module is defined
239
+ - [`naming.md`](./naming.md) — terminology conventions every example here follows
240
+ - [`testing.md`](./testing.md) — `createTestSystem` for the modules you're learning to write
@@ -1,5 +1,7 @@
1
1
  # Error Boundaries
2
2
 
3
+ > Covers `@directive-run/core` — error boundaries, recovery strategies, lifecycle hooks, and circuit breakers.
4
+
3
5
  How to handle errors in Directive: recovery strategies, error boundaries, lifecycle hooks, and the circuit breaker pattern.
4
6
 
5
7
  ## Decision Tree: "How should errors be handled?"
@@ -320,3 +322,9 @@ try {
320
322
  6. Add `onError` callback for logging/monitoring
321
323
  7. Use `"throw"` for derivation errors (they indicate bugs)
322
324
  8. Use `"skip"` for non-critical effects (logging, analytics)
325
+
326
+ ## See also
327
+
328
+ - [`resolvers.md`](./resolvers.md) — retry policies and cancellation; the most common error source
329
+ - [`plugins.md`](./plugins.md) — `createCircuitBreaker` lives in `@directive-run/core/plugins`; pair it with error boundaries for cascading-failure isolation
330
+ - [`anti-patterns.md`](./anti-patterns.md) — common error-handling mistakes (catching the wrong type, swallowing recoverable errors)
package/core/history.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # History & Snapshots
2
2
 
3
+ > Covers `@directive-run/core` — time-travel: snapshot, undo/redo, replay, export/import, changeset grouping.
4
+
3
5
  Directive records fact changes as snapshots, enabling undo/redo, replay, export/import, and changeset grouping.
4
6
 
5
7
  ## Decision Tree: "Should I enable history?"
@@ -342,3 +344,8 @@ const system = createSystem({
342
344
  history: true,
343
345
  });
344
346
  ```
347
+
348
+ ## See also
349
+
350
+ - [`system-api.md`](./system-api.md) — `history` config in `createSystem` + the full `system.history.*` API
351
+ - [`testing.md`](./testing.md) — replay-driven testing patterns that pair with recorded snapshots
@@ -1,5 +1,7 @@
1
1
  # Multi-Module Systems
2
2
 
3
+ > Covers `@directive-run/core` — namespaced multi-module systems, cross-module deps, `facts.self.*`.
4
+
3
5
  How to compose multiple modules into a namespaced system with cross-module type safety.
4
6
 
5
7
  ## Decision Tree: "Single or Multi-Module?"
@@ -303,13 +305,23 @@ system.registerModule("chat", chatModule.default);
303
305
 
304
306
  ## Cross-Module Events
305
307
 
306
- Events are namespaced at the system level but dispatched through the events accessor:
308
+ Events are namespaced at the system level. **Prefer the typed events accessor** — it carries autocomplete and per-event payload typing.
307
309
 
308
310
  ```typescript
309
- // Multi-module events
311
+ // Multi-module events — canonical form
310
312
  system.events.auth.login({ token: "abc" });
311
313
  system.events.cart.addItem({ id: "item-1", qty: 1 });
312
314
 
313
- // dispatch() also works with type discriminator
315
+ // dispatch() is supported when you need to forward a programmatically-built
316
+ // event (e.g., replaying a serialized event). The string form
317
+ // (system.dispatch("login", payload)) does NOT exist — only the single-arg
318
+ // object form is valid.
314
319
  system.dispatch({ type: "login", token: "abc" });
315
320
  ```
321
+
322
+ ## See also
323
+
324
+ - [`core-patterns.md`](./core-patterns.md) — start here for the single-module shape before going namespaced
325
+ - [`system-api.md`](./system-api.md) — `createSystem({ modules: { ... } })` and the namespaced facts proxy
326
+ - [`constraints.md`](./constraints.md) — `crossModuleDeps` for constraints that fire on facts owned by another module
327
+ - [`naming.md`](./naming.md) — `facts.self.*` convention; dot-notation vs bracket-notation rules
package/core/naming.md CHANGED
@@ -1,81 +1,123 @@
1
1
  # Naming Conventions
2
2
 
3
- Directive naming rules that AI coding assistants must follow. These are non-negotiable project conventions.
3
+ > Covers all `@directive-run/*` packages terminology, parameter names, return-style rules.
4
4
 
5
- ## Decision Tree: "What do I call this?"
5
+ Directive uses precise vocabulary by design: each concept has one canonical name across every package, every language adapter, and every doc. The names are non-negotiable for code Directive ships, AND every term has a cross-paradigm alias so a developer coming from Redux / Zustand / XState / Jotai / React Query can find the right Directive concept on the first search.
6
6
 
7
- ```
8
- Resolver parameter names?
9
- → (req, context) req = requirement, NEVER "request"
10
- → NEVER (req, ctx) context is NEVER abbreviated
7
+ This file is both the rules and the bridge. Search for the term you already know; you'll land on the Directive equivalent.
11
8
 
12
- Computed values?
13
- → "derivations" / derive NEVER "computed", "selectors", "getters"
14
- → system.derive.myValue NEVER system.computed.myValue
9
+ ## Coming from another library? Start here
15
10
 
16
- State values?
17
- → "facts" NEVER "state", "store", "atoms"
18
- system.facts.count NEVER system.state.count
11
+ | If you call it… | (in this library) | Directive calls it… | Why the name |
12
+ |---|---|---|---|
13
+ | **state**, **store**, **atom**, **signal**, **observable** | Redux, Zustand, Jotai, Preact Signals, MobX | **facts** | "Facts about the world" — the system observes them. Same value-bag role as state, with a proxy that auto-tracks reads. |
14
+ | **selector**, **computed**, **getter**, **memo**, **derived store** | Redux, Vue/MobX, Zustand getters, Memoize, Svelte | **derivations** / `derive` | Auto-tracked computed values. No dep arrays. Directive's name aligns with "derived from facts." |
15
+ | **action**, **dispatch**, **reducer**, **command**, **intent** | Redux, Redux Toolkit, CQRS | **events** + **resolvers** | Events are the user-facing trigger; resolvers fulfill them. Reducers are split into the two halves Directive cares about. |
16
+ | **thunk**, **saga**, **effect**, **middleware**, **listener** | Redux Toolkit, redux-saga, redux-observable, NgRx | **resolvers** | Async logic that mutates state in response to a requirement. Same role as a thunk; declared once, run by the runtime. |
17
+ | **rule**, **condition**, **guard**, **trigger**, **policy** | XState guards, Cerbos, OPA, business-rule engines | **constraints** | Declarative "when X is true, Y must happen." Constraints emit requirements; resolvers fulfill them. |
18
+ | **request**, **query**, **side-effect spec** | React Query / TanStack Query queries, Apollo queries | **requirements** | The object a constraint emits. The runtime dedupes them, dispatches to resolvers, tracks status. |
19
+ | **subscription**, **listener**, **reaction**, **watcher** | Zustand subscribe, MobX reactions, Redux subscriptions | **effects** | Side-effects that run when watched facts change. Cleaner than `subscribe()` callbacks because effects auto-track. |
20
+ | **slice**, **feature**, **domain**, **bounded context** | Redux Toolkit slices, NgRx feature modules | **modules** | Encapsulates facts + derivations + constraints + resolvers + events for one bounded slice of the system. |
21
+ | **store**, **container**, **context**, **app state** | Redux Store, Pinia, React Context, NgRx Store | **system** | The runtime that wires modules together, evaluates constraints, dispatches resolvers, and exposes observation. |
22
+ | **state machine**, **statechart**, **xstate machine** | XState | (closest: **module** + **constraints**) | Directive isn't a state machine — but if your XState `states` model business rules (not UI flow), constraints + facts express the same logic declaratively with no transition functions. |
23
+ | **cache**, **query cache**, **stale-while-revalidate** | TanStack Query, SWR, Apollo cache | (closest: `@directive-run/query` + **constraints**) | Use `@directive-run/query` for the cache; constraints decide when refetches fire. Directive doesn't replace TanStack Query — it composes with it. |
24
+ | **agent**, **chain**, **graph**, **workflow** | LangChain, LangGraph, OpenAI Assistants | **agent** + **orchestrator** | `@directive-run/ai` keeps the names — agents are agents, orchestrators are orchestrators — but they run under the same constraint engine as the rest of Directive. |
25
+ | **guardrail**, **filter**, **safety check**, **moderation** | OpenAI moderation API, NVIDIA NeMo Guardrails | **guardrails** | Same name, same role; declarative input/output/tool-call checks. |
19
26
 
20
- Conditional triggers?
21
- → "constraints" NEVER "rules", "conditions", "triggers"
22
- → when() + require() NEVER if/then, trigger/action
27
+ If your term isn't in the table, search the canonical name in this doc's [Terminology quick reference](#terminology-quick-reference) — both directions are listed.
23
28
 
24
- Fulfillment logic?
25
- → "resolvers" NEVER "handlers", "actions", "reducers"
26
- resolve(req, context) NEVER handle(req, ctx)
27
- ```
29
+ ## Canonical terms (non-negotiable for code Directive ships)
30
+
31
+ Above is the bridge from your existing vocabulary. Below are the canonical names — the only ones that should appear in `@directive-run/*` source, tests, docs, and generated AI rules.
32
+
33
+ ### `facts` — the value bag
34
+
35
+ Not state, not store, not atoms. **Facts.** Accessed at `system.facts.x`. Mutated through events and resolvers. Read through derivations, hooks, and `system.facts.$store`.
36
+
37
+ ### `derivations` — auto-tracked computed values
38
+
39
+ Declared via `derive: { name: (facts) => … }`. Read at `system.derive.name`. The hook is `useDerived` (not `useComputed`, not `useSelector` — Directive's `useSelector` is a different, broader primitive that takes a selector function).
40
+
41
+ ### `constraints` — when-then declarations
42
+
43
+ Declared via `constraints: { name: { when: …, require: … } }`. The `when` returns a boolean; the `require` returns a requirement.
44
+
45
+ ### `resolvers` — requirement fulfillment
46
+
47
+ Declared via `resolvers: { name: { requirement: …, resolve: async (req, context) => … } }`. Mutate `context.facts`; never return data from `resolve`.
48
+
49
+ ### `requirements` — what constraints emit
50
+
51
+ Tagged union `{ type: "FETCH_USER", … }`. Constraints emit them; the runtime dedupes by `type` + `key()`; resolvers fulfill them.
52
+
53
+ ### `effects` — side effects from watched changes
54
+
55
+ Declared via `effects: { name: { run: (facts, prev) => … } }`. Run on relevant fact changes. The auto-tracking dependency model means no `deps` array unless you specifically need a partial dep set.
56
+
57
+ ### `events` — typed mutation entry points
58
+
59
+ Declared via `events: { name: (facts, payload) => … }`. Called as `system.events.name(payload)`. The typed events accessor is the canonical way to dispatch — `system.dispatch({type, ...payload})` works but the typed accessor carries autocomplete.
60
+
61
+ ### `module` — bounded slice
28
62
 
29
- ## Parameter Naming
63
+ Created via `createModule(name, { schema, init, derive, effects, events, constraints, resolvers })`. Composes into systems.
64
+
65
+ ### `system` — the runtime
66
+
67
+ Created via `createSystem({ module })` or `createSystem({ modules: { x, y } })`. Hosts the reconciliation loop.
68
+
69
+ ## Parameter naming
30
70
 
31
71
  ### `req` = requirement (NOT request)
32
72
 
33
- The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** -- the object emitted by a constraint's `require` property.
73
+ The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** the object emitted by a constraint's `require` property.
34
74
 
35
75
  ```typescript
36
- // CORRECT req is a requirement
76
+ // CORRECT req is a requirement
37
77
  resolvers: {
38
78
  fetchUser: {
39
79
  requirement: "FETCH_USER",
40
80
  key: (req) => `fetch-${req.userId}`,
41
81
  resolve: async (req, context) => {
42
82
  // req.type === "FETCH_USER"
43
- // req.userId from the requirement payload
44
83
  const user = await fetchUser(req.userId);
45
84
  context.facts.user = user;
46
85
  },
47
86
  },
48
87
  },
49
88
 
50
- // WRONG never use "request" or "r"
89
+ // WRONG never "request" or "r"
51
90
  resolve: async (request, context) => { /* ... */ },
52
91
  resolve: async (r, context) => { /* ... */ },
53
92
  ```
54
93
 
55
- ### `context` is Never Abbreviated
94
+ ### `context` is never abbreviated
56
95
 
57
96
  ```typescript
58
97
  // CORRECT
59
98
  resolve: async (req, context) => {
60
99
  context.facts.status = "loaded";
61
- context.signal; // AbortSignal
62
- context.snapshot(); // facts snapshot
100
+ context.signal; // AbortSignal
101
+ context.snapshot(); // facts snapshot
63
102
  },
64
103
 
65
- // WRONG never abbreviate to ctx
104
+ // WRONG never abbreviate to ctx
66
105
  resolve: async (req, ctx) => { /* ... */ },
67
106
  ```
68
107
 
69
- ## Return Style
108
+ ## Return style
70
109
 
71
- ### Always Use Braces
110
+ ### Braces for `if` blocks with `return` (NOT for arrow expressions)
72
111
 
73
- No single-line returns. Always wrap in braces.
112
+ The brace rule applies to control-flow blocks not to arrow-expression bodies.
113
+
114
+ **Arrow expressions** (single-line derivations, predicates, computed requirements): the concise form is preferred. No braces, no explicit `return`.
74
115
 
75
116
  ```typescript
76
- // WRONG
117
+ // CORRECT — single-line arrow expressions stay concise
77
118
  derive: {
78
119
  isReady: (facts) => facts.phase === "ready",
120
+ greeting: (facts) => `Hi, ${facts.name}!`,
79
121
  },
80
122
 
81
123
  constraints: {
@@ -84,25 +126,26 @@ constraints: {
84
126
  require: { type: "PROCESS" },
85
127
  },
86
128
  },
129
+ ```
87
130
 
88
- // Wait -- the above IS correct for one-line arrow expressions.
89
- // The brace rule applies to if/return blocks:
131
+ **Control-flow statements** (`if`, `for`, `while`): braces required, even for single-line bodies. Single-line `if (x) return y` shapes are never used.
90
132
 
91
- // WRONG – single-line if return
133
+ ```typescript
134
+ // WRONG — single-line if return
92
135
  if (facts.user) return "ready";
93
136
 
94
- // CORRECT always use braces
137
+ // CORRECT always wrap the body in braces
95
138
  if (facts.user) {
96
139
  return "ready";
97
140
  }
98
141
  ```
99
142
 
100
- ### Blank Line Before `return`
143
+ ### Blank line before `return`
101
144
 
102
145
  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
146
 
104
147
  ```typescript
105
- // CORRECT blank line before return when code precedes it
148
+ // CORRECT blank line before return when code precedes it
106
149
  function getStatus(facts) {
107
150
  const phase = facts.phase;
108
151
  const hasUser = facts.user !== null;
@@ -110,12 +153,12 @@ function getStatus(facts) {
110
153
  return phase === "ready" && hasUser;
111
154
  }
112
155
 
113
- // CORRECT no blank line when return is first statement
156
+ // CORRECT no blank line when return is first statement
114
157
  function isReady(facts) {
115
158
  return facts.phase === "ready";
116
159
  }
117
160
 
118
- // CORRECT blank line after brace-style return block
161
+ // CORRECT blank line after brace-style return block
119
162
  function process(facts) {
120
163
  if (!facts.ready) {
121
164
  return null;
@@ -125,26 +168,20 @@ function process(facts) {
125
168
 
126
169
  return result;
127
170
  }
128
-
129
- // WRONG – no blank line before return after code
130
- function getStatus(facts) {
131
- const phase = facts.phase;
132
- return phase === "ready"; // Missing blank line
133
- }
134
171
  ```
135
172
 
136
- ## Multi-Line Code Formatting
173
+ ## Multi-line code formatting
137
174
 
138
175
  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
176
 
140
177
  ```typescript
141
- // WRONG properties crammed on one line
178
+ // WRONG properties crammed on one line
142
179
  schema: {
143
180
  facts: { phase: t.string(), count: t.number() },
144
181
  requirements: { FETCH_USER: { id: t.string() }, RESET: {} },
145
182
  },
146
183
 
147
- // CORRECT one property per line, always expanded
184
+ // CORRECT one property per line, always expanded
148
185
  schema: {
149
186
  facts: {
150
187
  phase: t.string(),
@@ -158,41 +195,31 @@ schema: {
158
195
  },
159
196
  },
160
197
 
161
- // WRONG statements crammed on one line
198
+ // WRONG statements crammed on one line
162
199
  init: (facts) => { facts.phase = "idle"; facts.count = 0; },
163
200
 
164
- // CORRECT one statement per line
201
+ // CORRECT one statement per line
165
202
  init: (facts) => {
166
203
  facts.phase = "idle";
167
204
  facts.count = 0;
168
205
  },
169
-
170
- // WRONG
171
- events: { reset: (facts) => { facts.count = 0; facts.phase = "idle"; } },
172
-
173
- // CORRECT
174
- events: {
175
- reset: (facts) => {
176
- facts.count = 0;
177
- facts.phase = "idle";
178
- },
179
- },
180
206
  ```
181
207
 
182
208
  Single-expression arrows (no braces) are fine on one line. Empty objects `{}` are fine inline.
209
+
183
210
  ```typescript
184
- // OK single expression, no braces
211
+ // OK single expression, no braces
185
212
  derive: {
186
213
  isReady: (facts) => facts.phase === "ready",
187
214
  },
188
215
 
189
- // OK empty object
216
+ // OK empty object
190
217
  RESET: {},
191
218
  ```
192
219
 
193
- ## Multi-Module Naming
220
+ ## Multi-module naming
194
221
 
195
- ### `facts.self.*` for Own Module
222
+ ### `facts.self.*` for own module
196
223
 
197
224
  In multi-module systems, constraints, effects, and derivations with `crossModuleDeps` receive namespaced facts. Own module facts are always at `facts.self.*`.
198
225
 
@@ -205,7 +232,7 @@ constraints: {
205
232
  },
206
233
  },
207
234
 
208
- // WRONG bare facts.* in multi-module context
235
+ // WRONG bare facts.* in multi-module context
209
236
  constraints: {
210
237
  loadWhenAuth: {
211
238
  when: (facts) => facts.isAuthenticated && !facts.loaded,
@@ -214,48 +241,48 @@ constraints: {
214
241
  },
215
242
  ```
216
243
 
217
- ### System-Level Access Uses Dot Notation
244
+ ### System-level access uses dot notation
218
245
 
219
246
  ```typescript
220
- // CORRECT dot notation through namespace proxy
247
+ // CORRECT dot notation through namespace proxy
221
248
  system.facts.auth.token;
222
249
  system.facts.cart.items;
223
250
  system.derive.auth.isLoggedIn;
224
251
  system.events.auth.login({ token: "..." });
225
252
 
226
- // WRONG bracket notation with internal separator
253
+ // WRONG bracket notation with internal separator
227
254
  system.facts["auth::token"];
228
255
  system.facts["auth_token"];
229
256
  ```
230
257
 
231
- ## Type Casting Rules
258
+ ## Type casting rules
232
259
 
233
- ### Never Cast When Reading
260
+ ### Never cast when reading
234
261
 
235
262
  The schema provides all types. Do not add `as` casts when reading facts or derivations from the system.
236
263
 
237
264
  ```typescript
238
- // CORRECT schema provides the type
265
+ // CORRECT schema provides the type
239
266
  const profile = system.facts.profile;
240
267
  const isReady = system.derive.isReady;
241
268
 
242
- // WRONG unnecessary cast
269
+ // WRONG unnecessary cast
243
270
  const profile = system.facts.profile as UserProfile;
244
271
  const isReady = system.derive.isReady as boolean;
245
272
  ```
246
273
 
247
- ### Cast Only in Schema Definition
274
+ ### Cast only in schema definition
248
275
 
249
- Type assertions are only valid in schema definition using the `{} as {}` pattern:
276
+ Type assertions are only valid in schema definition using the `{} as {}` pattern, or via the `t.*` builders (preferred):
250
277
 
251
278
  ```typescript
252
- // CORRECT cast in schema definition
279
+ // CORRECT cast in schema definition
253
280
  schema: {
254
281
  facts: {} as { profile: UserProfile; settings: AppSettings },
255
282
  derivations: {} as { displayName: string },
256
283
  },
257
284
 
258
- // OR use t.* builders (preferred)
285
+ // PREFERRED t.* builders
259
286
  schema: {
260
287
  facts: {
261
288
  profile: t.object<UserProfile>(),
@@ -267,17 +294,28 @@ schema: {
267
294
  },
268
295
  ```
269
296
 
270
- ## Terminology Quick Reference
297
+ ## Terminology quick reference
298
+
299
+ Two-way lookup. Search the term you know.
271
300
 
272
- | Directive Term | NEVER Use |
301
+ | Directive term | Cross-paradigm aliases (use these to search) |
273
302
  |---|---|
274
- | facts | state, store, atoms, signals |
275
- | derivations / derive | computed, selectors, getters, memos |
276
- | constraints | rules, conditions, triggers, guards |
277
- | resolvers | handlers, actions, reducers, sagas |
278
- | requirements | requests, commands, intents |
279
- | effects | watchers, subscriptions, reactions |
280
- | module | slice, feature, domain |
281
- | system | store, container, context |
282
- | `req` (parameter) | request, r, requirement (spelled out) |
283
- | `context` (parameter) | ctx, c, resolverContext |
303
+ | **facts** | state, store, atoms, signals, observables, model |
304
+ | **derivations** / `derive` | computed, selectors, getters, memos, derived stores, $: blocks (Svelte) |
305
+ | **constraints** | rules, conditions, triggers, guards, policies, invariants |
306
+ | **resolvers** | handlers, actions, reducers, sagas, thunks, effects (Redux), middleware, listeners |
307
+ | **requirements** | requests, commands, intents, queries (TanStack), tasks |
308
+ | **effects** | watchers, subscriptions, reactions, autoruns, listeners |
309
+ | **events** | actions, intents, commands, methods (Pinia), signals (NgRx) |
310
+ | **module** | slice, feature, domain, bounded context, NgRx feature module |
311
+ | **system** | store, container, context, app state, app shell |
312
+ | **`req`** (parameter) | request, r, requirement (spelled out) |
313
+ | **`context`** (parameter) | ctx, c, resolverContext |
314
+
315
+ The forbidden direction is also non-negotiable: in code Directive ships, the columns reverse. Do NOT use `state`, `store`, `selectors`, `computed`, `actions`, `reducers`, `subscriptions`, `slices`, `request`, or `ctx` in `@directive-run/*` source. The alias map is for retrieval — the canonical names are for code.
316
+
317
+ ## See also
318
+
319
+ - [`core-patterns.md`](./core-patterns.md) — the actual code shapes every naming rule here applies to
320
+ - [`multi-module.md`](./multi-module.md) — `facts.self.*` convention and dot-notation rules
321
+ - [`anti-patterns.md`](./anti-patterns.md) — naming-shaped mistakes (`request` for `req`, `ctx` for `context`, hallucinated TS schema types)
package/core/plugins.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Plugins
2
2
 
3
+ > Covers `@directive-run/core/plugins` — plugin authoring + built-ins (logging, devtools, persistence, audit-ledger, observability, OTLP).
4
+
3
5
  Plugins extend Directive systems with cross-cutting functionality like logging, persistence, devtools, and resilience patterns.
4
6
 
5
7
  ## Decision Tree: "Which plugin do I need?"
@@ -352,3 +354,8 @@ persistencePlugin({
352
354
  exclude: ["authToken", "isLoading", "error"],
353
355
  })
354
356
  ```
357
+
358
+ ## See also
359
+
360
+ - [`system-api.md`](./system-api.md) — `plugins:` option on `createSystem` and the lifecycle hooks plugins observe
361
+ - [`error-boundaries.md`](./error-boundaries.md) — `createCircuitBreaker` and the resilience plugins that pair with error boundaries