@x12i/memorix-retrieval 1.8.2 → 1.9.2

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 (71) hide show
  1. package/README.md +34 -5
  2. package/dist/client/types.d.ts +24 -0
  3. package/dist/client/types.d.ts.map +1 -1
  4. package/dist/data/collection-parser.d.ts +3 -0
  5. package/dist/data/collection-parser.d.ts.map +1 -1
  6. package/dist/data/collection-parser.js +3 -0
  7. package/dist/data/collection-parser.js.map +1 -1
  8. package/dist/data/record-identity.d.ts +3 -1
  9. package/dist/data/record-identity.d.ts.map +1 -1
  10. package/dist/data/record-identity.js +25 -4
  11. package/dist/data/record-identity.js.map +1 -1
  12. package/dist/explorer/collection-inventory.d.ts.map +1 -1
  13. package/dist/explorer/collection-inventory.js +23 -6
  14. package/dist/explorer/collection-inventory.js.map +1 -1
  15. package/dist/explorer/collection-records.d.ts.map +1 -1
  16. package/dist/explorer/collection-records.js +6 -2
  17. package/dist/explorer/collection-records.js.map +1 -1
  18. package/dist/explorer/entity-graph.d.ts +36 -1
  19. package/dist/explorer/entity-graph.d.ts.map +1 -1
  20. package/dist/explorer/entity-graph.js +161 -0
  21. package/dist/explorer/entity-graph.js.map +1 -1
  22. package/dist/explorer/health.d.ts +54 -0
  23. package/dist/explorer/health.d.ts.map +1 -1
  24. package/dist/explorer/health.js +135 -122
  25. package/dist/explorer/health.js.map +1 -1
  26. package/dist/explorer/raw-collection-records.d.ts +45 -7
  27. package/dist/explorer/raw-collection-records.d.ts.map +1 -1
  28. package/dist/explorer/raw-collection-records.js +46 -7
  29. package/dist/explorer/raw-collection-records.js.map +1 -1
  30. package/dist/explorer/unified-inventory.d.ts +80 -17
  31. package/dist/explorer/unified-inventory.d.ts.map +1 -1
  32. package/dist/explorer/unified-inventory.js +324 -89
  33. package/dist/explorer/unified-inventory.js.map +1 -1
  34. package/dist/index.d.ts +4 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/retrieval/fetch-item.d.ts.map +1 -1
  39. package/dist/retrieval/fetch-item.js +52 -3
  40. package/dist/retrieval/fetch-item.js.map +1 -1
  41. package/dist/retrieval/fetch-list.d.ts.map +1 -1
  42. package/dist/retrieval/fetch-list.js +46 -0
  43. package/dist/retrieval/fetch-list.js.map +1 -1
  44. package/dist/retrieval/fetch-slices.d.ts.map +1 -1
  45. package/dist/retrieval/fetch-slices.js +30 -9
  46. package/dist/retrieval/fetch-slices.js.map +1 -1
  47. package/dist/runtime/source-provenance.d.ts +94 -0
  48. package/dist/runtime/source-provenance.d.ts.map +1 -0
  49. package/dist/runtime/source-provenance.js +129 -0
  50. package/dist/runtime/source-provenance.js.map +1 -0
  51. package/dist/runtime/target-bindings.d.ts +29 -0
  52. package/dist/runtime/target-bindings.d.ts.map +1 -0
  53. package/dist/runtime/target-bindings.js +170 -0
  54. package/dist/runtime/target-bindings.js.map +1 -0
  55. package/dist/tests/collection-parser.test.js +8 -1
  56. package/dist/tests/collection-parser.test.js.map +1 -1
  57. package/dist/tests/entity-graph.test.js +21 -0
  58. package/dist/tests/entity-graph.test.js.map +1 -1
  59. package/dist/tests/source-provenance.test.d.ts +2 -0
  60. package/dist/tests/source-provenance.test.d.ts.map +1 -0
  61. package/dist/tests/source-provenance.test.js +94 -0
  62. package/dist/tests/source-provenance.test.js.map +1 -0
  63. package/dist/tests/unified-inventory.test.d.ts +2 -0
  64. package/dist/tests/unified-inventory.test.d.ts.map +1 -0
  65. package/dist/tests/unified-inventory.test.js +122 -0
  66. package/dist/tests/unified-inventory.test.js.map +1 -0
  67. package/docs/DATA-TIER-CONTRACT.md +20 -2
  68. package/docs/EXPLORER-HOST-APIS.md +21 -5
  69. package/docs/MEMORIX-CATALOX-CONTRACTS.md +14 -2
  70. package/docs/MEMORIX-DATABASE-CONVENTIONS.md +10 -5
  71. package/package.json +2 -2
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isLegacyCatalogId, legacyCatalogSourceRef, mongoPayloadSourceRef, runtimeProjectionSourceRef, } from "../runtime/source-provenance.js";
3
+ import { parseMemorixCollectionName } from "../data/collection-parser.js";
4
+ import { resolveMemorixRecordIdentity } from "../data/record-identity.js";
5
+ import { resolveMemorixTargetBindings } from "../runtime/target-bindings.js";
6
+ import { createMemorixRetrieval } from "../client/create-client.js";
7
+ describe("source provenance", () => {
8
+ it("creates runtime projection source refs", () => {
9
+ const source = runtimeProjectionSourceRef("buildMemorixUnifiedInventory", {
10
+ appId: "memorix",
11
+ sourceLens: "db-first",
12
+ });
13
+ expect(source.sourceClass).toBe("runtime-projection");
14
+ expect(source.canonicalStatus).toBe("derived");
15
+ expect(source.generatedBy).toBe("buildMemorixUnifiedInventory");
16
+ expect(source.generatedAt).toBeTruthy();
17
+ });
18
+ it("marks legacy catalogs as not used", () => {
19
+ expect(isLegacyCatalogId("memorix-entities")).toBe(true);
20
+ expect(isLegacyCatalogId("memorix-entity-descriptors")).toBe(false);
21
+ const source = legacyCatalogSourceRef("memorix-entities", "memorix");
22
+ expect(source.sourceClass).toBe("legacy-catalog-not-used");
23
+ expect(source.trustWarning).toContain("does not use");
24
+ });
25
+ it("creates mongo payload source refs with target and collection", () => {
26
+ const source = mongoPayloadSourceRef("entity", "memorix-entities", "assets-snapshots", {
27
+ objectType: "assets",
28
+ contentType: "snapshots",
29
+ });
30
+ expect(source.target).toBe("entity");
31
+ expect(source.databaseName).toBe("memorix-entities");
32
+ expect(source.collectionName).toBe("assets-snapshots");
33
+ expect(source.sourceClass).toBe("mongo-payload");
34
+ });
35
+ });
36
+ describe("parseMemorixCollectionName", () => {
37
+ it("uses last-dash rule and exposes objectType alias", () => {
38
+ const parsed = parseMemorixCollectionName("topology-cidr-graphs-snapshots");
39
+ expect(parsed.ok).toBe(true);
40
+ if (parsed.ok) {
41
+ expect(parsed.objectType).toBe("topology-cidr-graphs");
42
+ expect(parsed.objectName).toBe("topology-cidr-graphs");
43
+ expect(parsed.contentType).toBe("snapshots");
44
+ expect(parsed.parseRule).toBe("last-dash");
45
+ }
46
+ });
47
+ });
48
+ describe("resolveMemorixRecordIdentity", () => {
49
+ it("prefers recordId before target default", () => {
50
+ const identity = resolveMemorixRecordIdentity("knowledge", {
51
+ recordId: "k1",
52
+ knowledgeId: "k2",
53
+ });
54
+ expect(identity.recordId).toBe("k1");
55
+ expect(identity.source).toBe("recordId");
56
+ });
57
+ it("uses knowledgeId as target default", () => {
58
+ const identity = resolveMemorixRecordIdentity("knowledge", { knowledgeId: "k1" });
59
+ expect(identity.recordId).toBe("k1");
60
+ expect(identity.identityField).toBe("knowledgeId");
61
+ expect(identity.source).toBe("target-default");
62
+ });
63
+ });
64
+ describe("resolveMemorixTargetBindings", () => {
65
+ it("returns not-configured for missing knowledge DB env", async () => {
66
+ const client = createMemorixRetrieval({
67
+ appId: "memorix",
68
+ catalox: { getCatalogItem: async () => ({ outcome: "not_found" }) },
69
+ processEnv: {
70
+ MEMORIX_ENTITIES_DB: "memorix-entities",
71
+ MEMORIX_EVENTS_DB: "memorix-events",
72
+ },
73
+ });
74
+ const bindings = await resolveMemorixTargetBindings(client);
75
+ expect(bindings.knowledge.configured).toBe(false);
76
+ expect(bindings.knowledge.status).toBe("not-configured");
77
+ expect(bindings.knowledge.warnings.some((w) => w.code === "TARGET_DB_NOT_CONFIGURED")).toBe(true);
78
+ });
79
+ it("marks shared physical database across targets", async () => {
80
+ const client = createMemorixRetrieval({
81
+ appId: "memorix",
82
+ catalox: { getCatalogItem: async () => ({ outcome: "not_found" }) },
83
+ processEnv: {
84
+ MEMORIX_ENTITIES_DB: "memorix",
85
+ MEMORIX_EVENTS_DB: "memorix",
86
+ MEMORIX_KNOWLEDGE_DB: "memorix",
87
+ },
88
+ });
89
+ const bindings = await resolveMemorixTargetBindings(client);
90
+ expect(bindings.entity.databaseName).toBe("memorix");
91
+ expect(bindings.event.sharedPhysicalDatabaseWith).toEqual(["entity", "knowledge"]);
92
+ });
93
+ });
94
+ //# sourceMappingURL=source-provenance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-provenance.test.js","sourceRoot":"","sources":["../../src/tests/source-provenance.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=unified-inventory.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-inventory.test.d.ts","sourceRoot":"","sources":["../../src/tests/unified-inventory.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,122 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { createMemorixRetrieval } from "../client/create-client.js";
3
+ import { MEMORIX_ENTITY_DESCRIPTORS_CATALOG } from "../descriptors/catalog-ids.js";
4
+ import { buildMemorixUnifiedInventory } from "../explorer/unified-inventory.js";
5
+ import { assetsEntity, vulnerabilitiesEntity } from "./fixtures.js";
6
+ function mockInventoryCatalox() {
7
+ const entityItems = [
8
+ { id: "assets", data: assetsEntity, title: "Assets" },
9
+ { id: "vulnerabilities", data: vulnerabilitiesEntity, title: "Vulnerabilities" },
10
+ ];
11
+ return {
12
+ getCatalogItem: vi.fn(async (_ctx, catalogId, itemId) => {
13
+ const map = {
14
+ assets: assetsEntity,
15
+ vulnerabilities: vulnerabilitiesEntity,
16
+ };
17
+ if (catalogId === MEMORIX_ENTITY_DESCRIPTORS_CATALOG && map[itemId]) {
18
+ return { outcome: "found", item: { data: map[itemId] } };
19
+ }
20
+ return { outcome: "not_found" };
21
+ }),
22
+ listCatalogItems: vi.fn(async () => ({
23
+ items: entityItems,
24
+ hasMore: false,
25
+ })),
26
+ };
27
+ }
28
+ function mockInventoryXronox() {
29
+ const entityCollections = ["assets-snapshots", "orphan-bucket"];
30
+ const eventCollections = ["vulnerabilities-snapshots"];
31
+ const counts = {
32
+ "assets-snapshots": 5,
33
+ "orphan-bucket": 2,
34
+ "vulnerabilities-snapshots": 3,
35
+ };
36
+ return {
37
+ listCollections: vi.fn(async (params) => {
38
+ if (params.role === "memorix_events") {
39
+ return { database: "memorix-events", collections: eventCollections.map((name) => ({ name })) };
40
+ }
41
+ return { database: "memorix-entities", collections: entityCollections.map((name) => ({ name })) };
42
+ }),
43
+ countDocuments: vi.fn(async (params) => counts[params.source] ?? 0),
44
+ read: vi.fn(async () => [
45
+ { entityId: "sample-1", name: "Sample One" },
46
+ { entityId: "sample-2", name: "Sample Two" },
47
+ ]),
48
+ };
49
+ }
50
+ function createInventoryClient(processEnv) {
51
+ return createMemorixRetrieval({
52
+ appId: "memorix",
53
+ catalox: mockInventoryCatalox(),
54
+ xronox: mockInventoryXronox(),
55
+ processEnv: {
56
+ MEMORIX_ENTITIES_DB: "memorix-entities",
57
+ MEMORIX_EVENTS_DB: "memorix-events",
58
+ ...processEnv,
59
+ },
60
+ });
61
+ }
62
+ describe("buildMemorixUnifiedInventory", () => {
63
+ it("db_first_toggle_returns_db_first_inventory_not_same_graph", async () => {
64
+ const client = createInventoryClient();
65
+ const inventory = await buildMemorixUnifiedInventory(client, {
66
+ sourceLens: "db-first",
67
+ targets: ["entity", "event"],
68
+ });
69
+ expect(inventory.source.sourceClass).toBe("runtime-projection");
70
+ expect(inventory.sourceLens).toBe("db-first");
71
+ expect(inventory.rows.length).toBeGreaterThan(0);
72
+ expect(inventory.rows.some((row) => row.sources.some((s) => s.sourceClass === "mongo-payload"))).toBe(true);
73
+ const sorted = [...inventory.rows];
74
+ sorted.sort((a, b) => {
75
+ const target = a.target.localeCompare(b.target);
76
+ if (target !== 0)
77
+ return target;
78
+ const db = (a.databaseName ?? "").localeCompare(b.databaseName ?? "");
79
+ if (db !== 0)
80
+ return db;
81
+ return (a.collectionName ?? "").localeCompare(b.collectionName ?? "");
82
+ });
83
+ expect(inventory.rows.map((r) => r.rowId)).toEqual(sorted.map((r) => r.rowId));
84
+ });
85
+ it("target_filter_events_excludes_entity_rows", async () => {
86
+ const client = createInventoryClient();
87
+ const inventory = await buildMemorixUnifiedInventory(client, {
88
+ sourceLens: "db-first",
89
+ targets: ["event"],
90
+ });
91
+ expect(inventory.rows.every((row) => row.target === "event")).toBe(true);
92
+ expect(inventory.rows.some((row) => row.target === "entity")).toBe(false);
93
+ });
94
+ it("knowledge_empty_is_not_fatal", async () => {
95
+ const client = createInventoryClient();
96
+ const inventory = await buildMemorixUnifiedInventory(client, {
97
+ targets: ["entity", "event", "knowledge"],
98
+ });
99
+ expect(inventory.targetBindings.knowledge.status).toMatch(/not-configured|empty|connected/);
100
+ const knowledgeIssues = inventory.issues.filter((issue) => issue.target === "knowledge");
101
+ expect(knowledgeIssues.every((issue) => issue.severity !== "error")).toBe(true);
102
+ expect(inventory.warnings.some((w) => w.code === "TARGET_DB_NOT_CONFIGURED")).toBe(true);
103
+ });
104
+ it("includes source refs on every row", async () => {
105
+ const client = createInventoryClient();
106
+ const inventory = await buildMemorixUnifiedInventory(client);
107
+ for (const row of inventory.rows) {
108
+ expect(row.source.sourceClass).toBeTruthy();
109
+ expect(row.source.generatedAt).toBeTruthy();
110
+ expect(row.objectType ?? row.objectName).toBeDefined();
111
+ }
112
+ });
113
+ it("attach samples when includeSamples is true", async () => {
114
+ const client = createInventoryClient();
115
+ const inventory = await buildMemorixUnifiedInventory(client, {
116
+ includeSamples: true,
117
+ });
118
+ const withData = inventory.rows.filter((row) => (row.counts.exact ?? row.counts.estimated ?? 0) > 0 && row.collectionName);
119
+ expect(withData.some((row) => (row.samples?.length ?? 0) > 0)).toBe(true);
120
+ });
121
+ });
122
+ //# sourceMappingURL=unified-inventory.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-inventory.test.js","sourceRoot":"","sources":["../../src/tests/unified-inventory.test.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,23 @@ Data reads and counts go through **Xronox** (`role: memorix_entities` / `memorix
44
44
 
