@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/xronox
Optional 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 TTL
const { 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-run
Library-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 # both
Live 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