@remnic/core 9.3.680 → 9.3.682

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 (167) hide show
  1. package/dist/access-boundary.d.ts +178 -0
  2. package/dist/access-boundary.js +121 -0
  3. package/dist/access-cli.js +115 -101
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +1 -1
  6. package/dist/access-http.js +48 -46
  7. package/dist/access-mcp.d.ts +1 -1
  8. package/dist/access-mcp.js +44 -42
  9. package/dist/access-operations.d.ts +127 -0
  10. package/dist/access-operations.js +115 -0
  11. package/dist/access-operations.js.map +1 -0
  12. package/dist/access-schema.d.ts +34 -34
  13. package/dist/access-schema.js +6 -6
  14. package/dist/{access-service-S9oGKPZc.d.ts → access-service-DvA6jyHL.d.ts} +1 -1
  15. package/dist/access-service.d.ts +1 -1
  16. package/dist/access-service.js +40 -40
  17. package/dist/access-surface-catalog.d.ts +125 -0
  18. package/dist/access-surface-catalog.js +162 -0
  19. package/dist/access-surface-catalog.js.map +1 -0
  20. package/dist/adapters/index.js +7 -7
  21. package/dist/adapters/registry.js +3 -3
  22. package/dist/auto-sync-5CJBJMPZ.js +1 -1
  23. package/dist/briefing.js +8 -8
  24. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  25. package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
  26. package/dist/causal-behavior.js +5 -5
  27. package/dist/causal-chain.js +3 -3
  28. package/dist/causal-consolidation.js +16 -16
  29. package/dist/causal-retrieval.js +3 -3
  30. package/dist/causal-trajectory.js +1 -1
  31. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  32. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  33. package/dist/{chunk-3OKWZT7F.js → chunk-3IND7N4X.js} +2 -2
  34. package/dist/{chunk-GYSYLGNE.js → chunk-7MOTEVAA.js} +2 -2
  35. package/dist/{chunk-6T4LTI2F.js → chunk-7XH7VJN4.js} +4 -4
  36. package/dist/{chunk-AGNBY3VG.js → chunk-APJQ6UEA.js} +4 -4
  37. package/dist/{chunk-LZSMQHXC.js → chunk-ARLRTZZZ.js} +5 -5
  38. package/dist/{chunk-DL6H3D7S.js → chunk-ARV3AUOM.js} +2 -2
  39. package/dist/{chunk-Q2H5U37U.js → chunk-B2B2IHUH.js} +2 -2
  40. package/dist/{chunk-SECQS4G4.js → chunk-BTVX7ZXZ.js} +5 -5
  41. package/dist/{chunk-DGEZKYVI.js → chunk-DOCTITOP.js} +4 -4
  42. package/dist/{chunk-EQYP3HA6.js → chunk-EG4TCVMU.js} +2 -2
  43. package/dist/{chunk-SLTKP5WJ.js → chunk-EW5KFXHL.js} +4 -4
  44. package/dist/{chunk-5TEYIXMP.js → chunk-FDSOMA6M.js} +28 -41
  45. package/dist/chunk-FDSOMA6M.js.map +1 -0
  46. package/dist/{chunk-CTCPB57O.js → chunk-G7Z3C2X6.js} +2 -2
  47. package/dist/{chunk-OBM7EVFU.js → chunk-H4BDNIKQ.js} +53 -53
  48. package/dist/{chunk-MTJ2LFAJ.js → chunk-H6PMGMNP.js} +2 -2
  49. package/dist/{chunk-7AAKSHDG.js → chunk-I3HSKQT7.js} +136 -136
  50. package/dist/{chunk-NXBXM7Q6.js → chunk-I75DF4FZ.js} +2 -2
  51. package/dist/{chunk-RC3AFF6Z.js → chunk-JD4SCARD.js} +1 -1
  52. package/dist/{chunk-LVTTO3VC.js → chunk-KACIOX42.js} +2 -2
  53. package/dist/{chunk-VDX2J7OX.js → chunk-KQAFEZQX.js} +2 -2
  54. package/dist/{chunk-ATRB6Q25.js → chunk-KV6CX4ON.js} +2 -2
  55. package/dist/{chunk-VL5JJOOY.js → chunk-L5MUA6Q7.js} +5 -5
  56. package/dist/{chunk-W67ZZDHO.js → chunk-M4I3TREG.js} +75 -75
  57. package/dist/chunk-NHFXF4ZO.js +107 -0
  58. package/dist/chunk-NHFXF4ZO.js.map +1 -0
  59. package/dist/{chunk-MNUPGYIV.js → chunk-NQMBSSWW.js} +2 -2
  60. package/dist/{chunk-V4ZHKCGA.js → chunk-O2WELT5C.js} +5 -5
  61. package/dist/{chunk-Z6SEG36L.js → chunk-OUWAQVDJ.js} +4 -4
  62. package/dist/{chunk-57ME5VSI.js → chunk-Q5ZU3RNY.js} +4 -4
  63. package/dist/{chunk-ACYX37IM.js → chunk-QUA2JPH2.js} +6 -6
  64. package/dist/{chunk-DWQPM67F.js → chunk-QVWM4C24.js} +37 -32
  65. package/dist/chunk-QVWM4C24.js.map +1 -0
  66. package/dist/{chunk-2AP4QJX5.js → chunk-TOQEZ63C.js} +8 -8
  67. package/dist/{chunk-EUM7CZFM.js → chunk-TY5NT3T3.js} +17 -17
  68. package/dist/{chunk-ZCVPFDHB.js → chunk-UAODC6GJ.js} +14 -14
  69. package/dist/{chunk-JI6HWBYL.js → chunk-UDJLF3BO.js} +2 -2
  70. package/dist/{chunk-YJ4J2JJ2.js → chunk-UJDV2NLT.js} +9 -9
  71. package/dist/chunk-V254FAT5.js +85 -0
  72. package/dist/chunk-V254FAT5.js.map +1 -0
  73. package/dist/{chunk-3IE22DJ2.js → chunk-WEPMT6SC.js} +10 -10
  74. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  75. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  76. package/dist/{cli-B2Ve7R22.d.ts → cli-feUe-x3I.d.ts} +1 -1
  77. package/dist/cli.d.ts +2 -2
  78. package/dist/cli.js +75 -73
  79. package/dist/compounding/engine.js +9 -9
  80. package/dist/connectors/codex-materialize-runner.js +9 -9
  81. package/dist/connectors/index.js +9 -9
  82. package/dist/consolidation-provenance-check.js +2 -2
  83. package/dist/dashboard-runtime.js +2 -2
  84. package/dist/entity-retrieval.js +7 -7
  85. package/dist/extraction.js +2 -2
  86. package/dist/{first-start-migration-PG5HBC3K.js → first-start-migration-FF7YFGRP.js} +4 -4
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.js +209 -207
  89. package/dist/index.js.map +1 -1
  90. package/dist/lcm/engine.js +4 -4
  91. package/dist/lcm/index.js +12 -12
  92. package/dist/maintenance/memory-governance.js +8 -8
  93. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
  94. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  95. package/dist/mcp-memory-inspector-app.d.ts +1 -1
  96. package/dist/namespaces/migrate.js +17 -17
  97. package/dist/namespaces/search.js +8 -8
  98. package/dist/namespaces/storage.js +8 -8
  99. package/dist/operator-toolkit.js +22 -22
  100. package/dist/orchestrator.js +70 -70
  101. package/dist/resume-bundles.js +1 -1
  102. package/dist/schemas.d.ts +28 -28
  103. package/dist/search/factory.js +7 -7
  104. package/dist/search/index.js +11 -11
  105. package/dist/search/lancedb-backend.js +3 -3
  106. package/dist/search/meilisearch-backend.js +3 -3
  107. package/dist/search/orama-backend.js +3 -3
  108. package/dist/semantic-consolidation.js +11 -11
  109. package/dist/semantic-rule-promotion.js +7 -7
  110. package/dist/semantic-rule-verifier.js +8 -8
  111. package/dist/storage.js +6 -6
  112. package/dist/transfer/backup.js +4 -4
  113. package/dist/transfer/capsule-export.js +4 -4
  114. package/dist/transfer/capsule-import.js +3 -3
  115. package/dist/transfer/import-sqlite.js +2 -2
  116. package/dist/transfer/types.d.ts +20 -20
  117. package/dist/verified-recall.js +8 -8
  118. package/package.json +2 -2
  119. package/src/access-boundary.test.ts +212 -0
  120. package/src/access-boundary.ts +235 -0
  121. package/src/access-cli.ts +32 -15
  122. package/src/access-http.ts +38 -28
  123. package/src/access-mcp.ts +41 -35
  124. package/src/access-operations.ts +157 -0
  125. package/src/access-surface-catalog.test.ts +772 -0
  126. package/src/access-surface-catalog.ts +218 -0
  127. package/dist/chunk-5TEYIXMP.js.map +0 -1
  128. package/dist/chunk-DWQPM67F.js.map +0 -1
  129. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-boundary.js.map} +0 -0
  130. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  131. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  132. /package/dist/{chunk-3OKWZT7F.js.map → chunk-3IND7N4X.js.map} +0 -0
  133. /package/dist/{chunk-GYSYLGNE.js.map → chunk-7MOTEVAA.js.map} +0 -0
  134. /package/dist/{chunk-6T4LTI2F.js.map → chunk-7XH7VJN4.js.map} +0 -0
  135. /package/dist/{chunk-AGNBY3VG.js.map → chunk-APJQ6UEA.js.map} +0 -0
  136. /package/dist/{chunk-LZSMQHXC.js.map → chunk-ARLRTZZZ.js.map} +0 -0
  137. /package/dist/{chunk-DL6H3D7S.js.map → chunk-ARV3AUOM.js.map} +0 -0
  138. /package/dist/{chunk-Q2H5U37U.js.map → chunk-B2B2IHUH.js.map} +0 -0
  139. /package/dist/{chunk-SECQS4G4.js.map → chunk-BTVX7ZXZ.js.map} +0 -0
  140. /package/dist/{chunk-DGEZKYVI.js.map → chunk-DOCTITOP.js.map} +0 -0
  141. /package/dist/{chunk-EQYP3HA6.js.map → chunk-EG4TCVMU.js.map} +0 -0
  142. /package/dist/{chunk-SLTKP5WJ.js.map → chunk-EW5KFXHL.js.map} +0 -0
  143. /package/dist/{chunk-CTCPB57O.js.map → chunk-G7Z3C2X6.js.map} +0 -0
  144. /package/dist/{chunk-OBM7EVFU.js.map → chunk-H4BDNIKQ.js.map} +0 -0
  145. /package/dist/{chunk-MTJ2LFAJ.js.map → chunk-H6PMGMNP.js.map} +0 -0
  146. /package/dist/{chunk-7AAKSHDG.js.map → chunk-I3HSKQT7.js.map} +0 -0
  147. /package/dist/{chunk-NXBXM7Q6.js.map → chunk-I75DF4FZ.js.map} +0 -0
  148. /package/dist/{chunk-RC3AFF6Z.js.map → chunk-JD4SCARD.js.map} +0 -0
  149. /package/dist/{chunk-LVTTO3VC.js.map → chunk-KACIOX42.js.map} +0 -0
  150. /package/dist/{chunk-VDX2J7OX.js.map → chunk-KQAFEZQX.js.map} +0 -0
  151. /package/dist/{chunk-ATRB6Q25.js.map → chunk-KV6CX4ON.js.map} +0 -0
  152. /package/dist/{chunk-VL5JJOOY.js.map → chunk-L5MUA6Q7.js.map} +0 -0
  153. /package/dist/{chunk-W67ZZDHO.js.map → chunk-M4I3TREG.js.map} +0 -0
  154. /package/dist/{chunk-MNUPGYIV.js.map → chunk-NQMBSSWW.js.map} +0 -0
  155. /package/dist/{chunk-V4ZHKCGA.js.map → chunk-O2WELT5C.js.map} +0 -0
  156. /package/dist/{chunk-Z6SEG36L.js.map → chunk-OUWAQVDJ.js.map} +0 -0
  157. /package/dist/{chunk-57ME5VSI.js.map → chunk-Q5ZU3RNY.js.map} +0 -0
  158. /package/dist/{chunk-ACYX37IM.js.map → chunk-QUA2JPH2.js.map} +0 -0
  159. /package/dist/{chunk-2AP4QJX5.js.map → chunk-TOQEZ63C.js.map} +0 -0
  160. /package/dist/{chunk-EUM7CZFM.js.map → chunk-TY5NT3T3.js.map} +0 -0
  161. /package/dist/{chunk-ZCVPFDHB.js.map → chunk-UAODC6GJ.js.map} +0 -0
  162. /package/dist/{chunk-JI6HWBYL.js.map → chunk-UDJLF3BO.js.map} +0 -0
  163. /package/dist/{chunk-YJ4J2JJ2.js.map → chunk-UJDV2NLT.js.map} +0 -0
  164. /package/dist/{chunk-3IE22DJ2.js.map → chunk-WEPMT6SC.js.map} +0 -0
  165. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  166. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  167. /package/dist/{first-start-migration-PG5HBC3K.js.map → first-start-migration-FF7YFGRP.js.map} +0 -0