45
45
  ---
46
46
 
47
+ ## Source-aware runtime provenance
48
+
49
+ Retrieval is the source-aware read engine for Explorer. Every inventory row, health response, raw read, and list result can carry `MemorixRuntimeSourceRef` metadata.
50
+
51
+ | Export | Purpose |
52
+ |--------|---------|
53
+ | `MemorixRuntimeSourceRef` | Primary runtime provenance type (`sourceClass`, `canonicalStatus`, catalog/Mongo fields) |
54
+ | `RuntimeSourceAware<T>` | Wrapper `{ data, source, sources? }` |
55
+ | `MemorixTargetDbBinding` | Per-target DB status (`connected`, `empty`, `not-configured`, shared physical DB) |
56
+ | `resolveMemorixTargetBindings(client, options?)` | Resolve entity/event/knowledge bindings with warnings |
57
+ | `getSourceAwareMemorixRetrievalHealth(client, options?)` | Full source-aware health (Catalox catalogs, targets, inventory summary) |
58
+ | `legacyCatalogSourceRef` / `isLegacyCatalogId` | Guardrails for legacy catalogs not used in descriptor-driven reads |
59
+
60
+ List/item responses include optional `source`, `sources`, `descriptorRefs`, `target`, `databaseName`, and `collectionNames` (default: source refs enabled).
61
+
62
+ ---
63
+
47
64
  ## Descriptor-driven reads (primary)
