@adhd/backlog 0.1.9 → 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.
Files changed (60) hide show
  1. package/CHANGELOG.md +80 -47
  2. package/README.md +332 -81
  3. package/api.d.ts +146 -0
  4. package/cli.d.ts +45 -18
  5. package/env.d.ts +23 -3
  6. package/envelope.d.ts +163 -0
  7. package/index.d.ts +11 -10
  8. package/index.js +531 -173
  9. package/index.mjs +30039 -15879
  10. package/install-skill.d.ts +23 -0
  11. package/package.json +50 -15
  12. package/query/card.d.ts +31 -0
  13. package/query/get.d.ts +11 -0
  14. package/query/index.d.ts +67 -0
  15. package/query/markdown.d.ts +11 -0
  16. package/query/query.d.ts +131 -0
  17. package/query/resolve.d.ts +123 -0
  18. package/query/types.d.ts +450 -0
  19. package/query/views/registry.d.ts +43 -0
  20. package/query/views/semantic.d.ts +101 -0
  21. package/query/views/stats.d.ts +109 -0
  22. package/search-shortcut.d.ts +79 -0
  23. package/serve.d.ts +18 -0
  24. package/server.d.ts +139 -4
  25. package/skill/SKILL.md +619 -138
  26. package/store/graph-backlog-store.d.ts +80 -17
  27. package/store/immediate-retry.d.ts +24 -13
  28. package/store/type-policy.d.ts +4 -0
  29. package/store/vocabulary-guard.d.ts +52 -0
  30. package/write/audit.d.ts +36 -0
  31. package/write/bootstrap.d.ts +123 -0
  32. package/write/catalog.d.ts +351 -0
  33. package/write/claim-lease.d.ts +21 -0
  34. package/write/claim.d.ts +80 -0
  35. package/write/create-issue.d.ts +250 -0
  36. package/write/delete.d.ts +39 -0
  37. package/write/embed-drain.d.ts +68 -0
  38. package/write/embedding-observer.d.ts +80 -0
  39. package/write/errors.d.ts +303 -0
  40. package/write/issue-status.d.ts +10 -0
  41. package/write/move.d.ts +70 -0
  42. package/write/relate.d.ts +52 -0
  43. package/write/transition.d.ts +60 -0
  44. package/write/tx.d.ts +344 -0
  45. package/write/update.d.ts +81 -0
  46. package/client.d.ts +0 -174
  47. package/markdown.d.ts +0 -75
  48. package/migration-admin.d.ts +0 -26
  49. package/model.d.ts +0 -437
  50. package/store/audit-log.d.ts +0 -16
  51. package/store/claim.d.ts +0 -24
  52. package/store/crud.d.ts +0 -62
  53. package/store/ids.d.ts +0 -24
  54. package/store/lifecycle.d.ts +0 -36
  55. package/store/mapping.d.ts +0 -101
  56. package/store/mutate-metadata.d.ts +0 -8
  57. package/store/query.d.ts +0 -68
  58. package/store/repo-migration.d.ts +0 -51
  59. package/store/serve-lock.d.ts +0 -42
  60. package/store/structure.d.ts +0 -66
@@ -1,36 +1,99 @@
1
- import { GraphBackend } from '@adhd/sox-graph-store';
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
- /** Store-adapter handle — ONLY for the CAS transaction wrapper (mutate-metadata.ts / ids.ts). */
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 SQLite `busy_timeout` (ms) — how long a blocked
42
+ * @param busyTimeoutMs `busy_timeout` (ms) — how long a blocked
12
43
  * `.transaction(fn, { mode: 'immediate' })` waits for a contended lock
13
- * before throwing `SQLITE_BUSY` (DEBT-BACKLOG-CONCURRENCY-BUSY-RETRY-001).
14
- * BUG-SOXGRAPH-002 moved busy_timeout ownership OUT of graph-store into the
15
- * adapters (SqliteAdapter hardcodes 3000 at connect; graph-store's
16
- * `PRAGMAS` no longer touches it), and `AdapterConfig` exposes no
17
- * busy_timeout field — so the caller's value is routed through the
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
- export declare function closeGraphBacklogStore(store: GraphBacklogStore): Promise<void>;
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
- * closeGraphBacklogStore may throw only in the extreme edge where the
30
- * driver's own db.close() fails (every checkpoint/verify failure is already
31
- * caught and logged inside the adapter — turso-adapter close()). On that edge
32
- * this logs and returns so a close failure can never mask a command/transport
33
- * error or turn a successful command into a failed exit. The adapter's own
34
- * logs are the durable record; the client never rethrows here.
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). `mutate-metadata.ts` / `ids.ts` are the ONLY
5
- * two write paths that call `.immediate()` directly (DESIGN.md §3/§4.3) and
6
- * both funnel through this wrapper — retrying ONLY busy-shaped errors, using
7
- * store-adapter's portable `isBusyError`/`isConcurrentConflict` duck-type
8
- * checks (the same helpers the adapter's own retry loop uses) so BOTH
9
- * adapter error shapes are covered: the legacy SQLite adapter's
10
- * `SQLITE_BUSY`/`SQLITE_BUSY_SNAPSHOT` codes and the turso driver's
11
- * `GenericFailure` with a
12
- * "database is locked"/"database is busy" message. Any other thrown error
13
- * (including `NotFoundError`, `ClaimContentionError`) propagates immediately,
14
- * unretried — and the semantic `'held'` claim-contention RESULT (claim.ts) is
15
- * a normal RETURN VALUE, never an exception, so it is never touched by this
16
- * wrapper either.
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,4 @@
1
+ import { TypePolicy } from '@adhd/sox-graph-store';
2
+
3
+ /** Unconditionally permissive — see this file's own doc comment for why. */
4
+ export declare const OPEN_TYPE_POLICY: TypePolicy;
@@ -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,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>;