@remnic/core 9.25.3 → 9.25.5

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 (161) hide show
  1. package/dist/access-admin-ops-surface.d.ts +3 -2
  2. package/dist/access-admin-ops-surface.js +9 -8
  3. package/dist/access-authorization-probe.d.ts +10 -3
  4. package/dist/access-authorization-probe.js +12 -9
  5. package/dist/access-boundary.d.ts +6 -3
  6. package/dist/access-boundary.js +13 -10
  7. package/dist/access-cli.js +42 -41
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-http.d.ts +3 -2
  10. package/dist/access-http.js +16 -15
  11. package/dist/access-identity-continuity-surface.d.ts +2 -1
  12. package/dist/access-identity-continuity-surface.js +9 -8
  13. package/dist/access-lcm-surface.d.ts +3 -2
  14. package/dist/access-lcm-surface.js +9 -8
  15. package/dist/access-mcp-output-schemas.js +1 -1
  16. package/dist/access-mcp.d.ts +3 -2
  17. package/dist/access-mcp.js +13 -12
  18. package/dist/access-namespace-preflight.js +9 -8
  19. package/dist/access-observe-write-surface.d.ts +3 -2
  20. package/dist/access-observe-write-surface.js +9 -8
  21. package/dist/access-operations-batch.js +10 -9
  22. package/dist/access-operations.d.ts +6 -5
  23. package/dist/access-operations.js +11 -10
  24. package/dist/access-recall-concurrency.d.ts +3 -2
  25. package/dist/access-recall-concurrency.js +9 -8
  26. package/dist/access-recall-response.d.ts +4 -2
  27. package/dist/access-recall-response.js +9 -8
  28. package/dist/access-recall-surface.d.ts +3 -2
  29. package/dist/access-recall-surface.js +9 -8
  30. package/dist/access-schema.d.ts +76 -76
  31. package/dist/{access-service-BlNKWBC9.d.ts → access-service-BJQ22URi.d.ts} +4 -1
  32. package/dist/access-service.d.ts +3 -2
  33. package/dist/access-service.js +9 -8
  34. package/dist/access-surface-catalog.d.ts +3 -2
  35. package/dist/bootstrap.d.ts +2 -1
  36. package/dist/briefing.js +3 -3
  37. package/dist/causal-consolidation.js +4 -4
  38. package/dist/{chunk-GF22HWS2.js → chunk-2PHX3I5C.js} +7 -7
  39. package/dist/{chunk-3I35RLJW.js → chunk-32XTXKIA.js} +14 -13
  40. package/dist/chunk-32XTXKIA.js.map +1 -0
  41. package/dist/{chunk-LXKJNUND.js → chunk-37VPMR4E.js} +2 -2
  42. package/dist/{chunk-3CDMIR3C.js → chunk-3CHQZVAL.js} +2 -2
  43. package/dist/{chunk-U37RGPJT.js → chunk-5J7HJ7RT.js} +2 -2
  44. package/dist/{chunk-AGR7MGUX.js → chunk-7IGWPXVC.js} +2 -2
  45. package/dist/{chunk-FIGDB2HR.js → chunk-7KXQ44PA.js} +2 -2
  46. package/dist/chunk-AHVEHR6K.js +82 -0
  47. package/dist/chunk-AHVEHR6K.js.map +1 -0
  48. package/dist/{chunk-MNLZGCM2.js → chunk-AQ2ZQYDI.js} +3 -3
  49. package/dist/{chunk-TWCOYET2.js → chunk-B6JDYXL7.js} +2 -1
  50. package/dist/chunk-B6JDYXL7.js.map +1 -0
  51. package/dist/{chunk-RROMWDDC.js → chunk-BL4JHZSO.js} +49 -12
  52. package/dist/chunk-BL4JHZSO.js.map +1 -0
  53. package/dist/{chunk-PXJ4A6IK.js → chunk-BUK2FXOL.js} +133 -105
  54. package/dist/chunk-BUK2FXOL.js.map +1 -0
  55. package/dist/{chunk-JMDZDT24.js → chunk-D7MAWMMK.js} +18 -4
  56. package/dist/chunk-D7MAWMMK.js.map +1 -0
  57. package/dist/{chunk-TG2DJFH7.js → chunk-E5A6C4A5.js} +20 -20
  58. package/dist/{chunk-NBT7O25Z.js → chunk-FR75B4UU.js} +82 -56
  59. package/dist/chunk-FR75B4UU.js.map +1 -0
  60. package/dist/{chunk-DPYYSG6F.js → chunk-G6MGAE36.js} +7 -7
  61. package/dist/{chunk-GNFZFJBJ.js → chunk-IR4LGIH6.js} +2 -2
  62. package/dist/{chunk-MPDX5QMH.js → chunk-JA4HEXV7.js} +2 -2
  63. package/dist/{chunk-XTAAG4SQ.js → chunk-K4DP5KZA.js} +6 -6
  64. package/dist/{chunk-AT6DNUCM.js → chunk-NY6W6CJW.js} +2 -2
  65. package/dist/{chunk-NMGO2HAZ.js → chunk-OIE242WM.js} +2 -2
  66. package/dist/{chunk-SZN6XVFC.js → chunk-PS5OG75R.js} +2 -2
  67. package/dist/{chunk-VY6SDKWZ.js → chunk-SSYBI43M.js} +2 -2
  68. package/dist/{chunk-IE4HB6O5.js → chunk-TPYZ727G.js} +3 -3
  69. package/dist/{chunk-5ZGWA4AG.js → chunk-UMFLAACL.js} +6 -6
  70. package/dist/{chunk-THHPDPMS.js → chunk-UOURUMBN.js} +2 -2
  71. package/dist/{chunk-6LRTGCRV.js → chunk-VPSAVXHM.js} +3 -3
  72. package/dist/{chunk-AL4TZWI3.js → chunk-W33DEUKR.js} +2 -2
  73. package/dist/{chunk-W4ZDTHWZ.js → chunk-WIGBTWXA.js} +2 -2
  74. package/dist/{chunk-NVYCTASB.js → chunk-WSEA52RI.js} +2 -2
  75. package/dist/{chunk-LARPWF3S.js → chunk-ZPUFQGUF.js} +4 -4
  76. package/dist/{cli-Zc6UclD1.d.ts → cli-1W7cNjJJ.d.ts} +2 -2
  77. package/dist/cli.d.ts +4 -3
  78. package/dist/cli.js +28 -27
  79. package/dist/compounding/engine.js +3 -3
  80. package/dist/connectors/codex-materialize-runner.js +3 -3
  81. package/dist/connectors/index.js +3 -3
  82. package/dist/corpus-watermark.js +5 -5
  83. package/dist/entity-retrieval.js +3 -3
  84. package/dist/explicit-capture.d.ts +2 -1
  85. package/dist/extraction.js +5 -1
  86. package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
  87. package/dist/index.d.ts +391 -390
  88. package/dist/index.js +74 -54
  89. package/dist/lcm/engine.js +3 -3
  90. package/dist/lcm/index.js +8 -8
  91. package/dist/maintenance/memory-governance.js +3 -3
  92. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  93. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  94. package/dist/mcp-memory-inspector-app.d.ts +3 -2
  95. package/dist/namespaces/migrate.js +4 -4
  96. package/dist/namespaces/storage.js +3 -3
  97. package/dist/operator-doctor-corpus.js +6 -6
  98. package/dist/operator-toolkit.js +9 -9
  99. package/dist/orchestration/maintenance.js +8 -8
  100. package/dist/{orchestrator-BTGgoKli.d.ts → orchestrator-BtA1wC5K.d.ts} +2 -0
  101. package/dist/orchestrator.d.ts +2 -1
  102. package/dist/orchestrator.js +42 -41
  103. package/dist/recall-context-composition.d.ts +30 -0
  104. package/dist/recall-context-composition.js +24 -0
  105. package/dist/recall-context-composition.js.map +1 -0
  106. package/dist/schemas.d.ts +54 -54
  107. package/dist/semantic-consolidation.js +4 -4
  108. package/dist/semantic-rule-promotion.js +3 -3
  109. package/dist/semantic-rule-verifier.js +3 -3
  110. package/dist/shared-context/manager.d.ts +8 -8
  111. package/dist/storage.js +2 -2
  112. package/dist/transfer/types.d.ts +66 -66
  113. package/dist/verified-recall.js +3 -3
  114. package/package.json +2 -2
  115. package/src/access-authorization-probe.ts +30 -1
  116. package/src/access-boundary.ts +21 -0
  117. package/src/access-http.test.ts +86 -1
  118. package/src/access-http.ts +6 -6
  119. package/src/access-mcp-output-schemas.ts +1 -0
  120. package/src/access-recall-response.ts +18 -13
  121. package/src/access-recall-surface.ts +11 -1
  122. package/src/access-service.ts +3 -0
  123. package/src/extraction-prompt-safety.test.ts +179 -0
  124. package/src/extraction.ts +186 -205
  125. package/src/index.ts +1 -1
  126. package/src/orchestration/orchestrator-helpers.ts +2 -0
  127. package/src/orchestration/recall-internal.ts +49 -49
  128. package/src/recall-context-composition.test.ts +90 -0
  129. package/src/recall-context-composition.ts +104 -0
  130. package/src/recall-curiosity-composition.test.ts +301 -0
  131. package/dist/chunk-3I35RLJW.js.map +0 -1
  132. package/dist/chunk-JMDZDT24.js.map +0 -1
  133. package/dist/chunk-NBT7O25Z.js.map +0 -1
  134. package/dist/chunk-PXJ4A6IK.js.map +0 -1
  135. package/dist/chunk-RROMWDDC.js.map +0 -1
  136. package/dist/chunk-TWCOYET2.js.map +0 -1
  137. /package/dist/{chunk-GF22HWS2.js.map → chunk-2PHX3I5C.js.map} +0 -0
  138. /package/dist/{chunk-LXKJNUND.js.map → chunk-37VPMR4E.js.map} +0 -0
  139. /package/dist/{chunk-3CDMIR3C.js.map → chunk-3CHQZVAL.js.map} +0 -0
  140. /package/dist/{chunk-U37RGPJT.js.map → chunk-5J7HJ7RT.js.map} +0 -0
  141. /package/dist/{chunk-AGR7MGUX.js.map → chunk-7IGWPXVC.js.map} +0 -0
  142. /package/dist/{chunk-FIGDB2HR.js.map → chunk-7KXQ44PA.js.map} +0 -0
  143. /package/dist/{chunk-MNLZGCM2.js.map → chunk-AQ2ZQYDI.js.map} +0 -0
  144. /package/dist/{chunk-TG2DJFH7.js.map → chunk-E5A6C4A5.js.map} +0 -0
  145. /package/dist/{chunk-DPYYSG6F.js.map → chunk-G6MGAE36.js.map} +0 -0
  146. /package/dist/{chunk-GNFZFJBJ.js.map → chunk-IR4LGIH6.js.map} +0 -0
  147. /package/dist/{chunk-MPDX5QMH.js.map → chunk-JA4HEXV7.js.map} +0 -0
  148. /package/dist/{chunk-XTAAG4SQ.js.map → chunk-K4DP5KZA.js.map} +0 -0
  149. /package/dist/{chunk-AT6DNUCM.js.map → chunk-NY6W6CJW.js.map} +0 -0
  150. /package/dist/{chunk-NMGO2HAZ.js.map → chunk-OIE242WM.js.map} +0 -0
  151. /package/dist/{chunk-SZN6XVFC.js.map → chunk-PS5OG75R.js.map} +0 -0
  152. /package/dist/{chunk-VY6SDKWZ.js.map → chunk-SSYBI43M.js.map} +0 -0
  153. /package/dist/{chunk-IE4HB6O5.js.map → chunk-TPYZ727G.js.map} +0 -0
  154. /package/dist/{chunk-5ZGWA4AG.js.map → chunk-UMFLAACL.js.map} +0 -0
  155. /package/dist/{chunk-THHPDPMS.js.map → chunk-UOURUMBN.js.map} +0 -0
  156. /package/dist/{chunk-6LRTGCRV.js.map → chunk-VPSAVXHM.js.map} +0 -0
  157. /package/dist/{chunk-AL4TZWI3.js.map → chunk-W33DEUKR.js.map} +0 -0
  158. /package/dist/{chunk-W4ZDTHWZ.js.map → chunk-WIGBTWXA.js.map} +0 -0
  159. /package/dist/{chunk-NVYCTASB.js.map → chunk-WSEA52RI.js.map} +0 -0
  160. /package/dist/{chunk-LARPWF3S.js.map → chunk-ZPUFQGUF.js.map} +0 -0
  161. /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
