@remnic/core 10.0.75 → 10.0.77
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/dist/access-admin-ops-surface.js +2 -2
- package/dist/access-authorization-probe.js +3 -3
- package/dist/access-boundary.js +2 -2
- package/dist/access-cli.js +17 -17
- package/dist/access-extraction-force-flush.js +2 -2
- package/dist/access-http-briefing.js +3 -3
- package/dist/access-http-query.js +2 -2
- package/dist/access-http.js +14 -14
- package/dist/access-identity-continuity-surface.js +2 -2
- package/dist/access-lcm-surface.js +2 -2
- package/dist/access-mcp.js +9 -9
- package/dist/access-namespace-preflight.js +2 -2
- package/dist/access-observe-helpers.d.ts.map +1 -1
- package/dist/access-observe-helpers.js +1 -1
- package/dist/access-observe-write-surface.js +2 -2
- package/dist/access-operations-batch.js +3 -3
- package/dist/access-operations.js +8 -8
- package/dist/access-recall-concurrency.js +2 -2
- package/dist/access-recall-response.js +2 -2
- package/dist/access-recall-surface.js +2 -2
- package/dist/access-service.js +2 -2
- package/dist/access-surface-catalog.js +4 -4
- package/dist/{chunk-R24RYSQX.js → chunk-2JRLKDHV.js} +2 -2
- package/dist/{chunk-N6GEGRCT.js → chunk-4NDDRYBY.js} +2 -2
- package/dist/{chunk-VEWTHVX2.js → chunk-5HVEYVNQ.js} +2 -2
- package/dist/{chunk-KAED7IBB.js → chunk-6L62IDS6.js} +2 -2
- package/dist/{chunk-IPHIIRDN.js → chunk-CYTTY4M2.js} +5 -7
- package/dist/chunk-CYTTY4M2.js.map +1 -0
- package/dist/{chunk-SZBZOUHR.js → chunk-D26XMQP5.js} +2 -2
- package/dist/{chunk-VPEMGBTI.js → chunk-D3USVQIV.js} +2 -2
- package/dist/{chunk-E22CQZ3H.js → chunk-EYIBIGIU.js} +8 -8
- package/dist/{chunk-IBQ7LGUJ.js → chunk-FQU65RJX.js} +3 -3
- package/dist/{chunk-FP2AT4WL.js → chunk-G3PBNYDH.js} +2 -2
- package/dist/{chunk-VYOAYFDV.js → chunk-I4W2ADBP.js} +144 -26
- package/dist/chunk-I4W2ADBP.js.map +1 -0
- package/dist/{chunk-ZG57BEUS.js → chunk-LXDERMOU.js} +2 -2
- package/dist/{chunk-SY4AFWUZ.js → chunk-MAURCRPQ.js} +4 -4
- package/dist/{chunk-3GGCMRO7.js → chunk-MUZWS6KB.js} +2 -2
- package/dist/{chunk-URS56HGW.js → chunk-MXQKGSMW.js} +2 -2
- package/dist/{chunk-RXGFITWS.js → chunk-NUBOY2LQ.js} +2 -2
- package/dist/{chunk-PLGBPFEO.js → chunk-TWHVCSLX.js} +2 -2
- package/dist/{chunk-VEQVXNWR.js → chunk-TX627XOF.js} +2 -2
- package/dist/cli.js +15 -15
- package/dist/external-wiki-access.js +3 -3
- package/dist/index.js +17 -17
- package/dist/memory-browse-operations.js +3 -3
- package/dist/orchestration/backlog-scheduler.js +18 -18
- package/dist/orchestration/buffer-drain-runner.js +18 -18
- package/dist/orchestration/extraction-queue-coordinator.d.ts +4 -9
- package/dist/orchestration/extraction-queue-coordinator.d.ts.map +1 -1
- package/dist/orchestration/extraction-queue-snapshot-sharing.d.ts +113 -0
- package/dist/orchestration/extraction-queue-snapshot-sharing.d.ts.map +1 -0
- package/dist/orchestration/turn-ingestion.d.ts +3 -0
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.js +17 -17
- package/dist/recall-navigation-operations.js +3 -3
- package/dist/recall-navigation.js +2 -2
- package/dist/support-passport/index.js +5 -5
- package/package.json +2 -2
- package/src/access-observe-helpers.test.ts +156 -0
- package/src/access-observe-helpers.ts +6 -6
- package/src/orchestration/extraction-queue-bounded-retention.test.ts +548 -0
- package/src/orchestration/extraction-queue-coordinator.ts +4 -19
- package/src/orchestration/extraction-queue-snapshot-sharing.ts +257 -0
- package/src/orchestration/turn-ingestion.ts +19 -6
- package/src/orchestrator-extraction-queue.test.ts +70 -13
- package/dist/chunk-IPHIIRDN.js.map +0 -1
- package/dist/chunk-VYOAYFDV.js.map +0 -1
- /package/dist/{chunk-R24RYSQX.js.map → chunk-2JRLKDHV.js.map} +0 -0
- /package/dist/{chunk-N6GEGRCT.js.map → chunk-4NDDRYBY.js.map} +0 -0
- /package/dist/{chunk-VEWTHVX2.js.map → chunk-5HVEYVNQ.js.map} +0 -0
- /package/dist/{chunk-KAED7IBB.js.map → chunk-6L62IDS6.js.map} +0 -0
- /package/dist/{chunk-SZBZOUHR.js.map → chunk-D26XMQP5.js.map} +0 -0
- /package/dist/{chunk-VPEMGBTI.js.map → chunk-D3USVQIV.js.map} +0 -0
- /package/dist/{chunk-E22CQZ3H.js.map → chunk-EYIBIGIU.js.map} +0 -0
- /package/dist/{chunk-IBQ7LGUJ.js.map → chunk-FQU65RJX.js.map} +0 -0
- /package/dist/{chunk-FP2AT4WL.js.map → chunk-G3PBNYDH.js.map} +0 -0
- /package/dist/{chunk-ZG57BEUS.js.map → chunk-LXDERMOU.js.map} +0 -0
- /package/dist/{chunk-SY4AFWUZ.js.map → chunk-MAURCRPQ.js.map} +0 -0
- /package/dist/{chunk-3GGCMRO7.js.map → chunk-MUZWS6KB.js.map} +0 -0
- /package/dist/{chunk-URS56HGW.js.map → chunk-MXQKGSMW.js.map} +0 -0
- /package/dist/{chunk-RXGFITWS.js.map → chunk-NUBOY2LQ.js.map} +0 -0
- /package/dist/{chunk-PLGBPFEO.js.map → chunk-TWHVCSLX.js.map} +0 -0
- /package/dist/{chunk-VEQVXNWR.js.map → chunk-TX627XOF.js.map} +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded-queue retention for automatic extraction snapshots (#3324
|
|
3
|
+
* follow-up).
|
|
4
|
+
*
|
|
5
|
+
* The coordinator's queue keeps every accepted task's own snapshot (that is
|
|
6
|
+
* the #3324 contract: per-entry captured scope and settlement), but nothing
|
|
7
|
+
* requires each queued snapshot to RETAIN its own turn objects. Automatic
|
|
8
|
+
* triggers hand out prefix-extended snapshots of the same buffer (the buffer
|
|
9
|
+
* clears only when extraction runs), so consecutive queued snapshots overlap
|
|
10
|
+
* almost entirely while their drain is slow. Retaining one deep copy per
|
|
11
|
+
* snapshot grows quadratic overhead (demonstrated: scaling exponent 1.89 on
|
|
12
|
+
* main, 36× the unique content at 1000 turns for one session).
|
|
13
|
+
*
|
|
14
|
+
* This registry makes the OVERLAP shared without changing ANY task's
|
|
15
|
+
* semantics: a queued snapshot is stored as a chain node
|
|
16
|
+
* `{ base, tail }` whose turns are verified element-wise equivalent to the
|
|
17
|
+
* base chain at admit time. Each task materializes its own fresh array at
|
|
18
|
+
* run time — identical values, same windows, same chunking, same clear
|
|
19
|
+
* matching, same settlements. Sharing is data-structure only.
|
|
20
|
+
*
|
|
21
|
+
* Safety properties:
|
|
22
|
+
* - Equivalence is CONSUMER-equivalence, not `bufferTurnsEqual` alone: the
|
|
23
|
+
* five fields `bufferTurnsEqual` ignores (extractionContextOnly, parts,
|
|
24
|
+
* rawContent, sourceFormat, importProvenance) are compared strictly
|
|
25
|
+
* (objects by reference identity), so an aliased segment is
|
|
26
|
+
* indistinguishable from a private copy to every downstream reader.
|
|
27
|
+
* - Turn objects are immutable by audit: no code path writes a BufferTurn
|
|
28
|
+
* field or a parts array in place (all writes go to freshly constructed
|
|
29
|
+
* objects: `copyBufferTurn`, the replay `pinned` spread). Audited across
|
|
30
|
+
* the extraction call graph.
|
|
31
|
+
* - Distinct scope pins can never share: pins are turn fields covered by
|
|
32
|
+
* `bufferTurnsEqual`, and the scope-class bucket is a lookup heuristic
|
|
33
|
+
* only — a wrong pairing fails the element-wise check and simply does not
|
|
34
|
+
* share.
|
|
35
|
+
* - Replay, bulk import, force flush, fail-closed callers, and claim-backed
|
|
36
|
+
* execution contexts are excluded (they are not automatic snapshots of the
|
|
37
|
+
* live buffer).
|
|
38
|
+
*/
|
|
39
|
+
import type { BufferTurn } from "../types.js";
|
|
40
|
+
/** Option surface of `queueBufferedExtraction` relevant to eligibility. */
|
|
41
|
+
export interface AutomaticSharingOptions {
|
|
42
|
+
/** Claim-backed backlog tasks own a different buffer view: never share. */
|
|
43
|
+
execution?: unknown;
|
|
44
|
+
/** Automatic trigger paths set this; forced replay/import do not. */
|
|
45
|
+
preemptable?: boolean;
|
|
46
|
+
failOnExtractionFailure?: boolean;
|
|
47
|
+
forceExtractionAttempt?: boolean;
|
|
48
|
+
/** Fail-closed front flush: never share. */
|
|
49
|
+
preemptRunning?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare function automaticSnapshotSharingEligible(options: AutomaticSharingOptions): boolean;
|
|
52
|
+
/** Consumer-visible equivalence: `bufferTurnsEqual` PLUS the fields it ignores. */
|
|
53
|
+
export declare function turnRepresentationEquivalent(left: BufferTurn, right: BufferTurn): boolean;
|
|
54
|
+
/** One queued automatic snapshot: `base` chain plus this trigger's own new turns. */
|
|
55
|
+
export interface SnapshotChain {
|
|
56
|
+
readonly key: string;
|
|
57
|
+
readonly scopeClass: string;
|
|
58
|
+
readonly base: SnapshotChain | undefined;
|
|
59
|
+
/** Total turns retained by the base chain. */
|
|
60
|
+
readonly baseLength: number;
|
|
61
|
+
/** This trigger's non-shared suffix (fresh reference slots, disjoint across the chain). */
|
|
62
|
+
readonly tail: readonly BufferTurn[];
|
|
63
|
+
/** Total turns this snapshot represents. */
|
|
64
|
+
readonly total: number;
|
|
65
|
+
/** Outstanding tasks holding this node; the node leaves the registry when it reaches 0. */
|
|
66
|
+
holders: number;
|
|
67
|
+
}
|
|
68
|
+
export interface SnapshotSharingStats {
|
|
69
|
+
/** Distinct content chains registered (not task count — see queuedHolders). */
|
|
70
|
+
queuedNodes: number;
|
|
71
|
+
/** Σ per-node window lengths over registered nodes. Sibling nodes sharing
|
|
72
|
+
* a base chain count that base once per node (per-task window basis). */
|
|
73
|
+
queuedTotalRefs: number;
|
|
74
|
+
/** Distinct turn references REACHABLE from queued nodes, counting
|
|
75
|
+
* released ancestors reached through `base` exactly once (visited-set). */
|
|
76
|
+
queuedTailRefs: number;
|
|
77
|
+
/** Longest base chain reachable from a queued node (must stay bounded). */
|
|
78
|
+
queuedReachableDepth: number;
|
|
79
|
+
/** Outstanding tasks holding nodes (per-task, not per-node). */
|
|
80
|
+
queuedHolders: number;
|
|
81
|
+
/** What retention would be WITHOUT sharing: Σ per-node window length ×
|
|
82
|
+
* holders (each outstanding task would carry its own full window). */
|
|
83
|
+
unsharedEquivalentRefs: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Element-wise consumer-equivalence of the chain's turns against a snapshot
|
|
87
|
+
* prefix. Cost is O(chain.total) compares per admit — required to prove the
|
|
88
|
+
* shared prefix is consumer-equivalent to the incoming snapshot — so a chain
|
|
89
|
+
* build is O(depth^2) compares in total (measured, acknowledged in the PR).
|
|
90
|
+
*/
|
|
91
|
+
export declare function chainPrefixEquivalent(chain: SnapshotChain, turns: readonly BufferTurn[]): boolean;
|
|
92
|
+
/** Fresh array with exactly this snapshot's turns, in order. Run-time only. */
|
|
93
|
+
export declare function materializeChain(chain: SnapshotChain): BufferTurn[];
|
|
94
|
+
export declare class ExtractionSnapshotSharingRegistry {
|
|
95
|
+
private readonly buckets;
|
|
96
|
+
/**
|
|
97
|
+
* Admit one automatic snapshot for `bufferKey`: chain it onto the newest
|
|
98
|
+
* queued same-scope snapshot when that is a verified prefix-extension,
|
|
99
|
+
* otherwise start a fresh chain. The caller's array is never mutated.
|
|
100
|
+
*/
|
|
101
|
+
admit(bufferKey: string, turns: readonly BufferTurn[]): SnapshotChain;
|
|
102
|
+
/** Release one holder of a node when its task exits (or on enqueue
|
|
103
|
+
* refusal). CONTRACT: called EXACTLY ONCE per admit, by the task that
|
|
104
|
+
* admitted it — the registry has no task identity, so a second call by the
|
|
105
|
+
* same task would steal another holder's count. The only production caller
|
|
106
|
+
* (queueBufferedExtraction) enforces this structurally: the closure-finally
|
|
107
|
+
* and the enqueue-refusal branch are mutually exclusive. Defensively, a
|
|
108
|
+
* release past zero is a no-op. */
|
|
109
|
+
release(node: SnapshotChain): void;
|
|
110
|
+
/** Proof seam: what the queue retains right now. */
|
|
111
|
+
stats(): SnapshotSharingStats;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=extraction-queue-snapshot-sharing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction-queue-snapshot-sharing.d.ts","sourceRoot":"","sources":["../../src/orchestration/extraction-queue-snapshot-sharing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qEAAqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAQ1F;AAED,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CASzF;AAgBD,qFAAqF;AACrF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IACzC,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;IACrC,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB;6EACyE;IACzE,eAAe,EAAE,MAAM,CAAC;IACxB;+EAC2E;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB;0EACsE;IACtE,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAWD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAWjG;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,EAAE,CAMnE;AAED,qBAAa,iCAAiC;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D;;;;OAIG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,aAAa;IAwCrE;;;;;;uCAMmC;IACnC,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAWlC,oDAAoD;IACpD,KAAK,IAAI,oBAAoB;CA6B9B"}
|
|
@@ -27,6 +27,7 @@ import { SessionObserverState } from "../session-observer-state.js";
|
|
|
27
27
|
import { TranscriptManager } from "../transcript.js";
|
|
28
28
|
import type { BufferTurn, PluginConfig, SourceConnectorProvenance } from "../types.js";
|
|
29
29
|
import { type ExtractionTaskExecutionContext } from "./extraction-task-queueing.js";
|
|
30
|
+
import { ExtractionSnapshotSharingRegistry } from "./extraction-queue-snapshot-sharing.js";
|
|
30
31
|
import { type ResolvedScopeProfilePlan } from "../namespaces/scope-profiles.js";
|
|
31
32
|
import { type BulkImportBatchIngestResult } from "../orchestrator.js";
|
|
32
33
|
/**
|
|
@@ -102,6 +103,8 @@ export interface TurnIngestionOptions extends SourceConnectorProvenance {
|
|
|
102
103
|
export declare class TurnIngestionCoordinator {
|
|
103
104
|
private readonly deps;
|
|
104
105
|
private readonly drain;
|
|
106
|
+
/** Queued automatic-snapshot chains: bounded-queue retention via structural sharing. */
|
|
107
|
+
readonly snapshotSharing: ExtractionSnapshotSharingRegistry;
|
|
105
108
|
constructor(deps: TurnIngestionDeps);
|
|
106
109
|
processTurn(role: "user" | "assistant", content: string, sessionKey?: string, options?: TurnIngestionOptions): Promise<void>;
|
|
107
110
|
ingestReplayBatch(turns: ReplayTurn[], options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-ingestion.d.ts","sourceRoot":"","sources":["../../src/orchestration/turn-ingestion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAI7E,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAEL,wBAAwB,EACxB,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,UAAU,EAA6B,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAKvF,OAAO,
|
|
1
|
+
{"version":3,"file":"turn-ingestion.d.ts","sourceRoot":"","sources":["../../src/orchestration/turn-ingestion.ts"],"names":[],"mappings":"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"}
|
package/dist/orchestrator.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
graphPathRelativeToStorage,
|
|
5
5
|
mergeGraphExpandedResults,
|
|
6
6
|
qmdStartupCollectionChecksWithTimeout
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-I4W2ADBP.js";
|
|
8
8
|
import "./chunk-B36ACJG7.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-TWHVCSLX.js";
|
|
10
10
|
import {
|
|
11
11
|
formatCompressionGuidelinesForRecall
|
|
12
12
|
} from "./chunk-5PHOU5QI.js";
|
|
@@ -122,7 +122,7 @@ import "./chunk-7G5NTS7F.js";
|
|
|
122
122
|
import "./chunk-HB5TNQMM.js";
|
|
123
123
|
import "./chunk-4NZQ7IID.js";
|
|
124
124
|
import "./chunk-3I4FUAVJ.js";
|
|
125
|
-
import "./chunk-
|
|
125
|
+
import "./chunk-MAURCRPQ.js";
|
|
126
126
|
import "./chunk-MMACM5G2.js";
|
|
127
127
|
import "./chunk-54BGIBCR.js";
|
|
128
128
|
import "./chunk-H4CKS5B2.js";
|
|
@@ -238,7 +238,7 @@ import "./chunk-43HUVDTD.js";
|
|
|
238
238
|
import "./chunk-4RA3C3EV.js";
|
|
239
239
|
import "./chunk-B32WYRXX.js";
|
|
240
240
|
import "./chunk-3NF4QUNZ.js";
|
|
241
|
-
import "./chunk-
|
|
241
|
+
import "./chunk-EYIBIGIU.js";
|
|
242
242
|
import "./chunk-V7IZKJI3.js";
|
|
243
243
|
import "./chunk-TB6CBZ5V.js";
|
|
244
244
|
import "./chunk-XW2T4QAW.js";
|
|
@@ -252,27 +252,27 @@ import "./chunk-2TGIKMMZ.js";
|
|
|
252
252
|
import "./chunk-SDESKFKT.js";
|
|
253
253
|
import "./chunk-3HSRWJTC.js";
|
|
254
254
|
import "./chunk-FETPTCQZ.js";
|
|
255
|
-
import "./chunk-
|
|
256
|
-
import "./chunk-
|
|
255
|
+
import "./chunk-D26XMQP5.js";
|
|
256
|
+
import "./chunk-5HVEYVNQ.js";
|
|
257
257
|
import "./chunk-SRT6SHVZ.js";
|
|
258
|
-
import "./chunk-
|
|
258
|
+
import "./chunk-TX627XOF.js";
|
|
259
259
|
import "./chunk-TE6S7KDF.js";
|
|
260
260
|
import "./chunk-EIB4FJVR.js";
|
|
261
261
|
import "./chunk-MZUQVWVC.js";
|
|
262
262
|
import "./chunk-A5KNZSNA.js";
|
|
263
263
|
import "./chunk-HUSTM6PU.js";
|
|
264
264
|
import "./chunk-D24OXEPB.js";
|
|
265
|
-
import "./chunk-
|
|
265
|
+
import "./chunk-FQU65RJX.js";
|
|
266
266
|
import "./chunk-SYDPJUFR.js";
|
|
267
|
-
import "./chunk-
|
|
267
|
+
import "./chunk-LXDERMOU.js";
|
|
268
268
|
import "./chunk-233S3MXC.js";
|
|
269
|
-
import "./chunk-
|
|
270
|
-
import "./chunk-
|
|
271
|
-
import "./chunk-
|
|
269
|
+
import "./chunk-4NDDRYBY.js";
|
|
270
|
+
import "./chunk-MUZWS6KB.js";
|
|
271
|
+
import "./chunk-D3USVQIV.js";
|
|
272
272
|
import "./chunk-7T4TOGMS.js";
|
|
273
273
|
import "./chunk-7YQ6ESEA.js";
|
|
274
274
|
import "./chunk-ZXF3O7P4.js";
|
|
275
|
-
import "./chunk-
|
|
275
|
+
import "./chunk-NUBOY2LQ.js";
|
|
276
276
|
import "./chunk-PQM3B54K.js";
|
|
277
277
|
import "./chunk-K36RMINQ.js";
|
|
278
278
|
import "./chunk-2RUTN7PR.js";
|
|
@@ -287,14 +287,14 @@ import "./chunk-KNZDGZSY.js";
|
|
|
287
287
|
import "./chunk-DEGE32C3.js";
|
|
288
288
|
import "./chunk-AB3A7EFH.js";
|
|
289
289
|
import "./chunk-KIUVEMBI.js";
|
|
290
|
-
import "./chunk-
|
|
290
|
+
import "./chunk-6L62IDS6.js";
|
|
291
291
|
import "./chunk-2BPPGNAQ.js";
|
|
292
292
|
import "./chunk-DJSJ4ULL.js";
|
|
293
|
-
import "./chunk-
|
|
293
|
+
import "./chunk-G3PBNYDH.js";
|
|
294
294
|
import {
|
|
295
295
|
hasIdentityRecoveryIntent,
|
|
296
296
|
resolveEffectiveIdentityInjectionMode
|
|
297
|
-
} from "./chunk-
|
|
297
|
+
} from "./chunk-2JRLKDHV.js";
|
|
298
298
|
import "./chunk-W4F3C7N7.js";
|
|
299
299
|
import "./chunk-MPC7TYTZ.js";
|
|
300
300
|
import "./chunk-2R7OCBRR.js";
|
|
@@ -592,7 +592,7 @@ import "./chunk-ESG6ITGP.js";
|
|
|
592
592
|
import "./chunk-PCXDUHQH.js";
|
|
593
593
|
import "./chunk-VUFL7X3H.js";
|
|
594
594
|
import "./chunk-C5LWPYS3.js";
|
|
595
|
-
import "./chunk-
|
|
595
|
+
import "./chunk-CYTTY4M2.js";
|
|
596
596
|
import "./chunk-F5GVIPC7.js";
|
|
597
597
|
import "./chunk-X4OZMANG.js";
|
|
598
598
|
import "./chunk-NGHDW6UU.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./chunk-
|
|
2
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-4NDDRYBY.js";
|
|
2
|
+
import "./chunk-2JRLKDHV.js";
|
|
3
3
|
import "./chunk-W4F3C7N7.js";
|
|
4
4
|
import "./chunk-MPC7TYTZ.js";
|
|
5
5
|
import "./chunk-2R7OCBRR.js";
|
|
@@ -256,7 +256,7 @@ import "./chunk-ESG6ITGP.js";
|
|
|
256
256
|
import "./chunk-PCXDUHQH.js";
|
|
257
257
|
import "./chunk-VUFL7X3H.js";
|
|
258
258
|
import "./chunk-C5LWPYS3.js";
|
|
259
|
-
import "./chunk-
|
|
259
|
+
import "./chunk-CYTTY4M2.js";
|
|
260
260
|
import "./chunk-F5GVIPC7.js";
|
|
261
261
|
import "./chunk-X4OZMANG.js";
|
|
262
262
|
import "./chunk-NGHDW6UU.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runRecallNavigation
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2JRLKDHV.js";
|
|
4
4
|
import "./chunk-W4F3C7N7.js";
|
|
5
5
|
import "./chunk-MPC7TYTZ.js";
|
|
6
6
|
import "./chunk-2R7OCBRR.js";
|
|
@@ -257,7 +257,7 @@ import "./chunk-ESG6ITGP.js";
|
|
|
257
257
|
import "./chunk-PCXDUHQH.js";
|
|
258
258
|
import "./chunk-VUFL7X3H.js";
|
|
259
259
|
import "./chunk-C5LWPYS3.js";
|
|
260
|
-
import "./chunk-
|
|
260
|
+
import "./chunk-CYTTY4M2.js";
|
|
261
261
|
import "./chunk-F5GVIPC7.js";
|
|
262
262
|
import "./chunk-X4OZMANG.js";
|
|
263
263
|
import "./chunk-NGHDW6UU.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
SUPPORT_PASSPORT_MODEL_RESULT_PATH,
|
|
5
5
|
SupportPassportModelBridge,
|
|
6
6
|
parseSupportPassportModelJob
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-TWHVCSLX.js";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_SUPPORT_PASSPORT_CONFIG,
|
|
10
10
|
parseSupportPassportConfig
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
buildSupportPassportPublicRequestHandler,
|
|
15
15
|
composeSupportPassportExternalRequestHandlers,
|
|
16
16
|
normalizeSupportPassportNetworkAddress
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-5HVEYVNQ.js";
|
|
18
|
+
import "../chunk-LXDERMOU.js";
|
|
19
19
|
import {
|
|
20
20
|
SUPPORT_PASSPORT_DRAFT_MAX_CONTENT_CHARACTERS,
|
|
21
21
|
SUPPORT_PASSPORT_DRAFT_MAX_MEMORIES,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
notifySupportPassportCommitted,
|
|
57
57
|
resolveSupportPassportModelRoutePlan,
|
|
58
58
|
syncDirectoryForDurability
|
|
59
|
-
} from "../chunk-
|
|
59
|
+
} from "../chunk-2JRLKDHV.js";
|
|
60
60
|
import "../chunk-W4F3C7N7.js";
|
|
61
61
|
import "../chunk-MPC7TYTZ.js";
|
|
62
62
|
import "../chunk-2R7OCBRR.js";
|
|
@@ -344,7 +344,7 @@ import "../chunk-ESG6ITGP.js";
|
|
|
344
344
|
import "../chunk-PCXDUHQH.js";
|
|
345
345
|
import "../chunk-VUFL7X3H.js";
|
|
346
346
|
import "../chunk-C5LWPYS3.js";
|
|
347
|
-
import "../chunk-
|
|
347
|
+
import "../chunk-CYTTY4M2.js";
|
|
348
348
|
import "../chunk-F5GVIPC7.js";
|
|
349
349
|
import "../chunk-X4OZMANG.js";
|
|
350
350
|
import "../chunk-NGHDW6UU.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.77",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3386,7 +3386,7 @@
|
|
|
3386
3386
|
"core"
|
|
3387
3387
|
],
|
|
3388
3388
|
"peerDependencies": {
|
|
3389
|
-
"@remnic/coding-graph": "^10.0.
|
|
3389
|
+
"@remnic/coding-graph": "^10.0.77"
|
|
3390
3390
|
},
|
|
3391
3391
|
"peerDependenciesMeta": {
|
|
3392
3392
|
"@remnic/coding-graph": {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
2
4
|
/**
|
|
3
5
|
* PendingObserveExtractionTracker settle hygiene — issue: `track`'s settle
|
|
4
6
|
* callback only removed the pending entry when the extraction SUCCEEDED or
|
|
@@ -70,3 +72,157 @@ test("a wait overlapping a failing extraction still surfaces the error", async (
|
|
|
70
72
|
reject(new Error("extraction failed"));
|
|
71
73
|
await waiter;
|
|
72
74
|
});
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Controller retention — issue: `track` copied every prior controller of the
|
|
78
|
+
* key into a fresh Set per tracked extraction, and never-settling promise
|
|
79
|
+
* chains keep every generation reachable, so overlapping stalled tracks grew
|
|
80
|
+
* quadratically (HeapRepro: ~543MB at 6000 tracks; measured 212.8MB at 4000
|
|
81
|
+
* pre-fix vs 4.2MB with the shared per-key set). The fix reuses one Set per
|
|
82
|
+
* key; `abortTracked` iterates a snapshot so a reentrant `track` fired from
|
|
83
|
+
* an abort listener keeps prior semantics (not aborted by the in-flight
|
|
84
|
+
* pass, iteration terminates).
|
|
85
|
+
*/
|
|
86
|
+
function stalled(): Promise<void> {
|
|
87
|
+
const { promise } = Promise.withResolvers<void>();
|
|
88
|
+
return promise;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function rejectingAfter(controller: AbortController): Promise<void> {
|
|
92
|
+
const { promise, reject } = Promise.withResolvers<void>();
|
|
93
|
+
controller.signal.addEventListener("abort", () => reject(controller.signal.reason), { once: true });
|
|
94
|
+
return promise;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Runs the retention loop in one short-lived child process with --expose-gc,
|
|
98
|
+
// so CI exercises it without exposing gc to the whole test tree. The
|
|
99
|
+
// assertion keeps a wide margin (4.2MB measured post-fix vs 212.8MB pre-fix
|
|
100
|
+
// at the same track count), not a fixed runner heap limit.
|
|
101
|
+
function drain(stream: NodeJS.ReadableStream): Promise<string> {
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
const chunks: string[] = [];
|
|
104
|
+
stream.on("data", (chunk) => chunks.push(String(chunk)));
|
|
105
|
+
stream.on("end", () => resolve(chunks.join("")));
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function retainedHeapInChild(): Promise<number> {
|
|
110
|
+
const trackerSource = fileURLToPath(new URL("./access-observe-helpers.js", import.meta.url));
|
|
111
|
+
const child = spawn(
|
|
112
|
+
process.execPath,
|
|
113
|
+
[
|
|
114
|
+
"--expose-gc",
|
|
115
|
+
"--input-type=module",
|
|
116
|
+
"--import",
|
|
117
|
+
"tsx",
|
|
118
|
+
"-e",
|
|
119
|
+
`import { pathToFileURL } from "node:url";
|
|
120
|
+
const { PendingObserveExtractionTracker } = await import(pathToFileURL(process.argv.at(-1)));
|
|
121
|
+
gc();
|
|
122
|
+
const before = process.memoryUsage().heapUsed;
|
|
123
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
124
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
125
|
+
for (let i = 0; i < 4000; i++) tracker.track(key, new Promise(() => {}), new AbortController());
|
|
126
|
+
gc();
|
|
127
|
+
console.log(JSON.stringify(process.memoryUsage().heapUsed - before));`,
|
|
128
|
+
trackerSource,
|
|
129
|
+
],
|
|
130
|
+
{ cwd: fileURLToPath(new URL("..", import.meta.url)), stdio: ["ignore", "pipe", "pipe"] },
|
|
131
|
+
);
|
|
132
|
+
const [stdout, stderr, code] = await Promise.all([
|
|
133
|
+
drain(child.stdout),
|
|
134
|
+
drain(child.stderr),
|
|
135
|
+
new Promise<number | null>((resolve) => child.on("close", resolve)),
|
|
136
|
+
]);
|
|
137
|
+
assert.equal(code, 0, `retention child failed (${code}): ${stderr.slice(0, 400)}`);
|
|
138
|
+
const lastLine = stdout.trim().split("\n").at(-1);
|
|
139
|
+
assert.ok(lastLine !== undefined, `retention child printed no output: ${stderr.slice(0, 400)}`);
|
|
140
|
+
return JSON.parse(lastLine);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
test("retained heap stays bounded across overlapping stalled tracks", { timeout: 15000 }, async () => {
|
|
144
|
+
const retained = await retainedHeapInChild();
|
|
145
|
+
assert.ok(
|
|
146
|
+
retained < 32 * 1024 * 1024,
|
|
147
|
+
`retained ${(retained / 1048576).toFixed(1)}MB for 4000 tracks; quadratic controller-set copies keep dead generations alive`,
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("cancel still aborts every distinct controller across overlapping tracks", () => {
|
|
152
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
153
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
154
|
+
const controllers = Array.from({ length: 50 }, () => new AbortController());
|
|
155
|
+
for (const controller of controllers) {
|
|
156
|
+
tracker.track(key, stalled(), controller);
|
|
157
|
+
}
|
|
158
|
+
tracker.cancel("session-a", "alice", "default");
|
|
159
|
+
for (const controller of controllers) {
|
|
160
|
+
assert.ok(controller.signal.aborted, "every tracked controller must be aborted");
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("a controller admitted by a reentrant track during cancel is not aborted by that pass", () => {
|
|
165
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
166
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
167
|
+
const first = new AbortController();
|
|
168
|
+
const reentrant = new AbortController();
|
|
169
|
+
first.signal.addEventListener(
|
|
170
|
+
"abort",
|
|
171
|
+
() => {
|
|
172
|
+
tracker.track(key, stalled(), reentrant);
|
|
173
|
+
},
|
|
174
|
+
{ once: true },
|
|
175
|
+
);
|
|
176
|
+
tracker.track(key, stalled(), first);
|
|
177
|
+
tracker.cancel("session-a", "alice", "default");
|
|
178
|
+
assert.ok(first.signal.aborted);
|
|
179
|
+
assert.equal(reentrant.signal.aborted, false, "prior behavior: the in-flight abort pass must not abort later admissions");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("each key aborts and cleans up in isolation", { timeout: 2000 }, async () => {
|
|
183
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
184
|
+
const keyA = tracker.key("session-a", "alice", "default");
|
|
185
|
+
const keyB = tracker.key("session-b", "bob", "default");
|
|
186
|
+
const controllerA = new AbortController();
|
|
187
|
+
const controllerB = new AbortController();
|
|
188
|
+
tracker.track(keyA, rejectingAfter(controllerA), controllerA);
|
|
189
|
+
tracker.track(keyB, stalled(), controllerB);
|
|
190
|
+
tracker.cancel("session-a", "alice", "default");
|
|
191
|
+
assert.ok(controllerA.signal.aborted);
|
|
192
|
+
assert.equal(controllerB.signal.aborted, false);
|
|
193
|
+
await settle();
|
|
194
|
+
await tracker.wait("session-a", "alice", "default");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("an aborted chain entry settles once every generation settles and cleans up", { timeout: 2000 }, async () => {
|
|
198
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
199
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
200
|
+
const first = new AbortController();
|
|
201
|
+
tracker.track(key, rejectingAfter(first), first);
|
|
202
|
+
const second = new AbortController();
|
|
203
|
+
const { promise: secondExtraction, resolve } = Promise.withResolvers<void>();
|
|
204
|
+
tracker.track(key, secondExtraction, second);
|
|
205
|
+
first.abort(preemptedExtractionError());
|
|
206
|
+
resolve();
|
|
207
|
+
await settle();
|
|
208
|
+
await tracker.wait("session-a", "alice", "default");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("wait surfaces a chained non-preempted rejection", async () => {
|
|
212
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
213
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
214
|
+
tracker.track(key, Promise.resolve(), new AbortController());
|
|
215
|
+
tracker.track(key, Promise.reject(new Error("extraction failed")), new AbortController());
|
|
216
|
+
await assert.rejects(tracker.wait("session-a", "alice", "default"), /extraction failed/);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("a wait overlapping a preempted rejection returns without throwing", { timeout: 2000 }, async () => {
|
|
220
|
+
const tracker = new PendingObserveExtractionTracker();
|
|
221
|
+
const key = tracker.key("session-a", "alice", "default");
|
|
222
|
+
const controller = new AbortController();
|
|
223
|
+
tracker.track(key, rejectingAfter(controller), controller);
|
|
224
|
+
const waiter = tracker.wait("session-a", "alice", "default");
|
|
225
|
+
await Promise.resolve();
|
|
226
|
+
controller.abort(preemptedExtractionError());
|
|
227
|
+
await waiter;
|
|
228
|
+
});
|
|
@@ -142,11 +142,9 @@ export class PendingObserveExtractionTracker {
|
|
|
142
142
|
if (rejected) throw rejected.reason;
|
|
143
143
|
})
|
|
144
144
|
: extraction;
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
controllers: new Set(previous ? [...previous.controllers, controller] : [controller]),
|
|
149
|
-
};
|
|
145
|
+
const controllers = previous?.controllers ?? new Set<AbortController>();
|
|
146
|
+
controllers.add(controller);
|
|
147
|
+
const entry = { promise, running: previous?.running ?? extraction, controllers };
|
|
150
148
|
this.entries.set(key, entry);
|
|
151
149
|
// Any settle (success OR rejection — preemption is just one rejection
|
|
152
150
|
// kind) ends the pending entry; leaving a settled failure tracked wedged
|
|
@@ -201,7 +199,9 @@ export class PendingObserveExtractionTracker {
|
|
|
201
199
|
(principal !== undefined && entryPrincipal !== (principal ?? "")) ||
|
|
202
200
|
(namespace !== undefined && entryNamespace !== (namespace ?? ""))
|
|
203
201
|
) continue;
|
|
204
|
-
|
|
202
|
+
// Snapshot: an abort listener may track() synchronously; iterating the
|
|
203
|
+
// shared live set would abort that new admission or never terminate.
|
|
204
|
+
for (const controller of [...entry.controllers]) controller.abort(reason);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|