@gmickel/gno 1.18.0 → 1.20.0

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 (153) hide show
  1. package/README.md +14 -7
  2. package/assets/skill/SKILL.md +54 -12
  3. package/assets/skill/mcp-reference.md +7 -2
  4. package/assets/skill/recipes/citation-and-provenance.md +32 -9
  5. package/package.json +2 -1
  6. package/spec/AGENTS.md +83 -0
  7. package/spec/CLAUDE.md +83 -0
  8. package/spec/bench-fixture.schema.json +137 -0
  9. package/spec/cli.md +2919 -0
  10. package/spec/db/schema.sql +442 -0
  11. package/spec/evals-agentic.md +592 -0
  12. package/spec/evals.md +1106 -0
  13. package/spec/mcp.md +2279 -0
  14. package/spec/output-schemas/activation-verification.schema.json +515 -0
  15. package/spec/output-schemas/ask.schema.json +564 -0
  16. package/spec/output-schemas/backlinks.schema.json +131 -0
  17. package/spec/output-schemas/bench-result.schema.json +120 -0
  18. package/spec/output-schemas/capture-receipt.schema.json +143 -0
  19. package/spec/output-schemas/claim-verification.schema.json +291 -0
  20. package/spec/output-schemas/collection-list.schema.json +45 -0
  21. package/spec/output-schemas/context-capsule-v1.schema.json +726 -0
  22. package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
  23. package/spec/output-schemas/context-list.schema.json +21 -0
  24. package/spec/output-schemas/doctor.schema.json +313 -0
  25. package/spec/output-schemas/error.schema.json +30 -0
  26. package/spec/output-schemas/expansion.schema.json +37 -0
  27. package/spec/output-schemas/get.schema.json +140 -0
  28. package/spec/output-schemas/graph-query.schema.json +99 -0
  29. package/spec/output-schemas/graph.schema.json +371 -0
  30. package/spec/output-schemas/links-list.schema.json +186 -0
  31. package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
  32. package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
  33. package/spec/output-schemas/mcp-http-error.schema.json +30 -0
  34. package/spec/output-schemas/mcp-job-list.schema.json +58 -0
  35. package/spec/output-schemas/mcp-job-status.schema.json +224 -0
  36. package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
  37. package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
  38. package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
  39. package/spec/output-schemas/models-list.schema.json +93 -0
  40. package/spec/output-schemas/multi-get.schema.json +103 -0
  41. package/spec/output-schemas/process-status.schema.json +119 -0
  42. package/spec/output-schemas/query-diagnose.schema.json +123 -0
  43. package/spec/output-schemas/resident-status.schema.json +154 -0
  44. package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
  45. package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
  46. package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
  47. package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
  48. package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
  49. package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
  50. package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
  51. package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
  52. package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
  53. package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
  54. package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
  55. package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
  56. package/spec/output-schemas/search-result.schema.json +154 -0
  57. package/spec/output-schemas/search-results.schema.json +338 -0
  58. package/spec/output-schemas/similar.schema.json +84 -0
  59. package/spec/output-schemas/status.schema.json +676 -0
  60. package/spec/output-schemas/tags-list.schema.json +48 -0
  61. package/src/app/context-runtime-contract.ts +10 -5
  62. package/src/app/context-runtime-input.ts +29 -1
  63. package/src/app/context-runtime-types.ts +7 -0
  64. package/src/app/context-runtime.ts +20 -2
  65. package/src/app/context-surface.ts +4 -0
  66. package/src/app/verified-ask.ts +291 -0
  67. package/src/cli/commands/ask-format.ts +255 -0
  68. package/src/cli/commands/ask.ts +144 -183
  69. package/src/cli/commands/context-build.ts +56 -9
  70. package/src/cli/commands/get.ts +64 -3
  71. package/src/cli/commands/query.ts +62 -23
  72. package/src/cli/commands/replay.ts +140 -0
  73. package/src/cli/commands/search.ts +48 -3
  74. package/src/cli/commands/shared.ts +3 -1
  75. package/src/cli/commands/trace.ts +200 -0
  76. package/src/cli/commands/vsearch.ts +75 -53
  77. package/src/cli/program.ts +287 -1
  78. package/src/config/index.ts +9 -0
  79. package/src/config/retrieval-traces.ts +56 -0
  80. package/src/config/types.ts +4 -0
  81. package/src/core/context-budget.ts +6 -0
  82. package/src/core/context-capsule-retrieval-schema.ts +4 -0
  83. package/src/core/context-capsule-schema.ts +17 -0
  84. package/src/core/context-capsule-validation.ts +3 -2
  85. package/src/core/context-capsule.ts +18 -0
  86. package/src/core/context-compiler.ts +44 -25
  87. package/src/core/context-evidence.ts +6 -0
  88. package/src/core/retrieval-qrels.ts +405 -0
  89. package/src/core/retrieval-replay-candidate.ts +368 -0
  90. package/src/core/retrieval-replay-types.ts +109 -0
  91. package/src/core/retrieval-replay-validation.ts +89 -0
  92. package/src/core/retrieval-replay.ts +441 -0
  93. package/src/core/retrieval-trace-evidence-origin.ts +178 -0
  94. package/src/core/retrieval-trace-export.ts +113 -0
  95. package/src/core/retrieval-trace-filter-normalization.ts +27 -0
  96. package/src/core/retrieval-trace-filters.ts +19 -0
  97. package/src/core/retrieval-trace-management-helpers.ts +247 -0
  98. package/src/core/retrieval-trace-management-types.ts +132 -0
  99. package/src/core/retrieval-trace-management.ts +422 -0
  100. package/src/core/retrieval-trace-request.ts +141 -0
  101. package/src/core/retrieval-trace-session.ts +507 -0
  102. package/src/core/retrieval-trace.ts +472 -0
  103. package/src/llm/errors.ts +10 -1
  104. package/src/llm/httpGeneration.ts +11 -1
  105. package/src/llm/nodeLlamaCpp/generation.ts +54 -10
  106. package/src/llm/types.ts +6 -0
  107. package/src/mcp/tools/ask.ts +228 -0
  108. package/src/mcp/tools/context.ts +87 -15
  109. package/src/mcp/tools/get.ts +35 -1
  110. package/src/mcp/tools/index.ts +83 -0
  111. package/src/mcp/tools/query.ts +95 -64
  112. package/src/mcp/tools/search.ts +36 -13
  113. package/src/mcp/tools/trace.ts +143 -0
  114. package/src/mcp/tools/vsearch.ts +71 -38
  115. package/src/pipeline/answer.ts +167 -26
  116. package/src/pipeline/claim-verification-schema.ts +235 -0
  117. package/src/pipeline/claim-verification.ts +487 -0
  118. package/src/pipeline/claim-verifier.ts +474 -0
  119. package/src/pipeline/graph-retrieval.ts +15 -1
  120. package/src/pipeline/hybrid.ts +151 -43
  121. package/src/pipeline/search.ts +36 -3
  122. package/src/pipeline/trace-metadata.ts +47 -0
  123. package/src/pipeline/types.ts +68 -0
  124. package/src/pipeline/vsearch.ts +101 -38
  125. package/src/sdk/client.ts +415 -73
  126. package/src/sdk/documents.ts +48 -1
  127. package/src/sdk/index.ts +17 -0
  128. package/src/sdk/types.ts +28 -0
  129. package/src/serve/context-capsule.ts +67 -8
  130. package/src/serve/public/app.tsx +12 -1
  131. package/src/serve/public/components/AskVerificationPanel.tsx +189 -0
  132. package/src/serve/public/globals.built.css +1 -1
  133. package/src/serve/public/lib/workspace-tabs.ts +2 -0
  134. package/src/serve/public/pages/Ask.tsx +42 -4
  135. package/src/serve/public/pages/Dashboard.tsx +10 -0
  136. package/src/serve/public/pages/TraceHistory.tsx +478 -0
  137. package/src/serve/public/pages/trace-history-detail.tsx +224 -0
  138. package/src/serve/retrieval-trace.ts +28 -0
  139. package/src/serve/routes/api.ts +508 -68
  140. package/src/serve/routes/traces.ts +156 -0
  141. package/src/serve/server.ts +87 -2
  142. package/src/store/index.ts +31 -0
  143. package/src/store/migrations/014-retrieval-traces.ts +303 -0
  144. package/src/store/migrations/index.ts +2 -0
  145. package/src/store/retrieval-trace-codec.ts +384 -0
  146. package/src/store/sqlite/adapter.ts +153 -1
  147. package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
  148. package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
  149. package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
  150. package/src/store/sqlite/retrieval-trace-store.ts +515 -0
  151. package/src/store/types.ts +297 -0
  152. package/src/store/vector/sqlite-vec.ts +76 -1
  153. package/src/store/vector/types.ts +1 -1
