@vue-skuilder/db 0.1.22 → 0.1.24
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.
- package/dist/{contentSource-BP9hznNV.d.ts → contentSource-BotbOOfX.d.ts} +227 -3
- package/dist/{contentSource-DsJadoBU.d.cts → contentSource-C90LH-OH.d.cts} +227 -3
- package/dist/core/index.d.cts +220 -6
- package/dist/core/index.d.ts +220 -6
- package/dist/core/index.js +2052 -559
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +2035 -555
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-CHYrQ5pB.d.cts → dataLayerProvider-DGKp4zFB.d.cts} +1 -1
- package/dist/{dataLayerProvider-MDTxXq2l.d.ts → dataLayerProvider-SBpz9jQf.d.ts} +1 -1
- package/dist/impl/couch/index.d.cts +11 -3
- package/dist/impl/couch/index.d.ts +11 -3
- package/dist/impl/couch/index.js +1811 -574
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +1792 -550
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.cts +4 -4
- package/dist/impl/static/index.d.ts +4 -4
- package/dist/impl/static/index.js +1797 -560
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +1789 -547
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/{index-Dj0SEgk3.d.ts → index-BWvO-_rJ.d.ts} +1 -1
- package/dist/{index-B_j6u5E4.d.cts → index-Ba7hYbHj.d.cts} +1 -1
- package/dist/index.d.cts +150 -12
- package/dist/index.d.ts +150 -12
- package/dist/index.js +2658 -791
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2584 -747
- package/dist/index.mjs.map +1 -1
- package/dist/{types-DQaXnuoc.d.ts → types-CJrLM1Ew.d.ts} +1 -1
- package/dist/{types-Bn0itutr.d.cts → types-W8n-B6HG.d.cts} +1 -1
- package/dist/{types-legacy-DDY4N-Uq.d.cts → types-legacy-JXDxinpU.d.cts} +5 -1
- package/dist/{types-legacy-DDY4N-Uq.d.ts → types-legacy-JXDxinpU.d.ts} +5 -1
- package/dist/util/packer/index.d.cts +3 -3
- package/dist/util/packer/index.d.ts +3 -3
- package/docs/brainstorm-navigation-paradigm.md +40 -34
- package/docs/future-orchestration-vision.md +216 -0
- package/docs/navigators-architecture.md +188 -5
- package/docs/todo-strategy-authoring.md +8 -6
- package/package.json +3 -3
- package/src/core/index.ts +2 -0
- package/src/core/interfaces/contentSource.ts +7 -0
- package/src/core/interfaces/userDB.ts +6 -0
- package/src/core/navigators/Pipeline.ts +46 -0
- package/src/core/navigators/PipelineAssembler.ts +14 -1
- package/src/core/navigators/filters/WeightedFilter.ts +141 -0
- package/src/core/navigators/filters/types.ts +4 -0
- package/src/core/navigators/generators/CompositeGenerator.ts +61 -19
- package/src/core/navigators/generators/types.ts +4 -0
- package/src/core/navigators/index.ts +194 -13
- package/src/core/orchestration/gradient.ts +133 -0
- package/src/core/orchestration/index.ts +210 -0
- package/src/core/orchestration/learning.ts +250 -0
- package/src/core/orchestration/recording.ts +92 -0
- package/src/core/orchestration/signal.ts +67 -0
- package/src/core/types/contentNavigationStrategy.ts +38 -0
- package/src/core/types/learningState.ts +77 -0
- package/src/core/types/types-legacy.ts +4 -0
- package/src/core/types/userOutcome.ts +51 -0
- package/src/courseConfigRegistration.ts +546 -0
- package/src/factory.ts +6 -0
- package/src/impl/common/BaseUserDB.ts +16 -0
- package/src/index.ts +2 -0
- package/src/study/SessionController.ts +64 -1
- package/tests/core/navigators/Pipeline.test.ts +2 -0
- package/docs/todo-evolutionary-orchestration.md +0 -310
|
@@ -14,7 +14,9 @@ declare enum DocType {
|
|
|
14
14
|
SCHEDULED_CARD = "SCHEDULED_CARD",
|
|
15
15
|
TAG = "TAG",
|
|
16
16
|
NAVIGATION_STRATEGY = "NAVIGATION_STRATEGY",
|
|
17
|
-
STRATEGY_STATE = "STRATEGY_STATE"
|
|
17
|
+
STRATEGY_STATE = "STRATEGY_STATE",
|
|
18
|
+
USER_OUTCOME = "USER_OUTCOME",
|
|
19
|
+
STRATEGY_LEARNING_STATE = "STRATEGY_LEARNING_STATE"
|
|
18
20
|
}
|
|
19
21
|
interface QualifiedCardID {
|
|
20
22
|
courseID: string;
|
|
@@ -91,6 +93,8 @@ declare const DocTypePrefixes: {
|
|
|
91
93
|
readonly PEDAGOGY: "PEDAGOGY";
|
|
92
94
|
readonly NAVIGATION_STRATEGY: "NAVIGATION_STRATEGY";
|
|
93
95
|
readonly STRATEGY_STATE: "STRATEGY_STATE";
|
|
96
|
+
readonly USER_OUTCOME: "USER_OUTCOME";
|
|
97
|
+
readonly STRATEGY_LEARNING_STATE: "STRATEGY_LEARNING_STATE";
|
|
94
98
|
};
|
|
95
99
|
interface CardHistory<T extends CardRecord> {
|
|
96
100
|
_id: PouchDB.Core.DocumentId;
|
|
@@ -14,7 +14,9 @@ declare enum DocType {
|
|
|
14
14
|
SCHEDULED_CARD = "SCHEDULED_CARD",
|
|
15
15
|
TAG = "TAG",
|
|
16
16
|
NAVIGATION_STRATEGY = "NAVIGATION_STRATEGY",
|
|
17
|
-
STRATEGY_STATE = "STRATEGY_STATE"
|
|
17
|
+
STRATEGY_STATE = "STRATEGY_STATE",
|
|
18
|
+
USER_OUTCOME = "USER_OUTCOME",
|
|
19
|
+
STRATEGY_LEARNING_STATE = "STRATEGY_LEARNING_STATE"
|
|
18
20
|
}
|
|
19
21
|
interface QualifiedCardID {
|
|
20
22
|
courseID: string;
|
|
@@ -91,6 +93,8 @@ declare const DocTypePrefixes: {
|
|
|
91
93
|
readonly PEDAGOGY: "PEDAGOGY";
|
|
92
94
|
readonly NAVIGATION_STRATEGY: "NAVIGATION_STRATEGY";
|
|
93
95
|
readonly STRATEGY_STATE: "STRATEGY_STATE";
|
|
96
|
+
readonly USER_OUTCOME: "USER_OUTCOME";
|
|
97
|
+
readonly STRATEGY_LEARNING_STATE: "STRATEGY_LEARNING_STATE";
|
|
94
98
|
};
|
|
95
99
|
interface CardHistory<T extends CardRecord> {
|
|
96
100
|
_id: PouchDB.Core.DocumentId;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig, S as StaticCourseManifest } from '../../types-
|
|
2
|
-
export { C as CouchDBToStaticPacker } from '../../index-
|
|
1
|
+
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig, S as StaticCourseManifest } from '../../types-W8n-B6HG.cjs';
|
|
2
|
+
export { C as CouchDBToStaticPacker } from '../../index-Ba7hYbHj.cjs';
|
|
3
3
|
import '@vue-skuilder/common';
|
|
4
|
-
import '../../types-legacy-
|
|
4
|
+
import '../../types-legacy-JXDxinpU.cjs';
|
|
5
5
|
import 'moment';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig, S as StaticCourseManifest } from '../../types-
|
|
2
|
-
export { C as CouchDBToStaticPacker } from '../../index-
|
|
1
|
+
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig, S as StaticCourseManifest } from '../../types-CJrLM1Ew.js';
|
|
2
|
+
export { C as CouchDBToStaticPacker } from '../../index-BWvO-_rJ.js';
|
|
3
3
|
import '@vue-skuilder/common';
|
|
4
|
-
import '../../types-legacy-
|
|
4
|
+
import '../../types-legacy-JXDxinpU.js';
|
|
5
5
|
import 'moment';
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Brainstorm: Navigation Paradigm Exploration
|
|
2
2
|
|
|
3
3
|
> **Status:** Informal brainstorming. Not a design doc or TODO.
|
|
4
|
+
>
|
|
5
|
+
> **Note:** Many concepts explored here have since been implemented.
|
|
6
|
+
> See `navigators-architecture.md` for current architecture and
|
|
7
|
+
> `devlog/1032-orchestrator` for evolutionary orchestration implementation.
|
|
4
8
|
|
|
5
9
|
This document explores the navigation strategy paradigm: what other strategy types
|
|
6
10
|
might exist, where the current design shines or struggles, and what alternative
|
|
@@ -79,7 +83,8 @@ Trigger-response generators need:
|
|
|
79
83
|
4. **Exit criteria** — When does intervention end?
|
|
80
84
|
|
|
81
85
|
This argues for strategies having **lifecycle state**, not just stateless scoring.
|
|
82
|
-
|
|
86
|
+
**Update:** Strategy state storage is now implemented via `StrategyStateDoc` — see
|
|
87
|
+
`navigators-architecture.md` for details.
|
|
83
88
|
|
|
84
89
|
---
|
|
85
90
|
|
|
@@ -138,7 +143,7 @@ Strategies are instantiated per-request. No persistence of:
|
|
|
138
143
|
- "Last time I surfaced tag X was..."
|
|
139
144
|
- "This user responds well to strategy Y"
|
|
140
145
|
|
|
141
|
-
**Mitigation:** `
|
|
146
|
+
**Mitigation:** ✅ Implemented via `StrategyStateDoc` — see `navigators-architecture.md`
|
|
142
147
|
|
|
143
148
|
### 2. Pull-Only Model
|
|
144
149
|
|
|
@@ -255,25 +260,30 @@ rules:
|
|
|
255
260
|
**Pros:** Declarative, inspectable, author-configurable
|
|
256
261
|
**Cons:** Limited expressiveness, new DSL to maintain
|
|
257
262
|
|
|
258
|
-
### 4. Bandit Selection (
|
|
263
|
+
### 4. Bandit-Style Selection (IMPLEMENTED ✅)
|
|
259
264
|
|
|
260
|
-
|
|
265
|
+
Strategies carry **learnable weights** that automatically tune based on outcomes:
|
|
261
266
|
|
|
262
267
|
```
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
-
|
|
268
|
+
Strategy weights = { weight: 1.2, confidence: 0.8, sampleSize: 500 }
|
|
269
|
+
|
|
270
|
+
Users are distributed across weight space via deviation:
|
|
271
|
+
effectiveWeight = peakWeight + deviation * spread
|
|
272
|
+
|
|
273
|
+
Gradient learning correlates deviation with outcomes:
|
|
274
|
+
+deviation → +outcome → increase peak
|
|
275
|
+
+deviation → -outcome → decrease peak
|
|
271
276
|
```
|
|
272
277
|
|
|
273
|
-
**
|
|
274
|
-
|
|
278
|
+
**Implemented features:**
|
|
279
|
+
- LearnableWeight on strategies
|
|
280
|
+
- Deviation-based cohort distribution
|
|
281
|
+
- Outcome recording per user/period
|
|
282
|
+
- Gradient computation via linear regression
|
|
283
|
+
- Automatic weight updates
|
|
284
|
+
- Observability API endpoints
|
|
275
285
|
|
|
276
|
-
See `
|
|
286
|
+
See `navigators-architecture.md` for details.
|
|
277
287
|
|
|
278
288
|
### 5. LLM-Guided Selection
|
|
279
289
|
|
|
@@ -316,23 +326,20 @@ Solver finds valid card sequence.
|
|
|
316
326
|
|
|
317
327
|
Rather than wholesale paradigm shift, extend current model:
|
|
318
328
|
|
|
319
|
-
###
|
|
329
|
+
### Completed ✅
|
|
320
330
|
|
|
321
|
-
1. **
|
|
322
|
-
2. **
|
|
323
|
-
3. **
|
|
331
|
+
1. **Pipeline architecture** — Generators + Filters with provenance tracking
|
|
332
|
+
2. **Strategy state storage** — User-scoped persistence via `StrategyStateDoc`
|
|
333
|
+
3. **Evolutionary orchestration** — Learnable weights with gradient learning
|
|
334
|
+
4. **Outcome measurement** — `UserOutcomeRecord` for tracking effectiveness
|
|
335
|
+
5. **Observability** — API endpoints and admin dashboard
|
|
324
336
|
|
|
325
|
-
###
|
|
337
|
+
### Still Applicable
|
|
326
338
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
### Long-term (with evolutionary orchestration)
|
|
332
|
-
|
|
333
|
-
7. **Bandit selection** among pipelines
|
|
334
|
-
8. **Outcome measurement** for strategy effectiveness
|
|
335
|
-
9. **Hybrid architectures** where blackboard/reactive patterns augment pipeline
|
|
339
|
+
1. **Trigger-response generators** — Event-driven strategies with activation state
|
|
340
|
+
2. **Richer context** — Session state, temporal context
|
|
341
|
+
3. **Event hooks** — Strategies subscribing to card results
|
|
342
|
+
4. **Intervention protocol** — Active intervention preempts normal generation
|
|
336
343
|
|
|
337
344
|
---
|
|
338
345
|
|
|
@@ -362,8 +369,7 @@ Rather than wholesale paradigm shift, extend current model:
|
|
|
362
369
|
|
|
363
370
|
## Related Documents
|
|
364
371
|
|
|
365
|
-
- `navigators-architecture.md` — Current architecture
|
|
366
|
-
- `
|
|
367
|
-
- `todo-strategy-
|
|
368
|
-
- `
|
|
369
|
-
- `todo-provenance.md` — Audit trail (transparency)
|
|
372
|
+
- `navigators-architecture.md` — Current architecture (includes evolutionary orchestration)
|
|
373
|
+
- `future-orchestration-vision.md` — Remaining vision items (programmable strategies, self-healing)
|
|
374
|
+
- `todo-strategy-authoring.md` — Strategy creation tools (UI complete)
|
|
375
|
+
- `devlog/1032-orchestrator` — Evolutionary orchestration implementation
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Future Orchestration Vision
|
|
2
|
+
|
|
3
|
+
This document tracks aspirational features for the evolutionary orchestration system
|
|
4
|
+
that extend beyond the current implementation.
|
|
5
|
+
|
|
6
|
+
## Status: VISION / NOT STARTED
|
|
7
|
+
|
|
8
|
+
> **Prerequisite:** The core orchestration system (learnable weights, deviation-based
|
|
9
|
+
> distribution, gradient learning) is implemented. See `navigators-architecture.md`
|
|
10
|
+
> for the current architecture.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Implemented (Reference)
|
|
15
|
+
|
|
16
|
+
The following are **complete** and documented in `navigators-architecture.md`:
|
|
17
|
+
|
|
18
|
+
- ✅ LearnableWeight interface with weight, confidence, sampleSize
|
|
19
|
+
- ✅ Deviation-based weight distribution (bell curve sampling)
|
|
20
|
+
- ✅ UserOutcomeRecord for tracking learning outcomes
|
|
21
|
+
- ✅ Gradient computation via linear regression
|
|
22
|
+
- ✅ Automatic weight updates based on gradient
|
|
23
|
+
- ✅ Observability API endpoints (6 endpoints)
|
|
24
|
+
- ✅ Admin dashboard in platform-ui
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Remaining Vision
|
|
29
|
+
|
|
30
|
+
### 1. Parameterizable / Programmable Strategies
|
|
31
|
+
|
|
32
|
+
**Goal:** Enable template-based prerequisite rules that generalize across courses.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface ParameterizedPrerequisite {
|
|
36
|
+
pattern: "grade-{n} & {subject}";
|
|
37
|
+
implies: "grade-{n+1} & {subject}";
|
|
38
|
+
constraints: {
|
|
39
|
+
n: { type: "number", min: 1, max: 12 },
|
|
40
|
+
subject: { type: "tag-category", category: "academic-subject" }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Example use cases:**
|
|
46
|
+
- `grade-3 & geometry` → requires `grade-2 & geometry`
|
|
47
|
+
- `unit-{n} & {topic}` → requires `unit-{n-1} & {topic}`
|
|
48
|
+
- Cross-course strategy reuse without copy-paste
|
|
49
|
+
|
|
50
|
+
**What's needed:**
|
|
51
|
+
1. Template syntax design
|
|
52
|
+
2. Variable binding and substitution
|
|
53
|
+
3. Rule engine to evaluate parameterized rules
|
|
54
|
+
4. Cross-course strategy registry
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### 2. Self-Healing Content
|
|
59
|
+
|
|
60
|
+
**Goal:** Automatically identify learning barriers and surface them to authors.
|
|
61
|
+
|
|
62
|
+
**Barrier signals:**
|
|
63
|
+
- High failure rate on specific cards/tags
|
|
64
|
+
- ELO stagnation on specific topics
|
|
65
|
+
- Long dwell time before mastery
|
|
66
|
+
- Drop-off (users abandon at specific points)
|
|
67
|
+
- Cohort-wide plateau detection
|
|
68
|
+
|
|
69
|
+
**Components needed:**
|
|
70
|
+
1. **Barrier Detection Pipeline** — Analyze outcomes to identify stuck points
|
|
71
|
+
2. **Alert System** — Notify authors of identified barriers
|
|
72
|
+
3. **Intervention Hooks** — Enable targeted content insertion
|
|
73
|
+
4. **Feedback Loop** — Measure whether interventions resolve barriers
|
|
74
|
+
|
|
75
|
+
**Example flow:**
|
|
76
|
+
```
|
|
77
|
+
Detection: 40% of users fail on "long-division-with-remainders" after
|
|
78
|
+
mastering "long-division-no-remainder"
|
|
79
|
+
|
|
80
|
+
Alert: "Learning barrier detected between division topics.
|
|
81
|
+
Consider intermediate content for remainder concept."
|
|
82
|
+
|
|
83
|
+
Author action: Adds 5 cards on "remainder as leftover" concept
|
|
84
|
+
|
|
85
|
+
Feedback: Barrier detection re-runs, measures improvement
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 3. Cross-Course Strategy Sharing
|
|
91
|
+
|
|
92
|
+
**Goal:** Strategies that prove effective in one course can be shared and
|
|
93
|
+
adapted to other courses.
|
|
94
|
+
|
|
95
|
+
**Components:**
|
|
96
|
+
- Strategy export/import format
|
|
97
|
+
- Cross-course strategy registry
|
|
98
|
+
- Adaptation hints for tag mapping
|
|
99
|
+
- Reputation/effectiveness scores from source course
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 4. Author Incentive Mechanisms
|
|
104
|
+
|
|
105
|
+
**Goal:** Create feedback loops that reward authors for effective content.
|
|
106
|
+
|
|
107
|
+
**Potential signals:**
|
|
108
|
+
- User outcomes correlated with specific content
|
|
109
|
+
- Content utility weights (cards that consistently help)
|
|
110
|
+
- Barrier resolution credit
|
|
111
|
+
|
|
112
|
+
**Considerations:**
|
|
113
|
+
- How to attribute outcomes to specific content when many cards contribute?
|
|
114
|
+
- How to handle content that is effective but not "fun"?
|
|
115
|
+
- Privacy implications of tracking detailed content effectiveness
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### 5. Trigger-Response Generators
|
|
120
|
+
|
|
121
|
+
**Goal:** Event-driven generators that activate under specific conditions.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface TriggerResponseGenerator {
|
|
125
|
+
trigger: {
|
|
126
|
+
condition: 'failureSpike' | 'plateau' | 'returnAfterGap' | 'frustration';
|
|
127
|
+
parameters: Record<string, number>;
|
|
128
|
+
};
|
|
129
|
+
response: {
|
|
130
|
+
mode: 'remedial' | 'confidence-building' | 'capstone';
|
|
131
|
+
targetTags?: string[];
|
|
132
|
+
duration?: { cards?: number; minutes?: number };
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Example triggers:**
|
|
138
|
+
- Frustration signal (N failures in M minutes) → easier content
|
|
139
|
+
- Plateau detection (no ELO movement for K sessions) → challenging content
|
|
140
|
+
- Inactivity return (first session after gap) → review-heavy session
|
|
141
|
+
|
|
142
|
+
**What's needed:**
|
|
143
|
+
- Event bus / signal mechanism for strategies to observe events
|
|
144
|
+
- Activation state tracking ("I am currently intervening on tag T")
|
|
145
|
+
- Priority over base generator (preempt vs blend)
|
|
146
|
+
- Exit criteria (when does intervention end)
|
|
147
|
+
|
|
148
|
+
See `brainstorm-navigation-paradigm.md` for detailed exploration.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### 6. Cohort-Aware Calibration
|
|
153
|
+
|
|
154
|
+
**Goal:** Use population data to improve cold-start behavior.
|
|
155
|
+
|
|
156
|
+
**Applications:**
|
|
157
|
+
- Initial card difficulty estimates from population performance
|
|
158
|
+
- Initial interval estimates based on similar users
|
|
159
|
+
- Strategy weight priors from population effectiveness
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### 7. LLM-Guided Selection (Experimental)
|
|
164
|
+
|
|
165
|
+
**Goal:** Use language models to interpret learner state and select content.
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
Given:
|
|
169
|
+
- User profile: { elo: 950, strugglingWith: ['vowel-sounds'], ... }
|
|
170
|
+
- Session context: { duration: 12min, cardsSeen: 8, recentFailures: 2 }
|
|
171
|
+
- Available cards: [...]
|
|
172
|
+
|
|
173
|
+
Select the next 5 cards and explain reasoning.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Considerations:**
|
|
177
|
+
- Latency and cost
|
|
178
|
+
- Unpredictability and debugging difficulty
|
|
179
|
+
- When is LLM guidance worth the overhead?
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Design Decisions Ahead
|
|
184
|
+
|
|
185
|
+
### Centralized vs Decentralized Orchestration
|
|
186
|
+
|
|
187
|
+
**Option A: Central Orchestrator Service**
|
|
188
|
+
- Single service decides strategy application
|
|
189
|
+
- Cleaner cohort tracking
|
|
190
|
+
- Requires backend infrastructure
|
|
191
|
+
|
|
192
|
+
**Option B: Client-Side Orchestration**
|
|
193
|
+
- Each client computes its own strategy set
|
|
194
|
+
- Works offline
|
|
195
|
+
- Harder to track cohorts
|
|
196
|
+
|
|
197
|
+
**Current:** Hybrid — client computes from synced registry, outcomes reported to backend.
|
|
198
|
+
|
|
199
|
+
### Outcome Attribution
|
|
200
|
+
|
|
201
|
+
When multiple strategies are active, how do we attribute outcomes?
|
|
202
|
+
|
|
203
|
+
- All strategies get credit/blame equally?
|
|
204
|
+
- Weight by score contribution?
|
|
205
|
+
- Require isolated A/B cells?
|
|
206
|
+
|
|
207
|
+
**Current:** Equal attribution. Future work may instrument isolated testing.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Related Documents
|
|
212
|
+
|
|
213
|
+
- `navigators-architecture.md` — Current implementation (complete)
|
|
214
|
+
- `brainstorm-navigation-paradigm.md` — Exploration of alternative mechanisms
|
|
215
|
+
- `todo-strategy-authoring.md` — Strategy creation tools
|
|
216
|
+
- `devlog/1032-orchestrator` — Implementation details
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
The navigation strategy system selects and scores cards for study sessions. It uses a
|
|
6
6
|
**Pipeline architecture** where generators produce candidates and filters transform scores.
|
|
7
7
|
|
|
8
|
+
An **Evolutionary Orchestration** layer enables strategies to carry learnable weights that
|
|
9
|
+
automatically tune toward optimal values based on observed learning outcomes.
|
|
10
|
+
|
|
8
11
|
## Core Concepts
|
|
9
12
|
|
|
10
13
|
### WeightedCard
|
|
@@ -27,6 +30,7 @@ interface StrategyContribution {
|
|
|
27
30
|
action: 'generated' | 'passed' | 'boosted' | 'penalized';
|
|
28
31
|
score: number; // Score after this strategy
|
|
29
32
|
reason: string; // Human-readable explanation
|
|
33
|
+
deviation?: number; // User's deviation from peak weight (evolutionary)
|
|
30
34
|
}
|
|
31
35
|
```
|
|
32
36
|
|
|
@@ -82,7 +86,7 @@ class Pipeline {
|
|
|
82
86
|
)
|
|
83
87
|
|
|
84
88
|
async getWeightedCards(limit: number): Promise<WeightedCard[]> {
|
|
85
|
-
// Build shared context (user ELO, etc.)
|
|
89
|
+
// Build shared context (user ELO, orchestration context, etc.)
|
|
86
90
|
const context = await this.buildContext();
|
|
87
91
|
|
|
88
92
|
// Generate candidates
|
|
@@ -104,7 +108,7 @@ class Pipeline {
|
|
|
104
108
|
```
|
|
105
109
|
|
|
106
110
|
**Responsibilities:**
|
|
107
|
-
- **Context building** — Fetches shared data (user ELO) once for all strategies
|
|
111
|
+
- **Context building** — Fetches shared data (user ELO, orchestration context) once for all strategies
|
|
108
112
|
- **Data hydration** — Pre-fetches commonly needed data (tags) in batch queries
|
|
109
113
|
- **Filter orchestration** — Applies filters in sequence, accumulating provenance
|
|
110
114
|
- **Result selection** — Removes zero-scores, sorts, and returns top N
|
|
@@ -170,7 +174,8 @@ provenance: [
|
|
|
170
174
|
strategyId: 'NAVIGATION_STRATEGY-hierarchy-phonics',
|
|
171
175
|
action: 'passed',
|
|
172
176
|
score: 0.85,
|
|
173
|
-
reason: 'Prerequisites met, tags: letter-sounds'
|
|
177
|
+
reason: 'Prerequisites met, tags: letter-sounds',
|
|
178
|
+
deviation: 0.23 // User's position on bell curve for this strategy
|
|
174
179
|
},
|
|
175
180
|
{
|
|
176
181
|
strategy: 'eloDistance',
|
|
@@ -185,6 +190,171 @@ provenance: [
|
|
|
185
190
|
|
|
186
191
|
Use `getCardOrigin(card)` to extract 'new', 'review', or 'failed' from provenance.
|
|
187
192
|
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Evolutionary Orchestration
|
|
196
|
+
|
|
197
|
+
The orchestration layer enables strategies to **learn optimal weights** from observed
|
|
198
|
+
learning outcomes. Instead of fixed configuration, strategies carry **learnable weights**
|
|
199
|
+
that automatically tune toward effectiveness.
|
|
200
|
+
|
|
201
|
+
### LearnableWeight
|
|
202
|
+
|
|
203
|
+
Every strategy can carry a learnable weight:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface LearnableWeight {
|
|
207
|
+
weight: number; // Peak value, 1.0 = neutral, range [0.1, 3.0]
|
|
208
|
+
confidence: number; // 0-1, controls exploration width
|
|
209
|
+
sampleSize: number; // Total observations for this strategy
|
|
210
|
+
|
|
211
|
+
history?: Array<{ // Optional: for visualization
|
|
212
|
+
timestamp: string;
|
|
213
|
+
weight: number;
|
|
214
|
+
confidence: number;
|
|
215
|
+
gradient: number;
|
|
216
|
+
}>;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Strategies extend with:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
interface ContentNavigationStrategyData {
|
|
224
|
+
// ... existing fields ...
|
|
225
|
+
learnable?: LearnableWeight; // Omitted = default weight 1.0
|
|
226
|
+
staticWeight?: boolean; // If true, not subject to learning
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Deviation-Based Weight Distribution
|
|
231
|
+
|
|
232
|
+
Each user experiences a **stable deviation** from the peak weight:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
effectiveWeight(user, strategy) = peakWeight + deviation * spread
|
|
236
|
+
|
|
237
|
+
where:
|
|
238
|
+
deviation = hash(userId, strategyId, salt) → [-1, 1] // stable per user
|
|
239
|
+
spread = max(MIN_SPREAD, (1 - confidence) * MAX_SPREAD)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Key insight:** Deviation is constant for a user. As confidence grows and spread
|
|
243
|
+
shrinks, all users are pulled toward the optimal peak.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Example: Low confidence = wide exploration
|
|
247
|
+
{ weight: 1.0, confidence: 0.2 }
|
|
248
|
+
→ spread = 0.8 * MAX_SPREAD
|
|
249
|
+
→ users range from weight 0.6 to 1.4
|
|
250
|
+
|
|
251
|
+
// Example: High confidence = narrow convergence
|
|
252
|
+
{ weight: 1.2, confidence: 0.9 }
|
|
253
|
+
→ spread = 0.1 * MAX_SPREAD
|
|
254
|
+
→ users cluster around weight 1.15 to 1.25
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Outcome Recording
|
|
258
|
+
|
|
259
|
+
At the end of each learning period, user outcomes are recorded:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
interface UserOutcomeRecord {
|
|
263
|
+
_id: `USER_OUTCOME::${courseId}::${periodId}`;
|
|
264
|
+
docType: DocType.USER_OUTCOME;
|
|
265
|
+
userId: string;
|
|
266
|
+
courseId: string;
|
|
267
|
+
periodStart: string;
|
|
268
|
+
periodEnd: string;
|
|
269
|
+
strategyExposures: Array<{
|
|
270
|
+
strategyId: string;
|
|
271
|
+
deviation: number; // User's stable deviation for this strategy
|
|
272
|
+
}>;
|
|
273
|
+
outcomeValue: number; // 0-1 learning outcome signal
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The outcome signal combines multiple factors:
|
|
278
|
+
- Accuracy within target zone (not too easy, not too hard)
|
|
279
|
+
- ELO progression
|
|
280
|
+
- Session completion
|
|
281
|
+
|
|
282
|
+
### Gradient Learning
|
|
283
|
+
|
|
284
|
+
The system discovers optimal weights by correlating **deviation with outcomes**
|
|
285
|
+
across users:
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
+deviation → +outcome = positive gradient → increase peak weight
|
|
289
|
+
+deviation → -outcome = negative gradient → decrease peak weight
|
|
290
|
+
flat gradient = at optimum, increase confidence
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Linear regression on (deviation, outcome) pairs produces:
|
|
294
|
+
- **Gradient**: Direction to adjust peak
|
|
295
|
+
- **R²**: Signal quality (high = consistent effect)
|
|
296
|
+
- **Sample size**: Update confidence
|
|
297
|
+
|
|
298
|
+
### Weight Update Cycle
|
|
299
|
+
|
|
300
|
+
Periodically (or on-demand), the system updates strategy weights:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
async function runPeriodUpdate(courseId: string): Promise<void> {
|
|
304
|
+
for (const strategy of await getLearnableStrategies(courseId)) {
|
|
305
|
+
const observations = await aggregateOutcomesForGradient(strategy);
|
|
306
|
+
const { gradient, rSquared } = computeStrategyGradient(observations);
|
|
307
|
+
await updateStrategyWeight(strategy, gradient, rSquared);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Update rules:**
|
|
313
|
+
- Positive gradient → increase peak weight
|
|
314
|
+
- Negative gradient → decrease peak weight
|
|
315
|
+
- Consistent observations → increase confidence
|
|
316
|
+
- Noisy observations → decrease confidence
|
|
317
|
+
|
|
318
|
+
### Observability
|
|
319
|
+
|
|
320
|
+
The orchestration layer exposes API endpoints for monitoring:
|
|
321
|
+
|
|
322
|
+
| Endpoint | Purpose |
|
|
323
|
+
|----------|---------|
|
|
324
|
+
| `GET /orchestration/:courseId/state` | All learning states |
|
|
325
|
+
| `GET /orchestration/:courseId/weights` | Current weights summary |
|
|
326
|
+
| `GET /orchestration/:courseId/strategy/:id/history` | Weight trajectory over time |
|
|
327
|
+
| `GET /orchestration/:courseId/strategy/:id/scatter` | Deviation vs outcome data |
|
|
328
|
+
| `GET /orchestration/:courseId/strategy/:id/distribution` | Bell curve visualization |
|
|
329
|
+
| `POST /orchestration/:courseId/update` | Trigger period update |
|
|
330
|
+
|
|
331
|
+
An admin dashboard in platform-ui visualizes strategy weights, confidence,
|
|
332
|
+
gradient direction, and historical trajectories.
|
|
333
|
+
|
|
334
|
+
### Lifecycle
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
New strategy: Low confidence → wide spread → noisy gradient → big adjustments
|
|
338
|
+
Learning: Gradient visible → peak drifts → confidence grows → spread shrinks
|
|
339
|
+
Converged: High confidence → minimum spread → flat gradient → stable
|
|
340
|
+
Disturbed: Gradient reappears → peak drifts → adapts to new optimal
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Static vs Learnable
|
|
344
|
+
|
|
345
|
+
Set `staticWeight: true` for foundational strategies that should not be tuned:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
{
|
|
349
|
+
strategyType: 'hierarchyDefinition',
|
|
350
|
+
name: 'Core Prerequisites',
|
|
351
|
+
staticWeight: true, // Never tuned by orchestration
|
|
352
|
+
// learnable field ignored
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
188
358
|
## Creating New Strategies
|
|
189
359
|
|
|
190
360
|
### Generator
|
|
@@ -249,6 +419,8 @@ class MyFilter extends ContentNavigator implements CardFilter {
|
|
|
249
419
|
|
|
250
420
|
Register in `NavigatorRoles` as `NavigatorRole.FILTER`.
|
|
251
421
|
|
|
422
|
+
---
|
|
423
|
+
|
|
252
424
|
## Strategy State Storage
|
|
253
425
|
|
|
254
426
|
Strategies can persist user-scoped state (preferences, learned patterns, temporal tracking)
|
|
@@ -294,7 +466,7 @@ interface StrategyStateDoc<T> {
|
|
|
294
466
|
courseId: string;
|
|
295
467
|
strategyKey: string;
|
|
296
468
|
data: T; // Strategy-specific payload
|
|
297
|
-
updatedAt: string;
|
|
469
|
+
updatedAt: string;
|
|
298
470
|
}
|
|
299
471
|
```
|
|
300
472
|
|
|
@@ -332,6 +504,8 @@ return { ...card, score: card.score * multiplier };
|
|
|
332
504
|
- All sliders share global max for consistent visual comparison
|
|
333
505
|
- Writes to strategy state via `userDB.putStrategyState()`
|
|
334
506
|
|
|
507
|
+
---
|
|
508
|
+
|
|
335
509
|
## File Reference
|
|
336
510
|
|
|
337
511
|
| File | Purpose |
|
|
@@ -355,9 +529,18 @@ return { ...card, score: card.score * multiplier };
|
|
|
355
529
|
| `core/navigators/inferredPreference.ts` | Inferred preference navigator (stub) |
|
|
356
530
|
| `core/types/strategyState.ts` | `StrategyStateDoc`, `StrategyStateId` |
|
|
357
531
|
| `impl/couch/courseDB.ts` | `createNavigator()` entry point |
|
|
532
|
+
| `core/orchestration/index.ts` | OrchestrationContext, deviation logic |
|
|
533
|
+
| `core/orchestration/gradient.ts` | Gradient computation |
|
|
534
|
+
| `core/orchestration/learning.ts` | Weight updates, period orchestration |
|
|
535
|
+
| `core/orchestration/signal.ts` | Outcome signal computation |
|
|
536
|
+
| `core/orchestration/recording.ts` | User outcome recording |
|
|
537
|
+
| `core/types/learningState.ts` | `StrategyLearningState` |
|
|
538
|
+
| `core/types/userOutcome.ts` | `UserOutcomeRecord` |
|
|
539
|
+
| `express/routes/orchestration.ts` | Observability API endpoints |
|
|
358
540
|
|
|
359
541
|
## Related Documentation
|
|
360
542
|
|
|
361
543
|
- `todo-strategy-authoring.md` — UX and DX for authoring strategies
|
|
362
|
-
- `
|
|
544
|
+
- `future-orchestration-vision.md` — Long-term adaptive strategy vision (beyond current implementation)
|
|
363
545
|
- `devlog/1004` — Implementation details for tag hydration optimization
|
|
546
|
+
- `devlog/1032-orchestrator` — Evolutionary orchestration implementation details
|