@avantf/dsh-mem 0.6.4 → 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.
- package/README.md +19 -10
- package/lib/client.js +1665 -3466
- package/lib/dsh-build.json +6 -5
- package/lib/engine/graph-recall/in-memory.d.ts +93 -0
- package/lib/engine/graph-recall/index.d.ts +22 -0
- package/lib/engine/graph-recall/traverse.d.ts +119 -0
- package/lib/engine/graph-recall/types.d.ts +188 -0
- package/lib/engine/mem/config/config_files.d.ts +1 -1
- package/lib/engine/mem/config/loader.d.ts +2 -3
- package/lib/engine/mem/config/paths.d.ts +2 -13
- package/lib/engine/mem/db/dao/contradictions.d.ts +4 -22
- package/lib/engine/mem/db/dao/entities.d.ts +80 -7
- package/lib/engine/mem/db/dao/fact_sources.d.ts +3 -13
- package/lib/engine/mem/db/dao/facts.d.ts +311 -56
- package/lib/engine/mem/db/dao/triples.d.ts +1 -26
- package/lib/engine/mem/db/graph.d.ts +249 -0
- package/lib/engine/mem/db/journal_notes.d.ts +35 -0
- package/lib/engine/mem/db/migrations.d.ts +9 -0
- package/lib/engine/mem/db/port.d.ts +22 -3
- package/lib/engine/mem/db/schema.d.ts +119 -0
- package/lib/engine/mem/db/tokenizer.d.ts +9 -0
- package/lib/engine/mem/dbdrivers/fake/driver.d.ts +75 -0
- package/lib/engine/mem/dbdrivers/fake/index.d.ts +7 -0
- package/lib/engine/mem/dbdrivers/fake/surface.d.ts +34 -0
- package/lib/engine/mem/dbdrivers/fake/transport.d.ts +61 -0
- package/lib/engine/mem/dbdrivers/sqlite/connection.d.ts +14 -0
- package/lib/engine/mem/dbdrivers/sqlite/contradictions.d.ts +35 -0
- package/lib/engine/mem/dbdrivers/sqlite/dao/index.d.ts +16 -0
- package/lib/engine/mem/dbdrivers/sqlite/driver.d.ts +54 -0
- package/lib/engine/mem/dbdrivers/sqlite/facts.d.ts +117 -0
- package/lib/engine/mem/dbdrivers/sqlite/index.d.ts +6 -0
- package/lib/engine/mem/dbdrivers/sqlite/migrations.d.ts +15 -0
- package/lib/engine/mem/dbdrivers/sqlite/relations.d.ts +62 -0
- package/lib/engine/mem/dbdrivers/sqlite/search.d.ts +56 -0
- package/lib/engine/mem/dbdrivers/sqlite/sources.d.ts +37 -0
- package/lib/engine/mem/defaults.d.ts +3 -4
- package/lib/engine/mem/dispatch.d.ts +7 -32
- package/lib/engine/mem/entities/extract.d.ts +44 -47
- package/lib/engine/mem/eval/derived_runner.d.ts +6 -1
- package/lib/engine/mem/eval/relation_gold.d.ts +251 -0
- package/lib/engine/mem/eval/write_metrics.d.ts +1 -1
- package/lib/engine/mem/facts_io.d.ts +328 -0
- package/lib/engine/mem/index.d.ts +10 -2
- package/lib/engine/mem/interfaces/capabilities.d.ts +30 -0
- package/lib/engine/mem/interfaces/common.d.ts +11 -0
- package/lib/engine/mem/interfaces/errors.d.ts +65 -0
- package/lib/engine/mem/interfaces/index.d.ts +18 -0
- package/lib/engine/mem/interfaces/migrations.d.ts +21 -0
- package/lib/engine/mem/interfaces/repositories.d.ts +471 -0
- package/lib/engine/mem/interfaces/search_index.d.ts +113 -0
- package/lib/engine/mem/interfaces/storage_backend.d.ts +84 -0
- package/lib/engine/mem/interfaces/storage_driver.d.ts +43 -0
- package/lib/engine/mem/interfaces/version.d.ts +34 -0
- package/lib/engine/mem/lifecycle/contradiction.d.ts +2 -2
- package/lib/engine/mem/maintenance_paths.d.ts +41 -0
- package/lib/engine/mem/modelBootstrap.d.ts +1 -1
- package/lib/engine/mem/relations/confidence.d.ts +39 -0
- package/lib/engine/mem/relations/extract.d.ts +128 -0
- package/lib/engine/mem/relations/index.d.ts +32 -0
- package/lib/engine/mem/relations/name-quality.d.ts +78 -0
- package/lib/engine/mem/relations/normalize.d.ts +275 -0
- package/lib/engine/mem/relations/patterns.d.ts +67 -0
- package/lib/engine/mem/relations/statement.d.ts +88 -0
- package/lib/engine/mem/relations/types.d.ts +79 -0
- package/lib/engine/mem/runtime.d.ts +117 -90
- package/lib/engine/mem/storage/create.d.ts +42 -0
- package/lib/engine/mem/storage/errors.d.ts +65 -0
- package/lib/engine/mem/storage/index.d.ts +15 -0
- package/lib/engine/mem/storage/ports.d.ts +472 -0
- package/lib/engine/mem/storage/registry.d.ts +37 -0
- package/lib/engine/mem/storage/sqlite.d.ts +28 -0
- package/lib/engine/mem/store/common.d.ts +1 -1
- package/lib/engine/mem/store/entity_leg.d.ts +59 -2
- package/lib/engine/mem/store/entity_sweep.d.ts +4 -3
- package/lib/engine/mem/store/explicit_relations.d.ts +52 -0
- package/lib/engine/mem/store/facts_restore.d.ts +124 -0
- package/lib/engine/mem/store/floors.d.ts +4 -1
- package/lib/engine/mem/store/graph_reader.d.ts +146 -0
- package/lib/engine/mem/store/hybrid.d.ts +50 -13
- package/lib/engine/mem/store/kinds.d.ts +47 -0
- package/lib/engine/mem/store/legs.d.ts +24 -29
- package/lib/engine/mem/store/lexical.d.ts +36 -45
- package/lib/engine/mem/store/memory.d.ts +486 -82
- package/lib/engine/mem/store/recall_policy.d.ts +49 -0
- package/lib/engine/mem/store/relation_backfill.d.ts +210 -0
- package/lib/engine/mem/store/relation_planner.d.ts +191 -0
- package/lib/engine/mem/store/secret_guard.d.ts +0 -1
- package/lib/engine/mem/store/self_query.d.ts +4 -2
- package/lib/engine/mem/store/time_filter.d.ts +121 -0
- package/lib/engine/mem/store/titles.d.ts +52 -0
- package/lib/engine/mem/store/vector_repair.d.ts +44 -54
- package/lib/engine/mem-contract/config.d.ts +44 -38
- package/lib/engine/mem-contract/text.d.ts +1 -1
- package/lib/engine/mem-contract/tools.d.ts +184 -117
- package/lib/engine/mem-contract/types.d.ts +364 -288
- package/lib/index.js +13898 -11500
- package/lib/interface-version.json +1 -1
- package/lib/types/client/index.d.ts +2 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/paging.d.ts +3 -12
- package/lib/types/client/paging.d.ts.map +1 -1
- package/lib/types/client/summarize.d.ts.map +1 -1
- package/lib/types/command.d.ts +61 -0
- package/lib/types/command.d.ts.map +1 -0
- package/lib/types/envinit-bootstrap.d.ts +1 -1
- package/lib/types/envinit.d.ts +2 -6
- package/lib/types/envinit.d.ts.map +1 -1
- package/lib/types/hints.d.ts +28 -24
- package/lib/types/hints.d.ts.map +1 -1
- package/lib/types/index.d.ts +21 -40
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/inject.d.ts +3 -2
- package/lib/types/inject.d.ts.map +1 -1
- package/lib/types/interface_gate.d.ts +9 -9
- package/lib/types/prompt.d.ts +17 -41
- package/lib/types/prompt.d.ts.map +1 -1
- package/lib/types/provision.d.ts +3 -0
- package/lib/types/provision.d.ts.map +1 -1
- package/lib/types/remote.d.ts +23 -9
- package/lib/types/remote.d.ts.map +1 -1
- package/lib/types/render.d.ts +3 -3
- package/lib/types/tool_schema.d.ts +4 -0
- package/lib/types/tool_schema.d.ts.map +1 -1
- package/lib/types/vectorMigration.d.ts +5 -7
- package/lib/types/vectorMigration.d.ts.map +1 -1
- package/package.json +16 -15
- package/lib/engine/mem/config/domains.d.ts +0 -20
- package/lib/engine/mem/db/dao/chunks.d.ts +0 -231
- package/lib/engine/mem/db/dao/documents.d.ts +0 -51
- package/lib/engine/mem/db/hash.d.ts +0 -2
- package/lib/engine/mem/db/knowledge.d.ts +0 -17
- package/lib/engine/mem/eval/index.d.ts +0 -4
- package/lib/engine/mem/git.d.ts +0 -73
- package/lib/engine/mem/router.d.ts +0 -51
- package/lib/engine/mem/store/doc_files.d.ts +0 -125
- package/lib/engine/mem/store/document_text.d.ts +0 -47
- package/lib/engine/mem/store/ingest_guard.d.ts +0 -25
- package/lib/engine/mem/store/knowledge.d.ts +0 -598
- package/lib/engine/mem/store/source_picker.d.ts +0 -43
- package/lib/engine/mem-retrieval/adapters/local_reranker.d.ts +0 -52
- package/lib/engine/mem-retrieval/adapters/none_reranker.d.ts +0 -10
- package/lib/engine/mem-retrieval/rerank.d.ts +0 -13
- package/lib/types/client/domains.d.ts +0 -53
- package/lib/types/client/domains.d.ts.map +0 -1
- package/lib/types/client/ingest.d.ts +0 -24
- package/lib/types/client/ingest.d.ts.map +0 -1
- package/lib/types/open.d.ts +0 -77
- package/lib/types/open.d.ts.map +0 -1
- package/lib/types/reconcile.d.ts +0 -64
- package/lib/types/reconcile.d.ts.map +0 -1
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend a driver OPENS (DB-1 boundary; DB-2 async; DB-3 ids/search/migrations).
|
|
3
|
+
*
|
|
4
|
+
* `MemoryStore` receives this object, never a `Db`, a DAO or SQL. Which driver produced it is the
|
|
5
|
+
* composition root's business (`storage/create.ts`); the store only sees the port shapes declared in
|
|
6
|
+
* this directory.
|
|
7
|
+
*
|
|
8
|
+
* `keyValue` and `lifecycle` are connection-scoped and therefore part of the backend rather than the
|
|
9
|
+
* repositories: retrieval health lives in the backend's own side table, and transactions / the
|
|
10
|
+
* lifecycle tick are things only the driver can implement (a remote backend must give the host an
|
|
11
|
+
* async unit of work — see {@link LifecycleService}).
|
|
12
|
+
*
|
|
13
|
+
* `relationalHandle` is the ONE transitional hole in the abstraction: the CLI's relation-backfill
|
|
14
|
+
* commands and the diagnostics still speak SQL through `Db` (docs/DB_DRIVER_LAYOUT.md §一 rule 4 is
|
|
15
|
+
* about the STORE and the retrieval paths). It is declared as `unknown` on purpose — a portable
|
|
16
|
+
* interface cannot name a driver type — and a caller that needs it casts explicitly.
|
|
17
|
+
*
|
|
18
|
+
* @module interfaces/storage_backend
|
|
19
|
+
*/
|
|
20
|
+
import type { FactsExportDocument } from '../facts_io.js';
|
|
21
|
+
import type { MaintenanceResult } from '../lifecycle/maintenance.js';
|
|
22
|
+
import type { TickResult } from '../lifecycle/tick.js';
|
|
23
|
+
import type { EntitySweepReport } from '../store/entity_sweep.js';
|
|
24
|
+
import type { RestoreOptions, RestoreReport } from '../store/facts_restore.js';
|
|
25
|
+
import type { Config } from '../../mem-contract/index.js';
|
|
26
|
+
import type { StorageCapabilities } from './capabilities.js';
|
|
27
|
+
import type { Awaitable } from './common.js';
|
|
28
|
+
import type { MigrationRunner } from './migrations.js';
|
|
29
|
+
import type { ContradictionRepository, KeyValueRepository, MemoryRepository, RelationRepository, SourceRepository } from './repositories.js';
|
|
30
|
+
import type { SearchIndex } from './search_index.js';
|
|
31
|
+
/**
|
|
32
|
+
* The backend's connection-scoped services: transactions, the lifecycle pass, the active-day clock
|
|
33
|
+
* and the restore transaction.
|
|
34
|
+
*
|
|
35
|
+
* TRANSACTIONS ARE ASYNC (DB-2). `work` may `await` repository calls — a remote backend has no other
|
|
36
|
+
* option, and the store's write paths are one unit of work whichever driver runs them. The callback
|
|
37
|
+
* form is deliberate: no driver can hand out a live transaction object that survives an `await`
|
|
38
|
+
* without leaking its dialect (docs/DATABASE_PORTABILITY.md §四).
|
|
39
|
+
*/
|
|
40
|
+
export interface LifecycleService {
|
|
41
|
+
transaction<T>(work: () => T | Promise<T>): Promise<T>;
|
|
42
|
+
immediateTransaction<T>(work: () => T | Promise<T>): Promise<T>;
|
|
43
|
+
optimize(): Awaitable<void>;
|
|
44
|
+
initClock(): Awaitable<void>;
|
|
45
|
+
clock(): Awaitable<number>;
|
|
46
|
+
advancePresence(opts?: {
|
|
47
|
+
nowMs?: number;
|
|
48
|
+
gapCapDays?: number;
|
|
49
|
+
}): Awaitable<{
|
|
50
|
+
clock: number;
|
|
51
|
+
counted: number;
|
|
52
|
+
}>;
|
|
53
|
+
trustTick(config: Config, opts: {
|
|
54
|
+
clock: number;
|
|
55
|
+
budget?: number | null;
|
|
56
|
+
}): Awaitable<TickResult>;
|
|
57
|
+
maintenance(config: Config, opts?: {
|
|
58
|
+
clock?: number;
|
|
59
|
+
budget?: number | null;
|
|
60
|
+
}): Awaitable<MaintenanceResult>;
|
|
61
|
+
restore(doc: FactsExportDocument, reindexEntities: (budget?: number) => Promise<EntitySweepReport>, options?: RestoreOptions): Promise<RestoreReport>;
|
|
62
|
+
}
|
|
63
|
+
/** The composition-root result: what a driver's `open()` returns and the store is built over. */
|
|
64
|
+
export interface StorageBackend {
|
|
65
|
+
/** The driver that opened this backend (`StorageDriver.name`) — a label, never branched on above. */
|
|
66
|
+
readonly kind: string;
|
|
67
|
+
/** What this driver declared it can do at open (docs/DB_DRIVER_LAYOUT.md §二). */
|
|
68
|
+
readonly capabilities: StorageCapabilities;
|
|
69
|
+
/** The facts aggregate (named `facts` per docs/DB_DRIVER_LAYOUT.md §二). */
|
|
70
|
+
readonly facts: MemoryRepository;
|
|
71
|
+
readonly relations: RelationRepository;
|
|
72
|
+
readonly sources: SourceRepository;
|
|
73
|
+
readonly contradictions: ContradictionRepository;
|
|
74
|
+
readonly search: SearchIndex;
|
|
75
|
+
readonly keyValue: KeyValueRepository;
|
|
76
|
+
readonly lifecycle: LifecycleService;
|
|
77
|
+
readonly migrations: MigrationRunner;
|
|
78
|
+
/**
|
|
79
|
+
* The driver's own relational handle, for the transitional SQL-speaking operator surfaces. A
|
|
80
|
+
* driver that has none omits it; callers must fail loudly rather than invent one.
|
|
81
|
+
*/
|
|
82
|
+
relationalHandle?(): unknown;
|
|
83
|
+
close(): Awaitable<void>;
|
|
84
|
+
}
|