@@ -0,0 +1,301 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { parseConfig } from "./config.js";
8
+ import { EngramAccessService } from "./access-service.js";
9
+ import { Orchestrator } from "./orchestrator.js";
10
+ import type { RecallContextComposition } from "./recall-context-composition.js";
11
+
12
+ async function makeOrchestrator(injectQuestions: boolean): Promise<{
13
+ orchestrator: Orchestrator;
14
+ memoryDir: string;
15
+ }> {
16
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-curiosity-composition-"));
17
+ const orchestrator = new Orchestrator(
18
+ parseConfig({
19
+ openaiApiKey: "test-key",
20
+ memoryDir,
21
+ workspaceDir: path.join(memoryDir, "workspace"),
22
+ injectQuestions,
23
+ qmdEnabled: false,
24
+ embeddingFallbackEnabled: false,
25
+ recallPlannerEnabled: false,
26
+ sharedContextEnabled: false,
27
+ }),
28
+ );
29
+ await orchestrator.initialize();
30
+ return { orchestrator, memoryDir };
31
+ }
32
+
33
+ async function recallWithComposition(orchestrator: Orchestrator): Promise<{
34
+ legacyContext: string;
35
+ composition: RecallContextComposition | undefined;
36
+ }> {
37
+ let composition: RecallContextComposition | undefined;
38
+ const legacyContext = await orchestrator.recall("Which deployment decision matters?", "session-a", {
39
+ onContextComposition: (value: RecallContextComposition) => {
40
+ composition = value;
41
+ },
42
+ });
43
+ return { legacyContext, composition };
44
+ }
45
+
46
+ test("enabled injectQuestions emits one separate curiosity footer while preserving legacy context", async () => {
47
+ const { orchestrator, memoryDir } = await makeOrchestrator(true);
48
+ try {
49
+ await orchestrator.storage.writeQuestion(
50
+ "Which deployment decision needs an owner?",
51
+ "The rollout is waiting for an owner.",
52
+ 1,
53
+ );
54
+
55
+ const { composition, legacyContext } = await recallWithComposition(orchestrator);
56
+
57
+ assert.equal(composition?.context.includes("## Open Question"), false);
58
+ assert.equal(
59
+ composition?.footer,
60
+ "## Open Question\n\n" +
61
+ "Something I've been curious about: Which deployment decision needs an owner?\n\n" +
62
+ "_Context: The rollout is waiting for an owner._",
63
+ );
64
+ assert.match(legacyContext, /## Open Question/);
65
+ } finally {
66
+ await orchestrator.destroy();
67
+ await rm(memoryDir, { recursive: true, force: true });
68
+ }
69
+ });
70
+
71
+ test("disabled or empty injectQuestions emits no curiosity footer", async () => {
72
+ const disabled = await makeOrchestrator(false);
73
+ const empty = await makeOrchestrator(true);
74
+ try {
75
+ await disabled.orchestrator.storage.writeQuestion("Should this stay hidden?", "Disabled.", 1);
76
+
77
+ const disabledResult = await recallWithComposition(disabled.orchestrator);
78
+ const emptyResult = await recallWithComposition(empty.orchestrator);
79
+
80
+ assert.equal(disabledResult.composition?.footer, undefined);
81
+ assert.doesNotMatch(disabledResult.legacyContext, /## Open Question/);
82
+ assert.equal(emptyResult.composition?.footer, undefined);
83
+ assert.doesNotMatch(emptyResult.legacyContext, /## Open Question/);
84
+ } finally {
85
+ await disabled.orchestrator.destroy();
86
+ await empty.orchestrator.destroy();
87
+ await rm(disabled.memoryDir, { recursive: true, force: true });
88
+ await rm(empty.memoryDir, { recursive: true, force: true });
89
+ }
90
+ });
91
+
92
+ test("injectQuestions reads the question queue for the recalled namespace", async () => {
93
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-curiosity-namespace-"));
94
+ const orchestrator = new Orchestrator(
95
+ parseConfig({
96
+ openaiApiKey: "test-key",
97
+ memoryDir,
98
+ workspaceDir: path.join(memoryDir, "workspace"),
99
+ injectQuestions: true,
100
+ namespacesEnabled: true,
101
+ defaultNamespace: "default",
102
+ sharedNamespace: "shared",
103
+ namespacePolicies: [
104
+ { name: "alpha", readPrincipals: ["reader"], writePrincipals: ["reader"] },
105
+ { name: "beta", readPrincipals: ["reader"], writePrincipals: ["reader"] },
106
+ ],
107
+ principalFromSessionKeyMode: "disabled",
108
+ defaultRecallNamespaces: [],
109
+ qmdEnabled: false,
110
+ embeddingFallbackEnabled: false,
111
+ recallPlannerEnabled: false,
112
+ sharedContextEnabled: false,
113
+ }),
114
+ );
115
+ await orchestrator.initialize();
116
+ try {
117
+ await (await orchestrator.getStorage("alpha")).writeQuestion(
118
+ "Which alpha decision needs review?",
119
+ "Alpha context.",
120
+ 1,
121
+ );
122
+ await (await orchestrator.getStorage("beta")).writeQuestion(
123
+ "Which beta decision needs review?",
124
+ "Beta context.",
125
+ 1,
126
+ );
127
+
128
+ let composition: RecallContextComposition | undefined;
129
+ await orchestrator.recall("Which decision matters?", "session-alpha", {
130
+ namespace: "alpha",
131
+ principalOverride: "reader",
132
+ onContextComposition: (value: RecallContextComposition) => {
133
+ composition = value;
134
+ },
135
+ });
136
+
137
+ assert.match(composition?.footer ?? "", /Which alpha decision needs review\?/);
138
+ assert.doesNotMatch(composition?.footer ?? "", /Which beta decision needs review\?/);
139
+ } finally {
140
+ await orchestrator.destroy();
141
+ await rm(memoryDir, { recursive: true, force: true });
142
+ }
143
+ });
144
+
145
+ test("access recall returns the configured curiosity footer in its server response", async () => {
146
+ const { orchestrator, memoryDir } = await makeOrchestrator(true);
147
+ try {
148
+ await orchestrator.storage.writeQuestion(
149
+ "Which server-side decision needs review?",
150
+ "The daemon should compose the same footer.",
151
+ 1,
152
+ );
153
+
154
+ const response = await new EngramAccessService(orchestrator).recall({
155
+ query: "Which decision matters?",
156
+ sessionKey: "daemon-session",
157
+ });
158
+
159
+ assert.match(response.context, /## Open Question/);
160
+ assert.equal(
161
+ response.contextComposition?.footer,
162
+ "## Open Question\n\n" +
163
+ "Something I've been curious about: Which server-side decision needs review?\n\n" +
164
+ "_Context: The daemon should compose the same footer._",
165
+ );
166
+ assert.match(response.context, /Which server-side decision needs review\?/);
167
+ } finally {
168
+ await orchestrator.destroy();
169
+ await rm(memoryDir, { recursive: true, force: true });
170
+ }
171
+ });
172
+ test("a throwing composition observer cannot discard the recall result", async () => {
173
+ const { orchestrator, memoryDir } = await makeOrchestrator(true);
174
+ try {
175
+ await orchestrator.storage.writeQuestion(
176
+ "Which deployment decision needs an owner?",
177
+ "The rollout is waiting for an owner.",
178
+ 1,
179
+ );
180
+
181
+ const recalled = await orchestrator.recall("Which deployment decision matters?", "observer-session", {
182
+ onContextComposition: () => {
183
+ throw new Error("observer failed");
184
+ },
185
+ });
186
+
187
+ assert.match(recalled, /Which deployment decision needs an owner\?/);
188
+ } finally {
189
+ await orchestrator.destroy();
190
+ await rm(memoryDir, { recursive: true, force: true });
191
+ }
192
+ });
193
+
194
+ test("questions section maxChars bounds the curiosity footer and reports it in recall metadata", async () => {
195
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-curiosity-section-cap-"));
196
+ const orchestrator = new Orchestrator(
197
+ parseConfig({
198
+ openaiApiKey: "test-key",
199
+ memoryDir,
200
+ workspaceDir: path.join(memoryDir, "workspace"),
201
+ injectQuestions: true,
202
+ recallPipeline: [{ id: "questions", enabled: true, maxChars: 40 }],
203
+ qmdEnabled: false,
204
+ embeddingFallbackEnabled: false,
205
+ recallPlannerEnabled: false,
206
+ sharedContextEnabled: false,
207
+ }),
208
+ );
209
+ await orchestrator.initialize();
210
+ try {
211
+ await orchestrator.storage.writeQuestion(
212
+ "Which deployment decision needs an owner?",
213
+ "The rollout is waiting for an owner.",
214
+ 1,
215
+ );
216
+
217
+ let composition: RecallContextComposition | undefined;
218
+ const recalled = await orchestrator.recall("Which deployment decision matters?", "section-cap-session", {
219
+ onContextComposition: (value: RecallContextComposition) => {
220
+ composition = value;
221
+ },
222
+ });
223
+ const footer = composition?.footer ?? "";
224
+ const snapshot = orchestrator.getLastRecall("section-cap-session");
225
+
226
+ assert.ok(footer.length > 0);
227
+ assert.ok(footer.length <= 40);
228
+ assert.match(recalled, /\.\.\.\(memory context trimmed\)$/);
229
+ assert.ok(snapshot?.sourcesUsed?.includes("questions"));
230
+ assert.ok(snapshot?.budgetsApplied?.includedSections?.includes("questions"));
231
+ } finally {
232
+ await orchestrator.destroy();
233
+ await rm(memoryDir, { recursive: true, force: true });
234
+ }
235
+ });
236
+
237
+ test("questions section maxChars zero suppresses the curiosity footer", async () => {
238
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-curiosity-section-disabled-"));
239
+ const orchestrator = new Orchestrator(
240
+ parseConfig({
241
+ openaiApiKey: "test-key",
242
+ memoryDir,
243
+ workspaceDir: path.join(memoryDir, "workspace"),
244
+ injectQuestions: true,
245
+ recallPipeline: [{ id: "questions", enabled: true, maxChars: 0 }],
246
+ qmdEnabled: false,
247
+ embeddingFallbackEnabled: false,
248
+ recallPlannerEnabled: false,
249
+ sharedContextEnabled: false,
250
+ }),
251
+ );
252
+ await orchestrator.initialize();
253
+ try {
254
+ await orchestrator.storage.writeQuestion(
255
+ "Which deployment decision needs an owner?",
256
+ "The rollout is waiting for an owner.",
257
+ 1,
258
+ );
259
+
260
+ let composition: RecallContextComposition | undefined;
261
+ const recalled = await orchestrator.recall("Which deployment decision matters?", "section-zero-session", {
262
+ onContextComposition: (value: RecallContextComposition) => {
263
+ composition = value;
264
+ },
265
+ });
266
+
267
+ assert.equal(composition?.footer, undefined);
268
+ assert.doesNotMatch(recalled, /## Open Question/);
269
+ } finally {
270
+ await orchestrator.destroy();
271
+ await rm(memoryDir, { recursive: true, force: true });
272
+ }
273
+ });
274
+ test("an async composition observer rejection cannot become unhandled", async () => {
275
+ const { orchestrator, memoryDir } = await makeOrchestrator(true);
276
+ let unhandled = false;
277
+ const onUnhandledRejection = () => {
278
+ unhandled = true;
279
+ };
280
+ process.on("unhandledRejection", onUnhandledRejection);
281
+ try {
282
+ await orchestrator.storage.writeQuestion(
283
+ "Which deployment decision needs an owner?",
284
+ "The rollout is waiting for an owner.",
285
+ 1,
286
+ );
287
+
288
+ await orchestrator.recall("Which deployment decision matters?", "async-observer-session", {
289
+ onContextComposition: async () => {
290
+ throw new Error("async observer failed");
291
+ },
292
+ });
293
+ await new Promise<void>((resolve) => setImmediate(resolve));
294
+
295
+ assert.equal(unhandled, false);
296
+ } finally {
297
+ process.off("unhandledRejection", onUnhandledRejection);
298
+ await orchestrator.destroy();
299
+ await rm(memoryDir, { recursive: true, force: true });
300
+ }
301
+ });