48
65
 
49
66
  | Export | Purpose |
@@ -94,11 +111,12 @@ List descriptor `filters` with `operator` + `value` are **always applied**; requ
94
111
 
95
112
  | Export | Purpose |
96
113
  |--------|---------|
97
- | `buildMemorixEntityGraph(client, options?)` | Discovery + counts + relation graph + optional inventory overlay (`nodes`, `inventory`) |
114
+ | `buildMemorixEntityGraph(client, options?)` | Discovery + counts + relation graph + optional `runtimeGraph` (source-aware nodes/edges), `nodes`, `inventory` |
98
115
  | `buildMemorixEntitySlices(client, entityName)` | Per–content-type counts for drill-down (includes zero counts) |
99
116
  | `buildMemorixCollectionInventory(client, options?)` | Legacy inventory (prefer `buildMemorixUnifiedInventory`) |
100
117
  | `orphanNodesFromInventory(entries)` | Group inventory orphans for entity graph canvas |
101
- | `getMemorixRetrievalHealth(client, options?)` | Catalox + Mongo per-target + descriptor counts + optional inventory summary |
118
+ | `getMemorixRetrievalHealth(client, options?)` | Legacy health shape (wraps source-aware health) |
119
+ | `getSourceAwareMemorixRetrievalHealth(client, options?)` | Source-aware Catalox + Mongo + inventory health |
102
120
  | `countMemorixEntityContentTypeDocuments` | Count by entity + content type (descriptor-resolved collection) |
