@leu2m/semantic-search 0.2.0-beta.1

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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/dist/adapters/file-storage.d.ts +8 -0
  4. package/dist/adapters/file-storage.js +55 -0
  5. package/dist/adapters/file-storage.js.map +1 -0
  6. package/dist/adapters/filesystem.d.ts +23 -0
  7. package/dist/adapters/filesystem.js +119 -0
  8. package/dist/adapters/filesystem.js.map +1 -0
  9. package/dist/adapters/minilm.d.ts +50 -0
  10. package/dist/adapters/minilm.js +141 -0
  11. package/dist/adapters/minilm.js.map +1 -0
  12. package/dist/catalog.d.ts +3 -0
  13. package/dist/catalog.js +26 -0
  14. package/dist/catalog.js.map +1 -0
  15. package/dist/chunking.d.ts +9 -0
  16. package/dist/chunking.js +54 -0
  17. package/dist/chunking.js.map +1 -0
  18. package/dist/contracts.d.ts +163 -0
  19. package/dist/contracts.js +4 -0
  20. package/dist/contracts.js.map +1 -0
  21. package/dist/embedding-input.d.ts +4 -0
  22. package/dist/embedding-input.js +13 -0
  23. package/dist/embedding-input.js.map +1 -0
  24. package/dist/engine.d.ts +63 -0
  25. package/dist/engine.js +257 -0
  26. package/dist/engine.js.map +1 -0
  27. package/dist/file-types/registry.d.ts +13 -0
  28. package/dist/file-types/registry.js +47 -0
  29. package/dist/file-types/registry.js.map +1 -0
  30. package/dist/file-types/types.d.ts +11 -0
  31. package/dist/file-types/types.js +2 -0
  32. package/dist/file-types/types.js.map +1 -0
  33. package/dist/index-state.d.ts +17 -0
  34. package/dist/index-state.js +91 -0
  35. package/dist/index-state.js.map +1 -0
  36. package/dist/index.d.ts +11 -0
  37. package/dist/index.js +8 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/parsers/index.d.ts +28 -0
  40. package/dist/parsers/index.js +113 -0
  41. package/dist/parsers/index.js.map +1 -0
  42. package/dist/retrieval.d.ts +20 -0
  43. package/dist/retrieval.js +108 -0
  44. package/dist/retrieval.js.map +1 -0
  45. package/docs/alpha5-hardening.md +86 -0
  46. package/docs/alpha6-answerability.md +131 -0
  47. package/docs/alpha6-c-validation.md +490 -0
  48. package/docs/alpha6-evidence-traces.md +486 -0
  49. package/docs/api.md +43 -0
  50. package/docs/architecture.md +121 -0
  51. package/docs/benchmarks/alpha5-retrieval.json +5233 -0
  52. package/docs/benchmarks/alpha5-scale.json +505 -0
  53. package/docs/benchmarks/alpha6-evidence.json +14185 -0
  54. package/docs/benchmarks/alpha6c-heldout-real.json +9389 -0
  55. package/docs/decisions/0001-minilm-loading.md +32 -0
  56. package/docs/decisions/0002-retrieval-modes.md +26 -0
  57. package/docs/decisions/0003-retrieval-evidence-boundary.md +19 -0
  58. package/docs/evaluation.md +315 -0
  59. package/docs/file-types.md +31 -0
  60. package/docs/integration.md +204 -0
  61. package/docs/next-slice.md +11 -0
  62. package/examples/README.md +38 -0
  63. package/examples/core.mjs +53 -0
  64. package/examples/evidence.mjs +20 -0
  65. package/examples/filesystem.mjs +9 -0
  66. package/examples/minilm.mjs +15 -0
  67. package/package.json +73 -0
