@x12i/memorix-metadata 3.6.2 → 3.6.3
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/CHANGELOG.md +4 -0
- package/README.md +3 -2
- package/docs/memorix-format-reference.md +117 -21
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 3.6.3
|
|
2
|
+
|
|
3
|
+
- Updated `docs/memorix-format-reference.md` (copied from `@x12i/memorix-format` at pack time). It now shows how a content type and its `profile` become the `ContentTypeProfileV2` that record validation uses, and how to validate a record against a pack offline. No validation change.
|
|
4
|
+
|
|
1
5
|
## 3.6.2
|
|
2
6
|
|
|
3
7
|
- Ship `docs/memorix-format-reference.md` and `CHANGELOG.md`. Object types, content types, and descriptors were already this package; the reference was not. No validation change.
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Install it on its own. The only runtime dependency is `@x12i/memorix-mapping`. R
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npm install @x12i/memorix-metadata@3.6.
|
|
12
|
+
npm install @x12i/memorix-metadata@3.6.3
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
| Audience | Use this package? |
|
|
@@ -83,5 +83,6 @@ Abstracts stay **virtual** — no abstract collections and no abstract `recordId
|
|
|
83
83
|
|
|
84
84
|
## Docs
|
|
85
85
|
|
|
86
|
-
- [`docs/memorix-format-reference.md`](./docs/memorix-format-reference.md) — records, object types, content types, descriptors, and mappings.
|
|
86
|
+
- [`docs/memorix-format-reference.md`](./docs/memorix-format-reference.md) — records, object types, content types, descriptors, and mappings. Section 5 covers object types, content types, and the descriptor; section 5.7 covers validating a record against a pack.
|
|
87
|
+
- [`examples/`](./examples/) — valid packs, and `examples/invalid/` with one failing rule each.
|
|
87
88
|
- Hub: [https://docs.memorix.x12i.com](https://docs.memorix.x12i.com)
|
|
@@ -6,15 +6,16 @@ This document puts in one place everything that defines how Memorix data is shap
|
|
|
6
6
|
2. The **metadata pack** (`memorix-metadata/1`): where an agent declares its **object types (OTs)**, their **content types (CTs)**, the CT **descriptor** (`profile`), fields, abstracts, and relationships.
|
|
7
7
|
3. **Mappings** (the mapping AST): how provider payloads land on an OT/CT, and how concrete fields project to abstract properties.
|
|
8
8
|
|
|
9
|
-
Each section names the
|
|
9
|
+
Each section names the package and export that is the law for it. When this document and the code disagree, the code wins.
|
|
10
10
|
|
|
11
11
|
## Using these packages on their own
|
|
12
12
|
|
|
13
13
|
Memorix depends on these packages. Anyone else can install them without the service, the database layer, or the pipeline runtime.
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install @x12i/memorix-format
|
|
17
|
-
npm install @x12i/memorix-metadata
|
|
16
|
+
npm install @x12i/memorix-format # records
|
|
17
|
+
npm install @x12i/memorix-metadata # object types, content types, descriptors (brings @x12i/memorix-mapping)
|
|
18
|
+
npm install @x12i/memorix-mapping # mappings only
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
| Package | What you get | Runtime dependencies |
|
|
@@ -25,7 +26,7 @@ npm install @x12i/memorix-metadata
|
|
|
25
26
|
|
|
26
27
|
`@x12i/memorix-metadata` installs `@x12i/memorix-mapping` for you. Validating a record or a pack does not require `@x12i/memorix-data`, `@x12i/memorix-service`, or Mongo. Routing and the write path live in `@x12i/memorix-data`; they are listed below so the error codes make sense, and they are not needed to use the format or the descriptors.
|
|
27
28
|
|
|
28
|
-
This file ships as `docs/memorix-format-reference.md` in
|
|
29
|
+
This file ships as `docs/memorix-format-reference.md` in all three packages. The copy in `@x12i/memorix-format` is the source; the other two are copied from it when they are packed.
|
|
29
30
|
|
|
30
31
|
```ts
|
|
31
32
|
import { validateMemorixRecordV2 } from "@x12i/memorix-format/v2";
|
|
@@ -36,14 +37,14 @@ import {
|
|
|
36
37
|
} from "@x12i/memorix-metadata";
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
| Layer | Package |
|
|
40
|
+
| Layer | Package | Exports and files |
|
|
40
41
|
|---|---|---|
|
|
41
|
-
| Record envelope | `@x12i/memorix-format` | `memorix-format/docs/memorix-record-v2.md
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
42
|
+
| Record envelope | `@x12i/memorix-format` | `MemorixRecordV2`, `validateMemorixRecordV2` (from `@x12i/memorix-format/v2`); `docs/memorix-record-v2.md` |
|
|
43
|
+
| Format-level content-type profile | `@x12i/memorix-format` | `ContentTypeProfileV2`, `BUILTIN_CONTENT_PROFILES`, `resolveContentProfile` |
|
|
44
|
+
| OT / CT / descriptor / abstracts / relationships / mapping declarations | `@x12i/memorix-metadata` | `MetadataPack`, `ObjectTypeDefinition`, `ContentTypeSpec`, `ContentTypeProfileDecl`, `validateMetadataPack` |
|
|
45
|
+
| Platform interfaces (Entity / Event / Knowledge) | `@x12i/memorix-metadata` | `PLATFORM_INTERFACES` |
|
|
46
|
+
| Mapping AST and execution | `@x12i/memorix-mapping` | `MappingDocument`, `MappingExpr`, `executeMapping`, `validateMappingDocument` |
|
|
47
|
+
| Physical routing and write-time checks | `@x12i/memorix-data` (Memorix runtime; not needed to use the format) | `databaseNameFor`, `contentCollectionName`, the content writer |
|
|
47
48
|
|
|
48
49
|
---
|
|
49
50
|
|
|
@@ -59,7 +60,7 @@ import {
|
|
|
59
60
|
| **Abstract type** | A metadata-only type that one or more OTs project into (for example `People`). Never has a collection or its own `recordId`. Views, agent services, and relationships speak abstracts. |
|
|
60
61
|
| **Platform interface** | The sealed abstracts `Entity`, `Event`, `Knowledge`. Every OT implements the one that matches its data category. |
|
|
61
62
|
| **Mapping** | A declarative transform written in the mapping AST. Purpose is `source`, `abstract`, or `completion`. |
|
|
62
|
-
| **Managed descriptor (legacy)** | Older Catalox "entity descriptors" in `memorix-retrieval/catalox-seeds`. Only an inventory of them is kept
|
|
63
|
+
| **Managed descriptor (legacy)** | Older Catalox "entity descriptors" in `memorix-retrieval/catalox-seeds`. Only an inventory of them is kept, in `meta/inventory/managed-descriptors.json` of `@x12i/memorix-format`. They are not format law and not agent packs. |
|
|
63
64
|
|
|
64
65
|
---
|
|
65
66
|
|
|
@@ -99,8 +100,10 @@ type MemorixRecordV2 = {
|
|
|
99
100
|
};
|
|
100
101
|
};
|
|
101
102
|
data: Record<string, unknown>;
|
|
103
|
+
subject?: { objectType: string; recordId: string };
|
|
102
104
|
context?: Record<string, unknown>;
|
|
103
105
|
_metadata?: Record<string, unknown>;
|
|
106
|
+
_markdown?: { content: string; source: "ai" | "json" | "content"; metadata?: Record<string, unknown> };
|
|
104
107
|
_audit?: Record<string, unknown>;
|
|
105
108
|
_history?: Array<Record<string, unknown>>;
|
|
106
109
|
analytics?: Record<string, unknown>;
|
|
@@ -112,8 +115,14 @@ type MemorixRecordV2 = {
|
|
|
112
115
|
createdAt: string;
|
|
113
116
|
modifiedAt: string;
|
|
114
117
|
observedAt?: string;
|
|
118
|
+
writtenAt?: string;
|
|
115
119
|
lifecycle?: Array<{ process: string; processedAt: string }>;
|
|
116
120
|
provenance?: Record<string, unknown>;
|
|
121
|
+
_datasource?: {
|
|
122
|
+
service: string; ingress: string; basis: string; recordedAt: string;
|
|
123
|
+
origin?: string; channel?: string; originRecordId?: string; originAt?: string;
|
|
124
|
+
sources?: Array<{ system: string; name: string }>;
|
|
125
|
+
};
|
|
117
126
|
deletion?: { deletedAt: string; by: string; via: "content" | "patch"; patchId?: string; reason?: string };
|
|
118
127
|
};
|
|
119
128
|
};
|
|
@@ -133,8 +142,10 @@ type MemorixRecordV2 = {
|
|
|
133
142
|
| `concept.identifiers.primary` | yes | `{ kind, value }`, optional `issuer` and `normalizedValue`. |
|
|
134
143
|
| `concept.identifiers.alternates` | no | Omit when empty. |
|
|
135
144
|
| `data` | yes | The subject content itself. JSON markdown is rendered from `data` only. |
|
|
145
|
+
| `subject` | no | `{ objectType, recordId }` of the subject this row is about, when that subject is a different OT. The row keeps its own `recordId`. List filters use `subject.recordId`. |
|
|
136
146
|
| `context` | no | Context payloads that are not the subject content. Omit when empty. Not rendered to markdown. |
|
|
137
147
|
| `_metadata` | no | Producer context (for example `stepId`, `writtenBy`). A key here must not also be in `data`. Not `_system.provenance` and not `_markdown.metadata`. |
|
|
148
|
+
| `_markdown` | no | Original text beside `data`. `source` is `ai`, `json`, or `content`. Writers fill `source: "json"` from `data` when it is omitted. Readers omit it unless the fetch asks for markdown. |
|
|
138
149
|
| `_audit` | no | Audit of the record. When present, `provider`, `model`, and `reasoningEffort` must be non-empty strings. Other keys are open. |
|
|
139
150
|
| `_history` | no | Earlier products of this record, oldest first. Each entry is an object stored as given. An empty array is valid and differs from an absent key. A write that removes fields appends `{ action: "patch", caller, modifiedAt, removed: string[] }`. |
|
|
140
151
|
| `analytics` | no | Numeric rollups. Allowed only when the CT descriptor has `allowSnapshotBuckets: true`. |
|
|
@@ -144,6 +155,8 @@ type MemorixRecordV2 = {
|
|
|
144
155
|
| `_system.state` | yes | `active`, `archived`, `superseded`, or `deleted`. |
|
|
145
156
|
| `_system.createdAt` / `modifiedAt` | yes | ISO timestamps. |
|
|
146
157
|
| `_system.observedAt` | no | Default source for the `Event.occurredAt` interface property. |
|
|
158
|
+
| `_system.writtenAt` | no | Clock time of the write that produced this revision. |
|
|
159
|
+
| `_system._datasource` | no | Memorix-owned document source (`service`, `ingress`, `basis`, `recordedAt`, optional `origin`, `channel`, `sources`). Not part of `data`. |
|
|
147
160
|
| `_system.lifecycle` | no | Appended only for meaningful process events. Omit when empty. Independent of `revision`. |
|
|
148
161
|
| `_system.provenance` | no | Source attribution such as `sourceId` or `endpoint`. |
|
|
149
162
|
| `_system.deletion` | conditional | Present if and only if `state` is `deleted` (`V2-DELETION`). |
|
|
@@ -154,8 +167,9 @@ type MemorixRecordV2 = {
|
|
|
154
167
|
- `analytics`, `enrichment`, and `insights` appear only on CTs whose descriptor sets `allowSnapshotBuckets: true`.
|
|
155
168
|
- If the CT declares a discriminator with a `defaultValue` and the record lacks it, validation warns `V2-DISCRIMINATOR-DEFAULT` and the writer fills the default. If it is required with no default, validation fails with `V2-DISCRIMINATOR`.
|
|
156
169
|
- What a delete does is declared on the CT (`profile.deletion`), see section 5.2.
|
|
170
|
+
- Section 5.7 shows how the metadata descriptor becomes the profile that `validateMemorixRecordV2` checks.
|
|
157
171
|
|
|
158
|
-
Golden examples live in `memorix-format
|
|
172
|
+
Golden examples live in `examples/v2/` of `@x12i/memorix-format`.
|
|
159
173
|
|
|
160
174
|
---
|
|
161
175
|
|
|
@@ -245,7 +259,7 @@ type ContentTypeProfileDecl = {
|
|
|
245
259
|
| `deletion.mode` | `logical`: the row stays with `_system.state: "deleted"` and reads hide it. `tracked`: the row is removed and a `memorix-deletion/1` entry is written to `deletions`. `untracked`: the row is removed and nothing is recorded. Omitted `deletion` means `{ mode: "tracked", keepBody: false }`. |
|
|
246
260
|
| `deletion.keepBody` | Only valid with `tracked`. Keeps the removed body on the ledger entry. Purges and legacy-instance deletions never keep the body. A CT declares the same policy on every OT that uses it. |
|
|
247
261
|
|
|
248
|
-
Write-time enforcement: if the effective catalog has no descriptor for the CT, the writer throws `METADATA_DESCRIPTOR_MISSING` (HTTP 400, with a `next` hint pointing at `/api/metadata/ensure`).
|
|
262
|
+
Write-time enforcement: if the effective catalog has no descriptor for the CT, the writer throws `METADATA_DESCRIPTOR_MISSING` (HTTP 400, with a `next` hint pointing at `/api/metadata/ensure`).
|
|
249
263
|
|
|
250
264
|
### 5.3 Fields (`ObjectTypeFieldSpec`)
|
|
251
265
|
|
|
@@ -275,7 +289,7 @@ Published by the skill API and run with `POST /api/v1/agent-functions/agents/{ag
|
|
|
275
289
|
|
|
276
290
|
### 5.5 Content-type vocabulary in use
|
|
277
291
|
|
|
278
|
-
Any routing-safe id may be declared. These are the CTs the platform and current packs use (`
|
|
292
|
+
Any routing-safe id may be declared. These are the CTs the platform and current packs use (`meta/content-types.json` in `@x12i/memorix-format`):
|
|
279
293
|
|
|
280
294
|
| CT | Typical descriptor | Purpose |
|
|
281
295
|
|---|---|---|
|
|
@@ -293,6 +307,80 @@ Any routing-safe id may be declared. These are the CTs the platform and current
|
|
|
293
307
|
|
|
294
308
|
The lander declares OTs and their source CTs. A skill appends only its target CTs to an OT that already exists, and never re-declares source CTs. Because ensure replaces the catalog, a skill always merges into the full pack from `/api/metadata/raw` before it ensures.
|
|
295
309
|
|
|
310
|
+
### 5.7 From metadata descriptor to format profile
|
|
311
|
+
|
|
312
|
+
`@x12i/memorix-format` does not read metadata packs. `validateMemorixRecordV2` takes a `ContentTypeProfileV2`, the format-level descriptor:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
type ContentTypeProfileV2 = {
|
|
316
|
+
contentType: string;
|
|
317
|
+
allowSnapshotBuckets: boolean;
|
|
318
|
+
discriminator?: { path: string; required: boolean; defaultValue?: string; allowedValues?: string[] };
|
|
319
|
+
allowedExtraRoots?: string[];
|
|
320
|
+
deletion?: { mode: "logical" | "tracked" | "untracked"; keepBody?: boolean };
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Memorix builds it from the metadata content type like this:
|
|
325
|
+
|
|
326
|
+
| `ContentTypeProfileV2` | Comes from (`ContentTypeSpec`) |
|
|
327
|
+
|---|---|
|
|
328
|
+
| `contentType` | `id` |
|
|
329
|
+
| `allowSnapshotBuckets` | `profile.allowSnapshotBuckets` |
|
|
330
|
+
| `deletion` | `profile.deletion`, parsed with `parseDeletionPolicy`. An invalid declaration reads as absent. |
|
|
331
|
+
| `discriminator.path` | `discriminator.path`. With no path, there is no discriminator. |
|
|
332
|
+
| `discriminator.required` | `discriminator.required === true` (default `false`) |
|
|
333
|
+
| `discriminator.defaultValue` | `discriminator.defaultValue` when it is a non-empty string |
|
|
334
|
+
| `allowedValues`, `allowedExtraRoots` | Not set from metadata. Available to callers that validate offline. |
|
|
335
|
+
|
|
336
|
+
The lookup is by content-type id across the caller's effective object types, and the first match wins. That is why one CT id must declare the same `allowSnapshotBuckets` and `deletion` on every OT (`META-CT-PROFILE`).
|
|
337
|
+
|
|
338
|
+
When no profile is passed, `validateMemorixRecordV2` falls back to `resolveContentProfile(contentType)`, which uses `BUILTIN_CONTENT_PROFILES`:
|
|
339
|
+
|
|
340
|
+
| CT | `allowSnapshotBuckets` | Built-in discriminator |
|
|
341
|
+
|---|---|---|
|
|
342
|
+
| `snapshots`, `knowledge` | `true` | none |
|
|
343
|
+
| `raw`, `workflow`, `context`, `relationships`, `events` | `false` | none |
|
|
344
|
+
| `discovery` | `false` | `data.discoveryType`, default `default` |
|
|
345
|
+
| `analysis` | `false` | `data.analysisType`, default `default` |
|
|
346
|
+
| `decisions` | `false` | `data.decisionType`, default `default` |
|
|
347
|
+
| any other id | `false` | none |
|
|
348
|
+
|
|
349
|
+
A pack's descriptor always replaces the built-in profile, including its discriminator.
|
|
350
|
+
|
|
351
|
+
To validate a record offline against a pack, without Memorix:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
import {
|
|
355
|
+
validateMemorixRecordV2,
|
|
356
|
+
parseDeletionPolicy,
|
|
357
|
+
type ContentTypeProfileV2,
|
|
358
|
+
} from "@x12i/memorix-format/v2";
|
|
359
|
+
import type { ContentTypeSpec } from "@x12i/memorix-metadata";
|
|
360
|
+
|
|
361
|
+
function toProfile(ct: ContentTypeSpec): ContentTypeProfileV2 {
|
|
362
|
+
const deletion = ct.profile.deletion ? parseDeletionPolicy(ct.profile.deletion) : undefined;
|
|
363
|
+
return {
|
|
364
|
+
contentType: ct.id,
|
|
365
|
+
allowSnapshotBuckets: ct.profile.allowSnapshotBuckets,
|
|
366
|
+
...(deletion?.ok ? { deletion: deletion.policy } : {}),
|
|
367
|
+
...(ct.discriminator?.path
|
|
368
|
+
? {
|
|
369
|
+
discriminator: {
|
|
370
|
+
path: ct.discriminator.path,
|
|
371
|
+
required: ct.discriminator.required === true,
|
|
372
|
+
...(ct.discriminator.defaultValue ? { defaultValue: ct.discriminator.defaultValue } : {}),
|
|
373
|
+
},
|
|
374
|
+
}
|
|
375
|
+
: {}),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const ct = pack.objectTypes.find((o) => o.id === record.objectType)!
|
|
380
|
+
.contentTypes.find((c) => c.id === record.contentType)!;
|
|
381
|
+
const result = validateMemorixRecordV2(record, { profile: toProfile(ct), enforceDiscriminator: true });
|
|
382
|
+
```
|
|
383
|
+
|
|
296
384
|
---
|
|
297
385
|
|
|
298
386
|
## 6. Abstract types and platform interfaces
|
|
@@ -414,7 +502,7 @@ Run with `executeMapping`, `simulateMapping` (adds coverage), and `executeRevers
|
|
|
414
502
|
|
|
415
503
|
## 9. Worked example
|
|
416
504
|
|
|
417
|
-
A pack fragment with one OT, two CTs, an abstract with a direct binding, a source mapping, and an abstract mapping. A complete real pack is in
|
|
505
|
+
A pack fragment with one OT, two CTs, an abstract with a direct binding, a source mapping, and an abstract mapping. A complete real pack is `examples/opx/normalized/pack.json` in `@x12i/memorix-metadata`.
|
|
418
506
|
|
|
419
507
|
```json
|
|
420
508
|
{
|
|
@@ -566,12 +654,20 @@ A stored record for that OT/CT, in collection `work-items-snapshots` of database
|
|
|
566
654
|
|
|
567
655
|
## Related documents
|
|
568
656
|
|
|
569
|
-
|
|
657
|
+
In `@x12i/memorix-format`:
|
|
570
658
|
|
|
571
659
|
- `docs/memorix-record-v2.md`: the full envelope contract and its locked decisions.
|
|
572
|
-
- `docs/migrate-present-to-v2.md`: migrating the older present envelope
|
|
660
|
+
- `docs/migrate-present-to-v2.md`: migrating the older present envelope to `memorix-record/2`.
|
|
573
661
|
- `docs/memorix-workflow-format.md`: the `workflow` content type.
|
|
574
|
-
- `docs/
|
|
575
|
-
- `meta/`: envelope, open-bucket, and content-type vocabulary.
|
|
662
|
+
- `docs/memorix-format.md`, `docs/memorix-format-requirements.md`, `docs/association-format.md`: the older present envelope. Read them only to migrate existing data.
|
|
663
|
+
- `meta/`: envelope, open-bucket, and content-type vocabulary as JSON.
|
|
664
|
+
- `examples/v2/`: valid `memorix-record/2` documents.
|
|
665
|
+
|
|
666
|
+
In `@x12i/memorix-metadata`:
|
|
667
|
+
|
|
668
|
+
- `examples/opx/`, `examples/knowx/`, `examples/analytics/`, `examples/custom-kinds/`: valid packs.
|
|
669
|
+
- `examples/invalid/`: packs that fail validation, one rule each.
|
|
670
|
+
|
|
671
|
+
In `@x12i/memorix-mapping`:
|
|
576
672
|
|
|
577
|
-
|
|
673
|
+
- `examples/`: source, abstract, and completion mappings.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x12i/memorix-metadata",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.3",
|
|
4
4
|
"description": "Memorix object-type and content-type descriptors, metadata pack contracts, and validation. Depends only on @x12i/memorix-mapping.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"build": "tsc -p tsconfig.build.json",
|
|
24
24
|
"test": "vitest run",
|
|
25
25
|
"test:watch": "vitest",
|
|
26
|
-
"typecheck": "tsc --noEmit"
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"prepack": "node ../scripts/sync-format-reference.mjs && npm run build"
|
|
27
28
|
},
|
|
28
29
|
"engines": {
|
|
29
30
|
"node": ">=18.0.0"
|