@mindrian_os/install 1.13.0-beta.13 → 1.13.0-beta.14

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 (116) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +16 -11
  3. package/README.md +74 -572
  4. package/commands/act.md +1 -0
  5. package/commands/admin.md +1 -0
  6. package/commands/analyze-needs.md +1 -0
  7. package/commands/analyze-systems.md +1 -0
  8. package/commands/analyze-timing.md +1 -0
  9. package/commands/auto-explore.md +1 -0
  10. package/commands/beautiful-question.md +1 -0
  11. package/commands/brain-derive.md +1 -0
  12. package/commands/build-knowledge.md +1 -0
  13. package/commands/build-thesis.md +1 -0
  14. package/commands/causal.md +1 -0
  15. package/commands/challenge-assumptions.md +1 -0
  16. package/commands/compare-ventures.md +1 -0
  17. package/commands/dashboard.md +1 -0
  18. package/commands/deep-grade.md +1 -0
  19. package/commands/diagnose.md +1 -0
  20. package/commands/diagnostics.md +1 -0
  21. package/commands/doctor.md +1 -0
  22. package/commands/dominant-designs.md +1 -0
  23. package/commands/explain-decision.md +1 -0
  24. package/commands/explore-domains.md +1 -0
  25. package/commands/explore-futures.md +1 -0
  26. package/commands/explore-trends.md +1 -0
  27. package/commands/export.md +1 -0
  28. package/commands/feynman-timeline-refresh.md +78 -0
  29. package/commands/file-meeting.md +1 -0
  30. package/commands/find-analogies.md +1 -0
  31. package/commands/find-bottlenecks.md +1 -0
  32. package/commands/find-connections.md +1 -0
  33. package/commands/funding.md +1 -0
  34. package/commands/grade.md +1 -0
  35. package/commands/graph.md +1 -0
  36. package/commands/hat-briefing.md +1 -0
  37. package/commands/heal.md +1 -0
  38. package/commands/help.md +1 -0
  39. package/commands/hmi-status.md +1 -0
  40. package/commands/jtbd.md +1 -0
  41. package/commands/leadership.md +1 -0
  42. package/commands/lean-canvas.md +1 -0
  43. package/commands/macro-trends.md +1 -0
  44. package/commands/map-unknowns.md +1 -0
  45. package/commands/memory.md +1 -0
  46. package/commands/models.md +1 -0
  47. package/commands/mos-reason.md +1 -0
  48. package/commands/mullins.md +1 -0
  49. package/commands/new-project.md +1 -0
  50. package/commands/onboard.md +1 -0
  51. package/commands/operator.md +1 -0
  52. package/commands/opportunities.md +1 -0
  53. package/commands/organize.md +1 -0
  54. package/commands/persona.md +1 -0
  55. package/commands/pipeline.md +1 -0
  56. package/commands/present.md +1 -0
  57. package/commands/publish.md +1 -0
  58. package/commands/query.md +1 -0
  59. package/commands/radar.md +1 -0
  60. package/commands/reanalyze.md +1 -0
  61. package/commands/research.md +1 -0
  62. package/commands/room.md +1 -0
  63. package/commands/rooms.md +1 -0
  64. package/commands/root-cause.md +1 -0
  65. package/commands/rs-experts.md +1 -0
  66. package/commands/rs-explain.md +1 -0
  67. package/commands/rs-fetch.md +1 -0
  68. package/commands/rs-thesis.md +1 -0
  69. package/commands/scenario-plan.md +1 -0
  70. package/commands/scheduled-tasks.md +1 -0
  71. package/commands/score-innovation.md +1 -0
  72. package/commands/scout.md +1 -0
  73. package/commands/setup.md +1 -0
  74. package/commands/snapshot.md +1 -0
  75. package/commands/speakers.md +1 -0
  76. package/commands/splash.md +1 -0
  77. package/commands/status.md +1 -0
  78. package/commands/structure-argument.md +1 -0
  79. package/commands/suggest-next.md +1 -0
  80. package/commands/systems-thinking.md +1 -0
  81. package/commands/think-hats.md +1 -0
  82. package/commands/update.md +1 -0
  83. package/commands/user-needs.md +1 -0
  84. package/commands/validate.md +1 -0
  85. package/commands/value-proposition.md +1 -0
  86. package/commands/vault.md +1 -0
  87. package/commands/visualize.md +1 -0
  88. package/commands/whitespace.md +1 -0
  89. package/commands/wiki.md +1 -0
  90. package/lib/brain/framework-chain-slice.cjs +193 -0
  91. package/lib/core/feynman/ROOM.md +25 -0
  92. package/lib/core/feynman/timeline-renderer.cjs +197 -0
  93. package/lib/core/feynman/timeline-runner.cjs +281 -0
  94. package/lib/core/navigation/edges.cjs +86 -0
  95. package/lib/core/navigation/insights.cjs +37 -0
  96. package/lib/core/navigation/memory-events.cjs +39 -0
  97. package/lib/core/navigation/packet.cjs +89 -9
  98. package/lib/core/navigation/projections.cjs +201 -0
  99. package/lib/core/navigation.cjs +25 -0
  100. package/lib/mcp/larry-server-instructions.md +1 -1
  101. package/lib/memory/brain-cypher-chain-slice.test.cjs +368 -0
  102. package/lib/memory/f-selector-ranker.test.cjs +593 -0
  103. package/lib/memory/navigation-projections.test.cjs +241 -0
  104. package/lib/memory/navigation-write-edge.test.cjs +206 -0
  105. package/lib/memory/packet-chain-hint.test.cjs +407 -0
  106. package/lib/memory/packet-schema-validation.test.cjs +317 -0
  107. package/lib/memory/per-command-jtbd-derivation.test.cjs +130 -0
  108. package/lib/memory/per-command-teaching.test.cjs +110 -0
  109. package/lib/memory/run-feynman-tests.cjs +36 -0
  110. package/lib/memory/selector-decisions.test.cjs +417 -0
  111. package/lib/memory/selector-miss.test.cjs +290 -0
  112. package/lib/workflow/f-selector-ranker.cjs +420 -0
  113. package/lib/workflow/selector-decisions.cjs +368 -0
  114. package/package.json +1 -1
  115. package/references/design/email-template-standard.md +1 -1
  116. package/references/user-research/2026-04-05-leah-lawrence-session.md +3 -3
