@x12i/memorix-hippox
Memorix Hippox stores reusable contextual links between Memorix object types. Operators can discover join keys from sampled data, define property-based joins without pre-modeled schema relations, simulate match quality, approve links into long-term memory, and resolve bounded context into jobMemory.context.
See memorix-format.md §13 and memorix-fomat-additions.md §K for how Hippox fits the Memorix 2.0 record model (data, associatedData, index.recordLinks, sourceFacts).
Full mapping landscape (consultation): docs/MEMORIX-MAPPING-OVERVIEW.md
Not this package
| Concern | Owner |
|---|---|
Durable bulk associated* on snapshots |
memorix-associator |
| Abstract types / propertyMap for apps | Mappix + memorix-abstraction |
Authored schema relations[] |
object-type descriptors / Schema UI |
| Vector nearest-neighbor indexes | memorix-similarity |
| LLM mapping inference | Mappix FuncX adapter (not Hippox); fuzzy infer-links uses @x12i/helpers |
Hippox resolve returns transient jobMemory.context. Materializing into snapshot associated* is a separate associator/assembly step.
Database
Approved and draft links persist in Mongo database memorix-hippox (collection context-links by default).
| Variable | Default | Purpose |
|---|---|---|
MEMORIX_HIPPOX_DB |
memorix-hippox |
Hippox Mongo database |
MEMORIX_HIPPOX_COLLECTION |
context-links |
Context links collection |
MEMORIX_HIPPOX_SIMULATION_LIMIT |
1000 |
Max records sampled per side during simulation |
MEMORIX_HIPPOX_SIMULATION_EXAMPLES_LIMIT |
25 |
Max example matches/misses in simulation summary |
MEMORIX_CONTEXT_LIST_LIMIT |
25 |
Default list retrieval limit at resolve time |
MEMORIX_HIPPOX_DISCOVERY_SAMPLE_LIMIT |
1000 |
Max records sampled per side during join discovery |
MEMORIX_HIPPOX_DISCOVERY_DISTINCT_CAP |
500 |
Max distinct source values per value probe |
MEMORIX_HIPPOX_DISCOVERY_MAX_PAIRS |
200 |
Max source×target field pairs to evaluate |
MEMORIX_HIPPOX_DISCOVERY_MIN_COVERAGE |
0.05 |
Minimum field coverage to include in discovery |
MEMORIX_HIPPOX_DISCOVERY_MIN_PAIR_SCORE |
0.15 |
Minimum score for join candidates / recommended join |
MEMORIX_HIPPOX_DISCOVERY_CACHE_TTL_MS |
300000 |
In-memory join-discovery cache TTL per pair |
MEMORIX_HIPPOX_DISCOVERY_MAX_CANDIDATES |
50 |
Max entries in joinCandidates |
Path conventions (Memorix 2.0)
Join paths are dot paths from the document root, consistent with entity descriptor relations:
{ "sourcePath": "data.subnetId", "targetPath": "data.id", "operator": "eq" }
Discovery walks the content-type dataRoot (default data) and returns paths with the data. prefix.
Record identity and sorting support both Memorix 2.0 and legacy shapes:
- IDs:
identity.recordId,identity.targetId, then legacyentityId/recordId/_id - Latest record:
data.scopedAt, thenlifecycle.capturedAt/lifecycle.modifiedAt, then root timestamps
Example: assets → subnets (record context)
{
"sourceObjectType": "assets",
"targetObjectType": "subnets",
"direction": "downstream",
"join": [
{ "sourcePath": "data.subnetId", "targetPath": "data.id", "operator": "eq" }
],
"retrieval": { "type": "record", "outputMode": "data" }
}
Resolved output:
{
"jobMemory": {
"context": {
"subnets": {
"cidr": "10.0.0.0/24",
"region": "eu-west-1"
}
}
}
}
Materializing this into a snapshot's associatedData block is a separate assembly step; Hippox resolve returns transient job context.
HTTP routes
When mounted through memorix-catalox-api:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/hippox/links?sourceObjectType=assets |
List draft + simulated + approved links |
POST |
/api/hippox/links |
Create draft link |
GET |
/api/hippox/join-discovery?sourceObjectType=…&targetObjectType=… |
Rank join fields and recommend default pair (findMode=field-join default) |
GET |
/api/hippox/join-discovery?…&findMode=identifier |
Mode A: source value paths → target identity / concept candidates |
POST |
/api/hippox/join-discovery |
Same as GET with body parameters (findMode optional) |
POST |
/api/hippox/infer-links |
Fuzzy-map joins across object types (@x12i/helpers ≥ 2.0) |
POST |
/api/hippox/links/from-relation-candidate |
Create Hippox draft from schema relation candidate |
POST |
/api/hippox/links/simulate |
Simulate unsaved definition |
POST |
/api/hippox/links/:id/simulate |
Simulate + persist summary |
POST |
/api/hippox/links/:id/approve |
Approve simulated link |
POST |
/api/hippox/context/resolve |
Resolve runtime context from approved links |
Join discovery response (summary)
Returns ranked sourceFields, targetFields, joinCandidates, and recommendedJoin for Mode B (findMode=field-join, default). Each field includes a classification of link-target | join-out | other; pure link-target identity fields are demoted so Mode B dropdowns do not treat them as outward join keys.
With findMode=identifier (Mode A), the response also includes sourceValuePaths, targetIdentityCandidates, and recommendedMatch (or null + warnings). Mode A does not require a target data.* join path — the target side is identity / concept matching.
Discovery is ephemeral (optional in-memory cache); only approved links persist.
Programmatic usage
import { createMemorixRetrievalStackFromEnv } from '@x12i/memorix-retrieval';
import { HippoxService } from '@x12i/memorix-hippox';
const { client } = await createMemorixRetrievalStackFromEnv();
const hippox = await HippoxService.create({ retrieval: client });
const discovery = await hippox.discoverJoinCandidates({
sourceObjectType: 'assets',
targetObjectType: 'subnets',
});
const draft = await hippox.createDraftLink({
sourceObjectType: 'assets',
targetObjectType: 'subnets',
direction: 'downstream',
join: [discovery.recommendedJoin ?? {
sourcePath: 'data.subnetId',
targetPath: 'data.id',
}],
retrieval: { type: 'record', outputMode: 'data' },
});
const { simulation } = await hippox.simulateAndPersist(draft.id);
await hippox.approveLink(draft.id);
const resolved = await hippox.resolveContextInput({
sourceObjectType: 'assets',
sourceRecordId: 'entity:asset:10.100.18.64',
linkIds: [draft.id],
});
Legacy relation links
Relation-based JobContextLink / contextLinks are not resolved into
jobMemory. Prefer Hippox approved links (resolveContext /
resolveContextInput). resolveMixedContext() remains as a deprecated alias
that only forwards Hippox resolution (no _legacy merge).
Retrieval types
- record — single best match (default latest
data.scopedAtorlifecycle.capturedAt) - list — bounded array (mandatory limit)
- aggregate — flat per-property value counts
Output modes: data (default), record, dataWithRecordId.
Relationship to other Memorix layers
| Layer | Hippox role |
|---|---|
sourceFacts.resolver.component: "memorix-hippox" |
value resolution rules (enum/lookup) — separate from context links |
index.recordLinks |
schema-declared indexed relations |
associatedData |
readable materialized join output on snapshots |
jobMemory.context |
runtime output of context/resolve |
Fuzzy mapping pipeline (@x12i/helpers ≥ 2.0)
@x12i/helpers@2.0.0 ships record key analysis at @x12i/helpers/record-key-analysis. Hippox orchestrates it via POST /api/hippox/infer-links.
This complements join-discovery (named object types, schema seeds, value overlap ranking). Fuzzy mapping is the cold-start path; join-discovery refines once types and collections are registered.
Prerequisites
- Runtime access to collection samples (Mongo via Hippox collection resolver).
- Optional peer
@x12i/helpers@^2.0.0(returns HTTP 501 if missing when calling infer-links).
API
POST /api/hippox/infer-links
{ "objectTypes": ["assets", "subnets"], "sampleLimit": 10000 }
Returns collectionProfiles (PRIMARY / FOREIGN / ENUM tags) and ranked inferredLinks with inclusion ratios.
Programmatic usage
const inference = await hippox.inferLinks({
objectTypes: ['assets', 'subnets', 'vulnerabilities'],
});
for (const link of inference.inferredLinks) {
await hippox.createDraftLink({
sourceObjectType: link.sourceObjectType,
targetObjectType: link.targetObjectType,
direction: 'downstream',
join: [{ sourcePath: link.sourcePath, targetPath: link.targetPath }],
retrieval: { type: 'record', outputMode: 'data' },
});
}
Schema relation bridge
POST /api/hippox/links/from-relation-candidate
POST /api/relationships/:sourceEntity/:relationKey/hippox-draft # schema-api operational wrapper
Converts a schema RelationCandidate or declared relation into a Hippox draft link.
See memorix-format.md §13.4 and memorix-fomat-additions.md §K.4.
Consultation maps: MEMORIX-MAPPING-OVERVIEW · MEMORIX-METADATA-CATALOX-OVERVIEW