@directive-run/knowledge 1.1.0 → 1.1.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.
@@ -182,6 +182,38 @@ const count = useSelector(system, (s) => s.facts.count);
182
182
  const events = useEvent(system);
183
183
  ```
184
184
 
185
+ ## createDirectiveContext
186
+
187
+ Eliminates prop-drilling by providing the system via React context:
188
+
189
+ ```typescript
190
+ import { createDirectiveContext } from "@directive-run/react";
191
+
192
+ const Counter = createDirectiveContext(counterSystem);
193
+
194
+ function App() {
195
+ return (
196
+ <Counter.Provider>
197
+ <Display />
198
+ </Counter.Provider>
199
+ );
200
+ }
201
+
202
+ function Display() {
203
+ const count = Counter.useFact("count"); // No system arg needed
204
+ const doubled = Counter.useDerived("doubled");
205
+ const events = Counter.useEvents();
206
+ return <button onClick={() => events.increment()}>{count}</button>;
207
+ }
208
+ ```
209
+
210
+ Returns: `{ Provider, useSystem, useFact, useDerived, useEvents, useDispatch, useSelector, useWatch, useInspect, useExplain, useHistory }`.
211
+
212
+ Provider accepts `system` prop override for testing:
213
+ ```tsx
214
+ <Counter.Provider system={testSystem}><ComponentUnderTest /></Counter.Provider>
215
+ ```
216
+
185
217
  ## Common Mistakes
186
218
 
187
219
  ### Creating the system inside a component without useSystem
@@ -150,29 +150,35 @@ const total = system.read("cart.totalPrice");
150
150
  ```typescript
151
151
  const inspection = system.inspect();
152
152
 
153
- // Full fact snapshot
154
- inspection.facts;
155
- // { count: 5, phase: "done", user: { id: "1", name: "Alice" } }
153
+ // Unmet requirements
154
+ inspection.unmet;
155
+ // [{ id: "req-1", requirement: { type: "FETCH_USER" }, fromConstraint: "needsUser" }]
156
156
 
157
- // Derivation values
158
- inspection.derivations;
159
- // { isLoading: false, displayName: "Alice" }
157
+ // Inflight resolvers
158
+ inspection.inflight;
159
+ // [{ id: "req-2", resolverId: "fetchData", startedAt: 1709000000 }]
160
160
 
161
- // Active requirements
162
- inspection.requirements;
163
- // [{ id: "req-1", type: "FETCH_USER", userId: "1" }]
161
+ // Facts with meta
162
+ inspection.facts;
163
+ // [{ key: "userId", meta: { label: "User ID" } }, { key: "count" }]
164
164
 
165
- // Constraint definitions and state
166
- inspection.constraintDefs;
167
- // [{ id: "fetchWhenAuth", priority: 0, disabled: false }]
165
+ // Constraints with state + meta
166
+ inspection.constraints;
167
+ // [{ id: "needsUser", active: true, disabled: false, priority: 0, hitCount: 3, meta: { label: "..." } }]
168
168
 
169
- // Resolver statuses
169
+ // Resolver definitions + meta
170
+ inspection.resolverDefs;
171
+ // [{ id: "fetchUser", requirement: "FETCH_USER", meta: { label: "..." } }]
172
+
173
+ // Resolver statuses (inflight only)
170
174
  inspection.resolvers;
171
- // { fetchUser: { state: "success", duration: 150 } }
175
+ // { "req-1": { state: "running" } }
172
176
 
173
- // Currently inflight resolvers
174
- inspection.inflight;
175
- // [{ id: "req-2", resolverId: "fetchData", startedAt: 1709000000 }]
177
+ // Effects, derivations, modules — all with optional meta
178
+ inspection.effects; // [{ id: "log", meta: { ... } }]
179
+ inspection.derivations; // [{ id: "doubled", meta: { ... } }]
180
+ inspection.modules; // [{ id: "auth", meta: { ... } }]
181
+ inspection.events; // [{ name: "increment", meta: { ... } }]
176
182
 