@@ -0,0 +1,290 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 125-07 -- lib/workflow/selector-decisions.cjs::recordSelectorMiss test suite (D8).
5
+ *
6
+ * Covers 10 acceptance behaviors from 125-07-PLAN.md <behavior> block:
7
+ * Test 1 recordSelectorMiss writes memory_event with event_type='f_selector_miss'
8
+ * Test 2 Payload preserves top_k_offered array verbatim ({command, score} pairs)
9
+ * Test 3 Payload preserves user_intent verbatim
10
+ * Test 4 Payload includes investment_level_at_decision (roomState or 0 default)
11
+ * Test 5 NO cascade edge written (count(*) FROM edges unchanged)
12
+ * Test 6 No external routing: source body has zero mos:do/invoke/exec/spawn matches
13
+ * Test 7 Invalid top_k_offered (not array) -> {ok:false, reason:'invalid_top_k_offered'}
14
+ * Test 8 Empty user_intent ('') -> {ok:false, reason:'invalid_user_intent'}
15
+ * Test 9 Missing db -> {ok:false, reason:'invalid_db'}
16
+ * Test 10 top_k_offered objects with extra fields are sanitized to {command, score} only
17
+ *
18
+ * Three-surface compatibility: pure CJS + node:test. Uses fs.mkdtempSync +
19
+ * openRoomDb fixture pattern from Plan 06 / Plan 00. All writes route through
20
+ * the navigation.cjs chokepoint; the test asserts the memory_event row lands
21
+ * AND that NO edge row is written (D8 temporal-only invariant).
22
+ */
23
+
24
+ 'use strict';
25
+
26
+ const { test } = require('node:test');
27
+ const { ok, equal, deepStrictEqual } = require('node:assert/strict');
28
+ const fs = require('node:fs');
29
+ const os = require('node:os');
30
+ const path = require('node:path');
31
+
32
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
33
+ const SELECTOR_DECISIONS_PATH = path.join(REPO_ROOT, 'lib', 'workflow', 'selector-decisions.cjs');
34
+ const { openRoomDb } = require(path.join(REPO_ROOT, 'lib', 'core', 'room-db.cjs'));
35
+ const selectorDecisions = require(SELECTOR_DECISIONS_PATH);
36
+
37
+ function freshDb() {
38
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'p125-07-selector-miss-'));
39
+ const db = openRoomDb(dir);
40
+ return { dir, db };
41
+ }
42
+
43
+ function fetchMemoryEvent(db, missId) {
44
+ return db.prepare(
45
+ "SELECT id, type, properties FROM nodes WHERE id = ?"
46
+ ).get(missId);
47
+ }
48
+
49
+ function countMemoryMissEvents(db) {
50
+ return db.prepare(
51
+ "SELECT COUNT(*) AS c FROM nodes WHERE type = 'memory_event' " +
52
+ "AND json_extract(properties, '$.event_type') = 'f_selector_miss'"
53
+ ).get().c;
54
+ }
55
+
56
+ function countAllEdges(db) {
57
+ return db.prepare("SELECT COUNT(*) AS c FROM edges").get().c;
58
+ }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Test 1: recordSelectorMiss writes memory_event with event_type='f_selector_miss'.
62
+ // ---------------------------------------------------------------------------
63
+ test('Test 1: recordSelectorMiss writes memory_event(event_type=f_selector_miss)', () => {
64
+ const { db } = freshDb();
65
+ const r = selectorDecisions.recordSelectorMiss({
66
+ top_k_offered: [{ command: 'mos:bq', score: 0.7 }],
67
+ user_intent: 'I need to validate my pricing strategy',
68
+ roomState: { db, investment_level: 0.3 },
69
+ });
70
+ ok(r.ok, 'recordSelectorMiss should return ok: true; got reason=' + (r && r.reason));
71
+ ok(typeof r.miss_id === 'string' && r.miss_id.length > 0, 'miss_id is non-empty string');
72
+ const row = fetchMemoryEvent(db, r.miss_id);
73
+ ok(row, 'memory_event row present in nodes table');
74
+ equal(row.type, 'memory_event');
75
+ const props = JSON.parse(row.properties);
76
+ equal(props.event_type, 'f_selector_miss');
77
+ equal(countMemoryMissEvents(db), 1, 'exactly one f_selector_miss row exists');
78
+ });
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Test 2: Payload preserves top_k_offered array verbatim with all {command, score} pairs.
82
+ // ---------------------------------------------------------------------------
83
+ test('Test 2: payload preserves top_k_offered array verbatim ({command, score} pairs)', () => {
84
+ const { db } = freshDb();
85
+ const offered = [
86
+ { command: 'mos:bq', score: 0.91 },
87
+ { command: 'mos:swot', score: 0.74 },
88
+ { command: 'mos:jtbd', score: 0.55 },
89
+ ];
90
+ const r = selectorDecisions.recordSelectorMiss({
91
+ top_k_offered: offered,
92
+ user_intent: 'something else entirely',
93
+ roomState: { db },
94
+ });
95
+ ok(r.ok);
96
+ const row = fetchMemoryEvent(db, r.miss_id);
97
+ const props = JSON.parse(row.properties);
98
+ ok(Array.isArray(props.top_k_offered), 'top_k_offered is array');
99
+ equal(props.top_k_offered.length, 3, '3 offered items preserved');
100
+ deepStrictEqual(props.top_k_offered, offered, 'top_k_offered preserved verbatim');
101
+ });
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // Test 3: Payload preserves user_intent verbatim.
105
+ // ---------------------------------------------------------------------------
106
+ test('Test 3: payload preserves user_intent verbatim', () => {
107
+ const { db } = freshDb();
108
+ const intent = 'help me think about board governance for a translational lab';
109
+ const r = selectorDecisions.recordSelectorMiss({
110
+ top_k_offered: [{ command: 'mos:bq', score: 0.5 }],
111
+ user_intent: intent,
112
+ roomState: { db },
113
+ });
114
+ ok(r.ok);
115
+ const row = fetchMemoryEvent(db, r.miss_id);
116
+ const props = JSON.parse(row.properties);
117
+ equal(props.user_intent, intent, 'user_intent verbatim in payload');
118
+ });
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // Test 4: Payload includes investment_level_at_decision (matches roomState or 0 default).
122
+ // ---------------------------------------------------------------------------
123
+ test('Test 4: payload includes investment_level_at_decision (roomState.investment_level)', () => {
124
+ const { db } = freshDb();
125
+ const r1 = selectorDecisions.recordSelectorMiss({
126
+ top_k_offered: [{ command: 'mos:a', score: 0.5 }],
127
+ user_intent: 'x',
128
+ roomState: { db, investment_level: 0.42 },
129
+ });
130
+ ok(r1.ok);
131
+ const props1 = JSON.parse(fetchMemoryEvent(db, r1.miss_id).properties);
132
+ equal(props1.investment_level_at_decision, 0.42, 'investment_level_at_decision matches roomState');
133
+
134
+ // Default 0 when not supplied.
135
+ const r2 = selectorDecisions.recordSelectorMiss({
136
+ top_k_offered: [{ command: 'mos:b', score: 0.5 }],
137
+ user_intent: 'y',
138
+ roomState: { db },
139
+ });
140
+ ok(r2.ok);
141
+ const props2 = JSON.parse(fetchMemoryEvent(db, r2.miss_id).properties);
142
+ equal(props2.investment_level_at_decision, 0, 'default 0 when roomState.investment_level absent');
143
+ });
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Test 5: NO cascade edge written -- count(*) FROM edges before == after.
147
+ // ---------------------------------------------------------------------------
148
+ test('Test 5: no cascade edge written (D8 temporal-only invariant)', () => {
149
+ const { db } = freshDb();
150
+ const before = countAllEdges(db);
151
+ const r = selectorDecisions.recordSelectorMiss({
152
+ top_k_offered: [{ command: 'mos:bq', score: 0.7 }, { command: 'mos:swot', score: 0.5 }],
153
+ user_intent: 'I want grant funding strategy',
154
+ roomState: { db, investment_level: 0.6 },
155
+ });
156
+ ok(r.ok);
157
+ const after = countAllEdges(db);
158
+ equal(after, before, 'edges row count unchanged (zero new edges from miss capture)');
159
+ });
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Test 6: Source-grep audit -- recordSelectorMiss body has zero external routing.
163
+ // Per D8: recordSelectorMiss does NOT invoke /mos:do; consumer is responsible.
164
+ // ---------------------------------------------------------------------------
165
+ test('Test 6: source-grep audit: no mos:do/invoke/exec/spawn in recordSelectorMiss body', () => {
166
+ const src = fs.readFileSync(SELECTOR_DECISIONS_PATH, 'utf8');
167
+ // Extract the recordSelectorMiss function body. Scan from declaration to the
168
+ // closing brace at column 0 (matches the existing module style).
169
+ const startIdx = src.indexOf('function recordSelectorMiss');
170
+ ok(startIdx >= 0, 'recordSelectorMiss declaration present in source');
171
+ // Capture roughly the next ~3000 chars (function is ~50 lines per Plan 07 spec).
172
+ const slice = src.slice(startIdx, startIdx + 3000);
173
+ // Find the function-closing brace (first `^}` at line start after the declaration).
174
+ const lines = slice.split('\n');
175
+ let body = '';
176
+ let depth = 0;
177
+ let started = false;
178
+ for (const line of lines) {
179
+ body += line + '\n';
180
+ for (const ch of line) {
181
+ if (ch === '{') { depth++; started = true; }
182
+ else if (ch === '}') { depth--; }
183
+ }
184
+ if (started && depth === 0) break;
185
+ }
186
+ // Now assert no external-routing tokens.
187
+ ok(!/mos:do/.test(body), 'no mos:do invocation in recordSelectorMiss body');
188
+ ok(!/\bspawn\s*\(/.test(body), 'no spawn() in recordSelectorMiss body');
189
+ ok(!/\bexec\s*\(/.test(body), 'no exec() in recordSelectorMiss body');
190
+ ok(!/child_process/.test(body), 'no child_process in recordSelectorMiss body');
191
+ });
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // Test 7: Invalid top_k_offered (not an array) returns {ok:false, reason:'invalid_top_k_offered'}.
195
+ // ---------------------------------------------------------------------------
196
+ test('Test 7: invalid top_k_offered returns {ok:false, reason:invalid_top_k_offered}', () => {
197
+ const { db } = freshDb();
198
+ const r = selectorDecisions.recordSelectorMiss({
199
+ top_k_offered: 'not-an-array',
200
+ user_intent: 'x',
201
+ roomState: { db },
202
+ });
203
+ equal(r.ok, false);
204
+ equal(r.reason, 'invalid_top_k_offered');
205
+ });
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Test 8: Empty user_intent ('') returns {ok:false, reason:'invalid_user_intent'}.
209
+ // ---------------------------------------------------------------------------
210
+ test('Test 8: empty user_intent returns {ok:false, reason:invalid_user_intent}', () => {
211
+ const { db } = freshDb();
212
+ const r = selectorDecisions.recordSelectorMiss({
213
+ top_k_offered: [{ command: 'mos:bq', score: 0.5 }],
214
+ user_intent: '',
215
+ roomState: { db },
216
+ });
217
+ equal(r.ok, false);
218
+ equal(r.reason, 'invalid_user_intent');
219
+
220
+ // Non-string also invalid.
221
+ const r2 = selectorDecisions.recordSelectorMiss({
222
+ top_k_offered: [{ command: 'mos:bq', score: 0.5 }],
223
+ user_intent: null,
224
+ roomState: { db },
225
+ });
226
+ equal(r2.ok, false);
227
+ equal(r2.reason, 'invalid_user_intent');
228
+ });
229
+
230
+ // ---------------------------------------------------------------------------
231
+ // Test 9: Missing db returns {ok:false, reason:'invalid_db'}.
232
+ // ---------------------------------------------------------------------------
233
+ test('Test 9: missing db on roomState returns {ok:false, reason:invalid_db}', () => {
234
+ const r = selectorDecisions.recordSelectorMiss({
235
+ top_k_offered: [{ command: 'mos:bq', score: 0.5 }],
236
+ user_intent: 'something',
237
+ roomState: {},
238
+ });
239
+ equal(r.ok, false);
240
+ equal(r.reason, 'invalid_db');
241
+
242
+ // Also when roomState entirely absent.
243
+ const r2 = selectorDecisions.recordSelectorMiss({
244
+ top_k_offered: [{ command: 'mos:bq', score: 0.5 }],
245
+ user_intent: 'something',
246
+ });
247
+ equal(r2.ok, false);
248
+ equal(r2.reason, 'invalid_db');
249
+ });
250
+
251
+ // ---------------------------------------------------------------------------
252
+ // Test 10: top_k_offered objects with extra fields are sanitized to {command, score} only.
253
+ // ---------------------------------------------------------------------------
254
+ test('Test 10: extra fields on top_k_offered items are sanitized away in payload', () => {
255
+ const { db } = freshDb();
256
+ const offeredWithExtras = [
257
+ {
258
+ command: 'mos:bq',
259
+ score: 0.91,
260
+ teaching: 'long teaching prose that should NOT land in the payload',
261
+ jtbd_summary: 'a summary that should NOT land either',
262
+ framework: 'Beautiful Question Framework',
263
+ why: 'should NOT land',
264
+ },
265
+ {
266
+ command: 'mos:swot',
267
+ score: 0.74,
268
+ teaching: 'more teaching prose',
269
+ source: 'packet',
270
+ },
271
+ ];
272
+ const r = selectorDecisions.recordSelectorMiss({
273
+ top_k_offered: offeredWithExtras,
274
+ user_intent: 'sanitize this',
275
+ roomState: { db },
276
+ });
277
+ ok(r.ok);
278
+ const props = JSON.parse(fetchMemoryEvent(db, r.miss_id).properties);
279
+ ok(Array.isArray(props.top_k_offered));
280
+ equal(props.top_k_offered.length, 2);
281
+ // Each item must carry ONLY command + score (no teaching, no jtbd_summary, no extras).
282
+ for (const item of props.top_k_offered) {
283
+ const keys = Object.keys(item).sort();
284
+ deepStrictEqual(keys, ['command', 'score'], 'sanitized to exactly command + score keys');
285
+ }
286
+ equal(props.top_k_offered[0].command, 'mos:bq');
287
+ equal(props.top_k_offered[0].score, 0.91);
288
+ equal(props.top_k_offered[1].command, 'mos:swot');
289
+ equal(props.top_k_offered[1].score, 0.74);
290
+ });