@adhd/backlog 0.1.8 → 1.0.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/CHANGELOG.md +93 -44
- package/README.md +332 -81
- package/api.d.ts +146 -0
- package/cli.d.ts +45 -18
- package/env.d.ts +23 -3
- package/envelope.d.ts +163 -0
- package/index.d.ts +11 -10
- package/index.js +531 -173
- package/index.mjs +29814 -15647
- package/install-skill.d.ts +23 -0
- package/package.json +50 -15
- package/query/card.d.ts +31 -0
- package/query/get.d.ts +11 -0
- package/query/index.d.ts +67 -0
- package/query/markdown.d.ts +11 -0
- package/query/query.d.ts +131 -0
- package/query/resolve.d.ts +123 -0
- package/query/types.d.ts +450 -0
- package/query/views/registry.d.ts +43 -0
- package/query/views/semantic.d.ts +101 -0
- package/query/views/stats.d.ts +109 -0
- package/search-shortcut.d.ts +79 -0
- package/serve.d.ts +18 -0
- package/server.d.ts +139 -4
- package/skill/SKILL.md +619 -138
- package/store/graph-backlog-store.d.ts +80 -17
- package/store/immediate-retry.d.ts +24 -13
- package/store/type-policy.d.ts +4 -0
- package/store/vocabulary-guard.d.ts +52 -0
- package/version-info.d.ts +15 -0
- package/write/audit.d.ts +36 -0
- package/write/bootstrap.d.ts +123 -0
- package/write/catalog.d.ts +351 -0
- package/write/claim-lease.d.ts +21 -0
- package/write/claim.d.ts +80 -0
- package/write/create-issue.d.ts +250 -0
- package/write/delete.d.ts +39 -0
- package/write/embed-drain.d.ts +68 -0
- package/write/embedding-observer.d.ts +80 -0
- package/write/errors.d.ts +303 -0
- package/write/issue-status.d.ts +10 -0
- package/write/move.d.ts +70 -0
- package/write/relate.d.ts +52 -0
- package/write/transition.d.ts +60 -0
- package/write/tx.d.ts +344 -0
- package/write/update.d.ts +81 -0
- package/client.d.ts +0 -169
- package/markdown.d.ts +0 -75
- package/migration-admin.d.ts +0 -26
- package/model.d.ts +0 -437
- package/store/audit-log.d.ts +0 -16
- package/store/claim.d.ts +0 -24
- package/store/crud.d.ts +0 -62
- package/store/ids.d.ts +0 -24
- package/store/lifecycle.d.ts +0 -36
- package/store/mapping.d.ts +0 -101
- package/store/mutate-metadata.d.ts +0 -8
- package/store/query.d.ts +0 -68
- package/store/repo-migration.d.ts +0 -51
- package/store/serve-lock.d.ts +0 -42
- package/store/structure.d.ts +0 -66
|
@@ -1,36 +1,99 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IEmbedDrainOptions, IEmbedDrainResult } from '../write/embed-drain.js';
|
|
2
|
+
import { GraphBackend, TypePolicy } from '@adhd/sox-graph-store';
|
|
2
3
|
import { StoreAdapter } from '@adhd/sox-store-adapter';
|
|
3
4
|
|
|
4
5
|
export interface GraphBacklogStore {
|
|
5
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Store-adapter handle — reached directly by the write layer's CAS
|
|
8
|
+
* transaction wrapper (`write/tx.ts`'s `executeWriteTransaction`), the
|
|
9
|
+
* vocabulary guard, and close. All other reads/writes go through `graph`.
|
|
10
|
+
*/
|
|
6
11
|
readonly adapter: StoreAdapter;
|
|
7
12
|
/** All non-CAS reads/writes go through this. */
|
|
8
13
|
readonly graph: GraphBackend;
|
|
14
|
+
/**
|
|
15
|
+
* The SAME `TypePolicy` instance `graph` was constructed with. The write
|
|
16
|
+
* layer's `IWriteStoreHandle` (write/tx.ts) requires one, and it must be
|
|
17
|
+
* the store's own — importing a second copy at the call site is exactly how
|
|
18
|
+
* the production/ETL/test divergence documented in store/type-policy.ts
|
|
19
|
+
* came about.
|
|
20
|
+
*
|
|
21
|
+
* `OPEN_TYPE_POLICY` — the single policy, installed on the graph backend and
|
|
22
|
+
* reported here as one value, so a caller and the backend can never disagree
|
|
23
|
+
* about what is permitted. The application layer's own node kinds
|
|
24
|
+
* (`project`/`component`/`issue`/`citation`/`audit`/…) and rels
|
|
25
|
+
* (`owns_project`/`has_status`/`has_citation`/…) are outside
|
|
26
|
+
* `@adhd/sox-graph-store`'s closed default vocabulary, so a closed policy
|
|
27
|
+
* rejects every write this package makes.
|
|
28
|
+
*/
|
|
29
|
+
readonly typePolicy: TypePolicy;
|
|
30
|
+
/**
|
|
31
|
+
* Await every embed the write layer scheduled against this store's adapter
|
|
32
|
+
* (`write/embed-drain.ts`'s per-adapter registry), bounded — RAG-SPEC.md
|
|
33
|
+
* §2.2's durability backstop for a short-lived process. `closeGraphBacklogStore`
|
|
34
|
+
* calls this BEFORE closing the adapter, so a fire-and-forget embed that has
|
|
35
|
+
* not yet settled gets its chance to land rather than dying on a closed
|
|
36
|
+
* connection. Exposed on the store (rather than only inside close) so a host
|
|
37
|
+
* that wants to drain without closing can, and so tests can override the bound.
|
|
38
|
+
*/
|
|
39
|
+
flushEmbeds(opts?: IEmbedDrainOptions): Promise<IEmbedDrainResult>;
|
|
9
40
|
}
|
|
10
41
|
/**
|
|
11
|
-
* @param busyTimeoutMs
|
|
42
|
+
* @param busyTimeoutMs `busy_timeout` (ms) — how long a blocked
|
|
12
43
|
* `.transaction(fn, { mode: 'immediate' })` waits for a contended lock
|
|
13
|
-
* before
|
|
14
|
-
* BUG-SOXGRAPH-002
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* adapter's own `pragmaSet('busy_timeout', N)` surface, which both
|
|
19
|
-
* adapters honor (verified: read-back works on turso and sqlite). Callers
|
|
44
|
+
* before it gives up (DEBT-BACKLOG-CONCURRENCY-BUSY-RETRY-001).
|
|
45
|
+
* BUG-SOXGRAPH-002 puts busy_timeout ownership in the adapter layer, and
|
|
46
|
+
* `AdapterConfig` exposes no busy_timeout field — so the caller's value is
|
|
47
|
+
* routed through the adapter's own `pragmaSet('busy_timeout', N)` surface,
|
|
48
|
+
* which every adapter honors (verified by read-back). Callers
|
|
20
49
|
* reading from `BacklogConfig` should pass `env.config.db.busyTimeoutMs`;
|
|
21
50
|
* the default here (5000) matches that config field's own default, for
|
|
22
51
|
* callers (tests, ad-hoc scripts) that open a store directly without going
|
|
23
52
|
* through `buildBacklogEnv`.
|
|
24
53
|
*/
|
|
25
54
|
export declare function openGraphBacklogStore(dbPath: string, busyTimeoutMs?: number): Promise<GraphBacklogStore>;
|
|
26
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Async — drains the adapter's in-flight embeds, records any that are still
|
|
57
|
+
* unsettled as durable `embedding_failed` audit rows, THEN closes the adapter.
|
|
58
|
+
*
|
|
59
|
+
* This is RAG-SPEC.md §2.2's durability backstop for a short-lived process: a
|
|
60
|
+
* write verb schedules its embed fire-and-forget by default, and without this
|
|
61
|
+
* drain a CLI that exits immediately after `create` would close the adapter
|
|
62
|
+
* out from under that embed — its `upsertVector`/audit write would hit a
|
|
63
|
+
* closed connection and die as a log line. The drain runs BEFORE `close()`, so
|
|
64
|
+
* the post-close state is never exercised on the normal path; anything the
|
|
65
|
+
* drain cannot settle within its bound is recorded as `embedding_failed`
|
|
66
|
+
* WHILE THE CONNECTION IS STILL OPEN, so the loss is durable rather than
|
|
67
|
+
* silent.
|
|
68
|
+
*
|
|
69
|
+
* `adapter.close()` runs unconditionally (in a `finally`): a failed drain, or
|
|
70
|
+
* a failed recording, must still close the adapter — a leaked connection is
|
|
71
|
+
* never an acceptable outcome of a close call. `opts` is the drain bound
|
|
72
|
+
* (default `DEFAULT_EMBED_DRAIN_TIMEOUT_MS`); it exists so a caller can tune
|
|
73
|
+
* the wait and so tests can bound it deterministically.
|
|
74
|
+
*
|
|
75
|
+
* Return type widened from `Promise<void>` to `Promise<IEmbedDrainResult>` —
|
|
76
|
+
* non-breaking, since `Promise<T>` is assignable where `Promise<void>` is
|
|
77
|
+
* expected and every existing caller `await`s or ignores the result.
|
|
78
|
+
*/
|
|
79
|
+
export declare function closeGraphBacklogStore(store: GraphBacklogStore, opts?: IEmbedDrainOptions): Promise<IEmbedDrainResult>;
|
|
27
80
|
/**
|
|
28
81
|
* Best-effort close for teardown finally-paths (cli.ts / server.ts).
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
82
|
+
*
|
|
83
|
+
* Unlike the pre-drain version, this is no longer a silent discard: a store
|
|
84
|
+
* close can now carry an embed-durability outcome, and swallowing it would
|
|
85
|
+
* recreate exactly the "died unrecorded" defect this wave fixes. So:
|
|
86
|
+
*
|
|
87
|
+
* - `closeGraphBacklogStore` throwing (the extreme edge where the driver's own
|
|
88
|
+
* `db.close()` fails) still logs and returns — a close failure must never
|
|
89
|
+
* mask a command/transport error or turn a successful command into a failed
|
|
90
|
+
* exit.
|
|
91
|
+
* - An **unrecorded** embed death (its `embedding_failed` audit row could not
|
|
92
|
+
* be written, so the outcome is not durably recorded anywhere) logs loudly
|
|
93
|
+
* AND sets `process.exitCode = 1`: the subject write is durable but the
|
|
94
|
+
* vector is missing and nothing recorded why. Only this case changes the
|
|
95
|
+
* exit code — a **recorded** failure (the `embedding_failed` row IS durable)
|
|
96
|
+
* warns but exits 0, because the subject write genuinely succeeded and the
|
|
97
|
+
* failure is recorded. Filing must never depend on RAG succeeding.
|
|
35
98
|
*/
|
|
36
99
|
export declare function closeGraphBacklogStoreSafe(store: GraphBacklogStore | undefined): Promise<void>;
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* immediate-retry.ts — bounded, jittered exponential-backoff retry wrapper
|
|
3
3
|
* around `adapter.transaction(fn, { mode: 'immediate' })` (DEBT-BACKLOG-
|
|
4
|
-
* CONCURRENCY-BUSY-RETRY-001).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
4
|
+
* CONCURRENCY-BUSY-RETRY-001). The write layer's `executeWriteTransaction`
|
|
5
|
+
* (`write/tx.ts`) and `graph-backlog-store.ts`'s schema apply are the write
|
|
6
|
+
* paths that reach the `immediate` mode directly, and both funnel through
|
|
7
|
+
* this wrapper.
|
|
8
|
+
*
|
|
9
|
+
* It retries ONLY busy-shaped errors, and it does not classify them itself:
|
|
10
|
+
* `@adhd/sox-store-adapter`'s `isBusyError`/`isConcurrentConflict` duck-type
|
|
11
|
+
* checks are the single portable definition of "this write lost a lock race"
|
|
12
|
+
* — the same helpers the adapter's own retry loop uses. Keeping the
|
|
13
|
+
* classification behind that seam is the point: every driver-specific error
|
|
14
|
+
* shape lives on the adapter's side of it, and nothing here needs to know
|
|
15
|
+
* which substrate raised the error.
|
|
16
|
+
*
|
|
17
|
+
* This wrapper retries a THROWN busy/locked error; it neither sets nor
|
|
18
|
+
* introspects a `busy_timeout` PRAGMA. The busy-timeout budget is a separate,
|
|
19
|
+
* adapter-owned concern applied at connect time (`graph-backlog-store.ts`
|
|
20
|
+
* applies the caller's value via `adapter.pragmaSet('busy_timeout', N)` after
|
|
21
|
+
* the factory's init; a substrate may apply its own equivalent). Nothing here
|
|
22
|
+
* reads a PRAGMA or classifies an error by one.
|
|
23
|
+
*
|
|
24
|
+
* Any other thrown error (including `NotFoundError`, `ClaimContentionError`)
|
|
25
|
+
* propagates immediately, unretried — and the semantic `'held'`
|
|
26
|
+
* claim-contention RESULT (claim.ts) is a normal RETURN VALUE, never an
|
|
27
|
+
* exception, so it is never touched by this wrapper either.
|
|
17
28
|
*/
|
|
18
29
|
export interface ImmediateRetryOpts {
|
|
19
30
|
/** Total attempts (first try + retries). Default 5. */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { StoreAdapter } from '@adhd/sox-store-adapter';
|
|
2
|
+
|
|
3
|
+
/** The node kind every backlog ITEM is stored under. The read path filters `kind:'issue'`, so a store holding items under any other kind reads as empty. */
|
|
4
|
+
export declare const ITEM_NODE_KIND = "issue";
|
|
5
|
+
/**
|
|
6
|
+
* Every node kind this build's write layer composes — the authoritative list
|
|
7
|
+
* is `write/tx.ts`'s `IWriteNodeTxInput.kind` doc comment (SPEC.md §3): the
|
|
8
|
+
* catalog kinds, the resolved-only kinds, and every subject kind. A store
|
|
9
|
+
* whose live nodes are entirely outside this set was written by a build
|
|
10
|
+
* speaking a different vocabulary.
|
|
11
|
+
*/
|
|
12
|
+
export declare const RECOGNIZED_NODE_KINDS: ReadonlySet<string>;
|
|
13
|
+
/** One row of the live-node kind histogram. */
|
|
14
|
+
export interface IObservedKind {
|
|
15
|
+
kind: string;
|
|
16
|
+
count: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A store whose live-node vocabulary this build does not recognize. Carries
|
|
20
|
+
* the observed histogram and the expected kind set as structured fields so a
|
|
21
|
+
* caller (e.g. the `doctor` CLI diagnostic) can render them without parsing
|
|
22
|
+
* the message.
|
|
23
|
+
*/
|
|
24
|
+
export declare class StoreVocabularyMismatchError extends Error {
|
|
25
|
+
readonly observed: readonly IObservedKind[];
|
|
26
|
+
readonly recognized: readonly string[];
|
|
27
|
+
constructor(observed: readonly IObservedKind[], recognized: readonly string[]);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the store's live-node kind histogram. A pure read — it never writes,
|
|
31
|
+
* so it is safe to run against any store, including the live one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function inspectStoreVocabulary(adapter: StoreAdapter): Promise<{
|
|
34
|
+
total: number;
|
|
35
|
+
observed: IObservedKind[];
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Assert the store's live nodes speak a vocabulary this build understands.
|
|
39
|
+
*
|
|
40
|
+
* Passes (no throw) when the store is empty, or when at least one live node
|
|
41
|
+
* is of a recognized kind. Throws {@link StoreVocabularyMismatchError} when
|
|
42
|
+
* the store holds live nodes but none of a recognized kind.
|
|
43
|
+
*
|
|
44
|
+
* BOUNDED BY CONSTRUCTION: this runs on every write verb (`api.ts`'s
|
|
45
|
+
* `writeHandle`) and every query (`api.ts`'s `queryHandle` → `query.ts`), so it
|
|
46
|
+
* must not scan the store per call. The criterion is answered by a single
|
|
47
|
+
* `LIMIT 1` existence probe ({@link hasRecognizedLiveNode}); only when that
|
|
48
|
+
* finds no recognized node — the empty-store and foreign-store cases — does the
|
|
49
|
+
* full histogram run, and there it is either trivial (no rows) or the payload
|
|
50
|
+
* of the error we are about to throw.
|
|
51
|
+
*/
|
|
52
|
+
export declare function assertRecognizedStoreVocabulary(adapter: StoreAdapter): Promise<void>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reports this running package's own real `name`/`version`, read fresh from
|
|
3
|
+
* `package.json` on every call (never a compiled-in constant, so a
|
|
4
|
+
* republished build can never drift from what this reports). Store-free —
|
|
5
|
+
* callable by `client.ts`'s `version()` (apigen-dispatched, ctx-carrying) and
|
|
6
|
+
* by `cli.ts`'s `version` short-circuit (never opens the store) identically.
|
|
7
|
+
* Returns the same `{ name, version }` shape `client.ts`'s `BacklogVersionInfo`
|
|
8
|
+
* declares; the return type is deliberately structural (not an import of that
|
|
9
|
+
* interface) so `client.ts`'s own extraction surface (`client.d.ts`) is
|
|
10
|
+
* byte-for-byte unchanged by this extraction.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readBacklogVersionInfo(): {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
package/write/audit.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TypePolicy } from '@adhd/sox-graph-store';
|
|
2
|
+
import { AdapterTransaction } from '@adhd/sox-store-adapter';
|
|
3
|
+
|
|
4
|
+
export interface IWriteAuditInput {
|
|
5
|
+
tx: AdapterTransaction;
|
|
6
|
+
typePolicy: TypePolicy;
|
|
7
|
+
/** The node the `audits` edge points FROM — any kind, per `audits`' declared `source_kind: '*'` sentinel (§2). */
|
|
8
|
+
subjectRowid: number;
|
|
9
|
+
subjectUid: string;
|
|
10
|
+
subjectKind: string;
|
|
11
|
+
/** The acting identity — the verb's own `by` (or the resolved `agent` catalog name), never the raw unresolved input. */
|
|
12
|
+
actor: string;
|
|
13
|
+
/** e.g. `'created'`, `'claimed'`, `'released'`, `'renewed'`, `'reclaimed-stale'`, `'transitioned'`, `'moved'`, `'related'`, `'deleted'`. */
|
|
14
|
+
action: string;
|
|
15
|
+
from?: string;
|
|
16
|
+
to?: string;
|
|
17
|
+
note?: string;
|
|
18
|
+
/** Defaults to `nowISO()`. Accepted explicitly so a verb that already computed `now` for its subject write reuses the identical timestamp rather than a microsecond-later second call. */
|
|
19
|
+
at?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface IAuditWriteResult {
|
|
22
|
+
rowid: number;
|
|
23
|
+
uid: string;
|
|
24
|
+
sha: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Write one `audit` node + its `audits` edge, against the SAME `tx` the
|
|
28
|
+
* caller's own subject write already opened. `sha` is computed HERE,
|
|
29
|
+
* unconditionally — "automatic, cannot be forgotten" (§4a) — as `sha256` over
|
|
30
|
+
* the canonical (sorted-key) JSON serialization of the audit's own recorded
|
|
31
|
+
* fields (DATA_MODEL.md §10 point 2: "the same convention SPEC.md §4a
|
|
32
|
+
* already states for the audit `sha`," applied identically to how
|
|
33
|
+
* `transition.sha` is computed — never hashing external content, unlike a
|
|
34
|
+
* `citation`'s `sha`, §8.5).
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeAudit(input: IWriteAuditInput): Promise<IAuditWriteResult>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { IEmbeddingBackend } from './tx.js';
|
|
2
|
+
import { BacklogConfig } from '../env.js';
|
|
3
|
+
import { StoreAdapter } from '@adhd/sox-store-adapter';
|
|
4
|
+
import { GraphBackend } from '@adhd/sox-graph-store';
|
|
5
|
+
import { AsyncVectorBackend } from '@adhd/sox-vector-store';
|
|
6
|
+
import { StoreSearchBackend } from '@adhd/sox-hybrid-search';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The two handle members `api.ts`'s `writeHandle`/`queryHandle` need, in the
|
|
10
|
+
* exact shapes their consumers require:
|
|
11
|
+
* - `search` matches `query/query.ts`'s `IQueryStoreHandle['search']`
|
|
12
|
+
* (mandatory `embedQuery` + `spacePopulated`) — a strict subset that also
|
|
13
|
+
* satisfies `write/create-issue.ts`'s `IDuplicateScanHandle['search']`
|
|
14
|
+
* (optional `embedQuery`), since a mandatory field trivially satisfies an
|
|
15
|
+
* optional one.
|
|
16
|
+
* - `embedding` matches `write/tx.ts`'s `IWriteStoreHandle['embedding']`
|
|
17
|
+
* (`IEmbeddingBackend`) exactly.
|
|
18
|
+
*
|
|
19
|
+
* Both are OPTIONAL and, per BUG-045's binding rule (quoted in `api.ts`'s
|
|
20
|
+
* former `queryHandle` comment), absence is the only honest degrade: never a
|
|
21
|
+
* stub whose methods run but return empty/wrong results. `deriveMembers`
|
|
22
|
+
* below returns `{}` — both members absent — whenever the real embedding
|
|
23
|
+
* model genuinely cannot be reached, so `scanForDuplicates` reports "scan
|
|
24
|
+
* unavailable" (zero candidates, write proceeds) and `filter.semantic`/
|
|
25
|
+
* `view:'similar'` throw `InvalidArgumentError('semantic', ...)` exactly as
|
|
26
|
+
* they did before this module existed — never a silently-empty "search".
|
|
27
|
+
*/
|
|
28
|
+
export interface SemanticStoreMembers {
|
|
29
|
+
readonly search?: {
|
|
30
|
+
readonly backend: StoreSearchBackend;
|
|
31
|
+
embedQuery(text: string): Promise<Float32Array>;
|
|
32
|
+
/**
|
|
33
|
+
* Bounded existence probe of the REAL vector table: `true` iff at least
|
|
34
|
+
* one vector exists under this member's own space `modelId`. Backed by
|
|
35
|
+
* `@adhd/sox-vector-store`'s `hasVectors` (`SELECT 1 … LIMIT 1`), so it
|
|
36
|
+
* never reads the embedding column or scans past the first row. This is
|
|
37
|
+
* per-query truth read straight from the write layer's durable vectors —
|
|
38
|
+
* never a process-lifetime latch — so it is correct across process
|
|
39
|
+
* boundaries (a second process's `create` is visible here; ADR-0012).
|
|
40
|
+
*/
|
|
41
|
+
spacePopulated(): Promise<boolean>;
|
|
42
|
+
};
|
|
43
|
+
readonly embedding?: IEmbeddingBackend;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* §2.5 (RAG-SPEC.md, carried over from `store/semantic-search.ts`'s own
|
|
47
|
+
* identically-named class) — a returned vector whose dimension does not
|
|
48
|
+
* match the resolved model. Permanent and non-retryable by construction: the
|
|
49
|
+
* dimensional contract is structural (the vector column's type encodes it),
|
|
50
|
+
* so a mismatch means the provider is not the model the space was built for.
|
|
51
|
+
* Truncating or padding to fit would produce plausible-looking, permanently
|
|
52
|
+
* wrong neighbours — so this throws instead. Defined locally (not imported)
|
|
53
|
+
* because the module it came from is on the deletion list — see this file's
|
|
54
|
+
* header comment.
|
|
55
|
+
*/
|
|
56
|
+
export declare class PermanentEmbeddingDimensionError extends Error {
|
|
57
|
+
readonly operation: string;
|
|
58
|
+
readonly modelId: string;
|
|
59
|
+
readonly expected: number;
|
|
60
|
+
readonly actual: number;
|
|
61
|
+
constructor(operation: string, modelId: string, expected: number, actual: number);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Bounded existence probe of a REAL vector table: `true` iff at least one
|
|
65
|
+
* vector exists under `modelId`. This is the readiness source the text-routing
|
|
66
|
+
* decision (`query/query.ts`'s `resolveTextInput`) consults — per query, read
|
|
67
|
+
* from the durable vector table the write layer's own `embedding` member writes
|
|
68
|
+
* to.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately NOT a flag latched at boot: a process that opens a store while
|
|
71
|
+
* its vector space is still empty (a fresh store, or one populated by another
|
|
72
|
+
* process) must still route `text:` to the semantic ranker the moment real
|
|
73
|
+
* vectors exist. Reading the table itself makes that true across process
|
|
74
|
+
* boundaries (ADR-0012: concurrent processes share the store).
|
|
75
|
+
*
|
|
76
|
+
* Delegates to `@adhd/sox-vector-store`'s `hasVectors` — a bounded
|
|
77
|
+
* `SELECT 1 … LIMIT 1` that projects no embedding column and stops at the
|
|
78
|
+
* first row, so the probe is O(1) in the size of the space and never
|
|
79
|
+
* materializes an embedding BLOB. This replaced an `iter`-first-row probe
|
|
80
|
+
* (BUG e19bc9d0): `AsyncVectorBackend.iter` is a FULL corpus scan on the Turso
|
|
81
|
+
* backend — its `db.all`-backed query materializes every row *and every
|
|
82
|
+
* embedding BLOB* before the first yield — so the old probe read the entire
|
|
83
|
+
* vector table on every bare-`text:` query. Returning on the first yielded row
|
|
84
|
+
* short-circuited nothing.
|
|
85
|
+
*
|
|
86
|
+
* The capability is additive, NOT on the pinned `AsyncVectorBackend` contract,
|
|
87
|
+
* so a backend predating it (or a structural test double) narrows to
|
|
88
|
+
* `undefined`; absence degrades to `false` — the honest conservative answer,
|
|
89
|
+
* and a backend that cannot answer cheaply must not fall back to the unbounded
|
|
90
|
+
* scan this probe exists to avoid. An absent table (a space never
|
|
91
|
+
* `ensureSpace`d) is likewise "empty", not an error (`hasVectors` tolerates it).
|
|
92
|
+
*/
|
|
93
|
+
export declare function isVectorSpacePopulated(vectorBackend: AsyncVectorBackend, modelId: string): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Derives the `search`/`embedding` members for a store's already-open
|
|
96
|
+
* `adapter`/`graph` pair, memoized per `adapter` instance. `cfg` is
|
|
97
|
+
* `BacklogConfig['embedding']` (`env.ts`) — the caller passes
|
|
98
|
+
* `ctx.env.config.embedding` verbatim.
|
|
99
|
+
*
|
|
100
|
+
* **The cache holds only a successful, member-ful derive.** `deriveMembers`
|
|
101
|
+
* never throws on a soft failure — it returns `{}` (both members absent) from
|
|
102
|
+
* five paths: `embedding` disabled, a non-Turso adapter (`nativeVectors !==
|
|
103
|
+
* true`), the optional packages unresolvable, `createEmbeddingProvider`
|
|
104
|
+
* throwing, or `openTursoVectorStore`/`ensureSpace` throwing. Several of those
|
|
105
|
+
* are TRANSIENT (a provider briefly unreachable, a store-open that hit a lock),
|
|
106
|
+
* so a member-less result is evicted rather than cached: the next semantic verb
|
|
107
|
+
* re-derives and recovers without a process restart. A hard rejection is
|
|
108
|
+
* likewise evicted, so it is surfaced to the current caller and retried later
|
|
109
|
+
* rather than replayed forever. Only a member-ful success is retained, which is
|
|
110
|
+
* where the expensive cold load actually is.
|
|
111
|
+
*
|
|
112
|
+
* (The `cfg.enabled === false` case is member-less and so is not retained
|
|
113
|
+
* either — but it does no I/O at all: `deriveMembers` returns `{}` on its first
|
|
114
|
+
* line. Re-deriving it per verb costs a `WeakMap` miss and a branch, which is
|
|
115
|
+
* cheaper than carrying a second "is it safe to cache?" signal through
|
|
116
|
+
* `deriveMembers`. Stated here as the deliberate choice.)
|
|
117
|
+
*
|
|
118
|
+
* @param log where a failed opt-in is reported (never thrown — mirrors
|
|
119
|
+
* `store/semantic-search.ts`'s own former `enableSemanticSearchFromConfig`
|
|
120
|
+
* "best-effort, never fatal" contract). Defaults to `console.error`; a host
|
|
121
|
+
* with a structured logger should pass its own sink.
|
|
122
|
+
*/
|
|
123
|
+
export declare function bootstrapSemanticStoreMembers(adapter: StoreAdapter, graph: GraphBackend, cfg: BacklogConfig['embedding'], log?: (message: string) => void): Promise<SemanticStoreMembers>;
|