@jungjaehoon/mama-core 1.9.0 → 2.1.0
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/db/migrations/043-add-tool-trace-failure-code.sql +11 -0
- package/dist/agent-graph/alias-write.js +3 -0
- package/dist/agent-graph/entity-resolve.js +3 -7
- package/dist/agent-graph/graph-query.js +5 -4
- package/dist/agent-graph/types.d.ts +30 -0
- package/dist/cases/store.d.ts +0 -4
- package/dist/cases/store.js +0 -66
- package/dist/cases/wiki-page-index.d.ts +0 -13
- package/dist/cases/wiki-page-index.js +0 -153
- package/dist/connectors/event-index.d.ts +1 -22
- package/dist/connectors/event-index.js +0 -157
- package/dist/context-compile/channel-grant.d.ts +46 -0
- package/dist/context-compile/channel-grant.js +66 -0
- package/dist/context-compile/compiler.js +5 -2
- package/dist/context-compile/index.d.ts +1 -0
- package/dist/context-compile/index.js +1 -0
- package/dist/context-compile/packet-store.d.ts +0 -1
- package/dist/context-compile/packet-store.js +0 -16
- package/dist/context-compile/source-readers.d.ts +1 -0
- package/dist/context-compile/source-readers.js +156 -23
- package/dist/context-compile/types.d.ts +17 -0
- package/dist/context-compile/visibility.js +28 -4
- package/dist/db-adapter/node-sqlite-adapter.js +4 -0
- package/dist/db-manager.d.ts +0 -13
- package/dist/db-manager.js +0 -66
- package/dist/decision-formatter.d.ts +0 -11
- package/dist/decision-formatter.js +0 -122
- package/dist/decision-tracker.d.ts +0 -12
- package/dist/decision-tracker.js +0 -50
- package/dist/edges/ref-validation.d.ts +1 -2
- package/dist/edges/ref-validation.js +33 -13
- package/dist/edges/store.d.ts +1 -3
- package/dist/edges/store.js +0 -214
- package/dist/edges/types.d.ts +10 -0
- package/dist/embedding-client.d.ts +0 -17
- package/dist/embedding-client.js +0 -80
- package/dist/embedding-server/mobile/auth.d.ts +1 -10
- package/dist/embedding-server/mobile/auth.js +0 -15
- package/dist/embeddings.d.ts +0 -12
- package/dist/embeddings.js +0 -68
- package/dist/entities/audit-metrics.d.ts +0 -5
- package/dist/entities/audit-metrics.js +0 -4
- package/dist/entities/candidate-generator.d.ts +1 -2
- package/dist/entities/candidate-generator.js +0 -412
- package/dist/entities/entity-list.d.ts +0 -1
- package/dist/entities/entity-list.js +0 -96
- package/dist/entities/entity-orphan-list.d.ts +0 -9
- package/dist/entities/entity-orphan-list.js +0 -88
- package/dist/entities/entity-search.d.ts +0 -1
- package/dist/entities/entity-search.js +0 -147
- package/dist/entities/errors.d.ts +0 -10
- package/dist/entities/errors.js +1 -25
- package/dist/entities/lineage-store.d.ts +0 -23
- package/dist/entities/lineage-store.js +0 -104
- package/dist/entities/policy-store.d.ts +0 -9
- package/dist/entities/policy-store.js +0 -188
- package/dist/entities/provenance-query.d.ts +0 -1
- package/dist/entities/provenance-query.js +0 -164
- package/dist/entities/resolution-engine.d.ts +1 -8
- package/dist/entities/resolution-engine.js +0 -66
- package/dist/entities/rollback-preview.d.ts +0 -4
- package/dist/entities/rollback-preview.js +0 -232
- package/dist/entities/store.d.ts +1 -10
- package/dist/entities/store.js +0 -49
- package/dist/index.d.ts +15 -31
- package/dist/index.js +4 -46
- package/dist/mama-api.d.ts +19 -1
- package/dist/mama-api.js +97 -2
- package/dist/memory/api.d.ts +8 -0
- package/dist/memory/api.js +55 -2
- package/dist/memory/event-store.d.ts +0 -1
- package/dist/memory/event-store.js +0 -15
- package/dist/memory/finding-store.d.ts +0 -1
- package/dist/memory/finding-store.js +0 -12
- package/dist/memory/scope-backfill.d.ts +0 -3
- package/dist/memory/scope-backfill.js +0 -74
- package/dist/memory/scope-store.d.ts +0 -1
- package/dist/memory/scope-store.js +0 -4
- package/dist/memory/truth-store.d.ts +0 -3
- package/dist/memory/truth-store.js +0 -22
- package/dist/memory/types.d.ts +0 -1
- package/dist/memory/types.js +0 -13
- package/dist/memory-store.d.ts +0 -16
- package/dist/memory-store.js +0 -51
- package/dist/model-runs/tool-trace-store.js +9 -5
- package/dist/model-runs/types.d.ts +3 -0
- package/dist/ollama-client.d.ts +0 -9
- package/dist/ollama-client.js +0 -125
- package/dist/outcome-tracker.d.ts +0 -14
- package/dist/outcome-tracker.js +0 -44
- package/dist/progress-indicator.d.ts +0 -4
- package/dist/progress-indicator.js +0 -7
- package/dist/provenance/source-ref.d.ts +0 -9
- package/dist/provenance/source-ref.js +0 -145
- package/dist/query-intent.d.ts +0 -4
- package/dist/query-intent.js +0 -30
- package/dist/relevance-scorer.d.ts +0 -9
- package/dist/relevance-scorer.js +0 -81
- package/dist/search/feedback-store.d.ts +0 -1
- package/dist/search/feedback-store.js +0 -4
- package/dist/search/ranker-rescore.d.ts +0 -3
- package/dist/search/ranker-rescore.js +0 -27
- package/dist/search/ranker-trainer.d.ts +0 -8
- package/dist/search/ranker-trainer.js +0 -376
- package/dist/tier-validator.d.ts +0 -12
- package/dist/tier-validator.js +0 -56
- package/package.json +1 -10
- package/dist/cases/case-links.d.ts +0 -116
- package/dist/cases/case-links.js +0 -794
- package/dist/cases/composition-overrides.d.ts +0 -90
- package/dist/cases/composition-overrides.js +0 -724
- package/dist/cases/corrections.d.ts +0 -156
- package/dist/cases/corrections.js +0 -1045
- package/dist/cases/freshness.d.ts +0 -57
- package/dist/cases/freshness.js +0 -283
- package/dist/cases/live-state.d.ts +0 -48
- package/dist/cases/live-state.js +0 -256
- package/dist/cases/membership-explain.d.ts +0 -56
- package/dist/cases/membership-explain.js +0 -140
- package/dist/cases/membership-matcher.d.ts +0 -23
- package/dist/cases/membership-matcher.js +0 -193
- package/dist/cases/merge-split.d.ts +0 -61
- package/dist/cases/merge-split.js +0 -368
- package/dist/cases/role-inference.d.ts +0 -10
- package/dist/cases/role-inference.js +0 -85
- package/dist/cases/sqlite-transaction.d.ts +0 -10
- package/dist/cases/sqlite-transaction.js +0 -62
- package/dist/cases/target-ref.d.ts +0 -25
- package/dist/cases/target-ref.js +0 -22
- package/dist/cases/tombstone-sweeper.d.ts +0 -13
- package/dist/cases/tombstone-sweeper.js +0 -128
- package/dist/entities/entity-impact.d.ts +0 -41
- package/dist/entities/entity-impact.js +0 -140
- package/dist/entities/exact-merge-backfill.d.ts +0 -11
- package/dist/entities/exact-merge-backfill.js +0 -161
- package/dist/entities/lineage-backfill.d.ts +0 -12
- package/dist/entities/lineage-backfill.js +0 -101
- package/dist/memory-inject.d.ts +0 -24
- package/dist/memory-inject.js +0 -116
|
@@ -1,167 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.queryProvenanceForMemory = queryProvenanceForMemory;
|
|
4
|
-
const db_manager_js_1 = require("../db-manager.js");
|
|
5
|
-
const source_locator_js_1 = require("./source-locator.js");
|
|
6
|
-
function parseSource(trustContext) {
|
|
7
|
-
if (typeof trustContext !== 'string' || trustContext.length === 0) {
|
|
8
|
-
return { package: 'mama-core', source_type: 'db' };
|
|
9
|
-
}
|
|
10
|
-
try {
|
|
11
|
-
const parsed = JSON.parse(trustContext);
|
|
12
|
-
if (parsed?.source && typeof parsed.source === 'object') {
|
|
13
|
-
return parsed.source;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
// ignore malformed trust_context
|
|
18
|
-
}
|
|
19
|
-
return { package: 'mama-core', source_type: 'db' };
|
|
20
|
-
}
|
|
21
|
-
function mapMemoryRecord(row, scopes) {
|
|
22
|
-
return {
|
|
23
|
-
id: row.id,
|
|
24
|
-
topic: row.topic,
|
|
25
|
-
kind: (row.kind ?? 'decision'),
|
|
26
|
-
summary: row.summary ?? row.decision,
|
|
27
|
-
details: row.reasoning ?? row.decision,
|
|
28
|
-
confidence: row.confidence ?? 0.5,
|
|
29
|
-
status: (row.status ?? 'active'),
|
|
30
|
-
scopes,
|
|
31
|
-
source: parseSource(row.trust_context),
|
|
32
|
-
created_at: row.created_at,
|
|
33
|
-
updated_at: row.updated_at ?? row.created_at,
|
|
34
|
-
event_date: row.event_date,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function loadScopes(memoryId) {
|
|
38
|
-
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
39
|
-
const rows = adapter
|
|
40
|
-
.prepare(`
|
|
41
|
-
SELECT msb.memory_id, ms.kind, ms.external_id
|
|
42
|
-
FROM memory_scope_bindings msb
|
|
43
|
-
JOIN memory_scopes ms ON ms.id = msb.scope_id
|
|
44
|
-
WHERE msb.memory_id = ?
|
|
45
|
-
ORDER BY msb.is_primary DESC
|
|
46
|
-
`)
|
|
47
|
-
.all(memoryId);
|
|
48
|
-
return rows.map((row) => ({
|
|
49
|
-
kind: row.kind,
|
|
50
|
-
id: row.external_id,
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
function loadObservations(memoryId) {
|
|
54
|
-
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
55
|
-
const rows = adapter
|
|
56
|
-
.prepare(`
|
|
57
|
-
SELECT
|
|
58
|
-
o.id,
|
|
59
|
-
o.observation_type,
|
|
60
|
-
o.entity_kind_hint,
|
|
61
|
-
o.surface_form,
|
|
62
|
-
o.normalized_form,
|
|
63
|
-
o.lang,
|
|
64
|
-
o.script,
|
|
65
|
-
o.context_summary,
|
|
66
|
-
o.scope_kind,
|
|
67
|
-
o.scope_id,
|
|
68
|
-
o.extractor_version,
|
|
69
|
-
o.embedding_model_version,
|
|
70
|
-
o.source_connector,
|
|
71
|
-
o.source_locator,
|
|
72
|
-
o.source_raw_record_id,
|
|
73
|
-
o.created_at
|
|
74
|
-
FROM decision_entity_sources des
|
|
75
|
-
JOIN entity_observations o ON o.id = des.entity_observation_id
|
|
76
|
-
WHERE des.decision_id = ?
|
|
77
|
-
ORDER BY des.created_at ASC, o.created_at ASC
|
|
78
|
-
`)
|
|
79
|
-
.all(memoryId);
|
|
80
|
-
return rows.map((row) => ({
|
|
81
|
-
id: row.id,
|
|
82
|
-
observation_type: row.observation_type,
|
|
83
|
-
entity_kind_hint: row.entity_kind_hint,
|
|
84
|
-
surface_form: row.surface_form,
|
|
85
|
-
normalized_form: row.normalized_form,
|
|
86
|
-
lang: row.lang,
|
|
87
|
-
script: row.script,
|
|
88
|
-
context_summary: row.context_summary,
|
|
89
|
-
scope_kind: row.scope_kind,
|
|
90
|
-
scope_id: row.scope_id,
|
|
91
|
-
extractor_version: row.extractor_version,
|
|
92
|
-
embedding_model_version: row.embedding_model_version,
|
|
93
|
-
source_connector: row.source_connector,
|
|
94
|
-
source_locator: row.source_locator,
|
|
95
|
-
source_locator_kind: (0, source_locator_js_1.detectSourceLocatorKind)(row.source_locator),
|
|
96
|
-
source_raw_record_id: row.source_raw_record_id,
|
|
97
|
-
created_at: row.created_at,
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
function loadProvenanceAudit(memoryId) {
|
|
101
|
-
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
102
|
-
const row = adapter
|
|
103
|
-
.prepare(`
|
|
104
|
-
SELECT event_type, reason, created_at
|
|
105
|
-
FROM memory_events
|
|
106
|
-
WHERE memory_id = ?
|
|
107
|
-
AND event_type IN ('provenance.empty_batch', 'provenance.link_write_failed')
|
|
108
|
-
ORDER BY created_at DESC
|
|
109
|
-
LIMIT 1
|
|
110
|
-
`)
|
|
111
|
-
.get(memoryId);
|
|
112
|
-
if (!row) {
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
return {
|
|
116
|
-
event_type: row.event_type,
|
|
117
|
-
reason: row.reason,
|
|
118
|
-
created_at: row.created_at,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
async function queryProvenanceForMemory(memoryId) {
|
|
122
|
-
await (0, db_manager_js_1.initDB)();
|
|
123
|
-
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
124
|
-
const row = adapter
|
|
125
|
-
.prepare(`
|
|
126
|
-
SELECT
|
|
127
|
-
id,
|
|
128
|
-
topic,
|
|
129
|
-
decision,
|
|
130
|
-
reasoning,
|
|
131
|
-
confidence,
|
|
132
|
-
created_at,
|
|
133
|
-
updated_at,
|
|
134
|
-
trust_context,
|
|
135
|
-
kind,
|
|
136
|
-
status,
|
|
137
|
-
summary,
|
|
138
|
-
event_date
|
|
139
|
-
FROM decisions
|
|
140
|
-
WHERE id = ?
|
|
141
|
-
`)
|
|
142
|
-
.get(memoryId);
|
|
143
|
-
if (!row) {
|
|
144
|
-
throw new Error(`Decision not found: ${memoryId}`);
|
|
145
|
-
}
|
|
146
|
-
const scopes = loadScopes(memoryId);
|
|
147
|
-
const memory = mapMemoryRecord(row, scopes);
|
|
148
|
-
const observations = loadObservations(memoryId);
|
|
149
|
-
const audit = loadProvenanceAudit(memoryId);
|
|
150
|
-
let status = 'legacy';
|
|
151
|
-
if (observations.length > 0) {
|
|
152
|
-
status = 'resolved';
|
|
153
|
-
}
|
|
154
|
-
else if (audit?.event_type === 'provenance.link_write_failed') {
|
|
155
|
-
status = 'dropped';
|
|
156
|
-
}
|
|
157
|
-
else if (audit?.event_type === 'provenance.empty_batch') {
|
|
158
|
-
status = 'manual';
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
status,
|
|
162
|
-
memory,
|
|
163
|
-
observations,
|
|
164
|
-
audit,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
3
|
//# sourceMappingURL=provenance-query.js.map
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import type { EntityMergeAction,
|
|
1
|
+
import type { EntityMergeAction, EntityResolutionCandidate } from './types.js';
|
|
2
2
|
export interface ResolutionDecision {
|
|
3
3
|
candidate: EntityResolutionCandidate;
|
|
4
4
|
decision: 'auto_merge' | 'review';
|
|
5
5
|
reason: string;
|
|
6
6
|
actions: EntityMergeAction[];
|
|
7
7
|
}
|
|
8
|
-
export declare function shouldAutoMerge(result: ResolutionDecision): boolean;
|
|
9
|
-
export declare function buildReviewReason(result: ResolutionDecision): string;
|
|
10
|
-
export declare function evaluateResolutionCandidate(input: {
|
|
11
|
-
candidate: EntityResolutionCandidate;
|
|
12
|
-
left: EntityObservation;
|
|
13
|
-
right: EntityObservation;
|
|
14
|
-
}): ResolutionDecision;
|
|
15
8
|
//# sourceMappingURL=resolution-engine.d.ts.map
|
|
@@ -1,69 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.shouldAutoMerge = shouldAutoMerge;
|
|
4
|
-
exports.buildReviewReason = buildReviewReason;
|
|
5
|
-
exports.evaluateResolutionCandidate = evaluateResolutionCandidate;
|
|
6
|
-
const errors_js_1 = require("./errors.js");
|
|
7
|
-
function isCrossLanguage(left, right) {
|
|
8
|
-
return Boolean(left.lang && right.lang && left.lang !== right.lang);
|
|
9
|
-
}
|
|
10
|
-
function shouldAutoMerge(result) {
|
|
11
|
-
return result.decision === 'auto_merge';
|
|
12
|
-
}
|
|
13
|
-
function buildReviewReason(result) {
|
|
14
|
-
return result.reason;
|
|
15
|
-
}
|
|
16
|
-
function evaluateResolutionCandidate(input) {
|
|
17
|
-
const { candidate, left, right } = input;
|
|
18
|
-
if (left.entity_kind_hint &&
|
|
19
|
-
right.entity_kind_hint &&
|
|
20
|
-
left.entity_kind_hint !== right.entity_kind_hint) {
|
|
21
|
-
throw new errors_js_1.OntologyViolationError({
|
|
22
|
-
left_entity_kind: left.entity_kind_hint,
|
|
23
|
-
right_entity_kind: right.entity_kind_hint,
|
|
24
|
-
candidate_id: candidate.id,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const sameNormalized = left.normalized_form === right.normalized_form;
|
|
28
|
-
const exactStructural = candidate.score_structural >= 1 && sameNormalized;
|
|
29
|
-
const crossLanguage = isCrossLanguage(left, right);
|
|
30
|
-
if (exactStructural && !crossLanguage) {
|
|
31
|
-
return {
|
|
32
|
-
candidate,
|
|
33
|
-
decision: 'auto_merge',
|
|
34
|
-
reason: 'Exact structural match with no cross-language ambiguity.',
|
|
35
|
-
actions: [
|
|
36
|
-
{
|
|
37
|
-
id: `merge_${candidate.id}`,
|
|
38
|
-
action_type: 'merge',
|
|
39
|
-
source_entity_id: candidate.left_ref,
|
|
40
|
-
target_entity_id: candidate.right_ref,
|
|
41
|
-
candidate_id: candidate.id,
|
|
42
|
-
actor_type: 'system',
|
|
43
|
-
actor_id: 'resolution-engine',
|
|
44
|
-
reason: 'Exact structural match with no cross-language ambiguity.',
|
|
45
|
-
evidence_json: JSON.stringify({
|
|
46
|
-
score_structural: candidate.score_structural,
|
|
47
|
-
normalized_form: left.normalized_form,
|
|
48
|
-
}),
|
|
49
|
-
created_at: Date.now(),
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (crossLanguage && candidate.score_embedding > 0) {
|
|
55
|
-
return {
|
|
56
|
-
candidate,
|
|
57
|
-
decision: 'review',
|
|
58
|
-
reason: 'High-similarity cross-language candidate requires human review.',
|
|
59
|
-
actions: [],
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
candidate,
|
|
64
|
-
decision: 'review',
|
|
65
|
-
reason: 'Candidate requires manual review before merge.',
|
|
66
|
-
actions: [],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
3
|
//# sourceMappingURL=resolution-engine.js.map
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type EntityStoreAdapter } from './store.js';
|
|
2
1
|
export interface RollbackPreviewInput {
|
|
3
2
|
entityId: string;
|
|
4
3
|
mergeActionId?: string;
|
|
@@ -33,7 +32,4 @@ export interface RollbackPreviewResult {
|
|
|
33
32
|
changed_memories: RollbackPreviewMemoryChange[];
|
|
34
33
|
metric_movement: RollbackPreviewMetricMovement[];
|
|
35
34
|
}
|
|
36
|
-
export declare function previewEntityRollback(input: RollbackPreviewInput, options?: {
|
|
37
|
-
adapter?: EntityStoreAdapter;
|
|
38
|
-
}): Promise<RollbackPreviewResult>;
|
|
39
35
|
//# sourceMappingURL=rollback-preview.d.ts.map
|
|
@@ -1,235 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.previewEntityRollback = previewEntityRollback;
|
|
4
|
-
const db_manager_js_1 = require("../db-manager.js");
|
|
5
|
-
const projection_js_1 = require("./projection.js");
|
|
6
|
-
const store_js_1 = require("./store.js");
|
|
7
|
-
const lineage_store_js_1 = require("./lineage-store.js");
|
|
8
|
-
function unavailableResult(entityId, mergeActionId, historyIncomplete) {
|
|
9
|
-
return {
|
|
10
|
-
entity_id: entityId,
|
|
11
|
-
merge_action_id: mergeActionId,
|
|
12
|
-
preview_unavailable: true,
|
|
13
|
-
history_incomplete: historyIncomplete,
|
|
14
|
-
truncated: false,
|
|
15
|
-
changed_entities: [],
|
|
16
|
-
changed_memories: [],
|
|
17
|
-
metric_movement: [],
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function uniqueStrings(values) {
|
|
21
|
-
return Array.from(new Set(values.filter((value) => Boolean(value))));
|
|
22
|
-
}
|
|
23
|
-
function getLatestTimeline(adapter, entityId) {
|
|
24
|
-
const row = adapter
|
|
25
|
-
.prepare(`
|
|
26
|
-
SELECT *
|
|
27
|
-
FROM entity_timeline_events
|
|
28
|
-
WHERE entity_id = ?
|
|
29
|
-
ORDER BY COALESCE(observed_at, created_at) DESC
|
|
30
|
-
LIMIT 1
|
|
31
|
-
`)
|
|
32
|
-
.get(entityId);
|
|
33
|
-
if (!row) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
id: String(row.id),
|
|
38
|
-
entity_id: String(row.entity_id),
|
|
39
|
-
event_type: row.event_type,
|
|
40
|
-
role: typeof row.role === 'string' ? row.role : null,
|
|
41
|
-
valid_from: typeof row.valid_from === 'number' ? row.valid_from : null,
|
|
42
|
-
valid_to: typeof row.valid_to === 'number' ? row.valid_to : null,
|
|
43
|
-
observed_at: typeof row.observed_at === 'number' ? row.observed_at : null,
|
|
44
|
-
source_ref: typeof row.source_ref === 'string' ? row.source_ref : null,
|
|
45
|
-
summary: String(row.summary ?? ''),
|
|
46
|
-
details: typeof row.details === 'string' ? row.details : null,
|
|
47
|
-
created_at: Number(row.created_at),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
const DEFAULT_MAX_AFFECTED_ROWS = 50;
|
|
51
|
-
function normalizeMaxAffectedRows(input) {
|
|
52
|
-
return Math.max(1, input.maxAffectedRows ?? DEFAULT_MAX_AFFECTED_ROWS);
|
|
53
|
-
}
|
|
54
|
-
function projectLabel(adapter, node) {
|
|
55
|
-
const summary = (0, projection_js_1.projectEntityToRecallSummary)(node, (0, store_js_1.listEntityAliases)(node.id, adapter), getLatestTimeline(adapter, node.id), { nodeLookup: { [node.id]: node } });
|
|
56
|
-
return summary.summary;
|
|
57
|
-
}
|
|
58
|
-
function loadMergeAction(adapter, entityId, mergeActionId) {
|
|
59
|
-
const sql = mergeActionId
|
|
60
|
-
? `
|
|
61
|
-
SELECT id, source_entity_id, target_entity_id, created_at
|
|
62
|
-
FROM entity_merge_actions
|
|
63
|
-
WHERE id = ?
|
|
64
|
-
AND (source_entity_id = ? OR target_entity_id = ?)
|
|
65
|
-
LIMIT 1
|
|
66
|
-
`
|
|
67
|
-
: `
|
|
68
|
-
SELECT id, source_entity_id, target_entity_id, created_at
|
|
69
|
-
FROM entity_merge_actions
|
|
70
|
-
WHERE target_entity_id = ?
|
|
71
|
-
ORDER BY created_at DESC
|
|
72
|
-
LIMIT 1
|
|
73
|
-
`;
|
|
74
|
-
const row = (mergeActionId
|
|
75
|
-
? adapter.prepare(sql).get(mergeActionId, entityId, entityId)
|
|
76
|
-
: adapter.prepare(sql).get(entityId));
|
|
77
|
-
return row ?? null;
|
|
78
|
-
}
|
|
79
|
-
function resolveMergePreviewRows(input) {
|
|
80
|
-
let removedRows = input.targetActive.filter((row) => row.source_entity_id === input.sourceEntityId &&
|
|
81
|
-
(!input.mergeActionId || row.review_action_id === input.mergeActionId));
|
|
82
|
-
const removedObservationIds = new Set(removedRows.map((row) => row.entity_observation_id));
|
|
83
|
-
const restoredRows = input.sourceHistory.filter((row) => row.status === 'superseded' &&
|
|
84
|
-
(!input.mergeActionId ||
|
|
85
|
-
row.review_action_id === input.mergeActionId ||
|
|
86
|
-
removedObservationIds.has(row.entity_observation_id)));
|
|
87
|
-
if (removedRows.length === 0 && restoredRows.length > 0) {
|
|
88
|
-
const restorableObservationIds = new Set(restoredRows.map((row) => row.entity_observation_id));
|
|
89
|
-
removedRows = input.targetActive.filter((row) => restorableObservationIds.has(row.entity_observation_id) &&
|
|
90
|
-
(!input.mergeActionId || row.review_action_id === input.mergeActionId));
|
|
91
|
-
}
|
|
92
|
-
return { restoredRows, removedRows };
|
|
93
|
-
}
|
|
94
|
-
function loadChangedMemories(adapter, observationIds) {
|
|
95
|
-
if (observationIds.length === 0) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
const placeholders = observationIds.map(() => '?').join(', ');
|
|
99
|
-
const rows = adapter
|
|
100
|
-
.prepare(`
|
|
101
|
-
SELECT DISTINCT d.id, d.topic, d.summary, d.created_at
|
|
102
|
-
FROM decision_entity_sources des
|
|
103
|
-
JOIN decisions d ON d.id = des.decision_id
|
|
104
|
-
WHERE des.entity_observation_id IN (${placeholders})
|
|
105
|
-
ORDER BY d.created_at DESC
|
|
106
|
-
`)
|
|
107
|
-
.all(...observationIds);
|
|
108
|
-
return rows.map((row) => ({
|
|
109
|
-
id: row.id,
|
|
110
|
-
topic: row.topic,
|
|
111
|
-
summary: row.summary ?? row.topic,
|
|
112
|
-
created_at: row.created_at,
|
|
113
|
-
}));
|
|
114
|
-
}
|
|
115
|
-
function buildMetricMovement(sourceLabel) {
|
|
116
|
-
return [
|
|
117
|
-
{
|
|
118
|
-
metric: 'false_merge_rate',
|
|
119
|
-
direction: 'decrease',
|
|
120
|
-
reason: `Splitting ${sourceLabel} back out would likely reduce false merge pressure.`,
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
metric: 'projection_fragmentation_rate',
|
|
124
|
-
direction: 'increase',
|
|
125
|
-
reason: `Reactivating a second canonical entity likely increases projection fragmentation.`,
|
|
126
|
-
},
|
|
127
|
-
];
|
|
128
|
-
}
|
|
129
|
-
async function previewMergeRollback(adapter, input, mergeAction) {
|
|
130
|
-
const sourceNode = (0, store_js_1.getEntityNode)(mergeAction.source_entity_id, adapter);
|
|
131
|
-
const targetNode = (0, store_js_1.getEntityNode)(mergeAction.target_entity_id, adapter);
|
|
132
|
-
if (!sourceNode || !targetNode) {
|
|
133
|
-
return unavailableResult(input.entityId, mergeAction.id, true);
|
|
134
|
-
}
|
|
135
|
-
const sourceHistory = await (0, lineage_store_js_1.listEntityLineageHistory)(sourceNode.id, adapter);
|
|
136
|
-
const targetActive = await (0, lineage_store_js_1.listActiveEntityLineage)(targetNode.id, adapter);
|
|
137
|
-
const { restoredRows, removedRows } = resolveMergePreviewRows({
|
|
138
|
-
sourceHistory,
|
|
139
|
-
targetActive,
|
|
140
|
-
sourceEntityId: sourceNode.id,
|
|
141
|
-
mergeActionId: input.mergeActionId,
|
|
142
|
-
});
|
|
143
|
-
if (restoredRows.length === 0 || removedRows.length === 0) {
|
|
144
|
-
return unavailableResult(input.entityId, mergeAction.id, true);
|
|
145
|
-
}
|
|
146
|
-
const affectedObservationIds = uniqueStrings([
|
|
147
|
-
...restoredRows.map((row) => row.entity_observation_id),
|
|
148
|
-
...removedRows.map((row) => row.entity_observation_id),
|
|
149
|
-
]);
|
|
150
|
-
const allChangedMemories = loadChangedMemories(adapter, affectedObservationIds);
|
|
151
|
-
const maxAffectedRows = normalizeMaxAffectedRows(input);
|
|
152
|
-
const truncated = allChangedMemories.length > maxAffectedRows;
|
|
153
|
-
return {
|
|
154
|
-
entity_id: input.entityId,
|
|
155
|
-
merge_action_id: mergeAction.id,
|
|
156
|
-
preview_unavailable: false,
|
|
157
|
-
history_incomplete: false,
|
|
158
|
-
truncated,
|
|
159
|
-
changed_entities: [
|
|
160
|
-
{
|
|
161
|
-
entity_id: sourceNode.id,
|
|
162
|
-
label: sourceNode.preferred_label,
|
|
163
|
-
status_after: 'active',
|
|
164
|
-
active_lineage_after: restoredRows.length,
|
|
165
|
-
summary: projectLabel(adapter, { ...sourceNode, status: 'active', merged_into: null }),
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
entity_id: targetNode.id,
|
|
169
|
-
label: targetNode.preferred_label,
|
|
170
|
-
status_after: 'active',
|
|
171
|
-
active_lineage_after: Math.max(0, targetActive.length - removedRows.length),
|
|
172
|
-
summary: projectLabel(adapter, targetNode),
|
|
173
|
-
},
|
|
174
|
-
],
|
|
175
|
-
changed_memories: allChangedMemories.slice(0, maxAffectedRows),
|
|
176
|
-
metric_movement: buildMetricMovement(sourceNode.preferred_label),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
async function previewObservationDetach(adapter, input) {
|
|
180
|
-
const activeTarget = await (0, lineage_store_js_1.listActiveEntityLineage)(input.entityId, adapter);
|
|
181
|
-
const targetNode = (0, store_js_1.getEntityNode)(input.entityId, adapter);
|
|
182
|
-
if (!targetNode) {
|
|
183
|
-
return unavailableResult(input.entityId, null, false);
|
|
184
|
-
}
|
|
185
|
-
const row = activeTarget.find((candidate) => candidate.entity_observation_id === input.observationId);
|
|
186
|
-
if (!row) {
|
|
187
|
-
return unavailableResult(input.entityId, null, false);
|
|
188
|
-
}
|
|
189
|
-
const changedMemories = loadChangedMemories(adapter, [row.entity_observation_id]);
|
|
190
|
-
const maxAffectedRows = normalizeMaxAffectedRows(input);
|
|
191
|
-
return {
|
|
192
|
-
entity_id: input.entityId,
|
|
193
|
-
merge_action_id: null,
|
|
194
|
-
preview_unavailable: false,
|
|
195
|
-
history_incomplete: false,
|
|
196
|
-
truncated: changedMemories.length > maxAffectedRows,
|
|
197
|
-
changed_entities: [
|
|
198
|
-
{
|
|
199
|
-
entity_id: targetNode.id,
|
|
200
|
-
label: targetNode.preferred_label,
|
|
201
|
-
status_after: 'active',
|
|
202
|
-
active_lineage_after: Math.max(0, activeTarget.length - 1),
|
|
203
|
-
summary: projectLabel(adapter, targetNode),
|
|
204
|
-
},
|
|
205
|
-
],
|
|
206
|
-
changed_memories: changedMemories.slice(0, maxAffectedRows),
|
|
207
|
-
metric_movement: [
|
|
208
|
-
{
|
|
209
|
-
metric: 'false_merge_rate',
|
|
210
|
-
direction: 'decrease',
|
|
211
|
-
reason: 'Removing one supporting observation may reduce merge confidence for the current entity.',
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
metric: 'projection_fragmentation_rate',
|
|
215
|
-
direction: 'increase',
|
|
216
|
-
reason: 'Detaching one observation may increase fragmentation if it needs a separate entity later.',
|
|
217
|
-
},
|
|
218
|
-
],
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
async function previewEntityRollback(input, options = {}) {
|
|
222
|
-
if (!options.adapter) {
|
|
223
|
-
await (0, db_manager_js_1.initDB)();
|
|
224
|
-
}
|
|
225
|
-
const adapter = options.adapter ?? (0, db_manager_js_1.getAdapter)();
|
|
226
|
-
if (input.observationId) {
|
|
227
|
-
return previewObservationDetach(adapter, input);
|
|
228
|
-
}
|
|
229
|
-
const mergeAction = loadMergeAction(adapter, input.entityId, input.mergeActionId);
|
|
230
|
-
if (!mergeAction) {
|
|
231
|
-
return unavailableResult(input.entityId, input.mergeActionId ?? null, false);
|
|
232
|
-
}
|
|
233
|
-
return previewMergeRollback(adapter, input, mergeAction);
|
|
234
|
-
}
|
|
235
3
|
//# sourceMappingURL=rollback-preview.js.map
|
package/dist/entities/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EntityAlias, type EntityNode, type EntityObservation
|
|
1
|
+
import { type EntityAlias, type EntityNode, type EntityObservation } from './types.js';
|
|
2
2
|
export interface EntityStoreAdapter {
|
|
3
3
|
prepare(sql: string): {
|
|
4
4
|
run(...params: unknown[]): {
|
|
@@ -18,13 +18,6 @@ type CreateEntityNodeInput = Omit<EntityNode, 'created_at' | 'updated_at'>;
|
|
|
18
18
|
type AttachEntityAliasInput = Omit<EntityAlias, 'created_at'>;
|
|
19
19
|
type ObservationContextKeyColumn = (typeof OBSERVATION_CONTEXT_KEY_COLUMNS)[number];
|
|
20
20
|
type UpsertEntityObservationInput = Omit<EntityObservation, 'created_at'> & Partial<Record<ObservationContextKeyColumn, string | null>>;
|
|
21
|
-
type AppendEntityTimelineEventInput = {
|
|
22
|
-
event: Omit<EntityTimelineEvent, 'id' | 'created_at'> & {
|
|
23
|
-
id?: string;
|
|
24
|
-
created_at?: number;
|
|
25
|
-
};
|
|
26
|
-
adapter?: EntityStoreAdapter;
|
|
27
|
-
};
|
|
28
21
|
export interface UpsertEntityObservationResult {
|
|
29
22
|
id: string;
|
|
30
23
|
created: boolean;
|
|
@@ -33,12 +26,10 @@ export declare function clearEntityTableColumnCache(adapter: EntityStoreAdapter)
|
|
|
33
26
|
export declare function parseObservationRow(row: Record<string, unknown>): EntityObservation;
|
|
34
27
|
export declare function createEntityNode(input: CreateEntityNodeInput): Promise<EntityNode>;
|
|
35
28
|
export declare function getEntityNode(id: string, adapter?: EntityStoreAdapter): EntityNode | null;
|
|
36
|
-
export declare function listEntityNodes(): EntityNode[];
|
|
37
29
|
export declare function attachEntityAlias(input: AttachEntityAliasInput): Promise<EntityAlias>;
|
|
38
30
|
export declare function listEntityAliases(entityId: string, adapter?: EntityStoreAdapter): EntityAlias[];
|
|
39
31
|
export declare function upsertEntityObservation(input: UpsertEntityObservationInput): Promise<EntityObservation>;
|
|
40
32
|
export declare function upsertEntityObservations(inputs: UpsertEntityObservationInput[]): Promise<UpsertEntityObservationResult[]>;
|
|
41
|
-
export declare function appendEntityTimelineEvent(input: AppendEntityTimelineEventInput): Promise<EntityTimelineEvent>;
|
|
42
33
|
/**
|
|
43
34
|
* Walks the `entity_nodes.merged_into` chain from the given id and returns the
|
|
44
35
|
* terminal (unmerged) entity id. Detects cycles and caps depth. Read-only.
|
package/dist/entities/store.js
CHANGED
|
@@ -5,12 +5,10 @@ exports.clearEntityTableColumnCache = clearEntityTableColumnCache;
|
|
|
5
5
|
exports.parseObservationRow = parseObservationRow;
|
|
6
6
|
exports.createEntityNode = createEntityNode;
|
|
7
7
|
exports.getEntityNode = getEntityNode;
|
|
8
|
-
exports.listEntityNodes = listEntityNodes;
|
|
9
8
|
exports.attachEntityAlias = attachEntityAlias;
|
|
10
9
|
exports.listEntityAliases = listEntityAliases;
|
|
11
10
|
exports.upsertEntityObservation = upsertEntityObservation;
|
|
12
11
|
exports.upsertEntityObservations = upsertEntityObservations;
|
|
13
|
-
exports.appendEntityTimelineEvent = appendEntityTimelineEvent;
|
|
14
12
|
exports.resolveCanonicalEntityId = resolveCanonicalEntityId;
|
|
15
13
|
exports.mergeEntityNodes = mergeEntityNodes;
|
|
16
14
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -236,23 +234,6 @@ function getEntityNode(id, adapter = (0, db_manager_js_1.getAdapter)()) {
|
|
|
236
234
|
updated_at: Number(row.updated_at),
|
|
237
235
|
};
|
|
238
236
|
}
|
|
239
|
-
function listEntityNodes() {
|
|
240
|
-
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
241
|
-
const rows = adapter
|
|
242
|
-
.prepare('SELECT * FROM entity_nodes ORDER BY created_at DESC')
|
|
243
|
-
.all();
|
|
244
|
-
return rows.map((row) => ({
|
|
245
|
-
id: String(row.id),
|
|
246
|
-
kind: row.kind,
|
|
247
|
-
preferred_label: String(row.preferred_label),
|
|
248
|
-
status: row.status,
|
|
249
|
-
scope_kind: typeof row.scope_kind === 'string' ? row.scope_kind : null,
|
|
250
|
-
scope_id: typeof row.scope_id === 'string' ? row.scope_id : null,
|
|
251
|
-
merged_into: typeof row.merged_into === 'string' ? row.merged_into : null,
|
|
252
|
-
created_at: Number(row.created_at),
|
|
253
|
-
updated_at: Number(row.updated_at),
|
|
254
|
-
}));
|
|
255
|
-
}
|
|
256
237
|
async function attachEntityAlias(input) {
|
|
257
238
|
await (0, db_manager_js_1.initDB)();
|
|
258
239
|
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
@@ -461,36 +442,6 @@ async function upsertEntityObservations(inputs) {
|
|
|
461
442
|
}
|
|
462
443
|
return observations;
|
|
463
444
|
}
|
|
464
|
-
async function appendEntityTimelineEvent(input) {
|
|
465
|
-
if (!input.adapter) {
|
|
466
|
-
await (0, db_manager_js_1.initDB)();
|
|
467
|
-
}
|
|
468
|
-
const adapter = input.adapter ?? (0, db_manager_js_1.getAdapter)();
|
|
469
|
-
const eventId = input.event.id ?? `et_${(0, node_crypto_1.randomUUID)()}`;
|
|
470
|
-
const createdAt = input.event.created_at ?? now();
|
|
471
|
-
adapter
|
|
472
|
-
.prepare(`
|
|
473
|
-
INSERT INTO entity_timeline_events (
|
|
474
|
-
id, entity_id, event_type, role, valid_from, valid_to, observed_at,
|
|
475
|
-
source_ref, summary, details, created_at
|
|
476
|
-
)
|
|
477
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
478
|
-
`)
|
|
479
|
-
.run(eventId, input.event.entity_id, input.event.event_type, input.event.role ?? null, input.event.valid_from ?? null, input.event.valid_to ?? null, input.event.observed_at ?? null, input.event.source_ref ?? null, input.event.summary, input.event.details ?? null, createdAt);
|
|
480
|
-
return {
|
|
481
|
-
id: eventId,
|
|
482
|
-
entity_id: input.event.entity_id,
|
|
483
|
-
event_type: input.event.event_type,
|
|
484
|
-
role: input.event.role ?? null,
|
|
485
|
-
valid_from: input.event.valid_from ?? null,
|
|
486
|
-
valid_to: input.event.valid_to ?? null,
|
|
487
|
-
observed_at: input.event.observed_at ?? null,
|
|
488
|
-
source_ref: input.event.source_ref ?? null,
|
|
489
|
-
summary: input.event.summary,
|
|
490
|
-
details: input.event.details ?? null,
|
|
491
|
-
created_at: createdAt,
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
445
|
/**
|
|
495
446
|
* Walks the `entity_nodes.merged_into` chain from the given id and returns the
|
|
496
447
|
* terminal (unmerged) entity id. Detects cycles and caps depth. Read-only.
|