177
183
  // Unmet requirements (no matching resolver)
178
184
  inspection.unmet;
@@ -221,6 +227,28 @@ system.meta.byTag("pii"); // MetaMatch[] — all PII-tagged fields
221
227
 
222
228
  Meta is frozen at registration (Object.create(null) + Object.freeze). Zero hot-path cost. See [Definition Meta docs](https://directive.run/docs/advanced/meta).
223
229
 
230
+ ## Observation Protocol
231
+
232
+ Typed event stream for all lifecycle events — enables browser extensions, third-party tools, and test assertions:
233
+
234
+ ```typescript
235
+ import type { ObservationEvent } from "@directive-run/core";
236
+
237
+ const unsub = system.observe((event: ObservationEvent) => {
238
+ if (event.type === "constraint.evaluate") console.log(event.id, event.active);
239
+ if (event.type === "resolver.complete") console.log(event.resolver, event.duration);
240
+ if (event.type === "fact.change") console.log(event.key, event.prev, "→", event.next);
241
+ });
242
+
243
+ // 18 event types: fact.change, constraint.evaluate/error, requirement.created/met/canceled,
244
+ // resolver.start/complete/error, effect.run/error, derivation.compute,
245
+ // reconcile.start/end, system.init/start/stop/destroy
246
+
247
+ unsub(); // Stop observing
248
+ ```
249
+
250
+ Zero overhead when no observers. Implemented as an internal plugin.
251
+
224
252
  ## Lifecycle
225
253
 
226
254
  ```typescript
package/core/testing.md CHANGED
@@ -215,6 +215,47 @@ it("processes intermediate state", async () => {
215
215
  });
216
216
  ```
217
217
 
218
+ ## Coverage Tracking
219
+
220
+ Track which constraints, resolvers, effects, and derivations are exercised:
221
+
222
+ ```typescript
223
+ import { createCoverageTracker } from "@directive-run/core/testing";
224
+
225
+ const { run, report } = createCoverageTracker(system);
226
+
227
+ await run(async () => {
228
+ system.facts.userId = 123;
229
+ await system.settle();
230
+ });
231
+
232
+ const coverage = report();
233
+ // coverage.constraintCoverage — 0-1 (percentage hit)
234
+ // coverage.resolverCoverage — 0-1
235
+ // coverage.effectCoverage — 0-1
236
+ // coverage.derivationCoverage — 0-1
237
+ // coverage.constraintsMissed — Set<string> of IDs never triggered
238
+ ```
239
+
240
+ ## Test Observer
241
+
242
+ Collect observation events for assertion-based testing:
243
+
244
+ ```typescript
245
+ import { createTestObserver } from "@directive-run/core/testing";
246
+
247
+ const observer = createTestObserver(system);
248
+
249
+ system.facts.count = 5;
250
+ await system.settle();
251
+
252
+ const evals = observer.ofType("constraint.evaluate");
253
+ expect(evals).toHaveLength(1);
254
+
255
+ observer.clear(); // Reset
256
+ observer.dispose(); // Stop observing
257
+ ```
258
+
218
259
  ## Common Mistakes
219
260
 
220
261
  ### Testing real resolvers instead of mocking
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directive-run/knowledge",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Knowledge files, examples, and validation for Directive — the constraint-driven TypeScript runtime.",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "author": "Jason Comes",
@@ -51,8 +51,8 @@
51
51
  "tsx": "^4.19.2",
52
52
  "typescript": "^5.7.2",
53
53
  "vitest": "^3.0.0",
54
- "@directive-run/core": "1.1.0",
55
- "@directive-run/ai": "1.1.0"
54
+ "@directive-run/core": "1.1.2",
55
+ "@directive-run/ai": "1.1.2"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsx scripts/generate-api-skeleton.ts && tsx scripts/generate-sitemap.ts && tsx scripts/extract-examples.ts && tsup",