@avantf/dsh-mem 0.7.0 → 0.8.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 (146) hide show
  1. package/README.md +4 -0
  2. package/lib/client.js +548 -1195
  3. package/lib/dsh-build.json +1 -0
  4. package/lib/engine/graph-recall/in-memory.d.ts +93 -0
  5. package/lib/engine/graph-recall/index.d.ts +22 -0
  6. package/lib/engine/graph-recall/traverse.d.ts +119 -0
  7. package/lib/engine/graph-recall/types.d.ts +188 -0
  8. package/lib/engine/mem/config/config_files.d.ts +1 -1
  9. package/lib/engine/mem/config/loader.d.ts +2 -3
  10. package/lib/engine/mem/config/paths.d.ts +2 -13
  11. package/lib/engine/mem/db/dao/contradictions.d.ts +4 -22
  12. package/lib/engine/mem/db/dao/entities.d.ts +80 -7
  13. package/lib/engine/mem/db/dao/fact_sources.d.ts +3 -13
  14. package/lib/engine/mem/db/dao/facts.d.ts +311 -56
  15. package/lib/engine/mem/db/dao/triples.d.ts +1 -26
  16. package/lib/engine/mem/db/graph.d.ts +249 -0
  17. package/lib/engine/mem/db/journal_notes.d.ts +35 -0
  18. package/lib/engine/mem/db/migrations.d.ts +9 -0
  19. package/lib/engine/mem/db/port.d.ts +22 -3
  20. package/lib/engine/mem/db/schema.d.ts +119 -0
  21. package/lib/engine/mem/db/tokenizer.d.ts +9 -0
  22. package/lib/engine/mem/dbdrivers/fake/driver.d.ts +75 -0
  23. package/lib/engine/mem/dbdrivers/fake/index.d.ts +7 -0
  24. package/lib/engine/mem/dbdrivers/fake/surface.d.ts +34 -0
  25. package/lib/engine/mem/dbdrivers/fake/transport.d.ts +61 -0
  26. package/lib/engine/mem/dbdrivers/sqlite/connection.d.ts +14 -0
  27. package/lib/engine/mem/dbdrivers/sqlite/contradictions.d.ts +35 -0
  28. package/lib/engine/mem/dbdrivers/sqlite/dao/index.d.ts +16 -0
  29. package/lib/engine/mem/dbdrivers/sqlite/driver.d.ts +54 -0
  30. package/lib/engine/mem/dbdrivers/sqlite/facts.d.ts +117 -0
  31. package/lib/engine/mem/dbdrivers/sqlite/index.d.ts +6 -0
  32. package/lib/engine/mem/dbdrivers/sqlite/migrations.d.ts +15 -0
  33. package/lib/engine/mem/dbdrivers/sqlite/relations.d.ts +62 -0
  34. package/lib/engine/mem/dbdrivers/sqlite/search.d.ts +56 -0
  35. package/lib/engine/mem/dbdrivers/sqlite/sources.d.ts +37 -0
  36. package/lib/engine/mem/defaults.d.ts +3 -4
  37. package/lib/engine/mem/dispatch.d.ts +7 -32
  38. package/lib/engine/mem/entities/extract.d.ts +44 -47
  39. package/lib/engine/mem/eval/derived_runner.d.ts +6 -1
  40. package/lib/engine/mem/eval/relation_gold.d.ts +251 -0
  41. package/lib/engine/mem/eval/write_metrics.d.ts +1 -1
  42. package/lib/engine/mem/facts_io.d.ts +50 -10
  43. package/lib/engine/mem/index.d.ts +6 -2
  44. package/lib/engine/mem/interfaces/capabilities.d.ts +30 -0
  45. package/lib/engine/mem/interfaces/common.d.ts +11 -0
  46. package/lib/engine/mem/interfaces/errors.d.ts +65 -0
  47. package/lib/engine/mem/interfaces/index.d.ts +18 -0
  48. package/lib/engine/mem/interfaces/migrations.d.ts +21 -0
  49. package/lib/engine/mem/interfaces/repositories.d.ts +471 -0
  50. package/lib/engine/mem/interfaces/search_index.d.ts +113 -0
  51. package/lib/engine/mem/interfaces/storage_backend.d.ts +84 -0
  52. package/lib/engine/mem/interfaces/storage_driver.d.ts +43 -0
  53. package/lib/engine/mem/interfaces/version.d.ts +34 -0
  54. package/lib/engine/mem/lifecycle/contradiction.d.ts +2 -2
  55. package/lib/engine/mem/modelBootstrap.d.ts +1 -1
  56. package/lib/engine/mem/relations/confidence.d.ts +39 -0
  57. package/lib/engine/mem/relations/extract.d.ts +128 -0
  58. package/lib/engine/mem/relations/index.d.ts +32 -0
  59. package/lib/engine/mem/relations/name-quality.d.ts +78 -0
  60. package/lib/engine/mem/relations/normalize.d.ts +275 -0
  61. package/lib/engine/mem/relations/patterns.d.ts +67 -0
  62. package/lib/engine/mem/relations/statement.d.ts +88 -0
  63. package/lib/engine/mem/relations/types.d.ts +79 -0
  64. package/lib/engine/mem/runtime.d.ts +61 -88
  65. package/lib/engine/mem/storage/create.d.ts +42 -0
  66. package/lib/engine/mem/storage/errors.d.ts +65 -0
  67. package/lib/engine/mem/storage/index.d.ts +15 -0
  68. package/lib/engine/mem/storage/ports.d.ts +472 -0
  69. package/lib/engine/mem/storage/registry.d.ts +37 -0
  70. package/lib/engine/mem/storage/sqlite.d.ts +28 -0
  71. package/lib/engine/mem/store/common.d.ts +1 -1
  72. package/lib/engine/mem/store/entity_leg.d.ts +59 -2
  73. package/lib/engine/mem/store/entity_sweep.d.ts +4 -3
  74. package/lib/engine/mem/store/explicit_relations.d.ts +52 -0
  75. package/lib/engine/mem/store/facts_restore.d.ts +10 -2
  76. package/lib/engine/mem/store/floors.d.ts +4 -1
  77. package/lib/engine/mem/store/graph_reader.d.ts +146 -0
  78. package/lib/engine/mem/store/hybrid.d.ts +50 -13
  79. package/lib/engine/mem/store/kinds.d.ts +47 -0
  80. package/lib/engine/mem/store/legs.d.ts +24 -29
  81. package/lib/engine/mem/store/lexical.d.ts +36 -45
  82. package/lib/engine/mem/store/memory.d.ts +471 -83
  83. package/lib/engine/mem/store/recall_policy.d.ts +49 -0
  84. package/lib/engine/mem/store/relation_backfill.d.ts +210 -0
  85. package/lib/engine/mem/store/relation_planner.d.ts +191 -0
  86. package/lib/engine/mem/store/secret_guard.d.ts +0 -1
  87. package/lib/engine/mem/store/self_query.d.ts +4 -2
  88. package/lib/engine/mem/store/time_filter.d.ts +121 -0
  89. package/lib/engine/mem/store/titles.d.ts +52 -0
  90. package/lib/engine/mem/store/vector_repair.d.ts +44 -54
  91. package/lib/engine/mem-contract/config.d.ts +44 -38
  92. package/lib/engine/mem-contract/text.d.ts +1 -1
  93. package/lib/engine/mem-contract/tools.d.ts +145 -132
  94. package/lib/engine/mem-contract/types.d.ts +364 -288
  95. package/lib/index.js +12048 -11337
  96. package/lib/interface-version.json +1 -1
  97. package/lib/types/client/index.d.ts +2 -2
  98. package/lib/types/client/index.d.ts.map +1 -1
  99. package/lib/types/client/paging.d.ts +3 -12
  100. package/lib/types/client/paging.d.ts.map +1 -1
  101. package/lib/types/client/summarize.d.ts.map +1 -1
  102. package/lib/types/envinit-bootstrap.d.ts +1 -1
  103. package/lib/types/envinit.d.ts +2 -6
  104. package/lib/types/envinit.d.ts.map +1 -1
  105. package/lib/types/hints.d.ts +28 -24
  106. package/lib/types/hints.d.ts.map +1 -1
  107. package/lib/types/index.d.ts +21 -40
  108. package/lib/types/index.d.ts.map +1 -1
  109. package/lib/types/inject.d.ts +3 -2
  110. package/lib/types/inject.d.ts.map +1 -1
  111. package/lib/types/interface_gate.d.ts +1 -1
  112. package/lib/types/prompt.d.ts +17 -41
  113. package/lib/types/prompt.d.ts.map +1 -1
  114. package/lib/types/provision.d.ts +3 -0
  115. package/lib/types/provision.d.ts.map +1 -1
  116. package/lib/types/remote.d.ts +14 -7
  117. package/lib/types/remote.d.ts.map +1 -1
  118. package/lib/types/tool_schema.d.ts +4 -0
  119. package/lib/types/tool_schema.d.ts.map +1 -1
  120. package/lib/types/vectorMigration.d.ts +5 -7
  121. package/lib/types/vectorMigration.d.ts.map +1 -1
  122. package/package.json +15 -14
  123. package/lib/engine/mem/config/domains.d.ts +0 -20
  124. package/lib/engine/mem/db/dao/chunks.d.ts +0 -231
  125. package/lib/engine/mem/db/dao/documents.d.ts +0 -51
  126. package/lib/engine/mem/db/hash.d.ts +0 -2
  127. package/lib/engine/mem/db/knowledge.d.ts +0 -17
  128. package/lib/engine/mem/eval/index.d.ts +0 -4
  129. package/lib/engine/mem/git.d.ts +0 -73
  130. package/lib/engine/mem/router.d.ts +0 -51
  131. package/lib/engine/mem/store/doc_files.d.ts +0 -125
  132. package/lib/engine/mem/store/document_text.d.ts +0 -47
  133. package/lib/engine/mem/store/ingest_guard.d.ts +0 -25
  134. package/lib/engine/mem/store/knowledge.d.ts +0 -598
  135. package/lib/engine/mem/store/source_picker.d.ts +0 -43
  136. package/lib/engine/mem-retrieval/adapters/local_reranker.d.ts +0 -52
  137. package/lib/engine/mem-retrieval/adapters/none_reranker.d.ts +0 -10
  138. package/lib/engine/mem-retrieval/rerank.d.ts +0 -13
  139. package/lib/types/client/domains.d.ts +0 -53
  140. package/lib/types/client/domains.d.ts.map +0 -1
  141. package/lib/types/client/ingest.d.ts +0 -24
  142. package/lib/types/client/ingest.d.ts.map +0 -1
  143. package/lib/types/open.d.ts +0 -77
  144. package/lib/types/open.d.ts.map +0 -1
  145. package/lib/types/reconcile.d.ts +0 -64
  146. package/lib/types/reconcile.d.ts.map +0 -1
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Schema migration state, as the HAL sees it (DB-3).
3
+ *
4
+ * A driver keeps its own schema state (SQLite's `PRAGMA user_version`, a remote backend's version
5
+ * table or a service endpoint). The host needs two things from it and nothing more: what this open
6
+ * applied, and a way to RE-READ the current version without applying anything (the hook the
7
+ * migration/import tooling needs).
8
+ *
9
+ * @module interfaces/migrations
10
+ */
11
+ import type { Awaitable } from './common.js';
12
+ export interface MigrationRunner {
13
+ /** The version the backend reported before this open. */
14
+ readonly from: number;
15
+ /** The version this build brings (or brought) the backend to. */
16
+ readonly to: number;
17
+ /** The steps this open actually applied, in order (empty = the backend was already current). */
18
+ readonly applied: readonly number[];
19
+ /** Re-read the backend's current schema version, applying nothing. */
20
+ current(): Awaitable<number>;
21
+ }
@@ -0,0 +1,471 @@
1
+ /**
2
+ * The document/relation repositories the store talks to (DB-1 boundary, DB-2 async, DB-3 ids).
3
+ *
4
+ * Everything here is a DOMAIN shape: no SQL, no `Db`, no `DbStatement`, no driver row class, no
5
+ * `TimeSql`, no rowid. `TimeRange` (the normalized window) crosses; how a driver turns it into a
6
+ * predicate is its own business. Rows are `FactRow` records because the store reads projections it
7
+ * does not own the shape of — the driver decides the columns, the port promises the fields the store
8
+ * names.
9
+ *
10
+ * METHOD NAMES mirror the DAOs DB-1 wrapped (`activeIds`, `countInStatus`, …) on purpose: the
11
+ * boundary was an extraction, not a redesign of what the store asks for. The async contract is in
12
+ * `./common.ts`; the ids are the backend's (`InsertRevisionOutcome`), and transactions live on the
13
+ * backend (`./storage_backend.ts#LifecycleService`).
14
+ *
15
+ * @module interfaces/repositories
16
+ */
17
+ import type { ContradictionRecord, FactSourceView, MemoryKind, RelationInput } from '../../mem-contract/index.js';
18
+ import type { GraphReader } from '../../graph-recall/index.js';
19
+ import type { RelationVocabulary, SurfaceMatch } from '../store/relation_planner.js';
20
+ import type { ExtractedEntity } from '../entities/extract.js';
21
+ import type { TimeRange } from '../store/time_filter.js';
22
+ import type { RelationCandidate, RelationDropReason, RelationTripleInput } from '../relations/index.js';
23
+ import type { AliasRegistration } from '../relations/normalize.js';
24
+ import type { CheckResult } from '../lifecycle/contradiction.js';
25
+ import type { Awaitable } from './common.js';
26
+ /** A facts row as the domain reads it. The driver owns the projection; the store names the fields. */
27
+ export type FactRow = Record<string, unknown>;
28
+ /** One fact's source provenance (P-08). */
29
+ export type FactSourceKind = FactSourceView['kind'];
30
+ export interface FactSource {
31
+ kind: FactSourceKind;
32
+ ref: string;
33
+ }
34
+ /** The scalar display columns of a hit (`factHits` maps these onto the contract envelope). */
35
+ export interface FactHitMeta {
36
+ created_at: string;
37
+ updated_at: string | null;
38
+ valid_from: string | null;
39
+ valid_to: string | null;
40
+ title: string | null;
41
+ }
42
+ /** One persisted semantic vector, as the reload/repair flows read it. */
43
+ export interface FactVectorRow {
44
+ fact_id: number;
45
+ semantic_vector: Uint8Array;
46
+ embedding_model: string | null;
47
+ }
48
+ /** The space-qualified vector inventory (`facts_wide` diagnostic). */
49
+ export interface FactVectorSpaceRow {
50
+ fact_id: number;
51
+ bytes: number;
52
+ embedding_model: string | null;
53
+ }
54
+ /** One persisted HRR bundle. */
55
+ export interface HrrVectorRow {
56
+ fact_id: number;
57
+ hrr_vector: Uint8Array;
58
+ }
59
+ /**
60
+ * What one insert-or-ignore did.
61
+ *
62
+ * `inserted: false` means the content already exists and the driver resolved the write onto the
63
+ * EXISTING row; `factId` names that row. Ids are the backend's to assign (a distributed backend does
64
+ * not have SQLite's rowids), which is why the store never reads a driver's `lastInsertRowid`.
65
+ */
66
+ export interface InsertRevisionOutcome {
67
+ inserted: boolean;
68
+ factId: number;
69
+ }
70
+ /**
71
+ * The facts aggregate: reads, lifecycle writes and the derived-state stamps.
72
+ */
73
+ export interface MemoryRepository {
74
+ activeIds(ids: readonly number[]): Awaitable<number[]>;
75
+ getById(factId: number): Awaitable<FactRow | undefined>;
76
+ rowsByIds(ids: readonly number[]): Awaitable<FactRow[]>;
77
+ textsByIds(ids: readonly number[]): Awaitable<Map<number, string>>;
78
+ hitMetaByIds(ids: readonly number[]): Awaitable<Map<number, FactHitMeta>>;
79
+ minSettleClock(): Awaitable<number | null>;
80
+ maxSettleClock(): Awaitable<number | null>;
81
+ countByStatus(): Awaitable<{
82
+ active: number;
83
+ archived: number;
84
+ }>;
85
+ countActive(): Awaitable<number>;
86
+ countPinnedActive(): Awaitable<number>;
87
+ countInStatus(status: string, kind?: MemoryKind, source?: string): Awaitable<number>;
88
+ countActiveWithValidFrom(): Awaitable<number>;
89
+ countForgettingWithin(p: {
90
+ step: number;
91
+ clock: number;
92
+ withinDays: number;
93
+ }): Awaitable<number>;
94
+ countIdleCandidates(days: number): Awaitable<number>;
95
+ countArchiveBacklog(p: {
96
+ forgetThreshold: number;
97
+ idleCalendarDays: number;
98
+ }): Awaitable<number>;
99
+ countPendingConflicts(): Awaitable<number>;
100
+ countStaleEntities(version: number): Awaitable<number>;
101
+ vectorCounts(): Awaitable<{
102
+ total: number;
103
+ withSemantic: number;
104
+ missing: number;
105
+ }>;
106
+ activeVectorRows(): Awaitable<FactVectorRow[]>;
107
+ activeVectorSpaces(): Awaitable<FactVectorSpaceRow[]>;
108
+ archivedByReason(): Awaitable<{
109
+ reason: string;
110
+ n: number;
111
+ }[]>;
112
+ embeddingModels(): Awaitable<{
113
+ model: string | null;
114
+ n: number;
115
+ }[]>;
116
+ assertCount(factId: number): Awaitable<number>;
117
+ supersededBy(factId: number): Awaitable<number | null>;
118
+ statusOf(factId: number): Awaitable<string | undefined>;
119
+ bonusStatedToday(): Awaitable<{
120
+ count: number;
121
+ granted: number;
122
+ }>;
123
+ page(status: string, kind: MemoryKind | undefined, limit: number, offset: number, source?: string): Awaitable<FactRow[]>;
124
+ /** `mem_admin list` narrowed by an explicit time window (same order as `page`). */
125
+ pageTimeWindow(status: string, kind: MemoryKind | undefined, time: TimeRange, limit: number, offset: number, source?: string): Awaitable<FactRow[]>;
126
+ /** How many rows `pageTimeWindow` pages through — the page's `total`. */
127
+ countStatusTimeWindow(status: string, kind: MemoryKind | undefined, time: TimeRange, source?: string): Awaitable<number>;
128
+ findByContent(content: string): Awaitable<FactRow | undefined>;
129
+ windowRows(from: string, to: string, kind: MemoryKind | undefined, cap: number, source?: string): Awaitable<number[]>;
130
+ staleEntityRows(version: number, limit: number): Awaitable<{
131
+ fact_id: number;
132
+ content: string;
133
+ kind: string;
134
+ }[]>;
135
+ pendingConflictRows(limit: number, after?: number): Awaitable<{
136
+ fact_id: number;
137
+ content: string;
138
+ }[]>;
139
+ missingVectorRows(): Awaitable<{
140
+ fact_id: number;
141
+ content: string;
142
+ }[]>;
143
+ activeHrrRows(kind?: MemoryKind, limit?: number, source?: string, time?: TimeRange): Awaitable<HrrVectorRow[]>;
144
+ hrrRowsForFacts(ids: readonly number[], kind?: MemoryKind, source?: string): Awaitable<HrrVectorRow[]>;
145
+ activeIdsIn(ids: readonly number[], kind?: MemoryKind, source?: string, time?: TimeRange): Awaitable<number[]>;
146
+ insertRevision(v: {
147
+ content: string;
148
+ kind: MemoryKind;
149
+ ttlDays: number;
150
+ supersedesId: number | null;
151
+ hrr: Uint8Array;
152
+ trust: number;
153
+ clock: number;
154
+ pinned: 0 | 1;
155
+ pinnedAt: string | null;
156
+ windowAt: string;
157
+ createdAt: string;
158
+ title?: string | null;
159
+ validFrom?: string | null;
160
+ validTo?: string | null;
161
+ validFromMs?: number | null;
162
+ validToMs?: number | null;
163
+ }): Awaitable<InsertRevisionOutcome>;
164
+ applyValidity(factId: number, validFrom: {
165
+ text: string;
166
+ ms: number;
167
+ } | undefined, validTo: {
168
+ text: string;
169
+ ms: number;
170
+ } | undefined): Awaitable<void>;
171
+ applyValues(factId: number, kind: MemoryKind, ttlDays: number): Awaitable<void>;
172
+ setTitle(factId: number, title: string): Awaitable<void>;
173
+ /** v17: record a handle this fact used to carry, so an old title search still finds it. */
174
+ insertTitleAlias(factId: number, title: string): Awaitable<void>;
175
+ /** v17: carry a revision's aliases forward onto the revision that replaces it. */
176
+ copyTitleAliases(fromFactId: number, toFactId: number, currentTitle: string): Awaitable<void>;
177
+ /** v17: drop an alias that has become the row's current title (a correction back to it). */
178
+ dropTitleAlias(factId: number, title: string): Awaitable<void>;
179
+ incrementAssertCount(factId: number): Awaitable<number>;
180
+ markValidTo(factId: number, at: string, atMs?: number | null): Awaitable<void>;
181
+ linkSupersede(factId: number, supersedesId: number): Awaitable<void>;
182
+ archiveSuperseded(factId: number, clock: number): Awaitable<number>;
183
+ revive(factId: number, kind: MemoryKind, ttlDays: number, trust: number, clock: number): Awaitable<number>;
184
+ archive(factId: number, clock: number, reason: string): Awaitable<number>;
185
+ restore(factId: number, trust: number, clock: number): Awaitable<number>;
186
+ bumpHelpful(factId: number, delta: number): Awaitable<void>;
187
+ pin(factId: number, clock: number): Awaitable<number>;
188
+ unpin(factId: number, clock: number): Awaitable<number>;
189
+ pinOutcome(factId: number, clock: number, bonusCount: number, windowAt: string): Awaitable<void>;
190
+ forgetOutcome(factId: number, trust: number, clock: number, bonusCount: number, windowAt: string): Awaitable<void>;
191
+ reinforceOutcome(factId: number, trust: number, clock: number, bonusCount: number, windowAt: string): Awaitable<void>;
192
+ touchUsage(ids: readonly number[]): Awaitable<void>;
193
+ settleTrust(factId: number, trust: number, clock: number): Awaitable<void>;
194
+ reinforce(factId: number, trust: number, clock: number, bonusCount: number, windowAt: string): Awaitable<void>;
195
+ setSemanticVector(factId: number, vector: Uint8Array, model: string, store: string): Awaitable<void>;
196
+ clearVectors(ids: readonly number[]): Awaitable<number>;
197
+ setHrrVector(factId: number, bytes: Uint8Array): Awaitable<void>;
198
+ setEntitiesVersion(ids: readonly number[], version: number): Awaitable<number>;
199
+ markConflictChecked(ids: readonly number[]): Awaitable<number>;
200
+ requeueConflictCheck(ids: readonly number[]): Awaitable<number>;
201
+ }
202
+ /** Entity writes/reads used by the write path, the entity leg and the contradiction detector. */
203
+ export interface EntityRepository {
204
+ linkFact(factId: number, entities: readonly ExtractedEntity[]): Awaitable<void>;
205
+ unlinkFact(factId: number): Awaitable<void>;
206
+ namesForFact(factId: number): Awaitable<string[]>;
207
+ bagsForFacts(ids: readonly number[]): Awaitable<Map<number, string[]>>;
208
+ activeDocFrequency(names: readonly string[]): Awaitable<Map<string, number>>;
209
+ candidateFactsForAnyEntity(names: readonly string[], kind: MemoryKind | undefined, limit: number, queryWidth: number, widthCap: number, source?: string, time?: TimeRange): Awaitable<number[]>;
210
+ /**
211
+ * The FACT-level entity vocabulary: entity surfaces occurring in `text` that are linked to at
212
+ * least one ACTIVE fact through `fact_entities` — journal entries and notes with no relation edge
213
+ * included (docs/GRAPH_RECALL_AND_SEMANTICS.md §7.9).
214
+ *
215
+ * Deliberately NOT the graph reader's `entitiesIn`: that one only reports entities with edges,
216
+ * which is exactly the corpus the fact-level AND must NOT be limited to. `kind`/`source`/`time`
217
+ * are likewise NOT applied here — the vocabulary answers "is this a known name in the live
218
+ * corpus", while the page applies the caller's filters and an empty page falls back to fuzzy.
219
+ */
220
+ factEntitiesIn(text: string): Awaitable<SurfaceMatch[]>;
221
+ /**
222
+ * One fact-level AND page: ACTIVE facts that mention EVERY one of `query.entities` (see
223
+ * {@link FactsContainingAllQuery}). `total` is the number of such FACTS before paging.
224
+ */
225
+ factsContainingAll(query: FactsContainingAllQuery): Awaitable<FactContainingPage>;
226
+ }
227
+ /**
228
+ * The fact-level AND request behind `factsContainingAll` (docs/GRAPH_RECALL_AND_SEMANTICS.md §7.9).
229
+ *
230
+ * `entities` may be canonical names or registered aliases; a fact must mention EVERY resolved
231
+ * entity (AND, not "at least N"). Fewer than two distinct entities is not a multi-entity question
232
+ * and returns an empty page. The status filter is fixed to `active` — the public recall surface has
233
+ * no status parameter, and a fact-level answer is a page of the live corpus.
234
+ */
235
+ export interface FactsContainingAllQuery {
236
+ entities: readonly string[];
237
+ /** `facts.kind`; omitted = BOTH layers (the documented `kind=all` default). */
238
+ kind?: MemoryKind;
239
+ /** `fact_sources.ref`, the same source axis `mem_recall.search` exposes. */
240
+ source?: string;
241
+ /** The caller's explicit time filter, on `facts` (the same normalized window the legs use). */
242
+ time?: TimeRange;
243
+ offset: number;
244
+ limit: number;
245
+ }
246
+ /** One page of the fact-level AND answer: ACTIVE fact rows plus the fact count before paging. */
247
+ export interface FactContainingPage {
248
+ total: number;
249
+ rows: FactRow[];
250
+ }
251
+ /** One stored triple row (detail view). */
252
+ export interface StoredTriple {
253
+ subj: string;
254
+ pred: string;
255
+ obj: string;
256
+ confidence: number;
257
+ }
258
+ /** One triple as the extractor/producer writes it. */
259
+ export interface TripleInput {
260
+ subj: string;
261
+ pred: string;
262
+ obj: string;
263
+ confidence: number;
264
+ source: string;
265
+ }
266
+ export interface TripleRepository {
267
+ insertMany(factId: number, triples: readonly TripleInput[]): Awaitable<void>;
268
+ listForFact(factId: number): Awaitable<StoredTriple[]>;
269
+ deleteForFact(factId: number): Awaitable<void>;
270
+ }
271
+ /**
272
+ * The relation-graph write/read shapes (STRUCTURED_RELATIONS §四/§七, RELATIONAL_RECALL §4.3).
273
+ *
274
+ * These are DOMAIN reports: they say how many edges one write produced and why the rest were
275
+ * refused. The SQL that produces them lives in the SQLite driver; declaring the shapes here is what
276
+ * lets `interfaces/` stay free of `db/graph.ts`.
277
+ */
278
+ export type EdgeSourceTriple = RelationTripleInput;
279
+ /** Why one extracted triple did not become an edge: the policy's reasons plus the storage step's. */
280
+ export type EdgeDropReason = RelationDropReason | 'self-relation';
281
+ /** One dropped triple, kept as EVIDENCE for the coverage report (§4.3 "记录抽取覆盖率/失败样本"). */
282
+ export interface EdgeDropSample {
283
+ fact_id: number;
284
+ subj: string;
285
+ pred: string;
286
+ obj: string;
287
+ /** The confidence the policy computed for it (below `EDGE_MIN_CONFIDENCE` for `low-confidence`). */
288
+ confidence: number;
289
+ reason: EdgeDropReason;
290
+ }
291
+ /** What one fact's edge write did. */
292
+ export interface EdgeWriteReport {
293
+ /** Rows actually inserted. */
294
+ written: number;
295
+ /** Rows already present (same fact/subject/predicate/object) — a repeat write's normal outcome. */
296
+ duplicates: number;
297
+ /** Rows the policy refused. */
298
+ dropped: number;
299
+ /** Up to the caller's `samples` cap, why they were refused. */
300
+ samples: EdgeDropSample[];
301
+ }
302
+ /** What one {@link RelationRepository.rebuildEdgesForFact} pass did. */
303
+ export interface EdgeRebuildReport extends EdgeWriteReport {
304
+ /** Edges deleted before re-deriving (always the non-explicit ones). */
305
+ removed: number;
306
+ }
307
+ /** Which facts one `reextractEdges` pass selects. */
308
+ export type EdgeReextractMode = 'stale' | 'all';
309
+ /** Options for {@link RelationRepository.reextractEdges}. */
310
+ export interface EdgeReextractOptions {
311
+ /** Facts one pass may rewrite (the driver's own bounded batch default). */
312
+ budget?: number;
313
+ /** `false` (default): only facts whose edges are older than the current extractor version. */
314
+ all?: boolean;
315
+ /** Cap on the failure samples returned (default 5). */
316
+ samples?: number;
317
+ }
318
+ /** What one `reextractEdges` pass did. */
319
+ export interface EdgeReextractReport {
320
+ mode: EdgeReextractMode;
321
+ /** Facts selected and re-derived (its budget when it filled it). */
322
+ facts: number;
323
+ /** Facts whose edge rows were replaced. */
324
+ rewritten: number;
325
+ /** Facts still waiting for a pass (`stale`: edges older than the current version). */
326
+ deferred: number;
327
+ edgesRemoved: number;
328
+ edgesCreated: number;
329
+ dropped: number;
330
+ samples: EdgeDropSample[];
331
+ /** Edges deleted because their fact is not a note (§四/§七). */
332
+ journalEdgesRemoved: number;
333
+ }
334
+ /** How many edges each extraction version has (the version axis of the coverage report). */
335
+ export interface EdgeVersionCount {
336
+ version: number;
337
+ edges: number;
338
+ }
339
+ /** The graph's coverage, as one read (§R2 "归一覆盖率报告" / §R6 observability). */
340
+ export interface GraphCoverageReport {
341
+ activeFacts: number;
342
+ /** Active facts the string extractor found at least one triple for. */
343
+ factsWithTriples: number;
344
+ /** Active facts with at least one edge (any version). */
345
+ factsWithEdges: number;
346
+ /** Active facts the version rule still selects (`reextractEdges()` would visit them). */
347
+ factsStale: number;
348
+ edges: number;
349
+ edgesByVersion: EdgeVersionCount[];
350
+ /** Extraction version a real pass would stamp today. */
351
+ extractionVersion: number;
352
+ entities: number;
353
+ entityAliases: number;
354
+ predicates: number;
355
+ predicateAliases: number;
356
+ /** `factsWithTriples / activeFacts` — how much of the corpus yields any relation at all. */
357
+ tripleCoverage: number;
358
+ /** `factsWithEdges / factsWithTriples` — how much of that survived normalization + the floor. */
359
+ relationCoverage: number;
360
+ /** Up to `samples` triples the current rules would refuse, with the reason. */
361
+ samples: EdgeDropSample[];
362
+ }
363
+ /**
364
+ * The relation graph: caller-stated/explicit edges, the versioned extractor's derived edges and the
365
+ * read-only walkers. The SQL stays in the driver.
366
+ */
367
+ export interface RelationRepository {
368
+ readonly entities: EntityRepository;
369
+ readonly triples: TripleRepository;
370
+ explicitRelationTriples(kind: MemoryKind, relations: readonly RelationInput[] | undefined): Awaitable<RelationCandidate[]>;
371
+ registerEntityAliasesFromText(text: string, knownNames: readonly string[]): Awaitable<AliasRegistration[]>;
372
+ explicitRelationsForFact(factId: number): Awaitable<{
373
+ subject: string;
374
+ predicate: string;
375
+ object: string;
376
+ }[]>;
377
+ writeEdgesForFact(factId: number, triples: readonly EdgeSourceTriple[], options?: {
378
+ dryRun?: boolean;
379
+ samples?: number;
380
+ }): Awaitable<EdgeWriteReport>;
381
+ writeExplicitEdgesForFact(factId: number, relations: readonly {
382
+ subject: string;
383
+ predicate: string;
384
+ object: string;
385
+ }[]): Awaitable<EdgeWriteReport>;
386
+ deleteEdgesForFact(factId: number, options?: {
387
+ keepExplicit?: boolean;
388
+ onlyExplicit?: boolean;
389
+ }): Awaitable<number>;
390
+ rebuildEdgesForFact(factId: number, kind: string): Awaitable<EdgeRebuildReport>;
391
+ reextractEdges(options?: EdgeReextractOptions): Awaitable<EdgeReextractReport>;
392
+ ensureVocabulary(): Awaitable<void>;
393
+ coverage(options?: {
394
+ samples?: number;
395
+ sampleFacts?: number;
396
+ }): Awaitable<GraphCoverageReport>;
397
+ /**
398
+ * The read-only walker. SYNCHRONOUS ON PURPOSE: `GraphReader` is the `@avantf/graph-recall`
399
+ * interface the relation planner and the UI call algorithmically (hundreds of `neighborsOf` hops
400
+ * per query), and it is a pure in-memory view over the rows the driver loaded when it was built.
401
+ * A remote driver fills that view asynchronously in `graphReader()` itself; the walk never
402
+ * crosses the boundary.
403
+ */
404
+ graphReader(filter?: {
405
+ kind?: MemoryKind;
406
+ source?: string;
407
+ time?: import('../../mem-contract/index.js').TimeFilter;
408
+ }): Awaitable<GraphReader & RelationVocabulary>;
409
+ }
410
+ /** `fact_sources` — where a fact came from. */
411
+ export interface SourceRepository {
412
+ /** The `kind:` prefix rule, kept beside the rows it writes (pure; no SQL). */
413
+ classifyRef(sourceRef: string): Awaitable<{
414
+ kind: FactSourceKind;
415
+ ref: string;
416
+ }>;
417
+ insert(factId: number, kind: FactSourceKind, ref: string): Awaitable<void>;
418
+ listForFact(factId: number): Awaitable<FactSource[]>;
419
+ activeCoverage(): Awaitable<{
420
+ active: number;
421
+ facts_with_source: number;
422
+ }>;
423
+ }
424
+ /** One contradiction pair, as the contract reports it. */
425
+ export interface ConflictPair {
426
+ /** Row id of the pair — the handle `contradict_resolve` takes. */
427
+ contradiction_id: number;
428
+ fact_a: number;
429
+ fact_b: number;
430
+ score: number;
431
+ }
432
+ /** A row of the conflict log as stored: the pair plus its adjudication state. */
433
+ export interface StoredConflict {
434
+ id: number;
435
+ fact_a: number;
436
+ fact_b: number;
437
+ score: number;
438
+ /** 0 = open, 1 = closed (see `resolution` / `loser_fact_id` for how). */
439
+ resolved: number;
440
+ resolution: string | null;
441
+ loser_fact_id: number | null;
442
+ /** `auto` (a fact left the corpus) or `verdict` (explicit adjudication). */
443
+ resolved_by: string | null;
444
+ }
445
+ /** The contradiction log + detector façade. */
446
+ export interface ContradictionRepository {
447
+ /**
448
+ * Supply the store's runtime knobs (the live vector index the embedding leg reads, plus the
449
+ * configured threshold). The detector is built lazily from these, so a direct store built on a
450
+ * backend cannot silently run with the schema default threshold.
451
+ */
452
+ configure(options: {
453
+ threshold?: number;
454
+ fetchVectors?: (ids: number[]) => Map<number, Float32Array>;
455
+ }): void;
456
+ checkOne(factId: number): Awaitable<CheckResult>;
457
+ checkMany(factIds: readonly number[]): Awaitable<CheckResult>;
458
+ openConflictsFor(factId: number): Awaitable<ConflictPair[]>;
459
+ resolveForFact(factId: number): Awaitable<number>;
460
+ resolveForFacts(factIds: readonly number[]): Awaitable<number>;
461
+ get(id: number): Awaitable<StoredConflict | undefined>;
462
+ resolve(id: number, resolution: 'true_positive' | 'false_positive', loserFactId?: number): Awaitable<void>;
463
+ list(resolved?: number, kind?: MemoryKind, threshold?: number, limit?: number): Awaitable<ContradictionRecord[]>;
464
+ }
465
+ /** The `avantf_stats` key/value side table (retrieval health; the lifecycle clock stays internal). */
466
+ export interface KeyValueRepository {
467
+ read(key: string): Awaitable<string | null>;
468
+ write(key: string, value: string): Awaitable<void>;
469
+ }
470
+ /** One conflict-check result (`lifecycle/contradiction.ts#CheckResult`), re-exported for driver authors. */
471
+ export type { CheckResult };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The search contract (DB-3, `docs/DB_DRIVER_LAYOUT.md` §二).
3
+ *
4
+ * The interface takes the CALLER'S QUERY, never a query-expression in a backend's syntax: the driver
5
+ * owns its tokenizer, its full-text dialect and its rank sign. That is what lets a second driver
6
+ * answer the same contract with `tsvector`/`pg_trgm` without the store knowing — and it is why
7
+ * `searchContent` may internally fall back from its index to a substring scan (the short-query shape)
8
+ * without the caller branching on which path ran.
9
+ *
10
+ * The index is maintained by the driver itself (SQLite: FTS triggers); {@link SearchIndex.rebuild} is
11
+ * the repair path a caller may run when the derived index must be re-derived from the source rows.
12
+ *
13
+ * @module interfaces/search_index
14
+ */
15
+ import type { MemoryKind } from '../../mem-contract/index.js';
16
+ import type { TimeRange } from '../store/time_filter.js';
17
+ import type { Awaitable } from './common.js';
18
+ /** One title-search row (`mem_recall.titles`). */
19
+ export interface TitleMatch {
20
+ fact_id: number;
21
+ /** The row's CURRENT title — the handle a caller should act on. */
22
+ title: string;
23
+ /**
24
+ * The title TEXT the query matched: the current title, or one of the aliases a corrected
25
+ * transaction used to carry (v17). A driver that keeps no alias set reports `title` here.
26
+ */
27
+ matched_title: string;
28
+ kind: string;
29
+ status: string;
30
+ created_at: string | null;
31
+ updated_at: string | null;
32
+ valid_from: string | null;
33
+ excerpt: string | null;
34
+ }
35
+ /** The filters every title statement applies. */
36
+ export interface TitleFilters {
37
+ kind?: MemoryKind;
38
+ status: 'active' | 'archived' | 'all';
39
+ time?: TimeRange;
40
+ }
41
+ /**
42
+ * One title search. The QUERY is the domain input: whether it is answered by a full-text index or by
43
+ * a substring scan is the driver's decision (DB-3), exactly like the content search below.
44
+ */
45
+ export interface TitleQuery extends TitleFilters {
46
+ query: string;
47
+ limit: number;
48
+ }
49
+ export interface ExactTitleQuery extends TitleFilters {
50
+ query: string;
51
+ }
52
+ /** The exact-content filter (docs/RECALL_INTERFACE.md §2.2). */
53
+ export interface ExactContentQuery {
54
+ query: string;
55
+ kind?: MemoryKind;
56
+ source?: string;
57
+ time?: TimeRange;
58
+ }
59
+ /**
60
+ * A pure time window — `mem_recall.search` with no query (`mode:"time"`, RECALL_INTERFACE §2.4).
61
+ *
62
+ * The window IS the question, so the filter is the whole request: status is always ACTIVE (a recall
63
+ * reads the current corpus), and the rows come back newest-first along the window's OWN axis
64
+ * (`time.field`). That order is why the domain `TimeRange` travels here instead of a compiled
65
+ * predicate.
66
+ */
67
+ export interface TimeWindowQuery {
68
+ time: TimeRange;
69
+ kind?: MemoryKind;
70
+ source?: string;
71
+ }
72
+ /**
73
+ * A full-text hit: the fact id and the backend's own relevance rank.
74
+ *
75
+ * HIGHER IS ALWAYS BETTER. The driver normalizes its index's convention (SQLite's `bm25` is
76
+ * negative; the substring predicate's match count is positive) so the store's floors and the fusion
77
+ * see one scale no matter which index answered (DB-3).
78
+ */
79
+ export interface SearchHit {
80
+ id: number;
81
+ rank: number;
82
+ }
83
+ /** The filters shared by the lexical legs. */
84
+ export interface SearchScope {
85
+ kind?: MemoryKind;
86
+ source?: string;
87
+ time?: TimeRange;
88
+ }
89
+ export interface SearchIndex {
90
+ /** Ranked content search. `rank` is normalized so HIGHER IS ALWAYS BETTER. */
91
+ searchContent(query: string, scope?: SearchScope, limit?: number): Awaitable<SearchHit[]>;
92
+ countContentContaining(query: ExactContentQuery): Awaitable<number>;
93
+ contentContainingRows(query: ExactContentQuery & {
94
+ limit: number;
95
+ offset: number;
96
+ }): Awaitable<number[]>;
97
+ countTitleEqual(query: ExactTitleQuery): Awaitable<number>;
98
+ titleEqualRows(query: ExactTitleQuery & {
99
+ limit: number;
100
+ offset: number;
101
+ }): Awaitable<TitleMatch[]>;
102
+ /** How many ACTIVE facts fall inside a pure time window (`mode:"time"`'s `total`). */
103
+ countInTimeWindow(query: TimeWindowQuery): Awaitable<number>;
104
+ /** One page of that window, newest first along the window's own axis. */
105
+ timeWindowRows(query: TimeWindowQuery & {
106
+ limit: number;
107
+ offset: number;
108
+ }): Awaitable<number[]>;
109
+ /** Title search: title-equal, else the driver's own title index / substring fallback. */
110
+ searchTitles(query: TitleQuery): Awaitable<TitleMatch[]>;
111
+ /** Clear and re-derive the index from the source rows. */
112
+ rebuild(): Awaitable<void>;
113
+ }