package/src/access-mcp.ts CHANGED
@@ -9,11 +9,15 @@ import {
9
9
  type CapsuleImportRequest,
10
10
  type CapsuleListRequest,
11
11
  type DaySummaryRequest,
12
- type MemoryStoreRequest,
13
12
  type SchemaName,
14
13
  type SchemaTypeFor,
15
14
  type SuggestionSubmitRequest,
16
15
  } from "./access-schema.js";
16
+ // Importing access-operations registers the pilot boundary operations
17
+ // (memory_get / memory_search / memory_store) as a side effect; callTool
18
+ // dispatches migrated tools through the registry (issue #1525).
19
+ import { getOperation, type OperationName } from "./access-boundary.js";
20
+ import "./access-operations.js";
17
21
  import { readEnvVar } from "./runtime/env.js";
18
22
  import type { RecallDisclosure, RecallPlanMode } from "./types.js";
19
23
  import { validateBriefingFormat } from "./briefing.js";
@@ -94,6 +98,19 @@ function withToolAliases(tool: McpTool, emitLegacyTools = true): McpTool[] {
94
98
  return emitLegacyTools ? [canonicalTool, tool] : [canonicalTool];
95
99
  }
96
100
 
101
+ /**
102
+ * MCP tool name (legacy `engram.*` form, since {@link toLegacyToolName}
103
+ * canonicalizes incoming calls) → boundary operation it dispatches through.
104
+ * A tool appears here once its `access-operations.ts` registration lands and
105
+ * its surface-local validation is deleted. The fitness test
106
+ * (`access-surface-catalog.test.ts`) asserts this map and the catalog agree.
107
+ */
108
+ const MCP_MIGRATED_OPERATIONS: Readonly<Record<string, OperationName>> = {
109
+ "engram.memory_get": "memory_get",
110
+ "engram.memory_search": "memory_search",
111
+ "engram.memory_store": "memory_store",
112
+ };
113
+
97
114
  function resolveChatGptInspectorRecallSessionKey(
98
115
  explicitSessionKey: string | undefined,
99
116
  authenticatedPrincipal: string | undefined,
@@ -2278,6 +2295,29 @@ export class EngramMcpServer {
2278
2295
  }
2279
2296
 
2280
2297
  private async callTool(name: string, args: Record<string, unknown>, effectivePrincipal?: string, mcpSessionId?: string): Promise<unknown> {
2298
+ // Migrated operations dispatch through the access boundary (issue #1525):
2299
+ // one registry entry owns schema validation, normalization (rules
2300
+ // 17/28/36/48/51), and error mapping for every surface. The switch
2301
+ // below still serves the not-yet-migrated tools. memory_store keeps its
2302
+ // parseMcpRequest strict-keys guard (MCP transport contract) before the
2303
+ // boundary re-validates the cleaned body.
2304
+ const migrated = MCP_MIGRATED_OPERATIONS[toLegacyToolName(name)];
2305
+ if (migrated) {
2306
+ const op = getOperation(migrated);
2307
+ if (!op) {
2308
+ throw new EngramAccessInputError(`access-boundary: operation not registered: ${migrated}`);
2309
+ }
2310
+ const envelope =
2311
+ migrated === "memory_store" ? parseMcpRequest("memoryStore", args) : args;
2312
+ // The registry erases In/Out at the Map boundary; the caller knows the
2313
+ // concrete output shape ({ result: <service response> }) so the cast is
2314
+ // the type-erasure seam, not a leap of faith.
2315
+ const output = (await op.run(envelope, {
2316
+ service: this.service,
2317
+ authenticatedPrincipal: effectivePrincipal,
2318
+ })) as { result: unknown };
2319
+ return output.result;
2320
+ }
2281
2321
  switch (toLegacyToolName(name)) {
2282
2322
  case "engram.recall": {
2283
2323
  // Forward `disclosure` only when the caller actually supplied it,
@@ -2744,12 +2784,6 @@ export class EngramMcpServer {
2744
2784
  },
2745
2785
  effectivePrincipal,
2746
2786
  );
2747
- case "engram.memory_get":
2748
- return this.service.memoryGet(
2749
- typeof args.memoryId === "string" ? args.memoryId : "",
2750
- typeof args.namespace === "string" ? args.namespace : undefined,
2751
- effectivePrincipal,
2752
- );
2753
2787
  case "engram.memory_timeline": {
2754
2788
  const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? args.limit : 200;
2755
2789
  return this.service.memoryTimeline(
@@ -2759,26 +2793,6 @@ export class EngramMcpServer {
2759
2793
  effectivePrincipal,
2760
2794
  );
2761
2795
  }
2762
- case "engram.memory_store": {
2763
- const body: MemoryStoreRequest = parseMcpRequest("memoryStore", args);
2764
- return this.service.memoryStore({
2765
- schemaVersion: body.schemaVersion,
2766
- idempotencyKey: body.idempotencyKey,
2767
- dryRun: body.dryRun,
2768
- sessionKey: body.sessionKey,
2769
- authenticatedPrincipal: effectivePrincipal,
2770
- content: body.content,
2771
- category: body.category,
2772
- confidence: body.confidence,
2773
- namespace: body.namespace,
2774
- tags: body.tags,
2775
- entityRef: body.entityRef,
2776
- ttl: body.ttl,
2777
- sourceReason: body.sourceReason,
2778
- cwd: body.cwd,
2779
- projectTag: body.projectTag,
2780
- });
2781
- }
2782
2796
  case "engram.suggestion_submit": {
2783
2797
  const body: SuggestionSubmitRequest = parseMcpRequest("suggestionSubmit", args);
2784
2798
  return this.service.suggestionSubmit({
@@ -3017,14 +3031,6 @@ export class EngramMcpServer {
3017
3031
  expectedGuidelineVersion: typeof args.expectedGuidelineVersion === "number" ? args.expectedGuidelineVersion : undefined,
3018
3032
  });
3019
3033
  // ── Memory search & debug tools ──────────────────────────────────
3020
- case "engram.memory_search":
3021
- return this.service.memorySearch({
3022
- query: typeof args.query === "string" ? args.query : "",
3023
- namespace: typeof args.namespace === "string" ? args.namespace : undefined,
3024
- maxResults: typeof args.maxResults === "number" && Number.isFinite(args.maxResults) ? args.maxResults : undefined,
3025
- collection: typeof args.collection === "string" ? args.collection : undefined,
3026
- principal: effectivePrincipal,
3027
- });
3028
3034
  case "engram.memory_profile":
3029
3035
  return this.service.memoryProfile(
3030
3036
  typeof args.namespace === "string" ? args.namespace : undefined,
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Pilot operation definitions for the access boundary (issue #1525).
3
+ *
4
+ * Three operations migrate through the registry in this PR — `memory_get`,
5
+ * `memory_search`, and the `memory_store` write op — so the boundary's
6
+ * normalization matrix (rules 17/28/36/48/51) and shared error mapping reach
7
+ * MCP, HTTP, and CLI from one place. Domain-group migrations (memory ops →
8
+ * connectors → namespaces …) land as follow-up PRs that add `defineOperation`
9
+ * calls here and delete the surface-local validation they replace.
10
+ *
11
+ * Importing this module for its side effects registers the pilot operations;
12
+ * surfaces then dispatch via {@link getOperation} from `./access-boundary.js`.
13
+ */
14
+
15
+ import { z } from "zod";
16
+
17
+ import { defineOperation } from "./access-boundary.js";
18
+ import { memoryStoreRequestSchema, type MemoryStoreRequest } from "./access-schema.js";
19
+ import type {
20
+ EngramAccessMemoryResponse,
21
+ EngramAccessWriteResponse,
22
+ } from "./access-service.js";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // memory_get — fetch one memory by id
26
+ // ---------------------------------------------------------------------------
27
+
28
+ /**
29
+ * `memoryId` is required and non-empty (rule 51: the MCP dispatcher previously
30
+ * fell back to `typeof args.memoryId === "string" ? args.memoryId : ""`,
31
+ * silently passing an empty id into the service). `namespace` is
32
+ * `.nullable().optional()` because MCP clients send `null` (gotcha #2).
33
+ * `namespace` has no `.min(1)` because the pre-boundary handlers forwarded
34
+ * empty/whitespace strings, and `resolveNamespace` treats empty identically
35
+ * to absent (both trim to falsy → default namespace). Rejecting empty would
36
+ * break HTTP callers that send a bare `?namespace=` (Cursor review).
37
+ */
38
+ const memoryGetSchema = z.object({
39
+ memoryId: z.string().trim().min(1, "memoryId is required").max(512),
40
+ namespace: z.string().trim().max(256).nullable().optional(),
41
+ });
42
+
43
+ export interface MemoryGetInput {
44
+ readonly memoryId: string;
45
+ readonly namespace?: string | null;
46
+ }
47
+
48
+ export interface MemoryGetOutput {
49
+ readonly result: EngramAccessMemoryResponse;
50
+ }
51
+
52
+ export const memoryGetOperation = defineOperation<MemoryGetInput, MemoryGetOutput>({
53
+ name: "memory_get",
54
+ description: "Fetch one memory by id.",
55
+ schema: memoryGetSchema,
56
+ handler: async (input, ctx) => {
57
+ const result = await ctx.service.memoryGet(
58
+ input.memoryId,
59
+ input.namespace ?? undefined,
60
+ ctx.authenticatedPrincipal,
61
+ );
62
+ return { result };
63
+ },
64
+ });
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // memory_search — semantic search across memories
68
+ // ---------------------------------------------------------------------------
69
+
70
+ const memorySearchSchema = z.object({
71
+ query: z.string().trim().min(1, "query is required").max(2048),
72
+ namespace: z.string().trim().max(256).nullable().optional(),
73
+ // No upper cap: the pre-boundary MCP handler forwarded any finite number to
74
+ // memorySearch, and the QMD/search backends honor large limits. Capping at
75
+ // 100 would reject existing clients that request larger result sets.
76
+ maxResults: z.number().int().min(1).nullable().optional(),
77
+ collection: z.string().trim().min(1).max(256).nullable().optional(),
78
+ });
79
+
80
+ export interface MemorySearchInput {
81
+ readonly query: string;
82
+ readonly namespace?: string | null;
83
+ readonly maxResults?: number | null;
84
+ readonly collection?: string | null;
85
+ }
86
+
87
+ export interface MemorySearchOutput {
88
+ readonly result: {
89
+ readonly query: string;
90
+ readonly results: ReadonlyArray<{ path: string; score: number; snippet: string }>;
91
+ readonly count: number;
92
+ };
93
+ }
94
+
95
+ export const memorySearchOperation = defineOperation<MemorySearchInput, MemorySearchOutput>({
96
+ name: "memory_search",
97
+ description: "Search memories across readable namespaces.",
98
+ schema: memorySearchSchema,
99
+ handler: async (input, ctx) => {
100
+ const result = await ctx.service.memorySearch({
101
+ query: input.query,
102
+ namespace: input.namespace ?? undefined,
103
+ maxResults: input.maxResults ?? undefined,
104
+ collection: input.collection ?? undefined,
105
+ principal: ctx.authenticatedPrincipal,
106
+ });
107
+ return { result };
108
+ },
109
+ });
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // memory_store — the pilot WRITE op
113
+ // ---------------------------------------------------------------------------
114
+
115
+ export type MemoryStoreInput = MemoryStoreRequest;
116
+
117
+ export interface MemoryStoreOutput {
118
+ readonly result: EngramAccessWriteResponse;
119
+ }
120
+
121
+ export const memoryStoreOperation = defineOperation<MemoryStoreInput, MemoryStoreOutput>({
122
+ name: "memory_store",
123
+ description: "Store an explicit memory through the access layer.",
124
+ // Reuse the existing schema verbatim — the migration is behavior-preserving;
125
+ // the schema's external contract is NOT changing in this PR (per the issue's
126
+ // pitfall note).
127
+ schema: memoryStoreRequestSchema,
128
+ handler: async (input, ctx) => {
129
+ const result = await ctx.service.memoryStore(
130
+ {
131
+ ...input,
132
+ authenticatedPrincipal: ctx.authenticatedPrincipal,
133
+ },
134
+ // Forward transport-level hooks (e.g. HTTP's atomic write-quota gate)
135
+ // so the hook still fires inside the service's idempotent-write lock —
136
+ // never before, never on a replay (#1434 invariant preserved by the
137
+ // boundary migration).
138
+ ctx.hooks,
139
+ );
140
+ return { result };
141
+ },
142
+ });
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Surface registration map — what each transport calls the pilot ops
146
+ // ---------------------------------------------------------------------------
147
+
148
+ /**
149
+ * The canonical short names (no `engram.`/`remnic.` prefix) of the operations
150
+ * the boundary owns today. The fitness test treats this set as the migrated
151
+ * set; everything else on a surface is unmigrated and counted by the ratchet.
152
+ */
153
+ export const REGISTERED_OPERATIONS = [
154
+ memoryGetOperation.spec.name,
155
+ memorySearchOperation.spec.name,
156
+ memoryStoreOperation.spec.name,
157
+ ] as const;