103
121
  | `listMemorixEntityContentTypeDocuments` | Paginated raw documents (descriptor-resolved) |
104
122
  | `getMemorixEntityContentTypeDocument` | Single document by record id |
@@ -19,12 +19,13 @@ Uses `createCataloxFromEnv` + `createCataloxAdapterFromBound` + `createMemorixRe
19
19
  ## Entity discovery
20
20
 
21
21
  - `discoverMemorixEntities(client)` — lists `memorix-entity-descriptors` via Catalox only (`source: "catalox" | "none"`). No env entity list fallback.
22
- - `buildMemorixEntityGraph(client, options?)` — discovery + per–content-type counts + relations. Options: `sourceLens`, `targets`, `includeInventory`, `includeOrphans`, `includeCounts`, `includeSlices`. Returns optional `nodes[]` and `inventory`.
23
- - `buildMemorixUnifiedInventory(client, options?)` — **preferred** inventory API for Explorer Inventory workspace. Options: `sourceLens` (`catalox-first` \| `db-first`), `targets`, `includeExactCounts`.
22
+ - `buildMemorixEntityGraph(client, options?)` — discovery + per–content-type counts + relations. Options: `sourceLens`, `targets`, `includeInventory`, `includeOrphans`, `includeCounts`, `includeSlices`, `includeSourceRefs`. Returns legacy `entities[]`, optional `nodes[]`, `inventory`, and **`runtimeGraph`** (`MemorixRuntimeGraph` with source refs on every node/edge).
23
+ - `buildMemorixUnifiedInventory(client, options?)` — **preferred** inventory API for Explorer Inventory workspace. Options: `sourceLens` (`catalox-first` \| `db-first`), `targets`, `includeExactCounts`, `includeSamples`.
24
24
  - `parseMemorixCollectionName(name)` — last-dash parser for DB-first mode.
25
25
  - `fetchMemorixRawCollectionRecords` / `fetchMemorixCollectionRecords` — open records from inventory rows.
26
- - `fetchMemorixSlices` / `fetchMemorixSliceRecords` — slice descriptor execution.
27
- - `getMemorixRetrievalHealth(client, { includeInventory })` — operational status for Explorer top bar.
26
+ - `fetchMemorixSlices` / `fetchMemorixSliceRecords` — slice descriptor execution with optional relation expansion per row.
27
+ - `getMemorixRetrievalHealth(client, { includeInventory })` — legacy operational status for Explorer top bar.
28
+ - `getSourceAwareMemorixRetrievalHealth(client, { includeInventory: true })` — source-aware health with target bindings and inventory summary.
28
29
  - `buildMemorixCollectionInventory(client, options?)` — legacy inventory (still supported).
29
30
 
30
31
  ## Collection inventory
@@ -112,7 +113,22 @@ Supports `page`, `includeTotal`, `searchText`, and global `sort` (v1: in-memory
112
113
 
113
114
  ## Health
114
115
 
115
- - `getMemorixRetrievalHealth(client)` — Mongo ping + discovery sample.
116
+ - `getMemorixRetrievalHealth(client, { includeInventory })` — legacy health shape.
117
+ - `getSourceAwareMemorixRetrievalHealth(client, { includeInventory: true })` — Catalox catalog status, per-target DB bindings (entity/event/knowledge), optional inventory summary, all with `MemorixRuntimeSourceRef`.
118
+
119
+ ## Source provenance (Explorer Source Card)
120
+
121
+ Every major retrieval result exposes runtime provenance:
122
+
123
+ | API | Primary `source.sourceClass` |
124
+ |-----|------------------------------|
125
+ | `buildMemorixUnifiedInventory` | `runtime-projection` |
126
+ | `buildMemorixEntityGraph` → `runtimeGraph` | `runtime-projection` |
127
+ | `fetchMemorixList` / `fetchMemorixItem` | `descriptor-backed-runtime-view` |
128
+ | `fetchMemorixRawCollectionRecords` | `raw-db-inspection` |
129
+ | `getSourceAwareMemorixRetrievalHealth` | `runtime-projection` |
130
+
131
+ Inventory rows include `source`, `sources[]`, `objectType`, `mappingStatus`, and optional `samples` when `includeSamples: true`.
116
132
 
117
133
  ## Catalox cleanliness
118
134
 
@@ -77,7 +77,19 @@ All Memorix descriptor catalogs live under this app. Peers must use the same `ap
77
77
 
