@remnic/core 9.3.761 → 9.3.762
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 +9 -8
- package/dist/access-boundary.js +10 -9
- package/dist/access-cli.js +44 -43
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.js +16 -15
- package/dist/access-identity-continuity-surface.js +9 -8
- package/dist/access-lcm-surface.js +9 -8
- package/dist/access-mcp.js +13 -12
- package/dist/access-observe-write-surface.js +9 -8
- package/dist/access-operations-batch.js +11 -10
- package/dist/access-operations.js +12 -11
- package/dist/access-recall-surface.js +9 -8
- package/dist/access-service.js +9 -8
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +4 -3
- package/dist/causal-consolidation.js +5 -4
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-4WOXD56B.js → chunk-2KYXXMTE.js} +5 -5
- package/dist/{chunk-HP23UD6W.js → chunk-2PGB63VU.js} +2 -2
- package/dist/{chunk-2B3BTQN4.js → chunk-4HYJETVO.js} +2 -2
- package/dist/{chunk-APJQ6UEA.js → chunk-AGNBY3VG.js} +4 -4
- package/dist/{chunk-ICVNVSKN.js → chunk-BRYPUVJU.js} +2 -2
- package/dist/{chunk-IRFHFRHP.js → chunk-DB647OZ4.js} +24 -24
- package/dist/{chunk-LG2MCUBC.js → chunk-DPZ5GJMD.js} +2 -2
- package/dist/chunk-DQC3ZZYM.js +35 -0
- package/dist/chunk-DQC3ZZYM.js.map +1 -0
- package/dist/{chunk-W4ADKEIY.js → chunk-EDC7RZCW.js} +22 -22
- package/dist/{chunk-DUU4VLOW.js → chunk-ES3GAMSQ.js} +2 -2
- package/dist/{chunk-5AZQZFJG.js → chunk-ESDBHQY6.js} +5 -5
- package/dist/{chunk-IV4INTAU.js → chunk-HDFS6RWQ.js} +2 -2
- package/dist/{chunk-P7UA66OG.js → chunk-HDYFNXVO.js} +2 -2
- package/dist/{chunk-YU4CLTZY.js → chunk-HMUEAKSD.js} +2 -2
- package/dist/{chunk-XDFWMY4X.js → chunk-IIURIWJG.js} +102 -12
- package/dist/chunk-IIURIWJG.js.map +1 -0
- package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
- package/dist/{chunk-Y3XEN5TL.js → chunk-JU6BKZHX.js} +3 -3
- package/dist/{chunk-NPZTEHR7.js → chunk-KZWUJC7Y.js} +2 -2
- package/dist/{chunk-3CBSKDRL.js → chunk-LAJIXABF.js} +8 -8
- package/dist/{chunk-3QLPBCFG.js → chunk-NKP6II6G.js} +4 -4
- package/dist/{chunk-742MWWVL.js → chunk-OQ6F3WBX.js} +2 -2
- package/dist/{chunk-3DAIQSVS.js → chunk-P7W4CDX6.js} +13 -6
- package/dist/chunk-P7W4CDX6.js.map +1 -0
- package/dist/{chunk-HHCMZEUC.js → chunk-PNFN7SIN.js} +2 -2
- package/dist/{chunk-P7N2DQLC.js → chunk-QPFO54VC.js} +3 -3
- package/dist/{chunk-ZAIU7ZEA.js → chunk-QWIE43BS.js} +2 -2
- package/dist/chunk-TEKTCF2V.js +118 -0
- package/dist/chunk-TEKTCF2V.js.map +1 -0
- package/dist/{chunk-CFHDI5CV.js → chunk-TIWRP5NW.js} +4 -4
- package/dist/{chunk-CXW6Y7SI.js → chunk-V5RVMULT.js} +4 -4
- package/dist/{chunk-6S2C5FQ4.js → chunk-VHYFY3JI.js} +2 -2
- package/dist/{chunk-JYH3XYWM.js → chunk-WAIMHMO3.js} +3 -3
- package/dist/{chunk-OCPVA4TH.js → chunk-ZTBH2OHD.js} +2 -2
- package/dist/cli.js +33 -32
- package/dist/compounding/engine.js +4 -3
- package/dist/connectors/codex-materialize-runner.js +4 -3
- package/dist/connectors/index.js +4 -3
- package/dist/entity-retrieval.js +4 -3
- package/dist/{forget-OEE5OELK.js → forget-WYLR4ZFV.js} +2 -2
- package/dist/index.js +46 -45
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +4 -4
- package/dist/maintenance/memory-governance.js +4 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +11 -1
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -3
- package/dist/maintenance/rebuild-memory-projection.d.ts +22 -1
- package/dist/maintenance/rebuild-memory-projection.js +5 -4
- package/dist/namespaces/migrate.js +8 -7
- package/dist/namespaces/search.js +3 -3
- package/dist/namespaces/storage.js +4 -3
- package/dist/operator-toolkit.js +11 -10
- package/dist/orchestration/maintenance.js +6 -5
- package/dist/orchestrator.js +44 -43
- package/dist/schemas.d.ts +22 -22
- package/dist/search/factory.js +2 -2
- package/dist/search/index.js +4 -4
- package/dist/semantic-consolidation.js +5 -4
- package/dist/semantic-rule-promotion.js +4 -3
- package/dist/semantic-rule-verifier.js +4 -3
- package/dist/storage-guards.d.ts +9 -0
- package/dist/storage-guards.js +11 -0
- package/dist/storage-guards.js.map +1 -0
- package/dist/storage.js +3 -2
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/transfer/types.d.ts +12 -12
- package/dist/verified-recall.js +4 -3
- package/package.json +2 -2
- package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +59 -8
- package/src/maintenance/rebuild-memory-projection.ts +149 -9
- package/src/storage-guards.ts +30 -0
- package/src/storage.ts +8 -8
- package/dist/chunk-3DAIQSVS.js.map +0 -1
- package/dist/chunk-GYJESQS5.js +0 -77
- package/dist/chunk-GYJESQS5.js.map +0 -1
- package/dist/chunk-XDFWMY4X.js.map +0 -1
- /package/dist/{chunk-4WOXD56B.js.map → chunk-2KYXXMTE.js.map} +0 -0
- /package/dist/{chunk-HP23UD6W.js.map → chunk-2PGB63VU.js.map} +0 -0
- /package/dist/{chunk-2B3BTQN4.js.map → chunk-4HYJETVO.js.map} +0 -0
- /package/dist/{chunk-APJQ6UEA.js.map → chunk-AGNBY3VG.js.map} +0 -0
- /package/dist/{chunk-ICVNVSKN.js.map → chunk-BRYPUVJU.js.map} +0 -0
- /package/dist/{chunk-IRFHFRHP.js.map → chunk-DB647OZ4.js.map} +0 -0
- /package/dist/{chunk-LG2MCUBC.js.map → chunk-DPZ5GJMD.js.map} +0 -0
- /package/dist/{chunk-W4ADKEIY.js.map → chunk-EDC7RZCW.js.map} +0 -0
- /package/dist/{chunk-DUU4VLOW.js.map → chunk-ES3GAMSQ.js.map} +0 -0
- /package/dist/{chunk-5AZQZFJG.js.map → chunk-ESDBHQY6.js.map} +0 -0
- /package/dist/{chunk-IV4INTAU.js.map → chunk-HDFS6RWQ.js.map} +0 -0
- /package/dist/{chunk-P7UA66OG.js.map → chunk-HDYFNXVO.js.map} +0 -0
- /package/dist/{chunk-YU4CLTZY.js.map → chunk-HMUEAKSD.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-Y3XEN5TL.js.map → chunk-JU6BKZHX.js.map} +0 -0
- /package/dist/{chunk-NPZTEHR7.js.map → chunk-KZWUJC7Y.js.map} +0 -0
- /package/dist/{chunk-3CBSKDRL.js.map → chunk-LAJIXABF.js.map} +0 -0
- /package/dist/{chunk-3QLPBCFG.js.map → chunk-NKP6II6G.js.map} +0 -0
- /package/dist/{chunk-742MWWVL.js.map → chunk-OQ6F3WBX.js.map} +0 -0
- /package/dist/{chunk-HHCMZEUC.js.map → chunk-PNFN7SIN.js.map} +0 -0
- /package/dist/{chunk-P7N2DQLC.js.map → chunk-QPFO54VC.js.map} +0 -0
- /package/dist/{chunk-ZAIU7ZEA.js.map → chunk-QWIE43BS.js.map} +0 -0
- /package/dist/{chunk-CFHDI5CV.js.map → chunk-TIWRP5NW.js.map} +0 -0
- /package/dist/{chunk-CXW6Y7SI.js.map → chunk-V5RVMULT.js.map} +0 -0
- /package/dist/{chunk-6S2C5FQ4.js.map → chunk-VHYFY3JI.js.map} +0 -0
- /package/dist/{chunk-JYH3XYWM.js.map → chunk-WAIMHMO3.js.map} +0 -0
- /package/dist/{chunk-OCPVA4TH.js.map → chunk-ZTBH2OHD.js.map} +0 -0
- /package/dist/{forget-OEE5OELK.js.map → forget-WYLR4ZFV.js.map} +0 -0
package/dist/transfer/types.d.ts
CHANGED
|
@@ -313,13 +313,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
313
313
|
peerProfiles: boolean;
|
|
314
314
|
}>;
|
|
315
315
|
}, "strip", z.ZodTypeAny, {
|
|
316
|
+
schemaVersion: string;
|
|
316
317
|
includes: {
|
|
317
318
|
procedural: boolean;
|
|
318
319
|
taxonomy: boolean;
|
|
319
320
|
identityAnchors: boolean;
|
|
320
321
|
peerProfiles: boolean;
|
|
321
322
|
};
|
|
322
|
-
schemaVersion: string;
|
|
323
323
|
id: string;
|
|
324
324
|
version: string;
|
|
325
325
|
description: string;
|
|
@@ -334,13 +334,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
334
334
|
forkRoot: string;
|
|
335
335
|
} | null;
|
|
336
336
|
}, {
|
|
337
|
+
schemaVersion: string;
|
|
337
338
|
includes: {
|
|
338
339
|
procedural: boolean;
|
|
339
340
|
taxonomy: boolean;
|
|
340
341
|
identityAnchors: boolean;
|
|
341
342
|
peerProfiles: boolean;
|
|
342
343
|
};
|
|
343
|
-
schemaVersion: string;
|
|
344
344
|
id: string;
|
|
345
345
|
version: string;
|
|
346
346
|
description: string;
|
|
@@ -464,13 +464,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
464
464
|
peerProfiles: boolean;
|
|
465
465
|
}>;
|
|
466
466
|
}, "strip", z.ZodTypeAny, {
|
|
467
|
+
schemaVersion: string;
|
|
467
468
|
includes: {
|
|
468
469
|
procedural: boolean;
|
|
469
470
|
taxonomy: boolean;
|
|
470
471
|
identityAnchors: boolean;
|
|
471
472
|
peerProfiles: boolean;
|
|
472
473
|
};
|
|
473
|
-
schemaVersion: string;
|
|
474
474
|
id: string;
|
|
475
475
|
version: string;
|
|
476
476
|
description: string;
|
|
@@ -485,13 +485,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
485
485
|
forkRoot: string;
|
|
486
486
|
} | null;
|
|
487
487
|
}, {
|
|
488
|
+
schemaVersion: string;
|
|
488
489
|
includes: {
|
|
489
490
|
procedural: boolean;
|
|
490
491
|
taxonomy: boolean;
|
|
491
492
|
identityAnchors: boolean;
|
|
492
493
|
peerProfiles: boolean;
|
|
493
494
|
};
|
|
494
|
-
schemaVersion: string;
|
|
495
495
|
id: string;
|
|
496
496
|
version: string;
|
|
497
497
|
description: string;
|
|
@@ -518,13 +518,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
518
518
|
pluginVersion: string;
|
|
519
519
|
includesTranscripts: boolean;
|
|
520
520
|
capsule: {
|
|
521
|
+
schemaVersion: string;
|
|
521
522
|
includes: {
|
|
522
523
|
procedural: boolean;
|
|
523
524
|
taxonomy: boolean;
|
|
524
525
|
identityAnchors: boolean;
|
|
525
526
|
peerProfiles: boolean;
|
|
526
527
|
};
|
|
527
|
-
schemaVersion: string;
|
|
528
528
|
id: string;
|
|
529
529
|
version: string;
|
|
530
530
|
description: string;
|
|
@@ -551,13 +551,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
551
551
|
pluginVersion: string;
|
|
552
552
|
includesTranscripts: boolean;
|
|
553
553
|
capsule: {
|
|
554
|
+
schemaVersion: string;
|
|
554
555
|
includes: {
|
|
555
556
|
procedural: boolean;
|
|
556
557
|
taxonomy: boolean;
|
|
557
558
|
identityAnchors: boolean;
|
|
558
559
|
peerProfiles: boolean;
|
|
559
560
|
};
|
|
560
|
-
schemaVersion: string;
|
|
561
561
|
id: string;
|
|
562
562
|
version: string;
|
|
563
563
|
description: string;
|
|
@@ -683,13 +683,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
683
683
|
peerProfiles: boolean;
|
|
684
684
|
}>;
|
|
685
685
|
}, "strip", z.ZodTypeAny, {
|
|
686
|
+
schemaVersion: string;
|
|
686
687
|
includes: {
|
|
687
688
|
procedural: boolean;
|
|
688
689
|
taxonomy: boolean;
|
|
689
690
|
identityAnchors: boolean;
|
|
690
691
|
peerProfiles: boolean;
|
|
691
692
|
};
|
|
692
|
-
schemaVersion: string;
|
|
693
693
|
id: string;
|
|
694
694
|
version: string;
|
|
695
695
|
description: string;
|
|
@@ -704,13 +704,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
704
704
|
forkRoot: string;
|
|
705
705
|
} | null;
|
|
706
706
|
}, {
|
|
707
|
+
schemaVersion: string;
|
|
707
708
|
includes: {
|
|
708
709
|
procedural: boolean;
|
|
709
710
|
taxonomy: boolean;
|
|
710
711
|
identityAnchors: boolean;
|
|
711
712
|
peerProfiles: boolean;
|
|
712
713
|
};
|
|
713
|
-
schemaVersion: string;
|
|
714
714
|
id: string;
|
|
715
715
|
version: string;
|
|
716
716
|
description: string;
|
|
@@ -737,13 +737,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
737
737
|
pluginVersion: string;
|
|
738
738
|
includesTranscripts: boolean;
|
|
739
739
|
capsule: {
|
|
740
|
+
schemaVersion: string;
|
|
740
741
|
includes: {
|
|
741
742
|
procedural: boolean;
|
|
742
743
|
taxonomy: boolean;
|
|
743
744
|
identityAnchors: boolean;
|
|
744
745
|
peerProfiles: boolean;
|
|
745
746
|
};
|
|
746
|
-
schemaVersion: string;
|
|
747
747
|
id: string;
|
|
748
748
|
version: string;
|
|
749
749
|
description: string;
|
|
@@ -770,13 +770,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
770
770
|
pluginVersion: string;
|
|
771
771
|
includesTranscripts: boolean;
|
|
772
772
|
capsule: {
|
|
773
|
+
schemaVersion: string;
|
|
773
774
|
includes: {
|
|
774
775
|
procedural: boolean;
|
|
775
776
|
taxonomy: boolean;
|
|
776
777
|
identityAnchors: boolean;
|
|
777
778
|
peerProfiles: boolean;
|
|
778
779
|
};
|
|
779
|
-
schemaVersion: string;
|
|
780
780
|
id: string;
|
|
781
781
|
version: string;
|
|
782
782
|
description: string;
|
|
@@ -815,13 +815,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
815
815
|
pluginVersion: string;
|
|
816
816
|
includesTranscripts: boolean;
|
|
817
817
|
capsule: {
|
|
818
|
+
schemaVersion: string;
|
|
818
819
|
includes: {
|
|
819
820
|
procedural: boolean;
|
|
820
821
|
taxonomy: boolean;
|
|
821
822
|
identityAnchors: boolean;
|
|
822
823
|
peerProfiles: boolean;
|
|
823
824
|
};
|
|
824
|
-
schemaVersion: string;
|
|
825
825
|
id: string;
|
|
826
826
|
version: string;
|
|
827
827
|
description: string;
|
|
@@ -854,13 +854,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
854
854
|
pluginVersion: string;
|
|
855
855
|
includesTranscripts: boolean;
|
|
856
856
|
capsule: {
|
|
857
|
+
schemaVersion: string;
|
|
857
858
|
includes: {
|
|
858
859
|
procedural: boolean;
|
|
859
860
|
taxonomy: boolean;
|
|
860
861
|
identityAnchors: boolean;
|
|
861
862
|
peerProfiles: boolean;
|
|
862
863
|
};
|
|
863
|
-
schemaVersion: string;
|
|
864
864
|
id: string;
|
|
865
865
|
version: string;
|
|
866
866
|
description: string;
|
package/dist/verified-recall.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareVerifiedEpisodeResults,
|
|
3
3
|
searchVerifiedEpisodes
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4HYJETVO.js";
|
|
5
5
|
import "./chunk-7FL4CNPV.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-P7W4CDX6.js";
|
|
7
7
|
import "./chunk-M7XQSUBB.js";
|
|
8
8
|
import "./chunk-L2B3EE7B.js";
|
|
9
9
|
import "./chunk-5UZXUTVO.js";
|
|
10
10
|
import "./chunk-5GPPACXK.js";
|
|
11
|
+
import "./chunk-LTJAMRGI.js";
|
|
11
12
|
import "./chunk-TKZ3AL5V.js";
|
|
12
13
|
import "./chunk-6CIAGZ6X.js";
|
|
13
14
|
import "./chunk-J6A3CX5N.js";
|
|
15
|
+
import "./chunk-DQC3ZZYM.js";
|
|
14
16
|
import "./chunk-SVOZFLIQ.js";
|
|
15
|
-
import "./chunk-LTJAMRGI.js";
|
|
16
17
|
import "./chunk-JS2HKKOK.js";
|
|
17
18
|
import "./chunk-AWJ2FHCF.js";
|
|
18
19
|
import "./chunk-42JKGUFJ.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.762",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3000,7 +3000,7 @@
|
|
|
3000
3000
|
"core"
|
|
3001
3001
|
],
|
|
3002
3002
|
"peerDependencies": {
|
|
3003
|
-
"@remnic/coding-graph": "^9.3.
|
|
3003
|
+
"@remnic/coding-graph": "^9.3.762"
|
|
3004
3004
|
},
|
|
3005
3005
|
"peerDependenciesMeta": {
|
|
3006
3006
|
"@remnic/coding-graph": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import { StorageManager } from "../storage.js";
|
|
4
|
+
import { log } from "../logger.js";
|
|
4
5
|
import type { MemoryLifecycleEvent } from "../types.js";
|
|
5
6
|
import { toBackupStamp } from "./backup-stamp.js";
|
|
6
7
|
import { writeFileAtomically } from "./atomic-file.js";
|
|
@@ -15,12 +16,24 @@ export interface RebuildMemoryLifecycleLedgerOptions {
|
|
|
15
16
|
now?: Date;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
export interface SkippedLifecycleBlankIdMemory {
|
|
20
|
+
path: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SkippedDuplicateLifecycleEvent {
|
|
24
|
+
eventId: string;
|
|
25
|
+
keptPath: string;
|
|
26
|
+
skippedPath: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
export interface RebuildMemoryLifecycleLedgerResult {
|
|
19
30
|
dryRun: boolean;
|
|
20
31
|
scannedMemories: number;
|
|
21
32
|
rebuiltRows: number;
|
|
22
33
|
outputPath: string;
|
|
23
34
|
backupPath?: string;
|
|
35
|
+
skippedBlankIdMemories: SkippedLifecycleBlankIdMemory[];
|
|
36
|
+
skippedDuplicateEvents: SkippedDuplicateLifecycleEvent[];
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
function isNodeError(err: unknown): err is NodeJS.ErrnoException {
|
|
@@ -59,16 +72,52 @@ export async function rebuildMemoryLifecycleLedger(
|
|
|
59
72
|
const now = options.now ?? new Date();
|
|
60
73
|
const outputPath = path.join(options.memoryDir, "state", "memory-lifecycle-ledger.jsonl");
|
|
61
74
|
const storage = new StorageManager(options.memoryDir);
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
]
|
|
67
|
-
|
|
75
|
+
const tiers = [
|
|
76
|
+
await storage.readAllMemories(),
|
|
77
|
+
await storage.readAllColdMemories(),
|
|
78
|
+
await storage.readArchivedMemories(),
|
|
79
|
+
];
|
|
80
|
+
const allMemories = tiers.flat();
|
|
81
|
+
const skippedBlankIdMemories: SkippedLifecycleBlankIdMemory[] = [];
|
|
82
|
+
const eventCandidates: Array<{ event: MemoryLifecycleEvent; path: string }> = [];
|
|
83
|
+
for (const tier of tiers) {
|
|
84
|
+
for (const memory of [...tier].sort((left, right) => left.path.localeCompare(right.path))) {
|
|
85
|
+
if (!memory.frontmatter.id.trim()) {
|
|
86
|
+
skippedBlankIdMemories.push({ path: memory.path });
|
|
87
|
+
log.warn(`lifecycle ledger rebuild skipped blank memory id: path=${memory.path}`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
for (const event of buildLifecycleEventsForMemory(memory)) {
|
|
91
|
+
eventCandidates.push({ event, path: memory.path });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
68
95
|
|
|
69
|
-
const
|
|
70
|
-
|
|
96
|
+
const orderedEvents = sortMemoryLifecycleEvents(eventCandidates.map((candidate) => candidate.event));
|
|
97
|
+
const candidateByEvent = new Map(
|
|
98
|
+
eventCandidates.map((candidate) => [candidate.event, candidate]),
|
|
71
99
|
);
|
|
100
|
+
const keptByEventId = new Map<string, { event: MemoryLifecycleEvent; path: string }>();
|
|
101
|
+
const events: MemoryLifecycleEvent[] = [];
|
|
102
|
+
const skippedDuplicateEvents: SkippedDuplicateLifecycleEvent[] = [];
|
|
103
|
+
for (const event of orderedEvents) {
|
|
104
|
+
const candidate = candidateByEvent.get(event)!;
|
|
105
|
+
const kept = keptByEventId.get(event.eventId);
|
|
106
|
+
if (kept) {
|
|
107
|
+
skippedDuplicateEvents.push({
|
|
108
|
+
eventId: event.eventId,
|
|
109
|
+
keptPath: kept.path,
|
|
110
|
+
skippedPath: candidate.path,
|
|
111
|
+
});
|
|
112
|
+
log.warn(
|
|
113
|
+
`lifecycle ledger rebuild skipped duplicate event_id=${event.eventId}: `
|
|
114
|
+
+ `kept=${kept.path} skipped=${candidate.path}`,
|
|
115
|
+
);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
keptByEventId.set(event.eventId, candidate);
|
|
119
|
+
events.push(event);
|
|
120
|
+
}
|
|
72
121
|
|
|
73
122
|
let backupPath: string | undefined;
|
|
74
123
|
if (!dryRun) {
|
|
@@ -87,5 +136,7 @@ export async function rebuildMemoryLifecycleLedger(
|
|
|
87
136
|
rebuiltRows: events.length,
|
|
88
137
|
outputPath,
|
|
89
138
|
backupPath,
|
|
139
|
+
skippedBlankIdMemories,
|
|
140
|
+
skippedDuplicateEvents,
|
|
90
141
|
};
|
|
91
142
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { mkdir, rm, stat } from "node:fs/promises";
|
|
3
3
|
import { StorageManager } from "../storage.js";
|
|
4
|
+
import { log } from "../logger.js";
|
|
4
5
|
import {
|
|
5
6
|
listMemoryGovernanceRuns,
|
|
6
7
|
readMemoryGovernanceRunArtifact,
|
|
@@ -51,6 +52,27 @@ export interface RebuildMemoryProjectionOptions {
|
|
|
51
52
|
updatedBefore?: string;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
export interface SkippedDuplicateMemory {
|
|
56
|
+
memoryId: string;
|
|
57
|
+
keptPath: string;
|
|
58
|
+
skippedPath: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SkippedBlankIdMemory {
|
|
62
|
+
path: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface SkippedDuplicateTimelineEvent {
|
|
66
|
+
eventId: string;
|
|
67
|
+
keptPath: string;
|
|
68
|
+
skippedPath: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface SkippedBlankIdTimelineEvent {
|
|
72
|
+
eventId: string;
|
|
73
|
+
path: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
54
76
|
export interface RebuildMemoryProjectionResult {
|
|
55
77
|
dryRun: boolean;
|
|
56
78
|
scannedMemories: number;
|
|
@@ -62,6 +84,10 @@ export interface RebuildMemoryProjectionResult {
|
|
|
62
84
|
outputPath: string;
|
|
63
85
|
backupPath?: string;
|
|
64
86
|
usedLifecycleLedger: boolean;
|
|
87
|
+
skippedDuplicateMemories: SkippedDuplicateMemory[];
|
|
88
|
+
skippedBlankIdMemories: SkippedBlankIdMemory[];
|
|
89
|
+
skippedDuplicateTimelineEvents: SkippedDuplicateTimelineEvent[];
|
|
90
|
+
skippedBlankIdTimelineEvents: SkippedBlankIdTimelineEvent[];
|
|
65
91
|
scope: {
|
|
66
92
|
updatedAfter: string | null;
|
|
67
93
|
updatedBefore: string | null;
|
|
@@ -435,6 +461,91 @@ function serializeGovernanceReviewQueueRow(
|
|
|
435
461
|
});
|
|
436
462
|
}
|
|
437
463
|
|
|
464
|
+
function selectProjectionMemories(
|
|
465
|
+
tiers: MemoryFile[][],
|
|
466
|
+
): {
|
|
467
|
+
allMemories: MemoryFile[];
|
|
468
|
+
memories: MemoryFile[];
|
|
469
|
+
skippedDuplicateMemories: SkippedDuplicateMemory[];
|
|
470
|
+
skippedBlankIdMemories: SkippedBlankIdMemory[];
|
|
471
|
+
} {
|
|
472
|
+
const allMemories = tiers.flat();
|
|
473
|
+
const memories: MemoryFile[] = [];
|
|
474
|
+
const keptById = new Map<string, MemoryFile>();
|
|
475
|
+
const skippedDuplicateMemories: SkippedDuplicateMemory[] = [];
|
|
476
|
+
const skippedBlankIdMemories: SkippedBlankIdMemory[] = [];
|
|
477
|
+
|
|
478
|
+
// Tier order is authoritative: hot wins over cold, and cold wins over archive.
|
|
479
|
+
// Paths break ties within a tier so the winner does not depend on readdir order.
|
|
480
|
+
for (const tier of tiers) {
|
|
481
|
+
for (const memory of [...tier].sort((left, right) => left.path.localeCompare(right.path))) {
|
|
482
|
+
const memoryId = memory.frontmatter.id.trim();
|
|
483
|
+
if (!memoryId) {
|
|
484
|
+
skippedBlankIdMemories.push({ path: memory.path });
|
|
485
|
+
log.warn(`projection rebuild skipped blank memory id: path=${memory.path}`);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const kept = keptById.get(memoryId);
|
|
489
|
+
if (kept) {
|
|
490
|
+
skippedDuplicateMemories.push({
|
|
491
|
+
memoryId,
|
|
492
|
+
keptPath: kept.path,
|
|
493
|
+
skippedPath: memory.path,
|
|
494
|
+
});
|
|
495
|
+
log.warn(
|
|
496
|
+
`projection rebuild skipped duplicate memory id=${memoryId}: kept=${kept.path} skipped=${memory.path}`,
|
|
497
|
+
);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
keptById.set(memoryId, memory);
|
|
501
|
+
memories.push(memory);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return { allMemories, memories, skippedDuplicateMemories, skippedBlankIdMemories };
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function deduplicateTimelineEvents(
|
|
509
|
+
events: MemoryLifecycleEvent[],
|
|
510
|
+
sourcePathFor: (event: MemoryLifecycleEvent) => string,
|
|
511
|
+
): {
|
|
512
|
+
events: MemoryLifecycleEvent[];
|
|
513
|
+
skipped: SkippedDuplicateTimelineEvent[];
|
|
514
|
+
skippedBlankIds: SkippedBlankIdTimelineEvent[];
|
|
515
|
+
} {
|
|
516
|
+
const keptById = new Map<string, { event: MemoryLifecycleEvent; path: string }>();
|
|
517
|
+
const unique: MemoryLifecycleEvent[] = [];
|
|
518
|
+
const skipped: SkippedDuplicateTimelineEvent[] = [];
|
|
519
|
+
const skippedBlankIds: SkippedBlankIdTimelineEvent[] = [];
|
|
520
|
+
for (const event of sortMemoryLifecycleEvents(events)) {
|
|
521
|
+
const sourcePath = sourcePathFor(event);
|
|
522
|
+
if (!event.memoryId.trim()) {
|
|
523
|
+
skippedBlankIds.push({ eventId: event.eventId, path: sourcePath });
|
|
524
|
+
log.warn(
|
|
525
|
+
`projection rebuild skipped timeline event with blank memory id: `
|
|
526
|
+
+ `event_id=${event.eventId} path=${sourcePath}`,
|
|
527
|
+
);
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
const kept = keptById.get(event.eventId);
|
|
531
|
+
if (kept) {
|
|
532
|
+
skipped.push({
|
|
533
|
+
eventId: event.eventId,
|
|
534
|
+
keptPath: kept.path,
|
|
535
|
+
skippedPath: sourcePath,
|
|
536
|
+
});
|
|
537
|
+
log.warn(
|
|
538
|
+
`projection rebuild skipped duplicate timeline event_id=${event.eventId}: `
|
|
539
|
+
+ `kept=${kept.path} skipped=${sourcePath}`,
|
|
540
|
+
);
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
keptById.set(event.eventId, { event, path: sourcePath });
|
|
544
|
+
unique.push(event);
|
|
545
|
+
}
|
|
546
|
+
return { events: unique, skipped, skippedBlankIds };
|
|
547
|
+
}
|
|
548
|
+
|
|
438
549
|
async function loadAuthoritativeProjectionSnapshot(options: {
|
|
439
550
|
memoryDir: string;
|
|
440
551
|
defaultNamespace?: string;
|
|
@@ -464,22 +575,43 @@ async function loadAuthoritativeProjectionSnapshot(options: {
|
|
|
464
575
|
updatedAfter: string | null;
|
|
465
576
|
updatedBefore: string | null;
|
|
466
577
|
};
|
|
578
|
+
skippedDuplicateMemories: SkippedDuplicateMemory[];
|
|
579
|
+
skippedBlankIdMemories: SkippedBlankIdMemory[];
|
|
580
|
+
skippedDuplicateTimelineEvents: SkippedDuplicateTimelineEvent[];
|
|
581
|
+
skippedBlankIdTimelineEvents: SkippedBlankIdTimelineEvent[];
|
|
467
582
|
}> {
|
|
468
583
|
const storage = new StorageManager(options.memoryDir);
|
|
469
584
|
// Force a fresh disk read — projection verify/rebuild must see the true
|
|
470
585
|
// on-disk state, not a potentially stale in-process cache.
|
|
471
586
|
storage.invalidateAllMemoriesCacheForDir();
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
]
|
|
477
|
-
|
|
587
|
+
const selected = selectProjectionMemories([
|
|
588
|
+
await storage.readAllMemories(),
|
|
589
|
+
await storage.readAllColdMemories(),
|
|
590
|
+
await storage.readArchivedMemories(),
|
|
591
|
+
]);
|
|
592
|
+
const allMemories = selected.allMemories;
|
|
593
|
+
const projectionMemories = selected.memories;
|
|
478
594
|
const lifecycleEvents = await storage.readAllMemoryLifecycleEvents();
|
|
479
|
-
const
|
|
480
|
-
const
|
|
595
|
+
const timeline = loadTimelineEvents(projectionMemories, lifecycleEvents);
|
|
596
|
+
const lifecycleLedgerPath = path.join(
|
|
597
|
+
options.memoryDir,
|
|
598
|
+
"state",
|
|
599
|
+
"memory-lifecycle-ledger.jsonl",
|
|
600
|
+
);
|
|
601
|
+
const memoryPathById = new Map(
|
|
602
|
+
projectionMemories.map((memory) => [memory.frontmatter.id, memory.path]),
|
|
603
|
+
);
|
|
604
|
+
const deduplicatedTimeline = deduplicateTimelineEvents(
|
|
605
|
+
timeline.events,
|
|
606
|
+
(event) => timeline.usedLifecycleLedger
|
|
607
|
+
? lifecycleLedgerPath
|
|
608
|
+
: memoryPathById.get(event.memoryId) ?? lifecycleLedgerPath,
|
|
609
|
+
);
|
|
610
|
+
const events = deduplicatedTimeline.events;
|
|
611
|
+
const usedLifecycleLedger = timeline.usedLifecycleLedger;
|
|
612
|
+
const currentRows = projectionMemories.map((memory) => toCurrentStateRow(options.memoryDir, memory));
|
|
481
613
|
const scope = normalizeProjectionScope(options);
|
|
482
|
-
const scopedMemories = filterMemoriesForProjectionScope(
|
|
614
|
+
const scopedMemories = filterMemoriesForProjectionScope(projectionMemories, scope);
|
|
483
615
|
const scopedMemoryIds = new Set(scopedMemories.map((memory) => memory.frontmatter.id));
|
|
484
616
|
const nativeKnowledgeRows = await loadPersistedNativeKnowledgeChunks({
|
|
485
617
|
memoryDir: options.memoryDir,
|
|
@@ -516,6 +648,10 @@ async function loadAuthoritativeProjectionSnapshot(options: {
|
|
|
516
648
|
governance,
|
|
517
649
|
usedLifecycleLedger,
|
|
518
650
|
scope,
|
|
651
|
+
skippedDuplicateMemories: selected.skippedDuplicateMemories,
|
|
652
|
+
skippedBlankIdMemories: selected.skippedBlankIdMemories,
|
|
653
|
+
skippedDuplicateTimelineEvents: deduplicatedTimeline.skipped,
|
|
654
|
+
skippedBlankIdTimelineEvents: deduplicatedTimeline.skippedBlankIds,
|
|
519
655
|
};
|
|
520
656
|
}
|
|
521
657
|
|
|
@@ -1040,6 +1176,10 @@ export async function rebuildMemoryProjection(
|
|
|
1040
1176
|
outputPath,
|
|
1041
1177
|
backupPath,
|
|
1042
1178
|
usedLifecycleLedger: snapshot.usedLifecycleLedger,
|
|
1179
|
+
skippedDuplicateMemories: snapshot.skippedDuplicateMemories,
|
|
1180
|
+
skippedBlankIdMemories: snapshot.skippedBlankIdMemories,
|
|
1181
|
+
skippedDuplicateTimelineEvents: snapshot.skippedDuplicateTimelineEvents,
|
|
1182
|
+
skippedBlankIdTimelineEvents: snapshot.skippedBlankIdTimelineEvents,
|
|
1043
1183
|
scope: snapshot.scope,
|
|
1044
1184
|
};
|
|
1045
1185
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { log } from "./logger.js";
|
|
2
|
+
|
|
3
|
+
const PROJECTION_FALLBACK_WARN_INTERVAL_MS = 5 * 60_000;
|
|
4
|
+
const projectionFallbackWarnedAt = new Map<string, number>();
|
|
5
|
+
|
|
6
|
+
export function assertMemoryFrontmatterId(
|
|
7
|
+
fm: { id: string; category?: string; created?: string; entityRef?: string },
|
|
8
|
+
): void {
|
|
9
|
+
if (typeof fm.id !== "string" || fm.id.trim().length === 0) {
|
|
10
|
+
const context = [
|
|
11
|
+
fm.category ? `category=${fm.category}` : null,
|
|
12
|
+
fm.created ? `created=${fm.created}` : null,
|
|
13
|
+
fm.entityRef ? `entityRef=${fm.entityRef}` : null,
|
|
14
|
+
].filter(Boolean).join(" ");
|
|
15
|
+
throw new Error(
|
|
16
|
+
`memory frontmatter id must not be blank${context ? ` (${context})` : ""}`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function warnProjectionFallback(memoryDir: string, consumer: string): null {
|
|
22
|
+
const key = `${memoryDir}\0${consumer}`;
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
const warnedAt = projectionFallbackWarnedAt.get(key) ?? 0;
|
|
25
|
+
if (now - warnedAt >= PROJECTION_FALLBACK_WARN_INTERVAL_MS) {
|
|
26
|
+
projectionFallbackWarnedAt.set(key, now);
|
|
27
|
+
log.warn(`storage.${consumer}: memory projection absent or empty; falling back to full corpus`);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
package/src/storage.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createHash } from "node:crypto"
|
|
|
4
4
|
import { normalizeContent, computeContentHash } from "./content-hash.js";;
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { log } from "./logger.js";
|
|
7
|
+
import { assertMemoryFrontmatterId, warnProjectionFallback } from "./storage-guards.js";
|
|
7
8
|
import { MemoryReadStore } from "./storage/memory-read-store.js";
|
|
8
9
|
import {
|
|
9
10
|
readMaybeEncryptedLines,
|
|
@@ -308,6 +309,7 @@ function stripCitationMarkersForHashRemoval(value: string, template: string): st
|
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
function serializeFrontmatter(fm: MemoryFrontmatter): string {
|
|
312
|
+
assertMemoryFrontmatterId(fm);
|
|
311
313
|
const lines = [
|
|
312
314
|
"---",
|
|
313
315
|
`id: ${fm.id}`,
|
|
@@ -6020,8 +6022,8 @@ export class StorageManager {
|
|
|
6020
6022
|
lastAccessed: entry.lastAccessed,
|
|
6021
6023
|
};
|
|
6022
6024
|
|
|
6023
|
-
const fileContent = `${serializeFrontmatter(newFm)}\n\n${memory.content}\n`;
|
|
6024
6025
|
try {
|
|
6026
|
+
const fileContent = `${serializeFrontmatter(newFm)}\n\n${memory.content}\n`;
|
|
6025
6027
|
await this.writeStorageSecureFile(memory.path, fileContent);
|
|
6026
6028
|
updated++;
|
|
6027
6029
|
} catch (err) {
|
|
@@ -6070,8 +6072,7 @@ export class StorageManager {
|
|
|
6070
6072
|
|
|
6071
6073
|
async getProjectedMemoryState(id: string): Promise<MemoryProjectionCurrentState | null> {
|
|
6072
6074
|
const projected = readProjectedMemoryState(this.baseDir, id);
|
|
6073
|
-
if (projected) return projected;
|
|
6074
|
-
|
|
6075
|
+
if (projected) return projected; warnProjectionFallback(this.baseDir, "getProjectedMemoryState");
|
|
6075
6076
|
const active = await this.getMemoryById(id);
|
|
6076
6077
|
if (active) return this.toProjectedCurrentState(active, "active");
|
|
6077
6078
|
|
|
@@ -6084,7 +6085,8 @@ export class StorageManager {
|
|
|
6084
6085
|
async browseProjectedMemories(
|
|
6085
6086
|
options: ProjectedMemoryBrowseOptions,
|
|
6086
6087
|
): Promise<ProjectedMemoryBrowsePage | null> {
|
|
6087
|
-
return readProjectedMemoryBrowse(this.baseDir, options)
|
|
6088
|
+
return readProjectedMemoryBrowse(this.baseDir, options)
|
|
6089
|
+
?? warnProjectionFallback(this.baseDir, "browseProjectedMemories");
|
|
6088
6090
|
}
|
|
6089
6091
|
|
|
6090
6092
|
async getProjectedGovernanceRecord(): Promise<ReturnType<typeof readProjectedGovernanceRecord>> {
|
|
@@ -6124,8 +6126,7 @@ export class StorageManager {
|
|
|
6124
6126
|
if (cappedLimit === 0) return [];
|
|
6125
6127
|
|
|
6126
6128
|
const projected = readProjectedMemoryTimeline(this.baseDir, memoryId, cappedLimit);
|
|
6127
|
-
if (projected && projected.length > 0) return projected;
|
|
6128
|
-
|
|
6129
|
+
if (projected && projected.length > 0) return projected; warnProjectionFallback(this.baseDir, "getMemoryTimeline");
|
|
6129
6130
|
const events = await this.readAllMemoryLifecycleEvents();
|
|
6130
6131
|
return events.filter((event) => event.memoryId === memoryId).slice(-cappedLimit);
|
|
6131
6132
|
}
|
|
@@ -6382,9 +6383,8 @@ export class StorageManager {
|
|
|
6382
6383
|
updated: now,
|
|
6383
6384
|
};
|
|
6384
6385
|
|
|
6385
|
-
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${memory.content}\n`;
|
|
6386
|
-
|
|
6387
6386
|
try {
|
|
6387
|
+
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${memory.content}\n`;
|
|
6388
6388
|
await this.writeStorageSecureFile(memory.path, fileContent);
|
|
6389
6389
|
await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.archiveMemories", {
|
|
6390
6390
|
memoryId: id,
|