@x12i/memorix-descriptors
v1.36.0
Published
Manage Memorix entity, list, and item descriptors in Catalox
Readme
@x12i/memorix-descriptors
Write-side control plane for Memorix entity, list, and item descriptors — plus content types, collections, relations, and completion mappings — stored in Catalox and consumed by @x12i/memorix-retrieval.
Role in the ecosystem
Hosts (Explorer Admin, CI, CLI, internal tools)
│
▼
@x12i/memorix-descriptors ← validate, mutate, seed, reconcile (this package)
│
├─ write ──► @x12i/catalox (descriptor catalogs)
│
└─ read / inventory ──► @x12i/memorix-retrieval (+ optional @x12i/xronox)| Concern | Package |
|--------|---------|
| Load descriptors, compose lists/items, graph, runtime reads | @x12i/memorix-retrieval |
| Create/update/delete descriptors and mappings in Catalox | @x12i/memorix-descriptors |
| Write Memorix payload documents to Mongo | @x12i/memorix-completion |
Canonical contracts: docs/MEMORIX-CATALOX-CONTRACTS.md, docs/MEMORIX-DATABASE-CONVENTIONS.md. Object types vs storage targets (naming cleanup): docs/MEMORIX-OBJECT-TYPES-AND-TARGETS.md.
Install
npm install @x12i/memorix-descriptors @x12i/catalox
# Optional, for Mongo inventory / reconcile:
npm install @x12i/xronoxOptional peer: @x12i/xronox ≥3.9 for Mongo inventory / reconcile. This package does not depend on @x12i/memorix-retrieval.
Package exports
The main entry re-exports the full write-side surface (mutations, seeds, reconcile, CLI helpers).
Retrieval-safe subpaths — for @x12i/memorix-retrieval and other read-side consumers that must not import the main "." entry (avoids TS5055 cycles):
| Subpath | Symbols | Use |
|---------|---------|-----|
| @x12i/memorix-descriptors/types | MemorixSliceDescriptor, MemorixTarget, GraphRunEntry, MemorixRecordRef, PersistencyTarget, … | Type-only imports |
| @x12i/memorix-descriptors/catalog | defaultIdFieldForTarget, resolveEntityIdentityField, MEMORIX_INVENTORY_POLICIES_CATALOG, … | Catalog ids |
| @x12i/memorix-descriptors/collections/parse | parseMemorixCollectionName | Last-dash collection naming |
| @x12i/memorix-descriptors/validation/slice-shape | isMemorixSliceDescriptor, validateMemorixSliceDescriptorShape | Slice shape validation |
| @x12i/memorix-descriptors/validation/inventory-policy | DEFAULT_INVENTORY_POLICY, isCollectionIgnored, … | Inventory ignore policy |
import type { MemorixSliceDescriptor } from "@x12i/memorix-descriptors/types";
import { defaultIdFieldForTarget, resolveEntityIdentityField } from "@x12i/memorix-descriptors/catalog";
import { resolveContentTypeCardinality } from "@x12i/memorix-descriptors";
import { parseMemorixCollectionName } from "@x12i/memorix-descriptors/collections/parse";Write-side / CLI / Metadata Studio hosts should import from "." or use MemorixDescriptorAdmin.
Bootstrap
From a bound Catalox client
import { bindCataloxContext } from "@x12i/catalox";
import {
createMemorixCataloxFromEnv,
createMemorixDescriptorAdmin,
resolveMemorixAppId,
} from "@x12i/memorix-descriptors";
const { catalox } = await createMemorixCataloxFromEnv();
const bound = bindCataloxContext(catalox, {
appId: resolveMemorixAppId(), // CATALOX_APP_ID → MEMORIX_APP_ID → "memorix"
actor: { type: "service", id: "memorix-descriptors" },
superAdmin: true,
});
const admin = createMemorixDescriptorAdmin({
catalox: bound,
processEnv: process.env,
});From environment
import { createMemorixDescriptorAdminFromEnv } from "@x12i/memorix-descriptors";
const admin = await createMemorixDescriptorAdminFromEnv();
// Uses MONGO_URI + MEMORIX_CATALOX_DB (default memorix-catalox) for Catalox metadata
// Uses MONGO_URI + Xronox when set (for reconcile / ensureCollection)Control plane (retrieval + descriptors)
For Explorer-like hosts that need both read and write stacks with shared catalox, xronox, and appId:
import { createMemorixControlPlaneFromEnv } from "@x12i/memorix-descriptors";
const { retrieval, descriptors } = await createMemorixControlPlaneFromEnv();
// retrieval.client — MemorixRetrievalClient (buildMemorixUnifiedInventory, fetchList, …)
// descriptors — MemorixDescriptorAdmin (mutations, reconcile, applyReconcileDraft)Uses shared Catalox + optional Xronox from env — no @x12i/memorix-retrieval import. The retrieval key exposes a compatible { appId, cataloxBound, catalox, client } stack for inventory/reconcile wiring; client is a UnifiedInventoryContext for buildMemorixUnifiedInventory.
Catalog object types and storage targets
Memorix overloads the word entity. Use this split:
| Concept | Examples | Where |
|---------|----------|--------|
| Catalog object type | assets, vulnerabilities, variabilities-groups | Catalox memorix-entity-descriptors (field entityName today) |
| Storage target | entity, event, knowledge | Descriptor field target → Mongo DB |
| Target | Default DB | Identity field | Typical object types |
|--------|------------|----------------|----------------------|
| entity | memorix-entities | entityId | assets, variabilities-groups |
| event | memorix-events | eventId | vulnerabilities (findings / timeline) |
| knowledge | memorix-knowledge | knowledgeId | knowledge-playbooks, content-documents |
Not the same: Mongo DB memorix-entities, legacy Catalox catalog memorix-entities, and catalog memorix-entity-descriptors are three different things. Full glossary and rename roadmap: docs/MEMORIX-OBJECT-TYPES-AND-TARGETS.md.
This package accepts target: "knowledge" on object type descriptors and mappings. Canonical specs include content-documents (snapshots, extractions, chunks). Corpus conventions: memorix-corpus/README.md.
Catalox catalogs
Do not introduce parallel catalog ids (per contracts).
| Catalog id | Descriptor type | Managed by |
|------------|-----------------|------------|
| memorix-entity-descriptors | Object type descriptor (legacy catalog id) | ✅ |
| lists | List descriptor (entity + workspace) | ✅ |
| memorix-item-descriptors | Item descriptor | ✅ |
| memorix-completion-mappings | Completion source → target maps | ✅ (optional catalog; missing catalog is treated as empty) |
App id: memorix (override via CATALOX_APP_ID / MEMORIX_APP_ID).
MemorixDescriptorAdmin API
All mutating methods accept DescriptorMutationOptions and return DescriptorMutationResult<T>.
Mutation options
| Option | Description |
|--------|-------------|
| dryRun | Validate + build projected graph; no Catalox write |
| skipMongo | Skip collection inventory / ensure steps |
| scope | Catalox seed scope (domains, agents) merged into item data |
| allowCreateCollection | When true and Xronox is configured, report create-required for missing collections (does not move data) |
| cascade | Property/relation removal updates list/item field sets (default true) |
| force | Hard delete / ignore default list-item guards |
| mode | soft | hard for removeEntityDescriptor |
| reason | Reserved for audit trail (not persisted yet) |
| expectedVersion | Reserved for optimistic concurrency (not enforced yet) |
Mutation result
{
ok: boolean; // false if validation/integrity errors on the projected graph
dryRun: boolean;
data?: T;
warnings: string[];
errors: Array<{ code: string; message: string; path?: string }>;
cataloxWrites: Array<{ catalogId; itemId; action: "create"|"update"|"delete" }>;
mongoActions?: Array<{ action; database; collection }>;
integrity: DescriptorIntegrityReport;
rollbackPlan?: CataloxWriteAction[]; // reserved — not populated on failed writes yet
}Every mutation validates against a projected full descriptor graph (in-memory) before writing.
Integrity & graph
| Method | Description |
|--------|-------------|
| validateMemorixDescriptors() | Load all catalogs + run referential integrity |
| getDescriptorGraph() | Nodes/edges: entities, lists, items, mappings, relations |
| getDescriptorGraphMermaid() | Mermaid diagram string |
| loadSnapshot() | Raw DescriptorSnapshot from Catalox |
Integrity checks include: default list/item ids exist; list fields ⊆ entity properties with humanReadable: true; item fields human-readable; content types on properties/lists/items; relation targets; mapping targetCollection / entityType; forbidden process.env in descriptor JSON; dangling relation references.
Also exported: validateDescriptorSnapshot, buildDescriptorGraph, descriptorGraphToMermaid.
Entity descriptors
| Method | Description |
|--------|-------------|
| registerEntityDescriptor(input) | Create entity + default {entity}-main-list + {entity}-detail-item (atomic logical transaction) |
| updateEntityDescriptor(entityName, patch) | Patch defaults, identity, content types, etc. Cannot rename entityName / id |
| removeEntityDescriptor(entityName, options?) | soft (default): deprecated flags; hard: delete entity + all list/item for that type, scrub inbound relations / inventory-policy refs / mappings / write descriptors |
registerEntityDescriptor input: entityName, target, collectionPrefix, canonicalContentType, optional identity, initialProperties, scope.
Content types & collections
Content types live under entityDescriptor.contentTypes (each resolves to a Mongo collection).
Entity-level join key (identityField): Primary FK linking all content-type collections of an object type. When omitted, defaults to the storage-target id field (entityId, eventId, or knowledgeId). Set explicitly for non-standard keys (e.g. subnetId on subnets). Resolve at runtime with resolveEntityIdentityField(entity).
Content-type cardinality (cardinality): 1:1 = one document per identity; 1:n = many per identity. When omitted: core / snapshots postfixes → 1:1; others → 1:n. Resolve with resolveContentTypeCardinality(ct, contentTypeKey).
| Method | Description |
|--------|-------------|
| addContentType(entityName, input) | Add key; at most one isCanonical: true |
| updateContentType(entityName, key, patch) | Patch postfix, collection, canonical flag, etc. |
| removeContentType(entityName, key) | Fails if referenced by properties, lists, items, relations, or sole canonical |
| resolveCollection(entityName, contentTypeKey) | Same resolution order as retrieval (explicit → env → {prefix}-{postfix}) |
| ensureCollection(entityName, contentTypeKey) | Inventory via Xronox listCollections |
| planCollectionRename(entityName, contentTypeKey, newName) | Migration plan only (no data move) |
Properties
| Method | Description |
|--------|-------------|
| addProperty(entityName, key, property, options?) | Validates source.contentType; optional addToDefaultList / addToDefaultItem |
| updateProperty(entityName, key, patch) | Merge patch |
| removeProperty(entityName, key, options?) | Cascades out of list fields[] and item sections[].fields[] unless cascade: false; fails if used in relation join paths |
List descriptors
| Method | Description |
|--------|-------------|
| createListDescriptor(input) | Entity list (kind omitted or "entity") or workspace list (kind: "workspace") |
| updateListDescriptor(id, patch) | |
| removeListDescriptor(id) | Blocked if still entity default unless force |
| setEntityDefaultList(entityName, listDescriptorId) | Wire defaultListDescriptorId with referential checks |
| addListExtension(listId, extension) | Add multi-collection join |
| removeListExtension(listId, contentType) | |
| addListAnalyticsField(listId, field) | Add computed analytics column |
| removeListAnalyticsField(listId, field) | |
| setListSort(listId, sort[]) | Set compound defaultSort |
Also dispatchable via executeDescriptorMutation / memorix-catalox-api POST /metadata/mutations.
Item descriptors
| Method | Description |
|--------|-------------|
| createItemDescriptor(input) | |
| updateItemDescriptor(id, patch) | |
| removeItemDescriptor(id) | Blocked if still entity default unless force |
| setEntityDefaultItem(entityName, itemDescriptorId) | |
Slice descriptors
Slice descriptors are list-catalog items with kind: "slice" (inventory-driven list views).
| Method | Description |
|--------|-------------|
| createSliceDescriptor(input) | Validate shape + snapshot refs; write to list catalog |
| updateSliceDescriptor(sliceId, patch) | |
| removeSliceDescriptor(sliceId) | |
| validateSliceDescriptor(sliceId) | Shape + entity/field/content-type checks |
| previewSliceDescriptor(sliceId) | Dry-run preview payload |
Also exported: validateMemorixSliceDescriptorShape, validateSliceDescriptorAgainstSnapshot, buildSlicePreview (main entry and ./validation/slice-shape for shape-only helpers).
Inventory policy
Ignored collections are stored in Catalox catalog memorix-inventory-policies (item id default).
| Method | Description |
|--------|-------------|
| getInventoryPolicy() | Load current policy |
| updateInventoryPolicy(patch) | Replace ignoredCollections |
| ignoreCollection(input) | Append ignored entry |
| unignoreCollection(input) | Remove ignored entry |
Also exported from ./validation/inventory-policy: DEFAULT_INVENTORY_POLICY, validateMemorixInventoryPolicy, isCollectionIgnored, ignoredCollectionKey.
Relations
Relations live on the source entity descriptor under relations.
| Method | Description |
|--------|-------------|
| addRelation(sourceEntity, relationKey, descriptor) | Validates target entity + content types |
| updateRelation(sourceEntity, relationKey, patch) | |
| removeRelation(sourceEntity, relationKey, options?) | Cascades includeRelations on list/item unless cascade: false |
RelationInput: targetEntity, type, source/target { contentType, path }, optional defaultMode, defaultArrayProperty, targetFields.
Completion mappings
| Method | Description |
|--------|-------------|
| registerMapping(input) | Cross-validates entityType, target, targetCollection, field paths |
| updateMapping(id, patch) | |
| removeMapping(id) | |
Shape: MemorixCompletionMapping (see src/types/index.ts and MEMORIX-DATABASE-CONVENTIONS.md).
Seed import / export
Compatible with the standard Memorix catalox-seeds/inputs/ layout (also used by @x12i/memorix-retrieval):
catalox-seeds/inputs/
entity-descriptors/*.json
list-descriptors/*.json
item-descriptors/*.json
mapping-descriptors/*.json # optional
scope.json
manifest.json # written on export| Method | Description |
|--------|-------------|
| buildDescriptorSeedManifest(scope?) | Build manifest from current Catalox snapshot |
| exportDescriptorSeedInputs(dir, scope?) | Write inputs layout to disk |
| importDescriptorSeedInputs(dir, { dryRun?, scope? }) | Validate + upsert |
| applyDescriptorSeedManifest(manifest, { dryRun?, force? }) | Upsert manifest items (scope merged into data) |
Uses local mergeSeedItemScopeIntoUpsertData for apply shape.
Mongo reconciliation
Uses buildMemorixUnifiedInventory implemented in this package (same shape as retrieval's Inventory UI). Legacy buildMemorixCollectionInventory is no longer used. Hosts may pass pre-built inventory from @x12i/memorix-retrieval or build via admin.reconcileDescriptorsWithMongo().
const result = await admin.reconcileDescriptorsWithMongo({
inventory: unifiedFromRetrieval, // optional — pass what Inventory already loaded
inventoryOptions: { sourceLens: "catalox-first", includeExactCounts: true },
allowCreateCollection: true, // create missing Mongo collections (native driver)
autoRegisterOrphans: true, // apply register-entity drafts for parseable orphans
skipMongo: true, // suggestions only, no Mongo side effects
});Returns:
{
inventory: MemorixUnifiedInventory;
issues: MemorixInventoryIssue[]; // same as inventory.issues
suggestions: ReconcileSuggestion[];
applied: Array<{ kind: string; detail: string }>;
}Suggestion kinds (aligned with unified inventory issues):
| Kind | Typical issue | Action |
|------|---------------|--------|
| ensure-collection | missing-collection | Create Mongo collection for declared content type |
| empty-declared-collection | empty-declared-collection | Informational |
| create-descriptor-for-orphan | orphan-collection, object-missing | Register new entity descriptor |
| add-content-type-for-orphan | content-type-missing | Add content type to existing entity |
| fix-collection-binding | collection-mismatch | Patch content type collection binding |
| ignore-collection | unparseable-collection | Add to inventory ignore policy |
| unparseable-collection | unparseable-collection | Informational / manual review |
Requires MONGO_URI and Xronox when building inventory internally (via createMemorixDescriptorAdminFromEnv or createMemorixControlPlaneFromEnv).
Reconcile drafts & apply
Draft builders produce a ReconcileDescriptorDraft (suggestedAction + draft payload + warnings). Metadata Studio flow: build draft → dry-run preview → apply.
| Builder | suggestedAction |
|---------|-------------------|
| buildDescriptorDraftFromOrphanCollection(input) | registerEntityDescriptor |
| buildAddContentTypeDraftFromCollection(input, snapshot?) | addContentType |
| buildFixCollectionBindingDraft(input, snapshot?, env?) | updateContentType |
| buildIgnoreCollectionDraft(input) | ignoreCollection |
| Method | Description |
|--------|-------------|
| buildReconcileDraftForSuggestion(suggestion, snapshot?, env?) | Map a ReconcileSuggestion to a draft (uses builders above) |
| applyReconcileDraft(ctx, draft, options?) | Low-level apply (also admin.applyReconcileDraft(draft, options?)) |
Supported apply actions: registerEntityDescriptor, addContentType, updateContentType, ignoreCollection. manualReview drafts return MANUAL_REVIEW_REQUIRED.
Authored narratives catalog (narratives)
Optional map on each object-type descriptor, keyed by narrative slug. Each entry uses MemorixNarrativeDefinition:
| Field | Type | Description |
|-------|------|-------------|
| kind | having-signal | association-common-property | Required classification |
| label | string | Optional display label |
| description | string | Optional UI description |
| sourceRef | string | Association source (e.g. assetVulnerabilities) |
| targetEntity | string | Target object type (e.g. vulnerabilities) |
| property | string | For association-common-property — matched property |
| value | string | For association-common-property — matched value |
Persist via updateEntityDescriptor(entity, { narratives }) or seed JSON under entity-descriptors/*.json. Validated by validateNarrativesCatalog / validateNarrativeDefinition. Survives the v2 Catalox round-trip and appears on loadSnapshot().entityDescriptors[<entity>].narratives.
Per-record narrative instances (addedAt, detectedBy, etc.) remain on Mongo documents at narratives.<key> — they are not part of this catalog.
Root envelope property catalog (rootPropertyCatalog)
Pipeline-computed catalog of root/envelope keys (outside data) per content type. Distinct from declarative rootProperties (managed snapshot buckets like possiblePaths on subnets).
Each MemorixContentTypeRootProperties entry includes contentType, properties[] (key, valueTypes, presentCount, totalCount, optional internal), computedAt, and fullScan.
| Method | Description |
|--------|-------------|
| computeRootPropertyCatalog(objectType, options?) | Full-scan Mongo collections per content type; persist on descriptor. Options: ttlMs (default 24h), contentTypes[], force |
Also exported: scanRootPropertyCatalogForDescriptor, mergeRootPropertyStatsFromDocs, DEFAULT_ROOT_PROPERTY_CATALOG_TTL_MS.
const result = await admin.computeRootPropertyCatalog("assets", { force: true });
// result.rootPropertyCatalog — persisted when not skipped by TTLconst { suggestions } = await admin.reconcileDescriptorsWithMongo({ skipMongo: true });
const snapshot = await admin.loadSnapshot();
const draft = buildReconcileDraftForSuggestion(suggestions[0]!, snapshot);
const preview = await admin.applyReconcileDraft(draft!, { dryRun: true });
const applied = await admin.applyReconcileDraft(draft!, { dryRun: false });Also on admin (with snapshot-aware validation): buildDescriptorDraftFromOrphanCollection, buildAddContentTypeDraftFromCollection, buildFixCollectionBindingDraft, buildIgnoreCollectionDraft.
Typed mutation dispatcher (optional)
Single entry for hosts that route mutation requests by operation name (Explorer POST /metadata/mutations, CLI, CI):
import { executeDescriptorMutation } from "@x12i/memorix-descriptors";
const result = await executeDescriptorMutation(admin, {
operation: "addContentType",
input: { entityName: "assets", contentType: { key: "enrichment", postfix: "enrichment", collection: "assets-enrichment" } },
options: { dryRun: true },
});Dispatches to MemorixDescriptorAdmin methods including applyReconcileDraft. Unknown operations return UNKNOWN_OPERATION.
CLI
Binary: memorix-descriptors (after npm run build).
| Command | Status |
|---------|--------|
| validate | ✅ |
| reconcile | ✅ (needs Xronox / MONGO_URI; JSON includes inventory, issues, suggestions, applied) |
| graph [--format mermaid] | ✅ |
| entity register --file <json> [--dry-run] | ✅ |
| content-type add <entity> <key> --postfix <p> [--dry-run] | ✅ |
| list create --file <json> [--dry-run] | ✅ |
| list update <id> --file <json> [--dry-run] | ✅ |
| list add-extension <id> --file <json> | ✅ |
| list remove-extension <id> <contentType> | ✅ |
| list add-analytics <id> --file <json> | ✅ |
| list remove-analytics <id> <field> | ✅ |
| list set-sort <id> --file <json> | ✅ |
| item update <id> --file <json> [--dry-run] | ✅ |
| mapping register --file <json> [--dry-run] | ✅ |
| seed export <dir> | ✅ |
| seed import <dir> [--dry-run] | ✅ |
npx memorix-descriptors validate
npx memorix-descriptors reconcile --allow-create-collection --auto-register-orphans
npx memorix-descriptors graph --format mermaid
npx memorix-descriptors entity register --file ./new-entity.json --dry-run
npx memorix-descriptors seed export ./catalox-seeds/inputs
npx memorix-descriptors seed import ./catalox-seeds/inputs --dry-runLibrary-only today (use MemorixDescriptorAdmin directly): entity update/remove, property CRUD, content-type update/remove, list/item/slice create/remove, relation CRUD, mapping update/remove, inventory policy, ensureCollection, reconcile draft builders, applyReconcileDraft, executeDescriptorMutation, etc.
Explorer / host integration
| UI surface | API |
|------------|-----|
| Entity graph canvas | getDescriptorGraph, reconcileDescriptorsWithMongo |
| Inventory / Metadata Studio reconcile | buildMemorixUnifiedInventory (retrieval) + reconcileDescriptorsWithMongo, buildReconcileDraftForSuggestion, applyReconcileDraft |
| Add entity wizard | registerEntityDescriptor |
| Column / field editor | addProperty, updateListDescriptor |
| Detail layout editor | updateItemDescriptor |
| Slice editor | createSliceDescriptor, validateSliceDescriptor, previewSliceDescriptor |
| Collection health | reconcileDescriptorsWithMongo |
| Ignore collection | ignoreCollection, buildIgnoreCollectionDraft |
| Mapping editor | registerMapping |
| Knowledge tab | Filter entities where target === "knowledge" |
| Generic mutation HTTP | executeDescriptorMutation (optional) |
Hosts should read via @x12i/memorix-retrieval and write only through this package. Pass pre-built MemorixUnifiedInventory into reconcile when the Inventory UI already loaded it.
Validation utilities (exported)
Main entry (".")
Re-exported / extended validators (aligned with retrieval rules, plus knowledge target):
validateMemorixEntityDescriptor,validateMemorixListDescriptor,validateMemorixEntityListDescriptor,validateMemorixItemDescriptorvalidateNarrativesCatalog,validateNarrativeDefinition,validateRootPropertyCatalogvalidateMemorixSliceDescriptorShape,validateSliceDescriptorAgainstSnapshot,buildSlicePreview,isMemorixSliceDescriptorvalidateMemorixInventoryPolicy,validateIgnoredCollectionEntry,isCollectionIgnored,DEFAULT_INVENTORY_POLICYvalidatePropertyDescriptor,assertListFieldsHumanReadabledefaultListDescriptorId,defaultItemDescriptorId,singularizeEntityName,isKebabCaseparseMemorixCollectionName,defaultIdFieldForTargetDescriptorValidationError
Retrieval-safe subpaths
See Package exports. Subpath entry modules avoid importing the main "." write-side graph.
Environment variables
See .env.example.
| Variable | Purpose |
|----------|---------|
| MONGO_URI | Mongo cluster for payload data (Xronox) and Catalox metadata |
| MEMORIX_CATALOX_DB | Catalox metadata database (default memorix-catalox) |
| CATALOX_APP_ID / MEMORIX_APP_ID | App namespace (default memorix) |
| MEMORIX_ENTITIES_DB, MEMORIX_EVENTS_DB, MEMORIX_KNOWLEDGE_DB | Payload DB names |
| MEMORIX_*_COLLECTION_<ENTITY> | Per-entity collection overrides |
| MEMORIX_ENSURE_DESCRIPTOR_CATALOGS=1 | Auto-create descriptor catalogs on createMemorixDescriptorAdminFromEnv / control plane bootstrap |
| MONGO_LIVE_TESTS=1 or MEMORIX_CATALOX_LIVE_TESTS=1 | Enable live integration tests |
Tests
npm test # unit tests only (no Mongo)
npm run test:live # integration tests (reads .env, needs MONGO_LIVE_TESTS=1)
npm run test:all # bothLive tests: Mongo/Catalox connectivity, validate deployed graph, load smoke entity (MEMORIX_SMOKE_ENTITY, default assets), catalog listing, graph, collection resolve, dry-run addProperty. Reconcile live test requires MONGO_URI and asserts MemorixUnifiedInventory shape (rows, issues, generatedAt).
CI (validate-descriptor-seeds workflow) runs npm ci and npm run build with no retrieval dependency.
Gap analysis (spec vs implementation)
Implemented ✅
| Area | Coverage |
|------|----------|
| Bootstrap | createMemorixDescriptorAdmin, createMemorixDescriptorAdminFromEnv, createMemorixControlPlaneFromEnv |
| Package exports | Retrieval-safe subpaths (/types, /catalog, /collections/parse, /validation/slice-shape, /validation/inventory-policy) |
| Entity lifecycle | Register (atomic list+item), update, soft/hard remove |
| Content types | Add, update, remove with referential guards |
| Collections | Resolve, ensure (inventory), rename plan |
| Properties | Add, update, remove with list/item cascade |
| List / item descriptors | Full CRUD + set default list/item |
| Slice descriptors | CRUD, validate, preview |
| Inventory policy | Ignore / unignore collections in Catalox |
| Relations | Add, update, remove with list/item cascade |
| Mappings | CRUD + cross-validation (memorix-completion-mappings) |
| Integrity engine | Full-graph validation, dangling refs, forbidden patterns |
| Descriptor graph | Build + Mermaid export |
| Seeds | Export/import/manifest; compatible with retrieval inputs layout |
| Reconcile | Unified inventory + issues + extended suggestions; applyReconcileDraft; autoRegisterOrphans, allowCreateCollection |
| Mutation dispatcher | executeDescriptorMutation (optional) |
| Dry-run | All mutations + reconcile apply |
| Targets | entity, event, knowledge in types and entity validation |
| Transactions | executeCataloxWrites — compensating rollback on mid-batch Catalox failure; rollbackPlan on success |
| Audit | JSONL via MEMORIX_DESCRIPTORS_AUDIT_LOG or per-mutation reason |
| Concurrency | expectedVersion optimistic check on Catalox updates |
| Rename | renameEntityDescriptor(from, to) with optional deprecated source |
| Catalog bootstrap | ensureMemorixDescriptorCatalogs on createMemorixDescriptorAdminFromEnv |
| CLI | Full CRUD for entity, content-type, property, list, item, relation, mapping + reconcile flags |
| CI seeds | npm run validate:seeds + GitHub workflow |
| Tests | Unit + live Catalox suite |
Partial ⚠️
| Item | Notes |
|------|------|
| Mutation ok vs graphValid | ok = Catalox write succeeded; graphValid = projected snapshot passes integrity (legacy graphs may differ) |
| ensureCollection via Xronox | Still inventory-only when using Xronox adapter; reconcile/create uses native mongodb driver |
| Completion mappings catalog | Gracefully empty if catalog not seeded in Catalox yet |
| Retrieval seed npm scripts | Still owned by @x12i/memorix-retrieval; this package provides equivalent CLI seed commands |
| Impact report command | Use validateMemorixDescriptors + dry-run removeEntityDescriptor |
Not implemented yet ❌
| Item | Notes |
|------|------|
| Standalone impact-report CLI subcommand | Compose validation + dry-run helpers manually today |
Explicit non-goals (v1)
- Writing Memorix payload documents (stays in
@x12i/memorix-completion) - Replacing Catalox storage or building Explorer UI
- Runtime list/item composition (stays in
@x12i/memorix-retrieval)
Implementation status by phase
| Phase | Focus | Status | |-------|--------|--------| | 1 | Bootstrap, validation, entity/content/property CRUD, seeds, dry-run | ✅ Done | | 2 | List/item/relation CRUD, cascades, graph | ✅ Done | | 3 | Mappings catalog, Mongo reconcile (unified inventory) | ✅ Done | | 4 | Knowledge target, slice descriptors, inventory policy, subpath exports | ✅ Done | | 5 | Rename/migrate, audit, rollback, CLI parity, CI seeds, reconcile apply | ✅ Done (impact-report CLI optional) |
Related packages
- @x12i/memorix-retrieval — read/composition layer (discover, fetchList, fetchItem,
buildMemorixUnifiedInventory) - @x12i/catalox — descriptor storage and native catalog APIs
- @x12i/memorix-completion — Memorix payload document writes (not descriptors)
- @x12i/xronox — optional Mongo inventory for reconcile and
ensureCollection