78
78
  Catalogs use **`sourceMode: "native"`** and **`catalogType: "memorix"`** in seed manifests. Do not introduce parallel catalog names (e.g. `memorix_entity_content_types`) for new work.
79
79
 
80
- ### 2.3 Item shape in Catalox
80
+ ### 2.4 Legacy catalogs (not used by retrieval)
81
+
82
+ Retrieval **does not** treat these as canonical descriptor sources for read-time composition:
83
+
84
+ | Catalog id | Status |
85
+ |------------|--------|
86
+ | `memorix-entities` | Legacy schema inference — not descriptor-driven retrieval |
87
+ | `memorix_entity_content_types` | Superseded by `contentTypes` on object type descriptors |
88
+ | `knowledge` | Knowledge/skills artifacts — not object type descriptors for `target: knowledge` |
89
+
90
+ If exposed in debug/source-inspector mode, mark with `sourceClass: "legacy-catalog-not-used"`. Normal list/item/inventory APIs load **`memorix-entity-descriptors`**, **`memorix-list-descriptors`**, and **`memorix-item-descriptors`** only.
91
+
92
+ ### 2.5 Item shape in Catalox
81
93
 
82
94
  Each catalog item is stored as:
83
95
 
@@ -97,7 +109,7 @@ Each catalog item is stored as:
97
109
  - Descriptor payload lives in the item **`data`** body when read via Catalox APIs.
