@jungjaehoon/mama-core 1.4.1 → 1.5.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.
Files changed (120) hide show
  1. package/db/migrations/026-create-canonical-entity-tables.sql +99 -0
  2. package/db/migrations/027-create-entity-review-support.sql +44 -0
  3. package/db/migrations/028-create-entity-audit-tables.sql +45 -0
  4. package/db/migrations/029-extend-entity-observations-observation-type.sql +60 -0
  5. package/db/migrations/030-case-first-memory-substrate.sql +901 -0
  6. package/db/migrations/031-wiki-page-index-provenance-columns.sql +2 -0
  7. package/dist/canonicalize.d.ts +38 -0
  8. package/dist/canonicalize.js +106 -0
  9. package/dist/cases/case-links.d.ts +116 -0
  10. package/dist/cases/case-links.js +794 -0
  11. package/dist/cases/composition-overrides.d.ts +90 -0
  12. package/dist/cases/composition-overrides.js +724 -0
  13. package/dist/cases/corrections.d.ts +156 -0
  14. package/dist/cases/corrections.js +1045 -0
  15. package/dist/cases/freshness.d.ts +57 -0
  16. package/dist/cases/freshness.js +283 -0
  17. package/dist/cases/live-state.d.ts +48 -0
  18. package/dist/cases/live-state.js +256 -0
  19. package/dist/cases/membership-explain.d.ts +56 -0
  20. package/dist/cases/membership-explain.js +140 -0
  21. package/dist/cases/membership-matcher.d.ts +23 -0
  22. package/dist/cases/membership-matcher.js +193 -0
  23. package/dist/cases/merge-split.d.ts +61 -0
  24. package/dist/cases/merge-split.js +368 -0
  25. package/dist/cases/role-inference.d.ts +10 -0
  26. package/dist/cases/role-inference.js +85 -0
  27. package/dist/cases/search-rollup.d.ts +23 -0
  28. package/dist/cases/search-rollup.js +225 -0
  29. package/dist/cases/sqlite-transaction.d.ts +10 -0
  30. package/dist/cases/sqlite-transaction.js +62 -0
  31. package/dist/cases/store.d.ts +74 -0
  32. package/dist/cases/store.js +816 -0
  33. package/dist/cases/target-ref.d.ts +25 -0
  34. package/dist/cases/target-ref.js +22 -0
  35. package/dist/cases/timeline-range.d.ts +6 -0
  36. package/dist/cases/timeline-range.js +322 -0
  37. package/dist/cases/tombstone-sweeper.d.ts +13 -0
  38. package/dist/cases/tombstone-sweeper.js +128 -0
  39. package/dist/cases/types.d.ts +244 -0
  40. package/dist/cases/types.js +47 -0
  41. package/dist/cases/wiki-page-index.d.ts +50 -0
  42. package/dist/cases/wiki-page-index.js +350 -0
  43. package/dist/config-loader.d.ts +1 -0
  44. package/dist/config-loader.js +43 -0
  45. package/dist/connectors/event-index.d.ts +44 -0
  46. package/dist/connectors/event-index.js +366 -0
  47. package/dist/connectors/types.d.ts +69 -0
  48. package/dist/connectors/types.js +3 -0
  49. package/dist/db-manager.d.ts +4 -0
  50. package/dist/db-manager.js +10 -3
  51. package/dist/decision-formatter.d.ts +2 -0
  52. package/dist/decision-formatter.js +11 -8
  53. package/dist/embedding-server/mobile/daemon.d.ts +1 -0
  54. package/dist/embedding-server/mobile/daemon.js +11 -1
  55. package/dist/entities/audit-metrics.d.ts +73 -0
  56. package/dist/entities/audit-metrics.js +128 -0
  57. package/dist/entities/candidate-generator.d.ts +9 -0
  58. package/dist/entities/candidate-generator.js +436 -0
  59. package/dist/entities/entity-impact.d.ts +41 -0
  60. package/dist/entities/entity-impact.js +140 -0
  61. package/dist/entities/entity-linked-decision-counts.d.ts +2 -0
  62. package/dist/entities/entity-linked-decision-counts.js +29 -0
  63. package/dist/entities/entity-list.d.ts +23 -0
  64. package/dist/entities/entity-list.js +99 -0
  65. package/dist/entities/entity-orphan-list.d.ts +26 -0
  66. package/dist/entities/entity-orphan-list.js +91 -0
  67. package/dist/entities/entity-search.d.ts +21 -0
  68. package/dist/entities/entity-search.js +150 -0
  69. package/dist/entities/errors.d.ts +65 -0
  70. package/dist/entities/errors.js +124 -0
  71. package/dist/entities/exact-merge-backfill.d.ts +11 -0
  72. package/dist/entities/exact-merge-backfill.js +161 -0
  73. package/dist/entities/lineage-backfill.d.ts +12 -0
  74. package/dist/entities/lineage-backfill.js +101 -0
  75. package/dist/entities/lineage-store.d.ts +51 -0
  76. package/dist/entities/lineage-store.js +308 -0
  77. package/dist/entities/normalization.d.ts +14 -0
  78. package/dist/entities/normalization.js +63 -0
  79. package/dist/entities/policy-store.d.ts +17 -0
  80. package/dist/entities/policy-store.js +263 -0
  81. package/dist/entities/policy-types.d.ts +72 -0
  82. package/dist/entities/policy-types.js +59 -0
  83. package/dist/entities/projection.d.ts +8 -0
  84. package/dist/entities/projection.js +82 -0
  85. package/dist/entities/provenance-query.d.ts +33 -0
  86. package/dist/entities/provenance-query.js +167 -0
  87. package/dist/entities/read-identity.d.ts +31 -0
  88. package/dist/entities/read-identity.js +264 -0
  89. package/dist/entities/recall-bridge.d.ts +5 -0
  90. package/dist/entities/recall-bridge.js +171 -0
  91. package/dist/entities/resolution-engine.d.ts +15 -0
  92. package/dist/entities/resolution-engine.js +69 -0
  93. package/dist/entities/rollback-preview.d.ts +39 -0
  94. package/dist/entities/rollback-preview.js +235 -0
  95. package/dist/entities/source-locator.d.ts +3 -0
  96. package/dist/entities/source-locator.js +32 -0
  97. package/dist/entities/store.d.ts +75 -0
  98. package/dist/entities/store.js +465 -0
  99. package/dist/entities/types.d.ts +162 -0
  100. package/dist/entities/types.js +30 -0
  101. package/dist/index.d.ts +47 -2
  102. package/dist/index.js +66 -25
  103. package/dist/mama-api.d.ts +22 -1
  104. package/dist/mama-api.js +272 -64
  105. package/dist/memory/api.d.ts +28 -1
  106. package/dist/memory/api.js +293 -31
  107. package/dist/memory/types.d.ts +11 -2
  108. package/dist/search/feedback-store.d.ts +59 -0
  109. package/dist/search/feedback-store.js +211 -0
  110. package/dist/search/question-type.d.ts +5 -0
  111. package/dist/search/question-type.js +41 -0
  112. package/dist/search/ranker-features.d.ts +23 -0
  113. package/dist/search/ranker-features.js +104 -0
  114. package/dist/search/ranker-rescore.d.ts +31 -0
  115. package/dist/search/ranker-rescore.js +226 -0
  116. package/dist/search/ranker-trainer.d.ts +94 -0
  117. package/dist/search/ranker-trainer.js +860 -0
  118. package/dist/test-utils.d.ts +14 -0
  119. package/dist/test-utils.js +52 -0
  120. package/package.json +21 -3
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listCanonicalEntities = listCanonicalEntities;
4
+ const db_manager_js_1 = require("../db-manager.js");
5
+ const entity_linked_decision_counts_js_1 = require("./entity-linked-decision-counts.js");
6
+ function normalizeBrowseLabel(input) {
7
+ return input.normalize('NFKC').trim().replace(/\s+/gu, ' ').toLowerCase();
8
+ }
9
+ function buildBrowseCollapseKey(row) {
10
+ return JSON.stringify([
11
+ row.kind,
12
+ row.scope_kind,
13
+ row.scope_id ?? '',
14
+ normalizeBrowseLabel(row.preferred_label),
15
+ ]);
16
+ }
17
+ function compareCanonicalRows(left, right) {
18
+ if (right.created_at !== left.created_at) {
19
+ return right.created_at - left.created_at;
20
+ }
21
+ const labelCompare = left.preferred_label.localeCompare(right.preferred_label);
22
+ if (labelCompare !== 0) {
23
+ return labelCompare;
24
+ }
25
+ return left.id.localeCompare(right.id);
26
+ }
27
+ function decodeCursor(cursor) {
28
+ if (!cursor) {
29
+ return 0;
30
+ }
31
+ try {
32
+ const decoded = Number(Buffer.from(cursor, 'base64').toString('utf8'));
33
+ return Number.isFinite(decoded) && decoded >= 0 ? decoded : 0;
34
+ }
35
+ catch {
36
+ return 0;
37
+ }
38
+ }
39
+ function encodeCursor(offset) {
40
+ return Buffer.from(String(offset), 'utf8').toString('base64');
41
+ }
42
+ function isNoisyCanonicalEntity(row) {
43
+ const label = row.preferred_label.trim().toLowerCase();
44
+ if (row.kind === 'person') {
45
+ return label === 'user' || label === 'claude';
46
+ }
47
+ if (row.kind === 'project') {
48
+ return label === 'workspace';
49
+ }
50
+ return false;
51
+ }
52
+ async function listCanonicalEntities(input) {
53
+ await (0, db_manager_js_1.initDB)();
54
+ const adapter = (0, db_manager_js_1.getAdapter)();
55
+ const rows = adapter
56
+ .prepare(`
57
+ SELECT id, kind, preferred_label, scope_kind, scope_id, created_at
58
+ FROM entity_nodes
59
+ WHERE status = 'active'
60
+ AND merged_into IS NULL
61
+ `)
62
+ .all();
63
+ const sorted = rows.sort(compareCanonicalRows);
64
+ const collapsedByKey = new Map();
65
+ for (const row of sorted) {
66
+ const key = buildBrowseCollapseKey(row);
67
+ const existing = collapsedByKey.get(key);
68
+ if (!existing) {
69
+ collapsedByKey.set(key, row);
70
+ continue;
71
+ }
72
+ if (row.created_at > existing.created_at ||
73
+ (row.created_at === existing.created_at && row.id.localeCompare(existing.id) < 0)) {
74
+ collapsedByKey.set(key, row);
75
+ }
76
+ }
77
+ const collapsed = Array.from(collapsedByKey.values()).sort(compareCanonicalRows);
78
+ const totalCount = sorted.length;
79
+ const visibleBase = input.include_noisy === false
80
+ ? collapsed.filter((row) => !isNoisyCanonicalEntity(row))
81
+ : collapsed;
82
+ const offset = decodeCursor(input.cursor);
83
+ const limit = Math.max(1, input.limit);
84
+ const page = visibleBase.slice(offset, offset + limit);
85
+ const linkedCounts = (0, entity_linked_decision_counts_js_1.loadLinkedDecisionCounts)(adapter, page.map((row) => row.id));
86
+ const entities = page.map((row) => ({
87
+ ...row,
88
+ linked_decision_count: linkedCounts.get(row.id) ?? 0,
89
+ }));
90
+ const visibleCount = visibleBase.length;
91
+ const nextCursor = offset + limit < visibleBase.length ? encodeCursor(offset + limit) : null;
92
+ return {
93
+ entities,
94
+ next_cursor: nextCursor,
95
+ total_count: totalCount,
96
+ visible_count: visibleCount,
97
+ };
98
+ }
99
+ //# sourceMappingURL=entity-list.js.map
@@ -0,0 +1,26 @@
1
+ import type { EntityNode } from './types.js';
2
+ export interface CanonicalEntityOrphanRow {
3
+ entity_id: string;
4
+ title: string;
5
+ kind: EntityNode['kind'];
6
+ scope_kind: EntityNode['scope_kind'];
7
+ scope_id: string | null;
8
+ scope_label: string;
9
+ created_at: number;
10
+ linked_decision_count: number;
11
+ evidence_summary: {
12
+ lineage_rows: number;
13
+ raw_evidence_rows: number;
14
+ last_seen_at: number | null;
15
+ };
16
+ }
17
+ interface ReadAdapter {
18
+ prepare(sql: string): {
19
+ all: (...params: unknown[]) => unknown[];
20
+ };
21
+ }
22
+ export declare function listCanonicalEntityOrphans(adapter?: ReadAdapter, options?: {
23
+ min_age_ms?: number | null;
24
+ }): CanonicalEntityOrphanRow[];
25
+ export {};
26
+ //# sourceMappingURL=entity-orphan-list.d.ts.map
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listCanonicalEntityOrphans = listCanonicalEntityOrphans;
4
+ const db_manager_js_1 = require("../db-manager.js");
5
+ const entity_linked_decision_counts_js_1 = require("./entity-linked-decision-counts.js");
6
+ function buildScopeLabel(scopeKind, scopeId) {
7
+ return scopeKind ? `${scopeKind}:${scopeId ?? ''}` : 'global';
8
+ }
9
+ function isNoisyCanonicalEntity(row) {
10
+ const label = row.title.trim().toLowerCase();
11
+ if (row.kind === 'person') {
12
+ return label === 'user' || label === 'claude';
13
+ }
14
+ if (row.kind === 'project') {
15
+ return label === 'workspace';
16
+ }
17
+ return false;
18
+ }
19
+ function compareOrphanRows(left, right) {
20
+ const leftSeen = typeof left.evidence_summary.last_seen_at === 'number' ? left.evidence_summary.last_seen_at : 0;
21
+ const rightSeen = typeof right.evidence_summary.last_seen_at === 'number'
22
+ ? right.evidence_summary.last_seen_at
23
+ : 0;
24
+ if (rightSeen !== leftSeen) {
25
+ return rightSeen - leftSeen;
26
+ }
27
+ return left.entity_id.localeCompare(right.entity_id);
28
+ }
29
+ function listCanonicalEntityOrphans(adapter = (0, db_manager_js_1.getAdapter)(), options = {}) {
30
+ const minAgeMs = typeof options.min_age_ms === 'number' && Number.isFinite(options.min_age_ms)
31
+ ? Math.max(0, options.min_age_ms)
32
+ : 0;
33
+ const minCreatedAt = Date.now() - minAgeMs;
34
+ const rows = adapter
35
+ .prepare(`
36
+ SELECT
37
+ n.id AS entity_id,
38
+ n.kind AS kind,
39
+ n.preferred_label AS title,
40
+ n.scope_kind AS scope_kind,
41
+ n.scope_id AS scope_id,
42
+ n.created_at AS created_at,
43
+ COUNT(DISTINCT l.entity_observation_id) AS lineage_rows,
44
+ COUNT(
45
+ DISTINCT CASE
46
+ WHEN COALESCE(o.source_raw_record_id, '') <> '' THEN l.entity_observation_id
47
+ ELSE NULL
48
+ END
49
+ ) AS raw_evidence_rows,
50
+ MAX(COALESCE(o.timestamp_observed, o.created_at)) AS last_seen_at
51
+ FROM entity_nodes n
52
+ INNER JOIN entity_lineage_links l
53
+ ON l.canonical_entity_id = n.id
54
+ AND l.status = 'active'
55
+ INNER JOIN entity_observations o
56
+ ON o.id = l.entity_observation_id
57
+ WHERE n.status = 'active'
58
+ AND n.merged_into IS NULL
59
+ AND n.created_at <= ?
60
+ GROUP BY n.id, n.kind, n.preferred_label, n.scope_kind, n.scope_id, n.created_at
61
+ `)
62
+ .all(minCreatedAt);
63
+ const orphanRows = rows.map((row) => ({
64
+ entity_id: row.entity_id,
65
+ title: row.title,
66
+ kind: row.kind,
67
+ scope_kind: row.scope_kind,
68
+ scope_id: row.scope_id,
69
+ scope_label: buildScopeLabel(row.scope_kind, row.scope_id),
70
+ created_at: Number(row.created_at),
71
+ linked_decision_count: 0,
72
+ evidence_summary: {
73
+ lineage_rows: Number(row.lineage_rows ?? 0),
74
+ raw_evidence_rows: Number(row.raw_evidence_rows ?? 0),
75
+ last_seen_at: row.last_seen_at === null || row.last_seen_at === undefined
76
+ ? null
77
+ : Number(row.last_seen_at),
78
+ },
79
+ }));
80
+ const linkedCounts = (0, entity_linked_decision_counts_js_1.loadLinkedDecisionCounts)(adapter, orphanRows.map((row) => row.entity_id));
81
+ return orphanRows
82
+ .map((row) => ({
83
+ ...row,
84
+ linked_decision_count: linkedCounts.get(row.entity_id) ?? 0,
85
+ }))
86
+ .filter((row) => row.evidence_summary.lineage_rows > 0 &&
87
+ row.linked_decision_count === 0 &&
88
+ !isNoisyCanonicalEntity(row))
89
+ .sort(compareOrphanRows);
90
+ }
91
+ //# sourceMappingURL=entity-orphan-list.js.map
@@ -0,0 +1,21 @@
1
+ import type { EntityNode } from './types.js';
2
+ export interface SearchCanonicalEntitiesInput {
3
+ query: string;
4
+ limit: number;
5
+ cursor?: string | null;
6
+ }
7
+ export interface EntitySearchRow {
8
+ id: string;
9
+ kind: EntityNode['kind'];
10
+ preferred_label: string;
11
+ scope_kind: EntityNode['scope_kind'];
12
+ scope_id: string | null;
13
+ score: number;
14
+ linked_decision_count: number;
15
+ }
16
+ export interface SearchCanonicalEntitiesResult {
17
+ entities: EntitySearchRow[];
18
+ next_cursor: string | null;
19
+ }
20
+ export declare function searchCanonicalEntities(input: SearchCanonicalEntitiesInput): Promise<SearchCanonicalEntitiesResult>;
21
+ //# sourceMappingURL=entity-search.d.ts.map
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchCanonicalEntities = searchCanonicalEntities;
4
+ const db_manager_js_1 = require("../db-manager.js");
5
+ const entity_linked_decision_counts_js_1 = require("./entity-linked-decision-counts.js");
6
+ const store_js_1 = require("./store.js");
7
+ function normalizeSearchLabel(input) {
8
+ return input.normalize('NFKC').trim().replace(/\s+/gu, ' ').toLowerCase();
9
+ }
10
+ function buildSearchCollapseKey(row) {
11
+ return JSON.stringify([
12
+ row.kind,
13
+ row.scope_kind,
14
+ row.scope_id ?? '',
15
+ normalizeSearchLabel(row.preferred_label),
16
+ ]);
17
+ }
18
+ function escapeLikeQuery(query) {
19
+ return query.replace(/[\\%_]/g, '\\$&');
20
+ }
21
+ function decodeCursor(cursor) {
22
+ if (!cursor) {
23
+ return 0;
24
+ }
25
+ try {
26
+ const decoded = Number(Buffer.from(cursor, 'base64').toString('utf8'));
27
+ return Number.isFinite(decoded) && decoded >= 0 ? decoded : 0;
28
+ }
29
+ catch {
30
+ return 0;
31
+ }
32
+ }
33
+ function encodeCursor(offset) {
34
+ return Buffer.from(String(offset), 'utf8').toString('base64');
35
+ }
36
+ async function searchCanonicalEntities(input) {
37
+ await (0, db_manager_js_1.initDB)();
38
+ const adapter = (0, db_manager_js_1.getAdapter)();
39
+ const query = input.query.trim();
40
+ if (!query) {
41
+ return { entities: [], next_cursor: null };
42
+ }
43
+ const escaped = escapeLikeQuery(query);
44
+ const normalizedQuery = normalizeSearchLabel(query);
45
+ const rows = adapter
46
+ .prepare(`
47
+ SELECT
48
+ n.id AS matched_id,
49
+ n.preferred_label,
50
+ n.kind,
51
+ n.scope_kind,
52
+ n.scope_id,
53
+ a.label AS alias_label,
54
+ o.surface_form AS observation_surface_form
55
+ FROM entity_nodes n
56
+ LEFT JOIN entity_aliases a ON a.entity_id = n.id
57
+ LEFT JOIN entity_lineage_links l ON l.canonical_entity_id = n.id AND l.status = 'active'
58
+ LEFT JOIN entity_observations o ON o.id = l.entity_observation_id
59
+ WHERE (
60
+ lower(n.preferred_label) LIKE '%' || lower(?) || '%' ESCAPE '\\'
61
+ OR lower(COALESCE(a.label, '')) LIKE '%' || lower(?) || '%' ESCAPE '\\'
62
+ OR lower(COALESCE(o.surface_form, '')) LIKE '%' || lower(?) || '%' ESCAPE '\\'
63
+ )
64
+ `)
65
+ .all(escaped, escaped, escaped);
66
+ const canonicalIdByMatchedId = new Map();
67
+ for (const matchedId of new Set(rows.map((row) => row.matched_id))) {
68
+ try {
69
+ canonicalIdByMatchedId.set(matchedId, (0, store_js_1.resolveCanonicalEntityId)(adapter, matchedId));
70
+ }
71
+ catch (error) {
72
+ if (error instanceof store_js_1.EntityMergeError) {
73
+ continue;
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+ const canonicalIds = Array.from(new Set(canonicalIdByMatchedId.values()));
79
+ const canonicalLookup = new Map();
80
+ if (canonicalIds.length > 0) {
81
+ const fetched = adapter
82
+ .prepare(`
83
+ SELECT id, kind, preferred_label, scope_kind, scope_id
84
+ FROM entity_nodes
85
+ WHERE id IN (${canonicalIds.map(() => '?').join(', ')})
86
+ AND status = 'active'
87
+ AND merged_into IS NULL
88
+ `)
89
+ .all(...canonicalIds);
90
+ for (const row of fetched) {
91
+ canonicalLookup.set(row.id, row);
92
+ }
93
+ }
94
+ const canonicalRows = new Map();
95
+ for (const row of rows) {
96
+ const canonicalId = canonicalIdByMatchedId.get(row.matched_id);
97
+ const canonical = canonicalId ? canonicalLookup.get(canonicalId) : undefined;
98
+ if (!canonical) {
99
+ continue;
100
+ }
101
+ const score = normalizeSearchLabel(row.preferred_label).includes(normalizedQuery)
102
+ ? 3
103
+ : row.alias_label && normalizeSearchLabel(row.alias_label).includes(normalizedQuery)
104
+ ? 2
105
+ : 1;
106
+ const existing = canonicalRows.get(canonical.id);
107
+ if (!existing || score > existing.score) {
108
+ canonicalRows.set(canonical.id, {
109
+ id: canonical.id,
110
+ kind: canonical.kind,
111
+ preferred_label: canonical.preferred_label,
112
+ scope_kind: canonical.scope_kind,
113
+ scope_id: canonical.scope_id,
114
+ score,
115
+ linked_decision_count: 0,
116
+ });
117
+ }
118
+ }
119
+ const collapsedRows = new Map();
120
+ for (const row of canonicalRows.values()) {
121
+ const key = buildSearchCollapseKey(row);
122
+ const existing = collapsedRows.get(key);
123
+ if (!existing ||
124
+ row.score > existing.score ||
125
+ (row.score === existing.score && row.id.localeCompare(existing.id) < 0)) {
126
+ collapsedRows.set(key, row);
127
+ }
128
+ }
129
+ const sorted = Array.from(collapsedRows.values()).sort((left, right) => {
130
+ if (right.score !== left.score) {
131
+ return right.score - left.score;
132
+ }
133
+ const labelCompare = left.preferred_label.localeCompare(right.preferred_label);
134
+ if (labelCompare !== 0) {
135
+ return labelCompare;
136
+ }
137
+ return left.id.localeCompare(right.id);
138
+ });
139
+ const offset = decodeCursor(input.cursor);
140
+ const limit = Math.max(1, input.limit);
141
+ const page = sorted.slice(offset, offset + limit);
142
+ const linkedCounts = (0, entity_linked_decision_counts_js_1.loadLinkedDecisionCounts)(adapter, page.map((row) => row.id));
143
+ const entities = page.map((row) => ({
144
+ ...row,
145
+ linked_decision_count: linkedCounts.get(row.id) ?? 0,
146
+ }));
147
+ const next_cursor = offset + limit < sorted.length ? encodeCursor(offset + limit) : null;
148
+ return { entities, next_cursor };
149
+ }
150
+ //# sourceMappingURL=entity-search.js.map
@@ -0,0 +1,65 @@
1
+ export interface EntityErrorEnvelope {
2
+ error: {
3
+ code: string;
4
+ message: string;
5
+ hint: string;
6
+ doc_url: string;
7
+ };
8
+ }
9
+ export declare abstract class EntityError extends Error {
10
+ abstract readonly code: string;
11
+ abstract readonly doc_section: string;
12
+ readonly context: Record<string, unknown>;
13
+ readonly hint: string;
14
+ constructor(opts: {
15
+ message: string;
16
+ context?: Record<string, unknown>;
17
+ hint: string;
18
+ });
19
+ toErrorEnvelope(): EntityErrorEnvelope;
20
+ }
21
+ export declare class InvalidEntityLabelError extends EntityError {
22
+ readonly code = "entity.invalid_label";
23
+ readonly doc_section = "#invalid-label";
24
+ constructor(context?: Record<string, unknown>);
25
+ }
26
+ export declare class EmbeddingUnavailableError extends EntityError {
27
+ readonly code = "entity.embedding_unavailable";
28
+ readonly doc_section = "#embedding-unavailable";
29
+ constructor(context?: Record<string, unknown>);
30
+ }
31
+ export declare class OntologyViolationError extends EntityError {
32
+ readonly code = "entity.ontology_violation";
33
+ readonly doc_section = "#ontology-violation";
34
+ constructor(context?: Record<string, unknown>);
35
+ }
36
+ export declare class MergeTargetStaleError extends EntityError {
37
+ readonly code = "entity.merge_target_stale";
38
+ readonly doc_section = "#merge-target-stale";
39
+ constructor(context?: Record<string, unknown>);
40
+ }
41
+ export declare class EntityLabelMissingError extends EntityError {
42
+ readonly code = "entity.label_missing";
43
+ readonly doc_section = "#label-missing";
44
+ constructor(context?: Record<string, unknown>);
45
+ }
46
+ export declare class CandidateStaleError extends EntityError {
47
+ readonly code = "entity.candidate_stale";
48
+ readonly doc_section = "#candidate-stale";
49
+ constructor(context?: Record<string, unknown>);
50
+ }
51
+ export declare class AuditRunInProgressError extends EntityError {
52
+ readonly code = "entity.audit_run_in_progress";
53
+ readonly doc_section = "#audit-run-in-progress";
54
+ constructor(context?: Record<string, unknown>);
55
+ }
56
+ export declare class CaseMergeChainCycleError extends EntityError {
57
+ readonly code = "case.merge_chain_cycle";
58
+ readonly doc_section = "#case-merge-chain-cycle";
59
+ constructor(context: {
60
+ case_id: string;
61
+ chain: string[];
62
+ detected_at_depth: number;
63
+ });
64
+ }
65
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CaseMergeChainCycleError = exports.AuditRunInProgressError = exports.CandidateStaleError = exports.EntityLabelMissingError = exports.MergeTargetStaleError = exports.OntologyViolationError = exports.EmbeddingUnavailableError = exports.InvalidEntityLabelError = exports.EntityError = void 0;
4
+ class EntityError extends Error {
5
+ context;
6
+ hint;
7
+ constructor(opts) {
8
+ super(opts.message);
9
+ this.name = new.target.name;
10
+ this.context = opts.context ?? {};
11
+ this.hint = opts.hint;
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, new.target);
14
+ }
15
+ }
16
+ toErrorEnvelope() {
17
+ return {
18
+ error: {
19
+ code: this.code,
20
+ message: this.message,
21
+ hint: this.hint,
22
+ doc_url: `docs/operations/entity-substrate-runbook.md${this.doc_section}`,
23
+ },
24
+ };
25
+ }
26
+ }
27
+ exports.EntityError = EntityError;
28
+ class InvalidEntityLabelError extends EntityError {
29
+ code = 'entity.invalid_label';
30
+ doc_section = '#invalid-label';
31
+ constructor(context = {}) {
32
+ super({
33
+ message: 'Invalid entity label.',
34
+ context,
35
+ hint: 'Provide a non-empty entity label before normalization.',
36
+ });
37
+ }
38
+ }
39
+ exports.InvalidEntityLabelError = InvalidEntityLabelError;
40
+ class EmbeddingUnavailableError extends EntityError {
41
+ code = 'entity.embedding_unavailable';
42
+ doc_section = '#embedding-unavailable';
43
+ constructor(context = {}) {
44
+ super({
45
+ message: 'Entity embedding model is unavailable.',
46
+ context,
47
+ hint: 'Verify the embedding model is installed and reachable before generating candidates.',
48
+ });
49
+ }
50
+ }
51
+ exports.EmbeddingUnavailableError = EmbeddingUnavailableError;
52
+ class OntologyViolationError extends EntityError {
53
+ code = 'entity.ontology_violation';
54
+ doc_section = '#ontology-violation';
55
+ constructor(context = {}) {
56
+ super({
57
+ message: 'Entity operation violates ontology constraints.',
58
+ context,
59
+ hint: 'Check entity kinds and relation signatures before applying the change.',
60
+ });
61
+ }
62
+ }
63
+ exports.OntologyViolationError = OntologyViolationError;
64
+ class MergeTargetStaleError extends EntityError {
65
+ code = 'entity.merge_target_stale';
66
+ doc_section = '#merge-target-stale';
67
+ constructor(context = {}) {
68
+ super({
69
+ message: 'Merge target is stale.',
70
+ context,
71
+ hint: 'Reload the target entity state and retry the merge against the latest version.',
72
+ });
73
+ }
74
+ }
75
+ exports.MergeTargetStaleError = MergeTargetStaleError;
76
+ class EntityLabelMissingError extends EntityError {
77
+ code = 'entity.label_missing';
78
+ doc_section = '#label-missing';
79
+ constructor(context = {}) {
80
+ super({
81
+ message: 'Canonical entity label is missing.',
82
+ context,
83
+ hint: 'Set a preferred label before projecting or displaying the entity.',
84
+ });
85
+ }
86
+ }
87
+ exports.EntityLabelMissingError = EntityLabelMissingError;
88
+ class CandidateStaleError extends EntityError {
89
+ code = 'entity.candidate_stale';
90
+ doc_section = '#candidate-stale';
91
+ constructor(context = {}) {
92
+ super({
93
+ message: 'Resolution candidate is stale.',
94
+ context,
95
+ hint: 'Refresh the candidate list and review the latest evidence before acting.',
96
+ });
97
+ }
98
+ }
99
+ exports.CandidateStaleError = CandidateStaleError;
100
+ class AuditRunInProgressError extends EntityError {
101
+ code = 'entity.audit_run_in_progress';
102
+ doc_section = '#audit-run-in-progress';
103
+ constructor(context = {}) {
104
+ super({
105
+ message: 'Another entity audit run is already in progress.',
106
+ context,
107
+ hint: 'Wait for the current audit to finish or inspect its run status before starting a new one.',
108
+ });
109
+ }
110
+ }
111
+ exports.AuditRunInProgressError = AuditRunInProgressError;
112
+ class CaseMergeChainCycleError extends EntityError {
113
+ code = 'case.merge_chain_cycle';
114
+ doc_section = '#case-merge-chain-cycle';
115
+ constructor(context) {
116
+ super({
117
+ message: `Case merge chain cycle detected at depth ${context.detected_at_depth} starting from case_id=${context.case_id}. Chain=${context.chain.join(' -> ')}.`,
118
+ context,
119
+ hint: 'Inspect case_truth.canonical_case_id links and remove the cycle before retrying.',
120
+ });
121
+ }
122
+ }
123
+ exports.CaseMergeChainCycleError = CaseMergeChainCycleError;
124
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,11 @@
1
+ export interface ExactMergeBackfillOptions {
2
+ dryRun?: boolean;
3
+ }
4
+ export interface ExactMergeBackfillResult {
5
+ groups: number;
6
+ merged: number;
7
+ incomplete: number;
8
+ skipped: number;
9
+ }
10
+ export declare function backfillExactDuplicateCanonicals(opts?: ExactMergeBackfillOptions): Promise<ExactMergeBackfillResult>;
11
+ //# sourceMappingURL=exact-merge-backfill.d.ts.map