/** * Memory Knowledge Graph — exhaustive paged namespace scans, write-failure * reporting and CAS retry, per-origin collection, and the K7 reference edge * lookup. Split out of memory-kg.ts, which re-exports the public symbols. */ import { bridgeListEntries, type bridgeStoreEntry } from './memory-bridge.js'; import type { KgScope } from './memory-kg-model.js'; /** Rows per `bridgeListEntries` call while scanning a namespace. * * A single list call cannot return more than the backend's own 10,000-row * ceiling (`MAX_QUERY_LIMIT` in sql-backend.ts), so the old `limit: MAX_LIST` * scans were not "large enough to be safe" — they were exactly the point past * which the graph goes silently invisible. Everything below pages instead. * * 1,000 balances the two costs: one page is at most ~1 MB even at the bridge's * 16 KB value cap (typical KG entries are far smaller), and it takes a tenth * of the round trips a 100-row page would. */ export declare const SCAN_PAGE = 1000; /** Edge rows `kgSearch` will read before giving up and reporting `truncated`. * Search is interactive and runs a full scan per query, so unlike rollback it * keeps a ceiling — five times the old silent one, and now stated in the * result rather than hidden. */ export declare const SEARCH_EDGE_SCAN_MAX = 50000; export type ScannedEntry = NonNullable>>['entries'][number]; /** Page through an entire namespace, handing each page to `onPage` so callers * fold as they go instead of materializing the namespace. * * `onPage` returning exactly `false` stops the scan early (only `kgSearch` * does that); any other return value continues. Returns false when the backend * was unavailable — an unreadable namespace must never be mistaken for an * empty one. * * Callers that MUTATE what they find must collect during the scan and mutate * afterwards: deleting a row pulls every later row back one position, so under * an advancing offset the row that slid into the gap is never read. (The * bridge's upsert no longer reorders — it reuses the existing entry id and * preserves `createdAt` — so rewrites alone are safe; deletes are not, and * both callers here delete.) */ export declare function scanNamespace(namespace: string, dbPath: string | undefined, onPage: (entries: ScannedEntry[]) => unknown): Promise; /** Delete every entry in `namespace`. Used only to reset a DERIVED-index * namespace (`kg:adj`/`kg:origin-idx`) before a fresh `kgRebuildIndex` — * never a canonical one. Collect-then-delete, same reason `kgRollback` * does: deleting mid-scan pulls later rows back under an advancing offset. * Returns false (nothing deleted) on an unreadable or partially-deletable * namespace, so the caller never proceeds as if a clear that didn't fully * happen did. */ export declare function clearNamespace(namespace: string, dbPath: string | undefined): Promise; /** Cap on reported failure messages — a dead backend fails every write, and a * 500-entry failure list is noise, not signal. `error` carries the true count. */ export declare const MAX_FAILURES = 20; /** Accumulates write failures across a multi-write operation. The memory * bridge exposes no transaction primitive, so ingest CANNOT be atomic: some * writes land and some do not. Rather than hide that, callers get exact * counters for what persisted plus the failure list for what did not. */ export declare class FailureLog { readonly messages: string[]; private count; /** @returns true when the write failed (caller should not count it). */ add(res: Awaited>, what: string): boolean; note(message: string): void; get failed(): boolean; /** Summary for the result's `error` field; undefined when everything landed. */ summary(): string | undefined; } /** Attempts a compare-and-swap claim write, retrying while the bridge reports * a version conflict (K5): a concurrent writer applied its own claim to the * same row between our read and our write. `attempt()` must re-read, * re-merge (via `applyClaim`), and re-attempt the write itself on every call * — retrying with the SAME stale write would just lose the update again, * the exact bug this exists to close. * * Exhausting `maxAttempts` under sustained contention is returned as-is (the * last conflict response) rather than retried forever: the caller's * `FailureLog` reports it as a real, visible failure — never a silent lost * update — same as any other write the bridge refused. */ export declare function withCasRetry(attempt: () => Promise>>, maxAttempts?: number): Promise>>; export declare function originsOf(entry: ScannedEntry): string[]; /** Every entry in `namespace` that `originRef` supports, collected by an * EXHAUSTIVE paged scan. `covered` is false when the backend became * unreadable partway — an incomplete answer, never an empty one. * * Collecting rather than streaming is required by the callers that mutate: * deleting a row pulls later rows back, so an advancing offset would skip * whatever slid into the gap. Only origin-carrying entries are retained, so * memory tracks the operation's own footprint, not the namespace size. */ export declare function collectByOrigin(namespace: string, originRef: string, dbPath: string | undefined): Promise<{ entries: ScannedEntry[]; covered: boolean; }>; export interface KgReferenceEdge { key: string; src: string; dst: string; relation: string; originRefs: string[]; } /** Complete, uncapped read of every edge touching `endpointId` (as either * src or dst) and/or asserted by `originRef` — at least one filter is * required. This is the ground truth an indexed adjacency/origin lookup * (K7) must agree with once one exists: an exhaustive paged scan, the same * mechanism `kgRollback` already trusts for origin withdrawal, so it never * depends on an index and never inherits the old first-page cap. * * `truncated: true` means the scan did not finish — an incomplete answer, * never an empty one. Callers comparing this against a future index must * treat a truncated reference read as "unknown", not as "no matches". */ export declare function kgReferenceEdges(options: { endpointId?: string; originRef?: string; scope?: KgScope; dbPath?: string; }): Promise<{ success: boolean; edges: KgReferenceEdge[]; truncated?: boolean; error?: string; }>; //# sourceMappingURL=memory-kg-scan.d.ts.map