98
110
  - **Seed apply note:** the Catalox seed CLI upserts `row.data` only, so `scripts/apply-seed-manifest.mjs` merges `scope` into the upsert `data` object. Hosts may see `scope` inside `data` until Catalox stores top-level scope natively; retrieval ignores unknown fields when validating descriptors.
99
111
 
100
- ### 2.4 Expected Catalox client behavior
112
+ ### 2.6 Expected Catalox client behavior
101
113
 
102
114
  Peers that integrate with Catalox must support:
103
115
 
@@ -10,7 +10,7 @@ Memorix uses **three logical database roles**:
10
10
  |------|---------|------------------------|
11
11
  | **Entities** | Canonical entity records (vulnerabilities, assets, groups, …) | `memorix-entities` |
12
12
  | **Events** | Event records derived from or linked to entities | `memorix-events` |
13
- | **Source** | Upstream operational / enrichment data used to extend Memorix records | *(environment-specific)* |
13
+ | **Knowledge** | Knowledge-tier object payloads when configured | `memorix-knowledge` |
14
14
 
15
15
  All three may live on the **same MongoDB cluster** (single `MONGO_URI`). They are separated by **database name**, not by connection string.
16
16
 
@@ -46,10 +46,15 @@ Packages resolve `memorix-entities`, `memorix-events`, collection names, and ent
46
46
 
