@x12i/memorix-format 2.2.2 → 2.2.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.
@@ -1,956 +0,0 @@
1
- # Appendix: Extended Memorix Record Parts
2
-
3
- > Shipped with `@x12i/memorix-format`. Examples may show the older `identity` envelope for illustration; the **canonical** clean envelope is [`memorix-format.md`](./memorix-format.md).
4
-
5
- ## A. Why this appendix exists
6
-
7
- The main Memorix 2.0 format defines the clean structure of a record:
8
-
9
- ```txt id="v3yvcs"
10
- identity
11
- lifecycle
12
- concept
13
- data
14
- index
15
- sourceFacts
16
- _system
17
- ```
18
-
19
- This appendix adds the missing higher-level distinction between four different kinds of information that are often mixed together:
20
-
21
- ```txt id="dw987j"
22
- native facts
23
- associated context
24
- numeric analytics
25
- interpretive insights
26
- ```
27
-
28
- The distinction matters because Memorix records need to be easy to consume, but also semantically clean.
29
-
30
- The existing Memorix contract already says that domain payload belongs in `data`, while system and provenance fields should stay outside `data`. The same idea should now be extended to associated context, analytics, and insights.
31
-
32
- ---
33
-
34
- ## B. Full snapshot record shape
35
-
36
- The full-scale Memorix record shape is intended mainly for the `snapshot` content type of an object type.
37
-
38
- ```ts id="km4sqn"
39
- type MemorixSnapshotRecord = {
40
- _id?: string;
41
-
42
- identity: MemorixIdentity;
43
- lifecycle: MemorixLifecycle;
44
- concept: MemorixConcept;
45
-
46
- data: JsonObject;
47
-
48
- associatedData?: JsonObject;
49
- analytics?: MemorixAnalytics;
50
- insights?: MemorixInsights;
51
-
52
- index?: MemorixIndexBlock;
53
- sourceFacts?: MemorixSourceFacts;
54
-
55
- _system?: MemorixSystemBlock;
56
- };
57
- ```
58
-
59
- This is the rich, readable, consumption-friendly version of the object.
60
-
61
- Other content types under the same object type do not need to carry all of these blocks. Memorix already stores records by object type and content type, for example `items-snapshots` or `findings-snapshots`.
62
-
63
- So the rule is:
64
-
65
- ```txt id="s9zbmc"
66
- The full record shape belongs primarily to snapshots.
67
- Other content types should contain only what makes sense for that content type.
68
- ```
69
-
70
- ---
71
-
72
- ## C. Minimal shape for non-snapshot content types
73
-
74
- For the product **workflow** content type (`{objectType}-workflow`, format
75
- `memorix-workflow/1`), see [memorix-workflow-format.md](./memorix-workflow-format.md).
76
- Workflow is 1:1 product state (owner, status, audit, tasks); catalog-driven
77
- fields under `data` are defined in Catalox `memorix-workflow-field-schemas`.
78
-
79
- Not every collection under an object type should look like a full snapshot.
80
-
81
- For example:
82
-
83
- ```txt id="evq5gl"
84
- items-snapshots
85
- items-events
86
- items-facts
87
- items-chunks
88
- items-history
89
- items-profiles
90
- ```
91
-
92
- Only `items-snapshots` needs the full record surface.
93
-
94
- Other content types should have the required Memorix structure, but not unnecessary blocks.
95
-
96
- Recommended minimal shape:
97
-
98
- ```ts id="uak8ve"
99
- type MemorixContentRecord = {
100
- _id?: string;
101
-
102
- identity: MemorixIdentity;
103
- lifecycle?: MemorixLifecycle;
104
- concept?: MemorixConcept;
105
-
106
- data: JsonObject;
107
-
108
- index?: MemorixIndexBlock;
109
- sourceFacts?: MemorixSourceFacts;
110
-
111
- _system?: MemorixSystemBlock;
112
- };
113
- ```
114
-
115
- Required minimum:
116
-
117
- ```txt id="rq22ev"
118
- identity
119
- data
120
- whatever metadata/keys Memorix needs for that content type
121
- ```
122
-
123
- Memorix should decide the exact required keys by content type, descriptor, and object behavior.
124
-
125
- The important point:
126
-
127
- ```txt id="6pdkqx"
128
- Do not force analytics, insights, or associatedData into every content type.
129
- ```
130
-
131
- ---
132
-
133
- ## D. `data`: native readable facts
134
-
135
- `data` is the record’s own readable truth.
136
-
137
- It should contain facts that are directly about the record itself.
138
-
139
- For a CVE record:
140
-
141
- ```json id="lqeccc"
142
- {
143
- "data": {
144
- "docId": "DOC-9",
145
- "severity": "critical",
146
- "description": "Unrestricted file upload vulnerability in WSO2 products.",
147
- "publishedAt": "2022-04-18"
148
- }
149
- }
150
- ```
151
-
152
- These are facts about the CVE itself.
153
-
154
- `data` should not contain unrelated records, source-system noise, enum codes, opaque ids, or product judgments.
155
-
156
- ---
157
-
158
- ## E. `associatedData`: readable related context
159
-
160
- `associatedData` contains useful readable context attached to the record because of related records.
161
-
162
- It is not the record’s native truth, but it is very useful for consumption.
163
-
164
- For example, a CVE record may need to show the items affected by that CVE.
165
-
166
- Those items are not part of the CVE itself, so they should not live in `data`.
167
-
168
- But consumers still need them.
169
-
170
- So they belong in `associatedData`.
171
-
172
- ```json id="m7pzc6"
173
- {
174
- "associatedData": {
175
- "affectedAssets": [
176
- {
177
- "assetName": "prod-api-01",
178
- "sku": "10.100.18.64",
179
- "recordId": "entity:asset:10.100.18.64"
180
- },
181
- {
182
- "assetName": "prod-db-02",
183
- "sku": "10.100.18.65",
184
- "recordId": "entity:asset:10.100.18.65"
185
- }
186
- ]
187
- }
188
- }
189
- ```
190
-
191
- This gives consumers the useful joined view without pretending that affected items are native CVE fields.
192
-
193
- ### Rule
194
-
195
- ```txt id="cqzqcl"
196
- associatedData = readable materialized context from related records
197
- ```
198
-
199
- ---
200
-
201
- ## F. `analytics`: numeric rollups about linked lists
202
-
203
- `analytics` is not the associated data itself.
204
-
205
- `analytics` contains numbers about associated lists.
206
-
207
- It is used when the record has links to lists of other records, and Memorix wants to store useful numeric summaries about those lists.
208
-
209
- For example:
210
-
211
- ```txt id="omk77f"
212
- CVE -> affected items
213
- asset -> related findings
214
- document -> exposed users
215
- user -> accessible sensitive files
216
- group -> member users
217
- policy -> affected resources
218
- ```
219
-
220
- If a CVE is linked to many affected items, then `analytics.affectedAssets` contains numbers about that list.
221
-
222
- ```json id="uerbc6"
223
- {
224
- "analytics": {
225
- "affectedAssets": {
226
- "total": 12,
227
- "internetExposed": 3,
228
- "production": 5,
229
- "withOpenFindings": 9
230
- }
231
- }
232
- }
233
- ```
234
-
235
- The actual affected asset list belongs in `associatedData`.
236
-
237
- The internal record links belong in `index.recordLinks`.
238
-
239
- The numeric summaries belong in `analytics`.
240
-
241
- ### What belongs in `analytics`
242
-
243
- ```txt id="fdwu3l"
244
- counts
245
- totals
246
- distributions
247
- buckets
248
- aggregations
249
- list summaries
250
- numeric rollups
251
- ```
252
-
253
- Examples:
254
-
255
- ```json id="1dwp79"
256
- {
257
- "analytics": {
258
- "affectedAssets": {
259
- "total": 12,
260
- "byEnvironment": {
261
- "production": 5,
262
- "staging": 4,
263
- "development": 3
264
- },
265
- "internetExposed": 3
266
- },
267
- "relatedFindings": {
268
- "total": 18,
269
- "open": 14,
270
- "closed": 4
271
- }
272
- }
273
- }
274
- ```
275
-
276
- ### What does not belong in `analytics`
277
-
278
- Do not put the actual related records in `analytics`.
279
-
280
- Bad:
281
-
282
- ```json id="8e7c4g"
283
- {
284
- "analytics": {
285
- "affectedAssets": [
286
- {
287
- "assetName": "prod-api-01",
288
- "sku": "10.100.18.64"
289
- }
290
- ]
291
- }
292
- }
293
- ```
294
-
295
- Good:
296
-
297
- ```json id="3t9cdo"
298
- {
299
- "associatedData": {
300
- "affectedAssets": [
301
- {
302
- "assetName": "prod-api-01",
303
- "sku": "10.100.18.64"
304
- }
305
- ]
306
- },
307
- "analytics": {
308
- "affectedAssets": {
309
- "total": 1
310
- }
311
- }
312
- }
313
- ```
314
-
315
- ### Rule
316
-
317
- ```txt id="7wh3kh"
318
- analytics answers: how many, how much, how distributed, how often.
319
- ```
320
-
321
- ---
322
-
323
- ## G. `insights`: interpretations, judgments, and decisions
324
-
325
- `insights` contains interpreted meaning about the record.
326
-
327
- It is the place for judgments, assessments, analysis, scores, conclusions, recommendations, classifications, confidence, and priority.
328
-
329
- ```json id="2dxvna"
330
- {
331
- "insights": {
332
- "risk": {
333
- "level": "critical",
334
- "score": 92,
335
- "confidence": 0.84,
336
- "reason": "Critical CVE affecting production and internet-exposed items."
337
- },
338
- "priority": {
339
- "level": "urgent",
340
- "reason": "Affected items include production systems."
341
- },
342
- "recommendations": [
343
- {
344
- "action": "Patch affected items",
345
- "urgency": "high"
346
- }
347
- ]
348
- }
349
- }
350
- ```
351
-
352
- ### Why this must be separate from `data`
353
-
354
- A score is not the same as a fact.
355
-
356
- This is a fact:
357
-
358
- ```json id="vfqhn8"
359
- {
360
- "severity": "critical"
361
- }
362
- ```
363
-
364
- This is an insight:
365
-
366
- ```json id="tdrpzw"
367
- {
368
- "riskScore": 92,
369
- "priority": "urgent",
370
- "recommendedAction": "Patch affected items"
371
- }
372
- ```
373
-
374
- If insights are placed inside `data`, they can pollute the record’s native meaning.
375
-
376
- ### Rule
377
-
378
- ```txt id="41g5nl"
379
- insights answers: so what, how bad, what should we do, how confident are we.
380
- ```
381
-
382
- ---
383
-
384
- ## H. Difference between `associatedData`, `analytics`, and `insights`
385
-
386
- These three are easy to confuse, so the distinction must be strict.
387
-
388
- ```txt id="d2vm9q"
389
- associatedData = the related things
390
- analytics = numbers about the related things
391
- insights = conclusions from the facts, context, and numbers
392
- ```
393
-
394
- Example:
395
-
396
- ```json id="3n6qlf"
397
- {
398
- "data": {
399
- "docId": "DOC-9",
400
- "severity": "critical"
401
- },
402
-
403
- "associatedData": {
404
- "affectedAssets": [
405
- {
406
- "assetName": "prod-api-01",
407
- "sku": "10.100.18.64"
408
- },
409
- {
410
- "assetName": "prod-db-02",
411
- "sku": "10.100.18.65"
412
- }
413
- ]
414
- },
415
-
416
- "analytics": {
417
- "affectedAssets": {
418
- "total": 2,
419
- "production": 2,
420
- "internetExposed": 1
421
- }
422
- },
423
-
424
- "insights": {
425
- "risk": {
426
- "level": "critical",
427
- "reason": "The CVE affects production items, including one internet-exposed asset."
428
- }
429
- }
430
- }
431
- ```
432
-
433
- This keeps the model clean:
434
-
435
- ```txt id="sjw9xv"
436
- data says what the record is.
437
- associatedData says what is connected to it.
438
- analytics says how much or how many.
439
- insights says what Memorix concludes.
440
- ```
441
-
442
- ---
443
-
444
- ## I. Relationship with `index.recordLinks`
445
-
446
- `index.recordLinks` is the internal link/index surface.
447
-
448
- It is not meant to replace `associatedData`.
449
-
450
- It is used by Memorix for search, expansion, linking, retrieval, ranking, and internal navigation.
451
-
452
- The existing Memorix model already treats relations as read-time joins rather than stored graph edges.
453
-
454
- The Memorix 2.0 model keeps that philosophy but gives links an indexed representation when needed.
455
-
456
- Example:
457
-
458
- ```json id="6akxmw"
459
- {
460
- "index": {
461
- "recordLinks": [
462
- {
463
- "key": "affectedAssets",
464
- "relation": "affects",
465
- "direction": "out",
466
- "target": {
467
- "recordId": "entity:asset:10.100.18.64",
468
- "target": "entity",
469
- "objectType": "items"
470
- },
471
- "display": {
472
- "name": "prod-api-01"
473
- },
474
- "indexed": true
475
- }
476
- ]
477
- }
478
- }
479
- ```
480
-
481
- The same relationship may appear in different ways:
482
-
483
- ```txt id="f0c6wq"
484
- index.recordLinks = internal link
485
- associatedData = readable related record view
486
- analytics = numeric summary of the linked list
487
- insights = interpretation based on the relationship
488
- ```
489
-
490
- ---
491
-
492
- ## J. Relationship with `sourceFacts`
493
-
494
- `sourceFacts` preserves raw values used for resolution and traceability.
495
-
496
- Example:
497
-
498
- ```json id="x0e556"
499
- {
500
- "sourceFacts": {
501
- "schemaVersion": "sourceFacts.v1",
502
- "values": {
503
- "assetId": {
504
- "rawValue": "a_918271",
505
- "kind": "foreign-key",
506
- "resolvedToPath": "associatedData.affectedAssets[0].assetName",
507
- "resolvedValue": "prod-api-01"
508
- }
509
- }
510
- }
511
- }
512
- ```
513
-
514
- The raw value belongs in `sourceFacts`.
515
-
516
- The readable related object belongs in `associatedData`.
517
-
518
- The internal link belongs in `index.recordLinks`.
519
-
520
- The count belongs in `analytics`.
521
-
522
- The conclusion belongs in `insights`.
523
-
524
- ---
525
-
526
- ## K. Relationship with Memorix-Hippox
527
-
528
- Memorix-Hippox is the metadata database of Memorix.
529
-
530
- It remembers how things relate, how values are resolved, and how source-system mess becomes Memorix meaning.
531
-
532
- For this appendix, Hippox should remember product-level metadata such as:
533
-
534
- ```txt id="y7qppy"
535
- which object types can be linked
536
- which links are one-to-one
537
- which links are one-to-many
538
- which linked lists should produce analytics
539
- which linked lists should produce associatedData
540
- which enum/code values resolve to readable values
541
- which fields should become insights
542
- which fields are native data
543
- which fields are raw source facts
544
- which sourcePath/targetPath pairs join two object types
545
- ```
546
-
547
- The record does not need to store the full Hippox metadata format.
548
-
549
- The record stores the result:
550
-
551
- ```txt id="s0v4wk"
552
- sourceFacts keeps raw resolver material.
553
- index.recordLinks keeps internal links.
554
- associatedData keeps readable related context.
555
- analytics keeps numeric rollups.
556
- insights keeps interpreted conclusions.
557
- ```
558
-
559
- ### K.1 Three Hippox surfaces on a snapshot record
560
-
561
- | Layer | Who writes it | Hippox involvement |
562
- |-------|---------------|-------------------|
563
- | `index.recordLinks` | ingest / indexer | schema relations; optional Hippox-approved join metadata |
564
- | `associatedData` | snapshot materializer | readable output from approved context links (`retrieval.type: record` or `list`) |
565
- | `analytics` / `insights` | downstream jobs | Hippox may define which linked lists feed rollups or conclusions |
566
-
567
- Context link rules themselves live in Mongo database **`memorix-hippox`** (collection **`context-links`**). Records only carry materialized results.
568
-
569
- ### K.2 Context links vs schema relations
570
-
571
- Schema relations (entity descriptors) declare durable product semantics and populate `index.recordLinks`.
572
-
573
- **Context links** (`@x12i/memorix-hippox`) let operators define property joins without changing schema first:
574
-
575
- ```txt
576
- discover → join-discovery ranks fields from sampled data
577
- simulate → validates proposed join on samples
578
- approve → persists reusable link definition
579
- resolve → bounded runtime context (jobMemory.context)
580
- ```
581
-
582
- Join paths use the same dot-path convention as descriptors: from document root, typically under `data.*`.
583
-
584
- Example operator flow for `items → locations`:
585
-
586
- ```http
587
- GET /api/hippox/join-discovery?sourceObjectType=items&targetObjectType=locations
588
- POST /api/hippox/links/simulate
589
- POST /api/hippox/links/:id/approve
590
- POST /api/hippox/context/resolve
591
- ```
592
-
593
- Discovery seeds from schema relations and previously approved Hippox links so declared joins stay rank 1 even on rediscovery.
594
-
595
- When a snapshot is fully materialized, readable joined targets belong in **`associatedData`**, not mixed into native `data` fields. Internal pointers stay in **`index.recordLinks`**.
596
-
597
- ### K.3 Snapshot-only materialization rule
598
-
599
- `associatedData`, `analytics`, and `insights` are snapshot-only by default (see §L). Hippox context resolution at job time produces transient `jobMemory.context`; persisting that output onto a snapshot is an explicit materialization step, not automatic on every resolve call.
600
-
601
- ### K.4 Automated fuzzy mapping (`@x12i/helpers` ≥ 2.0)
602
-
603
- For scopes **without** entity descriptors or schema relations — migration dumps, external API clusters, audit JSON — Hippox can use the **`@x12i/helpers/record-key-analysis`** pipeline to infer joins before an operator touches the UI.
604
-
605
- **Prerequisite:** `@x12i/helpers@^2.0.0` with `analyzeSingleRecordKeys`, `analyzeCollectionKeys`, and `mapCrossCollectionRelationships`.
606
-
607
- **Phase 1 — Ingestion and sampling**
608
-
609
- Loop all collections in scope. Sample up to **10,000** records per collection (same order of magnitude as Hippox discovery/simulation limits). Hippox reuses its Mongo collection resolver for Memorix object types; raw JSON arrays use the same sample cap in memory.
610
-
611
- **Phase 2 — Entity profiling (per collection)**
612
-
613
- 1. `analyzeSingleRecordKeys(firstRecord)` — candidate property names with confidence scores.
614
- 2. Keep properties where **`confidence >= 40`** (reduces CPU vs profiling every column).
615
- 3. `analyzeCollectionKeys(fullSample, candidateProperties)` — classify each property:
616
- - **`PRIMARY`** → entity primary identifiers (candidate join targets)
617
- - **`FOREIGN`** → unresolved outbound keys (candidate Hippox `sourcePath`)
618
- - **`ENUM`** → data dictionary entries (future `sourceFacts` resolver seeds)
619
-
620
- Store results in a central schema registry (in-memory map or JSON artifact).
621
-
622
- **Phase 3 — Cross-collection relationship mapping**
623
-
624
- After all collections are profiled:
625
-
626
- 1. Build `targetCollectionsMap`: each collection name → `{ primaryKeys, records }` using Phase 2 `PRIMARY` paths.
627
- 2. For every collection with **`FOREIGN`** keys, call `mapCrossCollectionRelationships(sourceSample, foreignKeyProperty, targetCollectionsMap)`.
628
- 3. Accept edges where **`inclusionRatio > 0.95`** (helpers default threshold).
629
- 4. Map winning edges to Hippox join candidates: `{ sourceObjectType, targetObjectType, join: [{ sourcePath, targetPath, operator: 'eq' }] }`.
630
-
631
- **Output handling**
632
-
633
- The orchestration produces a structured link graph of the previously unknown scope. Feed it into:
634
-
635
- - Hippox **simulate → approve** for durable context links
636
- - Schema **relation detect** for descriptor promotion
637
- - Migration validators and agentic schema tools
638
-
639
- This is **complementary** to `GET /api/hippox/join-discovery`, which assumes named Memorix object types and blends live overlap with schema/approved-link seeds. Fuzzy mapping is the cold-start path; join-discovery is the operator refinement path once types exist.
640
-
641
- ---
642
-
643
- ## L. Snapshot-only full-scale rule
644
-
645
- The full-scale shape should be expected mainly in snapshot collections.
646
-
647
- Example:
648
-
649
- ```txt id="ot7c3i"
650
- findings-snapshots
651
- items-snapshots
652
- users-snapshots
653
- documents-snapshots
654
- ```
655
-
656
- A snapshot is the best place for:
657
-
658
- ```txt id="kr0jcs"
659
- concept
660
- data
661
- associatedData
662
- analytics
663
- insights
664
- index
665
- sourceFacts
666
- _system
667
- ```
668
-
669
- Other content types should stay smaller and purpose-specific.
670
-
671
- Example:
672
-
673
- ```txt id="i0znxj"
674
- findings-events
675
- findings-facts
676
- findings-chunks
677
- findings-history
678
- ```
679
-
680
- These may only need:
681
-
682
- ```txt id="nqsr18"
683
- identity
684
- lifecycle
685
- data
686
- sourceFacts
687
- _system
688
- ```
689
-
690
- or whatever Memorix decides is required by descriptor and use case.
691
-
692
- ### Rule
693
-
694
- ```txt id="l97dza"
695
- Snapshots are the full readable object view.
696
- Other content types are specialized records.
697
- ```
698
-
699
- ---
700
-
701
- ## M. Final full-scale snapshot example
702
-
703
- ```json id="eey88y"
704
- {
705
- "_id": "667f00000000000000000001",
706
-
707
- "identity": {
708
- "recordId": "entity:cve:DOC-9",
709
- "target": "entity",
710
- "targetId": "entity:cve:DOC-9",
711
- "objectType": "findings",
712
- "contentType": "snapshots",
713
- "version": "memorix-record.2.0"
714
- },
715
-
716
- "lifecycle": {
717
- "createdAt": "2026-06-30T10:00:00.000Z",
718
- "modifiedAt": "2026-06-30T10:00:00.000Z",
719
- "capturedAt": "2026-06-30T09:55:00.000Z",
720
- "status": "active"
721
- },
722
-
723
- "concept": {
724
- "kind": "cve",
725
- "name": "DOC-9",
726
- "title": "DOC-9",
727
- "summary": "Critical unrestricted file upload vulnerability affecting WSO2 products.",
728
- "keywords": ["DOC-9", "WSO2", "critical"]
729
- },
730
-
731
- "data": {
732
- "docId": "DOC-9",
733
- "severity": "critical",
734
- "description": "Unrestricted file upload vulnerability affecting WSO2 products.",
735
- "publishedAt": "2022-04-18"
736
- },
737
-
738
- "associatedData": {
739
- "affectedAssets": [
740
- {
741
- "assetName": "prod-api-01",
742
- "sku": "10.100.18.64",
743
- "recordId": "entity:asset:10.100.18.64"
744
- },
745
- {
746
- "assetName": "prod-db-02",
747
- "sku": "10.100.18.65",
748
- "recordId": "entity:asset:10.100.18.65"
749
- }
750
- ]
751
- },
752
-
753
- "analytics": {
754
- "affectedAssets": {
755
- "total": 2,
756
- "production": 2,
757
- "internetExposed": 1
758
- },
759
- "relatedFindings": {
760
- "total": 4,
761
- "open": 3,
762
- "closed": 1
763
- }
764
- },
765
-
766
- "insights": {
767
- "risk": {
768
- "level": "critical",
769
- "score": 92,
770
- "confidence": 0.84,
771
- "reason": "The CVE affects production items, including one internet-exposed asset."
772
- },
773
- "priority": {
774
- "level": "urgent",
775
- "reason": "Production exposure and critical severity require fast remediation."
776
- },
777
- "recommendations": [
778
- {
779
- "action": "Patch affected items",
780
- "urgency": "high"
781
- }
782
- ]
783
- },
784
-
785
- "index": {
786
- "text": {
787
- "title": "DOC-9",
788
- "summary": "Critical unrestricted file upload vulnerability affecting WSO2 products.",
789
- "keywords": ["DOC-9", "critical", "prod-api-01", "prod-db-02"]
790
- },
791
- "facets": {
792
- "severity": "critical",
793
- "affectedAssetsTotal": 2,
794
- "internetExposedAssets": 1
795
- },
796
- "recordLinks": [
797
- {
798
- "key": "affectedAssets",
799
- "relation": "affects",
800
- "direction": "out",
801
- "target": {
802
- "recordId": "entity:asset:10.100.18.64",
803
- "target": "entity",
804
- "objectType": "items"
805
- },
806
- "display": {
807
- "name": "prod-api-01"
808
- },
809
- "indexed": true
810
- },
811
- {
812
- "key": "affectedAssets",
813
- "relation": "affects",
814
- "direction": "out",
815
- "target": {
816
- "recordId": "entity:asset:10.100.18.65",
817
- "target": "entity",
818
- "objectType": "items"
819
- },
820
- "display": {
821
- "name": "prod-db-02"
822
- },
823
- "indexed": true
824
- }
825
- ]
826
- },
827
-
828
- "sourceFacts": {
829
- "schemaVersion": "sourceFacts.v1",
830
- "values": {
831
- "severityCode": {
832
- "rawValue": 4,
833
- "kind": "enum-code",
834
- "readable": false,
835
- "resolvedToPath": "data.severity",
836
- "resolvedValue": "critical"
837
- }
838
- }
839
- },
840
-
841
- "_system": {
842
- "memorix": {
843
- "entity": "findings",
844
- "contentType": "snapshots",
845
- "operation": "upsert"
846
- },
847
- "processing": {
848
- "graphRuns": {},
849
- "jobTypeRuns": {}
850
- }
851
- }
852
- }
853
- ```
854
-
855
- ---
856
-
857
- ## N. Final mental model
858
-
859
- Use this as the lighthouse:
860
-
861
- ```txt id="tbgvry"
862
- identity = how Memorix identifies the record
863
-
864
- lifecycle = when the record exists and changed
865
-
866
- concept = what the record is
867
-
868
- data = native readable facts about the record
869
-
870
- associatedData = readable related records/context attached for consumption
871
-
872
- analytics = numeric rollups about linked lists
873
-
874
- insights = interpretations, judgments, scores, and recommendations
875
-
876
- index = internal search/link/index surface
877
-
878
- sourceFacts = raw source values and resolver inputs
879
-
880
- _system = Memorix-managed metadata, processing, provenance, and audit
881
- ```
882
-
883
- The clean separation is:
884
-
885
- ```txt id="blxjhb"
886
- Facts stay in data.
887
- Related context goes in associatedData.
888
- Numbers about related context go in analytics.
889
- Conclusions go in insights.
890
- Links go in index.
891
- Raw source mess goes in sourceFacts.
892
- System state goes in _system.
893
- ```
894
-
895
-
896
- ---------------------------
897
-
898
- ```txt id="m7zj8c"
899
- The full rich Memorix record shape exists only on snapshot content types / snapshot collections.
900
- ```
901
-
902
- Meaning these extra consumption/summary layers should be **snapshot-only by default**:
903
-
904
- ```txt id="g8756x"
905
- associatedData
906
- analytics
907
- insights
908
- full record-level index projections
909
- ```
910
-
911
- So for example:
912
-
913
- ```txt id="cpyqdi"
914
- findings-snapshots ✅ full record shape
915
- findings-events ❌ not full shape
916
- findings-facts ❌ not full shape
917
- findings-chunks ❌ not full shape
918
- findings-history ❌ not full shape
919
- ```
920
-
921
- The clean rule:
922
-
923
- ```txt id="0fdcos"
924
- Snapshots are the full readable object view.
925
- Other content types are specialized records.
926
- ```
927
-
928
- For non-snapshot collections, the record should usually have only what the content type actually needs:
929
-
930
- ```txt id="nqyy5v"
931
- identity
932
- lifecycle, if relevant
933
- concept, if useful
934
- data
935
- sourceFacts, if raw/resolution material exists
936
- _system
937
- minimal index, only if that content type needs indexing
938
- ```
939
-
940
- So the final model should say:
941
-
942
- ```txt id="8ba054"
943
- data exists on every content record.
944
-
945
- associatedData, analytics, and insights belong to snapshots only by default.
946
-
947
- index may exist outside snapshots only when the content type itself requires indexing, like chunks or searchable facts.
948
-
949
- _system and sourceFacts can exist anywhere when needed.
950
- ```
951
-
952
- I would add this sentence to the appendix:
953
-
954
- ```txt id="65cb87"
955
- Unless a descriptor explicitly opts in, associatedData, analytics, and insights are allowed only on snapshot content types, because they represent the full materialized view of the object, not the minimal record format for every collection.
956
- ```