@@ -0,0 +1,384 @@
1
+ /** Runtime validation and deterministic encoding for local retrieval receipts. */
2
+
3
+ import { z } from "zod";
4
+
5
+ import type {
6
+ RetrievalTraceEventInput,
7
+ RetrievalTraceExportInput,
8
+ RetrievalTraceInput,
9
+ RetrievalTraceJudgmentInput,
10
+ RetrievalTraceRunInput,
11
+ } from "./types";
12
+
13
+ const MAX_ID_LENGTH = 128;
14
+ const MAX_IDEMPOTENCY_KEY_LENGTH = 256;
15
+ const sha256Schema = z.string().regex(/^[a-f0-9]{64}$/);
16
+ const idSchema = z.string().min(1).max(MAX_ID_LENGTH);
17
+ const idempotencyKeySchema = z.string().min(1).max(MAX_IDEMPOTENCY_KEY_LENGTH);
18
+ const epochMsSchema = z.number().int().safe().nonnegative();
19
+ const DANGEROUS_JSON_KEYS = new Set(["__proto__", "constructor", "prototype"]);
20
+
21
+ const jsonValueSchema: z.ZodType<unknown> = z.lazy(() =>
22
+ z.union([
23
+ z.string(),
24
+ z.number().finite(),
25
+ z.boolean(),
26
+ z.null(),
27
+ z.array(jsonValueSchema),
28
+ z.record(z.string(), jsonValueSchema),
29
+ ])
30
+ );
31
+
32
+ export const traceJsonObjectSchema = z.record(z.string(), jsonValueSchema);
33
+
34
+ const SAFE_RECEIPT_STRING_KEYS = new Set([
35
+ "capability",
36
+ "capsuleId",
37
+ "collection",
38
+ "code",
39
+ "docid",
40
+ "filterFingerprint",
41
+ "heading",
42
+ "id",
43
+ "kind",
44
+ "mirrorHash",
45
+ "mode",
46
+ "name",
47
+ "outcome",
48
+ "passageHash",
49
+ "reasonCode",
50
+ "ref",
51
+ "sourceHash",
52
+ "status",
53
+ "type",
54
+ "uri",
55
+ ]);
56
+ const SAFE_RECEIPT_STRING_LIST_KEYS = new Set([
57
+ "capabilities",
58
+ "categories",
59
+ "collections",
60
+ "fallbackCodes",
61
+ "fallbacks",
62
+ "itemTypes",
63
+ "sources",
64
+ "tags",
65
+ ]);
66
+
67
+ const validateReceiptStrings = (
68
+ value: unknown,
69
+ context: z.RefinementCtx,
70
+ key = "",
71
+ path: Array<string | number> = []
72
+ ): void => {
73
+ if (typeof value === "string") {
74
+ if (
75
+ !(
76
+ SAFE_RECEIPT_STRING_KEYS.has(key) ||
77
+ SAFE_RECEIPT_STRING_LIST_KEYS.has(key)
78
+ )
79
+ ) {
80
+ context.addIssue({
81
+ code: "custom",
82
+ path,
83
+ message: `String field ${key || "<root>"} is not allowed in trace receipt payloads`,
84
+ });
85
+ } else if (key === "uri" && !value.startsWith("gno://")) {
86
+ context.addIssue({
87
+ code: "custom",
88
+ path,
89
+ message: "Trace evidence URI must use gno://",
90
+ });
91
+ } else if (traceUtf8Bytes(value) > 4096) {
92
+ context.addIssue({
93
+ code: "custom",
94
+ path,
95
+ message: `String field ${key} exceeds 4096 UTF-8 bytes`,
96
+ });
97
+ }
98
+ return;
99
+ }
100
+ if (Array.isArray(value)) {
101
+ for (const [index, child] of value.entries()) {
102
+ validateReceiptStrings(child, context, key, [...path, index]);
103
+ }
104
+ return;
105
+ }
106
+ if (value !== null && typeof value === "object") {
107
+ for (const [childKey, child] of Object.entries(value)) {
108
+ validateReceiptStrings(child, context, childKey, [...path, childKey]);
109
+ }
110
+ }
111
+ };
112
+
113
+ const traceReceiptPayloadSchema = traceJsonObjectSchema.superRefine(
114
+ (value, context) => validateReceiptStrings(value, context)
115
+ );
116
+
117
+ const queryShapeSchema = z
118
+ .object({
119
+ characters: z.number().int().nonnegative(),
120
+ terms: z.number().int().nonnegative(),
121
+ })
122
+ .strict();
123
+
124
+ const traceInputBaseSchema = z
125
+ .object({
126
+ traceId: idSchema,
127
+ schemaVersion: z.literal("1.0"),
128
+ redactionMode: z.enum(["metadata", "replay"]),
129
+ replayCapable: z.boolean(),
130
+ queryText: z.string().max(8192).nullable(),
131
+ queryDigest: sha256Schema.nullable(),
132
+ queryShape: queryShapeSchema,
133
+ goalText: z.string().max(8192).nullable(),
134
+ goalDigest: sha256Schema.nullable(),
135
+ goalShape: queryShapeSchema,
136
+ filters: traceJsonObjectSchema,
137
+ fingerprints: z
138
+ .object({
139
+ pipeline: sha256Schema,
140
+ model: sha256Schema,
141
+ config: sha256Schema,
142
+ index: sha256Schema,
143
+ })
144
+ .strict(),
145
+ status: z.literal("open"),
146
+ createdAtMs: epochMsSchema,
147
+ updatedAtMs: epochMsSchema,
148
+ expiresAtMs: epochMsSchema,
149
+ })
150
+ .strict();
151
+
152
+ export const retrievalTraceInputSchema = traceInputBaseSchema.superRefine(
153
+ (value, context) => {
154
+ if (value.updatedAtMs < value.createdAtMs) {
155
+ context.addIssue({
156
+ code: "custom",
157
+ path: ["updatedAtMs"],
158
+ message: "updatedAtMs must not precede createdAtMs",
159
+ });
160
+ }
161
+ if (value.updatedAtMs !== value.createdAtMs) {
162
+ context.addIssue({
163
+ code: "custom",
164
+ path: ["updatedAtMs"],
165
+ message: "new traces must start with updatedAtMs equal to createdAtMs",
166
+ });
167
+ }
168
+ if (value.expiresAtMs <= value.createdAtMs) {
169
+ context.addIssue({
170
+ code: "custom",
171
+ path: ["expiresAtMs"],
172
+ message: "expiresAtMs must be later than createdAtMs",
173
+ });
174
+ }
175
+ const metadataInvariant =
176
+ value.redactionMode === "metadata" &&
177
+ !value.replayCapable &&
178
+ value.queryText === null &&
179
+ value.queryDigest === null &&
180
+ value.goalText === null &&
181
+ value.goalDigest === null;
182
+ const replayInvariant =
183
+ value.redactionMode === "replay" &&
184
+ value.replayCapable &&
185
+ value.queryText !== null &&
186
+ value.queryDigest !== null &&
187
+ ((value.goalText === null && value.goalDigest === null) ||
188
+ (value.goalText !== null && value.goalDigest !== null));
189
+ if (!(metadataInvariant || replayInvariant)) {
190
+ context.addIssue({
191
+ code: "custom",
192
+ message:
193
+ "metadata traces cannot retain query material; replay traces require explicit replay inputs",
194
+ });
195
+ }
196
+ if (value.redactionMode === "replay" && value.queryText !== null) {
197
+ const expectedDigest = new Bun.CryptoHasher("sha256")
198
+ .update(value.queryText)
199
+ .digest("hex");
200
+ if (value.queryDigest !== expectedDigest) {
201
+ context.addIssue({
202
+ code: "custom",
203
+ path: ["queryDigest"],
204
+ message: "queryDigest does not match queryText",
205
+ });
206
+ }
207
+ const expectedShape = shapeTraceText(value.queryText);
208
+ if (
209
+ value.queryShape.characters !== expectedShape.characters ||
210
+ value.queryShape.terms !== expectedShape.terms
211
+ ) {
212
+ context.addIssue({
213
+ code: "custom",
214
+ path: ["queryShape"],
215
+ message: "queryShape does not match queryText",
216
+ });
217
+ }
218
+ }
219
+ if (value.redactionMode === "replay" && value.goalText !== null) {
220
+ const expectedDigest = new Bun.CryptoHasher("sha256")
221
+ .update(value.goalText)
222
+ .digest("hex");
223
+ if (value.goalDigest !== expectedDigest) {
224
+ context.addIssue({
225
+ code: "custom",
226
+ path: ["goalDigest"],
227
+ message: "goalDigest does not match goalText",
228
+ });
229
+ }
230
+ const expectedShape = shapeTraceText(value.goalText);
231
+ if (
232
+ value.goalShape.characters !== expectedShape.characters ||
233
+ value.goalShape.terms !== expectedShape.terms
234
+ ) {
235
+ context.addIssue({
236
+ code: "custom",
237
+ path: ["goalShape"],
238
+ message: "goalShape does not match goalText",
239
+ });
240
+ }
241
+ }
242
+ }
243
+ );
244
+
245
+ export const retrievalTraceRunInputSchema = z
246
+ .object({
247
+ runId: idSchema,
248
+ traceId: idSchema,
249
+ idempotencyKey: idempotencyKeySchema,
250
+ kind: z.enum(["retrieval", "context", "get"]),
251
+ payload: traceReceiptPayloadSchema,
252
+ createdAtMs: epochMsSchema,
253
+ })
254
+ .strict();
255
+
256
+ export const retrievalTraceEventInputSchema = z
257
+ .object({
258
+ eventId: idSchema,
259
+ traceId: idSchema,
260
+ runId: idSchema.nullable(),
261
+ idempotencyKey: idempotencyKeySchema,
262
+ kind: z.enum([
263
+ "query",
264
+ "retrieval",
265
+ "context",
266
+ "get",
267
+ "open",
268
+ "cite",
269
+ "pin",
270
+ "capability",
271
+ "complete",
272
+ ]),
273
+ payload: traceReceiptPayloadSchema,
274
+ createdAtMs: epochMsSchema,
275
+ })
276
+ .strict();
277
+
278
+ export const retrievalTraceJudgmentInputSchema = z
279
+ .object({
280
+ judgmentId: idSchema,
281
+ traceId: idSchema,
282
+ runId: idSchema.nullable(),
283
+ idempotencyKey: idempotencyKeySchema,
284
+ label: z.enum(["relevant", "irrelevant", "missing_expected"]),
285
+ targetKind: z.enum(["document", "chunk", "span", "query"]),
286
+ targetRef: z.string().min(1).max(4096),
287
+ target: traceReceiptPayloadSchema,
288
+ createdAtMs: epochMsSchema,
289
+ })
290
+ .strict()
291
+ .superRefine((value, context) => {
292
+ if (value.label === "missing_expected" && value.targetKind !== "document") {
293
+ context.addIssue({
294
+ code: "custom",
295
+ path: ["targetKind"],
296
+ message: "missing_expected judgments must target a document",
297
+ });
298
+ }
299
+ });
300
+
301
+ export const retrievalTraceExportInputSchema = z
302
+ .object({
303
+ exportId: idSchema,
304
+ traceId: idSchema,
305
+ format: z.enum(["agentic-receipt", "qrels"]),
306
+ artifactHash: sha256Schema,
307
+ createdAtMs: epochMsSchema,
308
+ })
309
+ .strict();
310
+
311
+ const compareCodeUnits = (left: string, right: string): number =>
312
+ left < right ? -1 : left > right ? 1 : 0;
313
+
314
+ const canonicalizeJsonValue = (value: unknown): unknown => {
315
+ if (Array.isArray(value)) return value.map(canonicalizeJsonValue);
316
+ if (value !== null && typeof value === "object") {
317
+ const sorted: Record<string, unknown> = Object.create(null) as Record<
318
+ string,
319
+ unknown
320
+ >;
321
+ for (const key of Object.keys(value).sort(compareCodeUnits)) {
322
+ if (DANGEROUS_JSON_KEYS.has(key)) {
323
+ throw new Error(`Canonical JSON rejects dangerous key ${key}`);
324
+ }
325
+ const child = (value as Record<string, unknown>)[key];
326
+ if (child === undefined) {
327
+ throw new Error(`Canonical JSON rejects undefined at ${key}`);
328
+ }
329
+ sorted[key] = canonicalizeJsonValue(child);
330
+ }
331
+ return sorted;
332
+ }
333
+ if (typeof value === "number" && !Number.isFinite(value)) {
334
+ throw new Error("Canonical JSON rejects non-finite numbers");
335
+ }
336
+ return value;
337
+ };
338
+
339
+ const shapeTraceText = (
340
+ value: string
341
+ ): { characters: number; terms: number } => ({
342
+ characters: Array.from(value).length,
343
+ terms: value.trim() ? value.trim().split(/\s+/u).length : 0,
344
+ });
345
+
346
+ export const canonicalTraceJson = (value: unknown): string =>
347
+ JSON.stringify(canonicalizeJsonValue(value));
348
+
349
+ export const traceUtf8Bytes = (value: string): number =>
350
+ new TextEncoder().encode(value).byteLength;
351
+
352
+ export const hashTraceCanonical = (value: unknown): string =>
353
+ new Bun.CryptoHasher("sha256")
354
+ .update(canonicalTraceJson(value))
355
+ .digest("hex");
356
+
357
+ /** Stable trace identity excludes terminal status and mutable updatedAtMs. */
358
+ export const hashRetrievalTraceCreation = (
359
+ trace: RetrievalTraceInput
360
+ ): string => {
361
+ const { status: _status, updatedAtMs: _updatedAtMs, ...immutable } = trace;
362
+ return hashTraceCanonical(immutable);
363
+ };
364
+
365
+ export const parseRetrievalTraceInput = (
366
+ input: RetrievalTraceInput
367
+ ): RetrievalTraceInput => retrievalTraceInputSchema.parse(input);
368
+
369
+ export const parseRetrievalTraceRunInput = (
370
+ input: RetrievalTraceRunInput
371
+ ): RetrievalTraceRunInput => retrievalTraceRunInputSchema.parse(input);
372
+
373
+ export const parseRetrievalTraceEventInput = (
374
+ input: RetrievalTraceEventInput
375
+ ): RetrievalTraceEventInput => retrievalTraceEventInputSchema.parse(input);
376
+
377
+ export const parseRetrievalTraceJudgmentInput = (
378
+ input: RetrievalTraceJudgmentInput
379
+ ): RetrievalTraceJudgmentInput =>
380
+ retrievalTraceJudgmentInputSchema.parse(input);
381
+
382
+ export const parseRetrievalTraceExportInput = (
383
+ input: RetrievalTraceExportInput
384
+ ): RetrievalTraceExportInput => retrievalTraceExportInputSchema.parse(input);
@@ -52,6 +52,24 @@ import type {
52
52
  IngestErrorInput,
53
53
  IngestErrorRow,
54
54
  MigrationResult,
55
+ RetrievalTraceAppendResult,
56
+ RetrievalTraceBundle,
57
+ RetrievalTraceCursor,
58
+ RetrievalTraceBoundedBundle,
59
+ RetrievalTraceDeleteCounts,
60
+ RetrievalTraceEventInput,
61
+ RetrievalTraceExportInput,
62
+ RetrievalTraceExportBundle,
63
+ RetrievalTraceExportManifestInput,
64
+ RetrievalTraceExportManifestRow,
65
+ RetrievalTraceInput,
66
+ RetrievalTraceJudgmentInput,
67
+ RetrievalTracePurgeResult,
68
+ RetrievalTraceRetentionPolicy,
69
+ RetrievalTraceRetentionResult,
70
+ RetrievalTraceRow,
71
+ RetrievalTraceRunInput,
72
+ RetrievalTraceTerminalStatus,
55
73
  StorePort,
56
74
  StoreResult,
57
75
  TagCount,
@@ -78,6 +96,28 @@ import { err, ok } from "../types";
78
96
  import { getStoredEmbeddingFingerprint } from "../vector/freshness";
79
97
  import { modelTableName } from "../vector/sqlite-vec";
80
98
  import { loadFts5Snowball } from "./fts5-snowball";
99
+ import {
100
+ appendExportManifest as appendStoredTraceExportManifest,
101
+ getBoundedTrace as getBoundedStoredTrace,
102
+ getExportBundle as getStoredTraceExportBundle,
103
+ getExportManifest as getStoredTraceExportManifest,
104
+ getOrCreateRedactionSecret as getOrCreateStoredTraceRedactionSecret,
105
+ } from "./retrieval-trace-management-store";
106
+ import {
107
+ deleteTrace as deleteStoredTrace,
108
+ enforceRetention as enforceStoredTraceRetention,
109
+ purgeTraces as purgeStoredTraces,
110
+ } from "./retrieval-trace-retention";
111
+ import {
112
+ appendEvent as appendStoredTraceEvent,
113
+ appendExport as appendStoredTraceExport,
114
+ appendJudgment as appendStoredTraceJudgment,
115
+ appendRun as appendStoredTraceRun,
116
+ createTrace as createStoredTrace,
117
+ finalizeTrace as finalizeStoredTrace,
118
+ getTrace as getStoredTrace,
119
+ listTraces as listStoredTraces,
120
+ } from "./retrieval-trace-store";
81
121
 
82
122
  // ─────────────────────────────────────────────────────────────────────────────
83
123
  // FTS5 Query Escaping
@@ -782,6 +822,107 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
782
822
  }