47
47
  Every Memorix record belongs to exactly one **target**:
48
48
 
49
- | Target | Database | Typical use |
50
- |--------|----------|-------------|
51
- | `entity` | `memorix-entities` | Stable domain objects (vulnerability, asset, group, …) |
52
- | `event` | `memorix-events` | Occurrences, detections, or timeline entries |
49
+ | Target | Database | Typical use | Identity field |
50
+ |--------|----------|-------------|----------------|
51
+ | `entity` | `memorix-entities` | Stable domain objects (vulnerability, asset, group, …) | `entityId` |
52
+ | `event` | `memorix-events` | Occurrences, detections, or timeline entries | `eventId` |
53
+ | `knowledge` | `memorix-knowledge` | Knowledge-tier objects when configured | `knowledgeId` |
54
+
55
+ Multiple logical targets may share one physical database (e.g. `MEMORIX_ENTITIES_DB=memorix`, `MEMORIX_EVENTS_DB=memorix`, `MEMORIX_KNOWLEDGE_DB=memorix`). Retrieval returns separate logical bindings and marks `sharedPhysicalDatabaseWith`.
56
+
57
+ An empty or unconfigured knowledge target is **non-fatal** — inventory and health return `status: "not-configured"` or `"empty"` with informational warnings.
53
58
 
54
59
  Tools must declare which target they read or write. Do not mix entity and event documents in the same collection.
55
60
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x12i/memorix-retrieval",
3
- "version": "1.8.2",
3
+ "version": "1.9.2",
4
4
  "description": "Read-side runtime data tier for Memorix: inventory, lists, items, slices, graph, and health",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@x12i/catalox": "^5.0.0",
35
35
  "@x12i/helpers": "^1.7.0",
36
- "@x12i/memorix-descriptors": "^1.4.2",
36
+ "@x12i/memorix-descriptors": "^1.5.0",
37
37
  "@x12i/xronox": "^3.9.0"
38
38
  },
39
39
  "devDependencies": {