@@ -0,0 +1,486 @@
1
+ # Alpha.6 development evidence traces
2
+
3
+ These are development traces, not independent judgments. L/S/H are ordinal lexical/semantic/hybrid ranks. Cosine is an internal similarity diagnostic, never sufficiency. Full exact text and provenance are bound in [the chunk manifest](https://github.com/leu2m/semantic-search/blob/b46b2d8/tests/fixtures/evidence/chunks.json); grades and task requirements are in [the overlay](https://github.com/leu2m/semantic-search/blob/b46b2d8/tests/fixtures/evidence/judgments.json). The report includes the union of channel top-five chunks and explicitly judged chunks, including low-ranked expected evidence. Missing lexical rank means no positive lexical score.
4
+ ## exact-symbol-2: normalizeAppend
5
+
6
+ Requirement: Locate the normalizeAppend implementation.
7
+
8
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["normalize.ts:1"]]`.
9
+
10
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
11
+ | --- | ---: | ---: | ---: | ---: | ---: |
12
+ | normalize.ts:1 | 2 | 1 | 1 | 1 | 0.5100 |
13
+ | migrations.md:1 | 0 | — | 2 | 2 | 0.1978 |
14
+ | uploads.md:1 | 0 | — | 3 | 3 | 0.1944 |
15
+ | rename.md:1 | 0 | — | 4 | 4 | 0.1881 |
16
+ | batching.md:1 | 0 | — | 5 | 5 | 0.1858 |
17
+
18
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
19
+
20
+ **normalize.ts:1**
21
+
22
+ ````text
23
+ export function normalizeAppend(existing: string, addition: string): string {
24
+ // Preserve the existing content and insert exactly one separating newline.
25
+ return existing.replace(/\n*$/, "") + "\n" + addition.replace(/^\n*/, "");
26
+ }
27
+ // This helper handles text joining, not path containment or authorization.
28
+ ````
29
+ ## terminology-1: expand-and-contract
30
+
31
+ Requirement: Explain expand-and-contract rollout.
32
+
33
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["migrations.md:1"]]`.
34
+
35
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
36
+ | --- | ---: | ---: | ---: | ---: | ---: |
37
+ | migrations.md:1 | 2 | 1 | 7 | 1 | 0.1349 |
38
+ | migrations.md:5 | 1 | 33 | 29 | 32 | 0.0603 |
39
+ | deploy.md:1 | 1 | 18 | 41 | 27 | 0.0388 |
40
+ | health.md:1 | 0 | 2 | 68 | 20 | -0.0554 |
41
+ | roadmap.md:1 | 0 | 3 | 9 | 2 | 0.1215 |
42
+ | alerts.md:1 | 0 | 4 | 26 | 4 | 0.0630 |
43
+ | api-keys.md:1 | 0 | 5 | 35 | 8 | 0.0532 |
44
+ | normalize.ts:1 | 0 | 36 | 1 | 5 | 0.2165 |
45
+ | leases.md:1 | 0 | — | 2 | 61 | 0.1824 |
46
+ | uploads.md:1 | 0 | 56 | 3 | 14 | 0.1454 |
47
+ | uploads.md:5 | 0 | 57 | 4 | 18 | 0.1395 |
48
+ | meetings.md:1 | 0 | 32 | 5 | 7 | 0.1389 |
49
+ | batching.md:1 | 0 | 10 | 6 | 3 | 0.1352 |
50
+
51
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
52
+
53
+ **migrations.md:1**
54
+
55
+ ````text
56
+ # Schema migration rollout
57
+
58
+ Use an expand-and-contract rollout when changing a populated table. Add a nullable column first, deploy code that writes both representations, backfill historical rows, then switch readers. Remove the old column only after earlier application versions are retired. Holding an exclusive lock for a long backfill can disrupt traffic even when the schema change itself is small.
59
+
60
+ ````
61
+
62
+ **migrations.md:5**
63
+
64
+ ````text
65
+ ## Backfill progress
66
+
67
+ Backfills process bounded key ranges and checkpoint the last completed range. They yield between batches to reduce lock pressure. Restarting the job resumes from that checkpoint, while live writes continue populating the new representation.
68
+ ````
69
+
70
+ **deploy.md:1**
71
+
72
+ ````text
73
+ # Canary deployment
74
+
75
+ A new version receives a small portion of production traffic before broad rollout. Compare error rate and latency against the previous version using the same request mix. Pause or roll back when guardrails are exceeded. A canary reduces exposure but does not replace schema compatibility checks. Background workers also require a controlled version transition.
76
+ ````
77
+ ## conceptual-1: How are earlier chats brought back when the application starts again?
78
+
79
+ Requirement: Explain how prior chats are restored at application startup.
80
+
81
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["session.md:1"]]`.
82
+
83
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
84
+ | --- | ---: | ---: | ---: | ---: | ---: |
85
+ | session.md:1 | 2 | 43 | 1 | 10 | 0.4928 |
86
+ | session.md:5 | 1 | 44 | 6 | 14 | 0.2591 |
87
+ | session-expiry.md:1 | 1 | 64 | 2 | 18 | 0.4342 |
88
+ | cookies.md:1 | 1 | 54 | 3 | 15 | 0.3801 |
89
+ | oauth.md:1 | 0 | 1 | 19 | 3 | 0.1794 |
90
+ | backup.md:1 | 0 | 2 | 8 | 1 | 0.2526 |
91
+ | backup.md:5 | 0 | 3 | 21 | 7 | 0.1711 |
92
+ | migrations.md:1 | 0 | 4 | 16 | 5 | 0.1841 |
93
+ | oauth.md:5 | 0 | 5 | 54 | 19 | 0.0661 |
94
+ | retention.md:1 | 0 | 14 | 4 | 2 | 0.2913 |
95
+ | audit.md:1 | 0 | 16 | 5 | 6 | 0.2803 |
96
+ | migrations.md:5 | 0 | 8 | 10 | 4 | 0.2314 |
97
+
98
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
99
+
100
+ **session.md:1**
101
+
102
+ ````text
103
+ # Session durability
104
+
105
+ SessionStore serializes conversation messages to a journal before acknowledging an update. At startup the service replays committed entries to rebuild the conversation timeline. An interrupted write leaves the last acknowledged messages available. Transient typing indicators are deliberately excluded from serialized state. The journal belongs to one account and is not shared with the browser response cache.
106
+
107
+ ````
108
+
109
+ **session.md:5**
110
+
111
+ ````text
112
+ ## Recovery verification
113
+
114
+ After replay, compare the last committed message sequence with the recorded acknowledgement. A corrupt journal stops startup rather than presenting an invented conversation. A diagnostic export can inspect sequence gaps without exposing message bodies.
115
+ ````
116
+
117
+ **session-expiry.md:1**
118
+
119
+ ````text
120
+ # Session expiry
121
+
122
+ Authentication sessions expire after thirty minutes of inactivity in this fictional service. A successful authenticated request extends the idle deadline. Expiry removes the login grant; it does not erase saved conversation messages. Operators can revoke all sessions for an account after a credential leak. SessionStore handles message durability separately from authentication grants.
123
+ ````
124
+
125
+ **cookies.md:1**
126
+
127
+ ````text
128
+ # Browser cookie policy
129
+
130
+ The login cookie uses HttpOnly, Secure and SameSite=Lax attributes. Scripts cannot inspect its opaque session identifier. The server checks the session grant on each protected request rather than trusting a client flag. Clearing a cookie logs out this browser, while a server-side revocation invalidates other devices too. Cookie policy does not restore conversation history.
131
+ ````
132
+ ## conceptual-3: Can a paused old worker overwrite what its replacement has done?
133
+
134
+ Requirement: Explain whether a paused former worker can overwrite a replacement.
135
+
136
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["leases.md:1"]]`.
137
+
138
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
139
+ | --- | ---: | ---: | ---: | ---: | ---: |
140
+ | leases.md:1 | 2 | 1 | 2 | 1 | 0.4245 |
141
+ | lease.sql:1 | 1 | 52 | 9 | 24 | 0.3139 |
142
+ | relevance.md:1 | 0 | 2 | 66 | 21 | -0.0038 |
143
+ | deploy.md:1 | 0 | 3 | 22 | 4 | 0.2257 |
144
+ | tokenization.md:1 | 0 | 4 | 48 | 18 | 0.0919 |
145
+ | api-keys.md:1 | 0 | 5 | 39 | 15 | 0.1534 |
146
+ | queue.md:1 | 0 | 66 | 1 | 20 | 0.4657 |
147
+ | uploads.md:1 | 0 | 37 | 3 | 11 | 0.4176 |
148
+ | migrations.md:5 | 0 | 43 | 4 | 16 | 0.4030 |
149
+ | uploads.md:5 | 0 | 38 | 5 | 14 | 0.3897 |
150
+ | atomic-save.md:1 | 0 | 10 | 6 | 2 | 0.3641 |
151
+ | migrations.md:1 | 0 | 7 | 12 | 3 | 0.2847 |
152
+ | shutdown-model.md:1 | 0 | 9 | 14 | 5 | 0.2715 |
153
+
154
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
155
+
156
+ **leases.md:1**
157
+
158
+ ````text
159
+ # Worker lease ownership
160
+
161
+ A worker claims a task using a lease with a monotonically increasing fencing token. If renewal stops, another worker may take over. Downstream writes reject older fencing tokens so a paused former owner cannot overwrite newer work. Heartbeats indicate liveness but do not by themselves guarantee exclusive ownership. Lease duration balances failover delay against renewal overhead.
162
+ ````
163
+
164
+ **lease.sql:1**
165
+
166
+ ````text
167
+ UPDATE task_leases
168
+ SET owner = :worker, fence = fence + 1, expires_at = :deadline
169
+ WHERE task_id = :task AND expires_at < CURRENT_TIMESTAMP
170
+ RETURNING fence;
171
+ -- Downstream writers must compare the returned fence; this update alone is not sufficient.
172
+ ````
173
+ ## mixed-2: OAuthCallback reject a login response from the wrong browser flow
174
+
175
+ Requirement: Explain OAuthCallback rejection of a response from the wrong browser flow.
176
+
177
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["oauth.md:1"], ["callback.ts:1"]]`.
178
+
179
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
180
+ | --- | ---: | ---: | ---: | ---: | ---: |
181
+ | oauth.md:1 | 2 | 2 | 1 | 1 | 0.6376 |
182
+ | callback.ts:1 | 2 | 33 | 2 | 9 | 0.5470 |
183
+ | oauth.md:5 | 1 | 43 | 12 | 20 | 0.1782 |
184
+ | csrf.md:1 | 1 | 56 | 3 | 16 | 0.5293 |
185
+ | http-cache.md:1 | 0 | 1 | 16 | 4 | 0.1505 |
186
+ | session.md:1 | 0 | 3 | 15 | 6 | 0.1576 |
187
+ | cookies.md:1 | 0 | 4 | 4 | 2 | 0.4211 |
188
+ | pagination.md:1 | 0 | 5 | 32 | 10 | 0.0379 |
189
+ | session-expiry.md:1 | 0 | 61 | 5 | 18 | 0.2675 |
190
+ | passwords.md:1 | 0 | 6 | 6 | 3 | 0.2527 |
191
+ | api-keys.md:1 | 0 | 10 | 7 | 5 | 0.2502 |
192
+
193
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
194
+
195
+ **oauth.md:1**
196
+
197
+ ````text
198
+ # OAuth callback
199
+
200
+ OAuthCallback verifies the returned state against a short-lived nonce stored before redirecting to the identity provider. A mismatch rejects the login attempt. The handler exchanges the authorization code once and deletes the nonce after success. Callback URLs must match the registered redirect URI. This flow establishes identity; permission checks happen later at the resource boundary.
201
+
202
+ ````
203
+
204
+ **callback.ts:1**
205
+
206
+ ````text
207
+ export async function OAuthCallback(request, nonces, provider) {
208
+ const expected = await nonces.consume(request.cookie);
209
+ if (!expected || expected !== request.state) throw new Error("Invalid state");
210
+ return provider.exchangeCode(request.code);
211
+ }
212
+ // Consumption is atomic so the same nonce cannot establish two login grants.
213
+ ````
214
+
215
+ **oauth.md:5**
216
+
217
+ ````text
218
+ ## Redirect registration
219
+
220
+ Register a precise callback URI for each deployment environment. Wildcard redirect destinations are not allowed in this fictional service. Changing the host or path requires updating the provider registration before deployment.
221
+ ````
222
+
223
+ **csrf.md:1**
224
+
225
+ ````text
226
+ # Request forgery protection
227
+
228
+ State-changing browser requests require a CSRF token tied to the current login grant. The handler also checks the request origin against an allowlist. A cookie being present is insufficient because another page may cause the browser to send it. Public read-only endpoints do not accept mutations through GET. OAuth state checks protect a different redirect boundary.
229
+ ````
230
+ ## noisy-1: hey I think the jobs keep failing um where do they go after all the attempts are used up
231
+
232
+ Requirement: State where jobs go when retry attempts are exhausted.
233
+
234
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["queue.md:1"], ["queue-config.yaml:1"]]`.
235
+
236
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
237
+ | --- | ---: | ---: | ---: | ---: | ---: |
238
+ | queue.md:1 | 2 | 27 | 1 | 7 | 0.5457 |
239
+ | queue-config.yaml:1 | 2 | 65 | 4 | 18 | 0.2960 |
240
+ | queue.md:5 | 1 | 47 | 9 | 16 | 0.2192 |
241
+ | uploads.md:1 | 0 | 1 | 27 | 8 | 0.1517 |
242
+ | backup.md:1 | 0 | 2 | 14 | 2 | 0.2039 |
243
+ | rate-limit.md:1 | 0 | 3 | 12 | 1 | 0.2080 |
244
+ | backup.md:5 | 0 | 4 | 18 | 5 | 0.1747 |
245
+ | meetings.md:1 | 0 | 5 | 62 | 19 | 0.0147 |
246
+ | shutdown.md:1 | 0 | 17 | 2 | 3 | 0.3743 |
247
+ | migrations.md:5 | 0 | 23 | 3 | 6 | 0.3367 |
248
+ | workers.md:1 | 0 | 52 | 5 | 14 | 0.2403 |
249
+ | uploads.md:5 | 0 | 7 | 11 | 4 | 0.2083 |
250
+
251
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
252
+
253
+ **queue.md:1**
254
+
255
+ ````text
256
+ # Job retry policy
257
+
258
+ Failed jobs return to the queue with exponential backoff and jitter. After five attempts the worker moves the job to a dead-letter queue for inspection. Permanent validation failures skip retries. A worker acknowledges a job only after durable side effects complete. Replaying a failed job requires idempotent handlers because the earlier attempt may have partly succeeded.
259
+
260
+ ````
261
+
262
+ **queue-config.yaml:1**
263
+
264
+ ````text
265
+ worker:
266
+ queue: notifications
267
+ attempts: 5
268
+ backoff: exponential
269
+ jitter: true
270
+ visibility_timeout_seconds: 90
271
+ dead_letter_queue: failed-notifications
272
+ ````
273
+
274
+ **queue.md:5**
275
+
276
+ ````text
277
+ ## Dead-letter inspection
278
+
279
+ Operators inspect the last failure category and attempt history before replaying a dead-letter item. Correct invalid input first. Replay preserves the original event identity so idempotency still protects against duplicate side effects.
280
+ ````
281
+ ## negative-1: What is the boiling point of liquid neon?
282
+
283
+ Requirement: What is the boiling point of liquid neon?
284
+
285
+ Development corpus judgment: **unsupported**. Sufficient alternatives (AND within a set; OR between sets): `[]`.
286
+
287
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
288
+ | --- | ---: | ---: | ---: | ---: | ---: |
289
+ | shutdown-model.md:1 | 0 | 1 | 44 | 7 | -0.0335 |
290
+ | meetings.md:1 | 0 | 2 | 67 | 15 | -0.0849 |
291
+ | permissions.md:1 | 0 | 3 | 49 | 11 | -0.0468 |
292
+ | backup.md:1 | 0 | 4 | 71 | 22 | -0.1146 |
293
+ | network.md:1 | 0 | 5 | 33 | 5 | -0.0187 |
294
+ | health.md:1 | 0 | 18 | 1 | 1 | 0.1630 |
295
+ | db-pool.md:1 | 0 | 35 | 2 | 3 | 0.1193 |
296
+ | deployment.yaml:1 | 0 | — | 3 | 71 | 0.1100 |
297
+ | cosine.md:1 | 0 | 34 | 4 | 4 | 0.1044 |
298
+ | pool.toml:1 | 0 | 64 | 5 | 20 | 0.0920 |
299
+ | csrf.md:1 | 0 | 14 | 12 | 2 | 0.0325 |
300
+
301
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
302
+ ## near-miss-3: What is the OAuth provider client secret for production?
303
+
304
+ Requirement: Supply the specific requested value/secret/measurement, not a general procedure.
305
+
306
+ Development corpus judgment: **unsupported**. Sufficient alternatives (AND within a set; OR between sets): `[]`.
307
+
308
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
309
+ | --- | ---: | ---: | ---: | ---: | ---: |
310
+ | oauth.md:1 | 1 | 1 | 1 | 1 | 0.4698 |
311
+ | oauth.md:5 | 1 | 3 | 13 | 6 | 0.2100 |
312
+ | api-keys.md:1 | 1 | 7 | 5 | 5 | 0.3115 |
313
+ | csrf.md:1 | 0 | 2 | 8 | 4 | 0.2846 |
314
+ | shutdown-model.md:1 | 0 | 4 | 45 | 13 | 0.0208 |
315
+ | meetings.md:1 | 0 | 5 | 69 | 22 | -0.0595 |
316
+ | callback.ts:1 | 0 | 8 | 2 | 3 | 0.3450 |
317
+ | permissions.md:1 | 0 | 6 | 3 | 2 | 0.3225 |
318
+ | users-api.md:1 | 0 | 40 | 4 | 12 | 0.3149 |
319
+
320
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
321
+
322
+ **oauth.md:1**
323
+
324
+ ````text
325
+ # OAuth callback
326
+
327
+ OAuthCallback verifies the returned state against a short-lived nonce stored before redirecting to the identity provider. A mismatch rejects the login attempt. The handler exchanges the authorization code once and deletes the nonce after success. Callback URLs must match the registered redirect URI. This flow establishes identity; permission checks happen later at the resource boundary.
328
+
329
+ ````
330
+
331
+ **oauth.md:5**
332
+
333
+ ````text
334
+ ## Redirect registration
335
+
336
+ Register a precise callback URI for each deployment environment. Wildcard redirect destinations are not allowed in this fictional service. Changing the host or path requires updating the provider registration before deployment.
337
+ ````
338
+
339
+ **api-keys.md:1**
340
+
341
+ ````text
342
+ # API key rotation
343
+
344
+ Automation clients authenticate using scoped API keys. Rotation creates a replacement credential, moves clients to it, and revokes the old key after a short overlap. Keep only key digests in storage and display the secret once. Key scopes limit actions independently of a user login session. Emergency rotation can skip the overlap when compromise is suspected.
345
+ ````
346
+ ## near-miss-4: What was the measured restore time in last Tuesdays backup drill?
347
+
348
+ Requirement: Supply the specific requested value/secret/measurement, not a general procedure.
349
+
350
+ Development corpus judgment: **unsupported**. Sufficient alternatives (AND within a set; OR between sets): `[]`.
351
+
352
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
353
+ | --- | ---: | ---: | ---: | ---: | ---: |
354
+ | backup.md:1 | 1 | 1 | 2 | 1 | 0.4713 |
355
+ | backup.md:5 | 1 | 2 | 1 | 2 | 0.6632 |
356
+ | pagination.md:1 | 0 | 3 | 43 | 13 | 0.0843 |
357
+ | batching.md:1 | 0 | 4 | 52 | 19 | 0.0583 |
358
+ | incident.md:1 | 0 | 5 | 19 | 3 | 0.1650 |
359
+ | retention.md:1 | 0 | 31 | 3 | 7 | 0.3437 |
360
+ | migrations.md:5 | 0 | 28 | 4 | 5 | 0.3225 |
361
+ | passwords.md:1 | 0 | 54 | 5 | 21 | 0.3105 |
362
+ | latency.md:1 | 0 | 6 | 22 | 4 | 0.1491 |
363
+
364
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
365
+
366
+ **backup.md:1**
367
+
368
+ ````text
369
+ # Backup restoration
370
+
371
+ Nightly snapshots and archived transaction logs support point-in-time restoration. Restore into an isolated database, replay logs up to the chosen timestamp, and validate row counts before switching traffic. A completed backup job is not proof that restoration works; operators run periodic recovery drills. Backups recover deleted data, whereas replicas can faithfully copy the deletion.
372
+
373
+ ````
374
+
375
+ **backup.md:5**
376
+
377
+ ````text
378
+ ## Recovery drill report
379
+
380
+ A quarterly drill restores the latest snapshot into a temporary database and compares checksums for selected tables. Record elapsed restoration time and the final replay position. The result informs the recovery objective instead of assuming the backup timestamp is enough.
381
+ ````
382
+ ## multi-relevant-1: How do retries avoid duplicate effects across payments, webhooks and queued jobs?
383
+
384
+ Requirement: Explain duplicate-effect protection for each of payments, webhooks and jobs.
385
+
386
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["idempotency.md:1", "webhooks.md:1", "queue.md:1"], ["idempotency.md:1", "webhooks.md:1", "queue.md:5"]]`.
387
+
388
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
389
+ | --- | ---: | ---: | ---: | ---: | ---: |
390
+ | idempotency.md:1 | 1 | 27 | 3 | 7 | 0.4648 |
391
+ | webhooks.md:1 | 1 | 2 | 2 | 1 | 0.4751 |
392
+ | queue.md:1 | 1 | 7 | 1 | 2 | 0.4918 |
393
+ | queue.md:5 | 1 | 10 | 10 | 5 | 0.3149 |
394
+ | outbox.md:1 | 1 | 5 | 20 | 6 | 0.2804 |
395
+ | shutdown.md:1 | 0 | 1 | 14 | 3 | 0.3029 |
396
+ | health.md:1 | 0 | 3 | 41 | 11 | 0.1735 |
397
+ | network.md:1 | 0 | 4 | 35 | 9 | 0.2055 |
398
+ | leases.md:1 | 0 | 54 | 4 | 15 | 0.3712 |
399
+ | transactions.md:1 | 0 | 66 | 5 | 20 | 0.3709 |
400
+ | workers.md:1 | 0 | 13 | 7 | 4 | 0.3464 |
401
+
402
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
403
+
404
+ **idempotency.md:1**
405
+
406
+ ````text
407
+ # Idempotent requests
408
+
409
+ Clients attach an Idempotency-Key when creating a payment. The server stores the normalized request digest and completed response with that key. A retry with the same payload receives the stored response instead of creating a second payment. Reusing the key with a different payload fails. Keys expire only after the advertised retry window has elapsed.
410
+ ````
411
+
412
+ **webhooks.md:1**
413
+
414
+ ````text
415
+ # Webhook delivery
416
+
417
+ Outgoing webhooks include an event ID and a signature over the exact body bytes. Receivers verify the signature and remember event IDs to handle duplicate deliveries. Temporary failures retry with increasing delays. A successful HTTP status acknowledges transport; it does not prove every downstream workflow completed. Rotating signing secrets permits a bounded overlap.
418
+ ````
419
+
420
+ **queue.md:1**
421
+
422
+ ````text
423
+ # Job retry policy
424
+
425
+ Failed jobs return to the queue with exponential backoff and jitter. After five attempts the worker moves the job to a dead-letter queue for inspection. Permanent validation failures skip retries. A worker acknowledges a job only after durable side effects complete. Replaying a failed job requires idempotent handlers because the earlier attempt may have partly succeeded.
426
+
427
+ ````
428
+
429
+ **queue.md:5**
430
+
431
+ ````text
432
+ ## Dead-letter inspection
433
+
434
+ Operators inspect the last failure category and attempt history before replaying a dead-letter item. Correct invalid input first. Replay preserves the original event identity so idempotency still protects against duplicate side effects.
435
+ ````
436
+
437
+ **outbox.md:1**
438
+
439
+ ````text
440
+ # Transactional outbox
441
+
442
+ The service records a domain change and an outgoing event in the same transaction. A separate publisher delivers outbox entries and marks successful delivery. A crash between delivery and marking can produce a duplicate, so consumers deduplicate event IDs. This avoids losing a notification when the database commits but the message broker is temporarily unavailable.
443
+ ````
444
+ ## multi-relevant-5: How can persisted retrieval state survive edits and renames without mixing incompatible vectors?
445
+
446
+ Requirement: Explain compatible persisted retrieval through edits/renames and safe publication.
447
+
448
+ Development corpus judgment: **supported**. Sufficient alternatives (AND within a set; OR between sets): `[["snapshot.md:1", "rename.md:1", "atomic-save.md:1"]]`.
449
+
450
+ | Chunk (document:start line) | Grade | L | S | H | Cosine |
451
+ | --- | ---: | ---: | ---: | ---: | ---: |
452
+ | snapshot.md:1 | 1 | 14 | 2 | 4 | 0.4508 |
453
+ | rename.md:1 | 1 | 1 | 1 | 1 | 0.5242 |
454
+ | atomic-save.md:1 | 1 | 8 | 7 | 5 | 0.3334 |
455
+ | deploy.md:1 | 0 | 2 | 52 | 15 | 0.0844 |
456
+ | evaluation.md:1 | 0 | 3 | 5 | 2 | 0.3668 |
457
+ | health.md:1 | 0 | 4 | 59 | 19 | 0.0182 |
458
+ | embeddings.md:1 | 0 | 5 | 12 | 6 | 0.3154 |
459
+ | search-cache.md:1 | 0 | 34 | 3 | 9 | 0.4235 |
460
+ | filesystem.md:1 | 0 | 10 | 4 | 3 | 0.3705 |
461
+
462
+ Expected/contextual chunk contents (exact source text; irrelevant returned contents remain in the linked manifest):
463
+
464
+ **snapshot.md:1**
465
+
466
+ ````text
467
+ # Snapshot compatibility
468
+
469
+ Persist schema, parser, chunker and embedding-input versions with model identity and dimensions. Reject reuse when any vector-affecting configuration differs. Compatible but malformed records surface corruption rather than mixing partial old data with new content. A restored snapshot is only a reuse candidate until registered sources have been reconciled with live contents.
470
+ ````
471
+
472
+ **rename.md:1**
473
+
474
+ ````text
475
+ # Rename without inference
476
+
477
+ A document rename changes provenance-sensitive chunk identifiers but need not change the text sent to an embedder. Reuse vectors by exact content and structural context, never by a weak hash alone. Remove the old path from the canonical index after successful refresh. If a heading changes meaningfully, the embedding input changes even when body text is identical.
478
+ ````
479
+
480
+ **atomic-save.md:1**
481
+
482
+ ````text
483
+ # Atomic snapshot publication
484
+
485
+ Write the complete candidate snapshot to a temporary sibling file, flush it, close it, and rename it over the canonical file. A failed replacement leaves the previous complete snapshot readable. Publish matching live state only after storage confirms success. Directory durability and multi-process writer coordination remain separate host responsibilities.
486
+ ````
package/docs/api.md ADDED
@@ -0,0 +1,43 @@
1
+ # Public API and host responsibilities
2
+
3
+ All root contracts are TypeScript/ESM and import no host or model runtime. The only public subpaths remain `/filesystem` (Node) and `/minilm` (portable optional runtime). Internal ranking helpers are not package exports. There is no implicit worker, scheduler, source discovery or storage directory.
4
+
5
+ ## Ownership and lifecycle
6
+
7
+ | Contract | Host owns | Engine/adapter owns | Failure and mutability expectations |
8
+ | --- | --- | --- | --- |
9
+ | `SearchSource` | Authorization, stable source ID, listing/reading, source event subscription | Per-source scan, parsing, reconciliation | IDs unique within a source; each document declares its owning source; throw on unavailable reads. Keep a scan coherent where practical; source I/O is not a filesystem transaction. |
10
+ | `Embedder` | Effective immutable model/config ID, dimensions, execution realm, resource lifetime | Engine finds unique missing inputs and reuses compatible vectors; embedder batches inference | Float32Array per input, finite and matching dimensions. Semantic use additionally needs nonzero norms. Propagate signal cooperatively and surface errors. Generic embedders need not normalize. |
11
+ | `IndexStorage` | Location/backend, provisioning, atomic transactions, single writer and recovery | Compatible snapshot creation/load/reconciliation | `load` returns snapshot or null; corrupt data/I/O errors surface. `save` rejects before publication, resolves after publication; late abort cannot undo a committed save. Do not mutate saved/loaded values behind the engine. |
12
+ | `SearchRequest` | Query, explicit mode if desired, approved sources and deterministic filters, final limit, signal | Effective mode, shared filtering, channel ranking, RRF and final limit | Nonempty semantic queries are sent unmodified to the embedder. Limit 1–100, default 8. No embedder: default lexical; embedder: default hybrid. Explicit semantic/hybrid without embedder fails. |
13
+ | `SearchResult` | Evidence interpretation, reopening source and checking current facts before actions | Stable source/document/chunk identity, URI/path/lines/snippet and ordinal ranks | Results are evidence candidates, not verified answers. Channel ranks and combinedRank are not confidence. No calibrated rejection or raw-score API exists. |
14
+ | `SemanticSearchEngine` | Source registration, serialized refresh requests, sharing/disposal of supplied adapters | Catalog, chunks, compatible vector reuse, atomic per-source publication, retrieval | A failed refresh preserves the last good source. `initialize` is per-source atomic, not whole-index atomic. Search sees a captured committed view; overlapping refresh may make it old but cannot mix vector generations. |
15
+ | `createSearchSession` | Per-run cache lifetime and optional capacity | Bounded FIFO insertion, defensive copies, effective-mode keys, revision invalidation | Failed calls are not cached. Equivalent unordered source/tag/extension sets share keys. Lexical queries normalize case/outer spaces; semantic/hybrid retain exact query text. `clear()` also prevents pending older work from repopulating the cache; it does not abort that work. |
16
+ | `MiniLMEmbedder` | Optional peer installation, model/backend assets, global runtime configuration, thread/worker placement and disposal | Lazy model load, modest batches, normalized 384-dimensional output, query/document inference, terminal disposal | Default pinned model/revision and identity remain documented in integration. No runtime import at construction. Active native inference may not be preemptible. Sharing one adapter across engines is allowed; finish all users before disposal. |
17
+
18
+ ## Small operational sequence
19
+
20
+ Create host adapters, construct an engine, register sources, then await `initialize({ signal })`. Search with `engine.search(request)` or a short-lived `createSearchSession(engine)`. After host-observed changes, await `refreshSource(sourceId, { signal })`; inspect its embedding/unchanged counts when diagnosing expensive updates. Keep the embedder alive for semantic queries.
21
+
22
+ `getCatalog()` returns a defensive copy. `revision` identifies committed index changes. `defaultMode` is read-only. `removeSource(id)` immediately clears that source in memory; the next successful refresh persists the removal. It is not an immediate durable storage operation. Adding a source does not index it automatically.
23
+
24
+ Mutation of parser or embedder behavior without changing its version/identity violates compatibility assumptions. Construct a new engine for changed embedding configuration. Hosts must serialize writes to a store; there is no multi-process lock. A custom parser registry requires an explicit behavior version for persistent reuse and parsers whose `supports` methods recognize their custom formats.
25
+
26
+ ## Cancellation and workers
27
+
28
+ Signals are checked before/after asynchronous stages and during candidate loops. Synchronous parsing/ranking/sorting does not yield to the event loop, so a same-thread timer cannot preempt a running scan. Large searches belong in a host-controlled worker when interactive responsiveness matters. Pass messages/serializable evidence across worker boundaries; instantiate source/storage/embedder objects within the chosen realm rather than transferring an engine object. Browser storage in examples is memory-only, not IndexedDB/OPFS.
29
+
30
+ ## Current awkward edges and release scope
31
+
32
+ - Returned evidence can be irrelevant, including high-cosine near misses. Use provenance to check the requested fact; a nonempty result is not proof that an answer exists.
33
+ - Raw scores are deliberately absent. Hosts cannot implement a score threshold from ranks, but Alpha.5 does not establish a reliable threshold or require a breaking score API. Alpha.6 selects retrieval-only core; a generic evaluator or score API requires separately demonstrated consumer needs.
34
+ - Full exact ranking becomes expensive at tens of thousands of unfiltered 384-dimensional candidates on the measured laptop. Scope sources/filters and choose execution placement; no universal latency promise is made.
35
+ - Snapshots serialize numeric arrays and refresh rescans sources. No automatic migrations, watcher subscription, durable removeSource call, or production browser store is provided.
36
+
37
+ See [integration](integration.md), [examples](../examples/README.md), [Alpha.5 evidence](alpha5-hardening.md) and [architecture](architecture.md).
38
+
39
+ ## Alpha.6: candidate retrieval is not a support judgment
40
+
41
+ `SearchRequest`, `SearchResult`, `SemanticSearchEngine.search` and `createSearchSession` retain their runtime signatures. TSDoc now explicitly states that ranked candidates are unassessed evidence; neither an empty nor a nonempty array establishes corpus answerability. Empty can mean lexical mismatch, query/filter restrictions or no indexed candidates. The engine does not classify these causes in a new result envelope.
42
+
43
+ The maintained [host example](../examples/evidence.mjs) preserves candidates and uses the example-local label `answerability: 'not-assessed'` for both `retrieved` and `no-results`. It propagates failures/abort, adds no inference or caching, and observes only whether the index revision changed during search. A false overlap flag is not a source-freshness guarantee. These fields are not exported engine/result types. Hosts can perform separate evidence verification, but this package neither implements nor certifies a host assessment. See [ADR 0003](decisions/0003-retrieval-evidence-boundary.md) and [the design record](alpha6-answerability.md).