783
823
  }
784
824
 
825
+ async createRetrievalTrace(
826
+ input: RetrievalTraceInput
827
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
828
+ return createStoredTrace(this.ensureOpen(), input);
829
+ }
830
+
831
+ async getRetrievalTrace(
832
+ traceId: string
833
+ ): Promise<StoreResult<RetrievalTraceBundle | null>> {
834
+ return getStoredTrace(this.ensureOpen(), traceId);
835
+ }
836
+
837
+ async getBoundedRetrievalTrace(
838
+ traceId: string,
839
+ detailLimit: number
840
+ ): Promise<StoreResult<RetrievalTraceBoundedBundle | null>> {
841
+ return getBoundedStoredTrace(this.ensureOpen(), traceId, detailLimit);
842
+ }
843
+
844
+ async listRetrievalTraces(
845
+ limit: number,
846
+ cursor?: RetrievalTraceCursor
847
+ ): Promise<StoreResult<RetrievalTraceRow[]>> {
848
+ return listStoredTraces(this.ensureOpen(), limit, cursor);
849
+ }
850
+
851
+ async finalizeRetrievalTrace(
852
+ traceId: string,
853
+ status: RetrievalTraceTerminalStatus,
854
+ updatedAtMs: number
855
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
856
+ return finalizeStoredTrace(this.ensureOpen(), traceId, status, updatedAtMs);
857
+ }
858
+
859
+ async appendRetrievalTraceRun(
860
+ input: RetrievalTraceRunInput
861
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
862
+ return appendStoredTraceRun(this.ensureOpen(), input);
863
+ }
864
+
865
+ async appendRetrievalTraceEvent(
866
+ input: RetrievalTraceEventInput
867
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
868
+ return appendStoredTraceEvent(this.ensureOpen(), input);
869
+ }
870
+
871
+ async appendRetrievalTraceJudgment(
872
+ input: RetrievalTraceJudgmentInput
873
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
874
+ return appendStoredTraceJudgment(this.ensureOpen(), input);
875
+ }
876
+
877
+ async appendRetrievalTraceExport(
878
+ input: RetrievalTraceExportInput
879
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
880
+ return appendStoredTraceExport(this.ensureOpen(), input);
881
+ }
882
+
883
+ async appendRetrievalTraceExportManifest(
884
+ input: RetrievalTraceExportManifestInput
885
+ ): Promise<StoreResult<RetrievalTraceAppendResult>> {
886
+ return appendStoredTraceExportManifest(this.ensureOpen(), input);
887
+ }
888
+
889
+ async getRetrievalTraceExportManifest(
890
+ exportId: string
891
+ ): Promise<StoreResult<RetrievalTraceExportManifestRow | null>> {
892
+ return getStoredTraceExportManifest(this.ensureOpen(), exportId);
893
+ }
894
+
895
+ async getRetrievalTraceExportBundle(
896
+ exportId: string
897
+ ): Promise<StoreResult<RetrievalTraceExportBundle | null>> {
898
+ return getStoredTraceExportBundle(this.ensureOpen(), exportId);
899
+ }
900
+
901
+ async getOrCreateRetrievalTraceRedactionSecret(): Promise<
902
+ StoreResult<string>
903
+ > {
904
+ return getOrCreateStoredTraceRedactionSecret(this.ensureOpen());
905
+ }
906
+
907
+ async deleteRetrievalTrace(
908
+ traceId: string
909
+ ): Promise<StoreResult<RetrievalTraceDeleteCounts>> {
910
+ return deleteStoredTrace(this.ensureOpen(), traceId);
911
+ }
912
+
913
+ async purgeRetrievalTraces(): Promise<
914
+ StoreResult<RetrievalTracePurgeResult>
915
+ > {
916
+ return purgeStoredTraces(this.ensureOpen());
917
+ }
918
+
919
+ async enforceRetrievalTraceRetention(
920
+ policy: RetrievalTraceRetentionPolicy,
921
+ nowMs: number
922
+ ): Promise<StoreResult<RetrievalTraceRetentionResult>> {
923
+ return enforceStoredTraceRetention(this.ensureOpen(), policy, nowMs);
924
+ }
925
+
785
926
  getContextGeneration(): number {
786
927
  return this.contextGeneration;
787
928
  }
@@ -1652,6 +1793,11 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
1652
1793
  SELECT id FROM documents
1653
1794
  WHERE active = 1
1654
1795
  ${options.collection ? "AND collection = ?" : ""}
1796
+ ${
1797
+ options.relPathPrefix !== undefined
1798
+ ? "AND (rel_path = ? OR substr(rel_path, 1, length(?) + 1) = ? || '/')"
1799
+ : ""
1800
+ }
1655
1801
  )
1656
1802
  ORDER BY score
1657
1803
  LIMIT ?
@@ -1705,6 +1851,13 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
1705
1851
  const queryParams = [
1706
1852
  builtQuery.query,
1707
1853
  ...(options.collection ? [options.collection] : []),
1854
+ ...(options.relPathPrefix !== undefined
1855
+ ? [
1856
+ options.relPathPrefix,
1857
+ options.relPathPrefix,
1858
+ options.relPathPrefix,
1859
+ ]
1860
+ : []),
1708
1861
  ftsLimit,
1709
1862
  ...params,
1710
1863
  ];
@@ -4622,7 +4775,6 @@ interface DbIngestErrorRow {
4622
4775
  details_json: string | null;
4623
4776
  }
4624
4777
 
4625
- // ─────────────────────────────────────────────────────────────────────────────
4626
4778
  // Row Mappers (snake_case -> camelCase)
4627
4779
  // ─────────────────────────────────────────────────────────────────────────────
4628
4780