@jungjaehoon/mama-core 1.9.0 → 2.0.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 (136) hide show
  1. package/dist/agent-graph/alias-write.js +3 -0
  2. package/dist/agent-graph/entity-resolve.js +3 -7
  3. package/dist/agent-graph/graph-query.js +5 -4
  4. package/dist/agent-graph/types.d.ts +30 -0
  5. package/dist/cases/store.d.ts +0 -4
  6. package/dist/cases/store.js +0 -66
  7. package/dist/cases/wiki-page-index.d.ts +0 -13
  8. package/dist/cases/wiki-page-index.js +0 -153
  9. package/dist/connectors/event-index.d.ts +1 -22
  10. package/dist/connectors/event-index.js +0 -157
  11. package/dist/context-compile/channel-grant.d.ts +46 -0
  12. package/dist/context-compile/channel-grant.js +66 -0
  13. package/dist/context-compile/compiler.js +5 -2
  14. package/dist/context-compile/index.d.ts +1 -0
  15. package/dist/context-compile/index.js +1 -0
  16. package/dist/context-compile/packet-store.d.ts +0 -1
  17. package/dist/context-compile/packet-store.js +0 -16
  18. package/dist/context-compile/source-readers.d.ts +1 -0
  19. package/dist/context-compile/source-readers.js +156 -23
  20. package/dist/context-compile/types.d.ts +17 -0
  21. package/dist/context-compile/visibility.js +28 -4
  22. package/dist/db-adapter/node-sqlite-adapter.js +4 -0
  23. package/dist/db-manager.d.ts +0 -13
  24. package/dist/db-manager.js +0 -66
  25. package/dist/decision-formatter.d.ts +0 -11
  26. package/dist/decision-formatter.js +0 -122
  27. package/dist/decision-tracker.d.ts +0 -12
  28. package/dist/decision-tracker.js +0 -50
  29. package/dist/edges/ref-validation.d.ts +1 -2
  30. package/dist/edges/ref-validation.js +33 -13
  31. package/dist/edges/store.d.ts +1 -3
  32. package/dist/edges/store.js +0 -214
  33. package/dist/edges/types.d.ts +10 -0
  34. package/dist/embedding-client.d.ts +0 -17
  35. package/dist/embedding-client.js +0 -80
  36. package/dist/embedding-server/mobile/auth.d.ts +1 -10
  37. package/dist/embedding-server/mobile/auth.js +0 -15
  38. package/dist/embeddings.d.ts +0 -12
  39. package/dist/embeddings.js +0 -68
  40. package/dist/entities/audit-metrics.d.ts +0 -5
  41. package/dist/entities/audit-metrics.js +0 -4
  42. package/dist/entities/candidate-generator.d.ts +1 -2
  43. package/dist/entities/candidate-generator.js +0 -412
  44. package/dist/entities/entity-list.d.ts +0 -1
  45. package/dist/entities/entity-list.js +0 -96
  46. package/dist/entities/entity-orphan-list.d.ts +0 -9
  47. package/dist/entities/entity-orphan-list.js +0 -88
  48. package/dist/entities/entity-search.d.ts +0 -1
  49. package/dist/entities/entity-search.js +0 -147
  50. package/dist/entities/errors.d.ts +0 -10
  51. package/dist/entities/errors.js +1 -25
  52. package/dist/entities/lineage-store.d.ts +0 -23
  53. package/dist/entities/lineage-store.js +0 -104
  54. package/dist/entities/policy-store.d.ts +0 -9
  55. package/dist/entities/policy-store.js +0 -188
  56. package/dist/entities/provenance-query.d.ts +0 -1
  57. package/dist/entities/provenance-query.js +0 -164
  58. package/dist/entities/resolution-engine.d.ts +1 -8
  59. package/dist/entities/resolution-engine.js +0 -66
  60. package/dist/entities/rollback-preview.d.ts +0 -4
  61. package/dist/entities/rollback-preview.js +0 -232
  62. package/dist/entities/store.d.ts +1 -10
  63. package/dist/entities/store.js +0 -49
  64. package/dist/index.d.ts +15 -31
  65. package/dist/index.js +4 -46
  66. package/dist/mama-api.d.ts +19 -1
  67. package/dist/mama-api.js +97 -2
  68. package/dist/memory/api.d.ts +8 -0
  69. package/dist/memory/api.js +55 -2
  70. package/dist/memory/event-store.d.ts +0 -1
  71. package/dist/memory/event-store.js +0 -15
  72. package/dist/memory/finding-store.d.ts +0 -1
  73. package/dist/memory/finding-store.js +0 -12
  74. package/dist/memory/scope-backfill.d.ts +0 -3
  75. package/dist/memory/scope-backfill.js +0 -74
  76. package/dist/memory/scope-store.d.ts +0 -1
  77. package/dist/memory/scope-store.js +0 -4
  78. package/dist/memory/truth-store.d.ts +0 -3
  79. package/dist/memory/truth-store.js +0 -22
  80. package/dist/memory/types.d.ts +0 -1
  81. package/dist/memory/types.js +0 -13
  82. package/dist/memory-store.d.ts +0 -16
  83. package/dist/memory-store.js +0 -51
  84. package/dist/ollama-client.d.ts +0 -9
  85. package/dist/ollama-client.js +0 -125
  86. package/dist/outcome-tracker.d.ts +0 -14
  87. package/dist/outcome-tracker.js +0 -44
  88. package/dist/progress-indicator.d.ts +0 -4
  89. package/dist/progress-indicator.js +0 -7
  90. package/dist/provenance/source-ref.d.ts +0 -9
  91. package/dist/provenance/source-ref.js +0 -145
  92. package/dist/query-intent.d.ts +0 -4
  93. package/dist/query-intent.js +0 -30
  94. package/dist/relevance-scorer.d.ts +0 -9
  95. package/dist/relevance-scorer.js +0 -81
  96. package/dist/search/feedback-store.d.ts +0 -1
  97. package/dist/search/feedback-store.js +0 -4
  98. package/dist/search/ranker-rescore.d.ts +0 -3
  99. package/dist/search/ranker-rescore.js +0 -27
  100. package/dist/search/ranker-trainer.d.ts +0 -8
  101. package/dist/search/ranker-trainer.js +0 -376
  102. package/dist/tier-validator.d.ts +0 -12
  103. package/dist/tier-validator.js +0 -56
  104. package/package.json +1 -10
  105. package/dist/cases/case-links.d.ts +0 -116
  106. package/dist/cases/case-links.js +0 -794
  107. package/dist/cases/composition-overrides.d.ts +0 -90
  108. package/dist/cases/composition-overrides.js +0 -724
  109. package/dist/cases/corrections.d.ts +0 -156
  110. package/dist/cases/corrections.js +0 -1045
  111. package/dist/cases/freshness.d.ts +0 -57
  112. package/dist/cases/freshness.js +0 -283
  113. package/dist/cases/live-state.d.ts +0 -48
  114. package/dist/cases/live-state.js +0 -256
  115. package/dist/cases/membership-explain.d.ts +0 -56
  116. package/dist/cases/membership-explain.js +0 -140
  117. package/dist/cases/membership-matcher.d.ts +0 -23
  118. package/dist/cases/membership-matcher.js +0 -193
  119. package/dist/cases/merge-split.d.ts +0 -61
  120. package/dist/cases/merge-split.js +0 -368
  121. package/dist/cases/role-inference.d.ts +0 -10
  122. package/dist/cases/role-inference.js +0 -85
  123. package/dist/cases/sqlite-transaction.d.ts +0 -10
  124. package/dist/cases/sqlite-transaction.js +0 -62
  125. package/dist/cases/target-ref.d.ts +0 -25
  126. package/dist/cases/target-ref.js +0 -22
  127. package/dist/cases/tombstone-sweeper.d.ts +0 -13
  128. package/dist/cases/tombstone-sweeper.js +0 -128
  129. package/dist/entities/entity-impact.d.ts +0 -41
  130. package/dist/entities/entity-impact.js +0 -140
  131. package/dist/entities/exact-merge-backfill.d.ts +0 -11
  132. package/dist/entities/exact-merge-backfill.js +0 -161
  133. package/dist/entities/lineage-backfill.d.ts +0 -12
  134. package/dist/entities/lineage-backfill.js +0 -101
  135. package/dist/memory-inject.d.ts +0 -24
  136. package/dist/memory-inject.js +0 -116
@@ -17,11 +17,9 @@ exports.formatContext = formatContext;
17
17
  exports.formatLegacyContext = formatLegacyContext;
18
18
  exports.ensureTokenBudget = ensureTokenBudget;
19
19
  exports.estimateTokens = estimateTokens;
20
- exports.formatInstantAnswer = formatInstantAnswer;
21
20
  exports.extractQuickAnswer = extractQuickAnswer;
22
21
  exports.extractCodeExample = extractCodeExample;
23
22
  exports.formatTrustContext = formatTrustContext;
24
- exports.formatTeaser = formatTeaser;
25
23
  exports.formatRecall = formatRecall;
26
24
  exports.formatList = formatList;
27
25
  const relevance_scorer_js_1 = require("./relevance-scorer.js");
@@ -362,42 +360,6 @@ function getOutcomeEmoji(outcome) {
362
360
  };
363
361
  return outcome ? emojiMap[outcome] || '' : '';
364
362
  }
365
- /**
366
- * Format context in Claude-friendly Instant Answer format
367
- *
368
- * Story 014.7.10: Claude-Friendly Context Formatting
369
- * AC #1: Instant Answer format with trust components
370
- */
371
- function formatInstantAnswer(decision, options = {}) {
372
- const { maxTokens = 500 } = options;
373
- if (!decision) {
374
- return null;
375
- }
376
- // Extract quick answer (first line of decision)
377
- const quickAnswer = extractQuickAnswer(decision);
378
- if (!quickAnswer) {
379
- return null;
380
- }
381
- // Extract code example (from reasoning)
382
- const codeExample = extractCodeExample(decision);
383
- // Format trust context
384
- const trustSection = formatTrustContext(typeof decision.trust_context === 'string'
385
- ? parseTrustContext(decision.trust_context)
386
- : decision.trust_context);
387
- // Build output
388
- let output = `⚡ INSTANT ANSWER\n\n${quickAnswer}`;
389
- if (codeExample) {
390
- output += `\n\n${codeExample}`;
391
- }
392
- if (trustSection) {
393
- output += `\n\n${trustSection}`;
394
- }
395
- // Token budget check
396
- if (estimateTokens(output) > maxTokens) {
397
- output = truncateToFit(output, maxTokens);
398
- }
399
- return output;
400
- }
401
363
  /**
402
364
  * Extract quick answer from decision
403
365
  */
@@ -500,50 +462,6 @@ function formatTrustContext(trustCtx) {
500
462
  lines.push('━'.repeat(40));
501
463
  return lines.join('\n');
502
464
  }
503
- /**
504
- * Truncate output to fit token budget
505
- */
506
- function truncateToFit(output, maxTokens) {
507
- const sections = output.split('\n\n');
508
- const quickAnswer = sections[0];
509
- let result = quickAnswer;
510
- let remainingTokens = maxTokens - estimateTokens(result);
511
- // Try to add code example
512
- const codeIndex = sections.findIndex((s) => s.startsWith('```'));
513
- if (codeIndex > 0) {
514
- const codeSection = sections[codeIndex];
515
- const codeTokens = estimateTokens(codeSection);
516
- if (codeTokens <= remainingTokens) {
517
- result += '\n\n' + codeSection;
518
- remainingTokens -= codeTokens;
519
- }
520
- }
521
- // Try to add trust section (trimmed if needed)
522
- const trustIndex = sections.findIndex((s) => s.startsWith('━'));
523
- if (trustIndex > 0 && remainingTokens > 50) {
524
- const trustSection = sections[trustIndex];
525
- const trustTokens = estimateTokens(trustSection);
526
- if (trustTokens <= remainingTokens) {
527
- result += '\n\n' + trustSection;
528
- }
529
- else {
530
- const trustLines = trustSection.split('\n');
531
- let trimmed = trustLines[0] + '\n' + trustLines[1] + '\n';
532
- for (let i = 2; i < trustLines.length - 1; i++) {
533
- const line = trustLines[i] + '\n';
534
- if (estimateTokens(trimmed + line) <= remainingTokens - 10) {
535
- trimmed += line;
536
- }
537
- else {
538
- break;
539
- }
540
- }
541
- trimmed += trustLines[trustLines.length - 1];
542
- result += '\n\n' + trimmed;
543
- }
544
- }
545
- return result;
546
- }
547
465
  /**
548
466
  * Format multiple decisions as Google-style search results
549
467
  */
@@ -578,46 +496,6 @@ function formatTeaserList(decisions, topN = 3) {
578
496
  }
579
497
  return output;
580
498
  }
581
- /**
582
- * Format decision as curiosity-inducing teaser
583
- */
584
- function formatTeaser(decision) {
585
- if (!decision) {
586
- return null;
587
- }
588
- const timeAgo = calculateDuration(getDecisionTimestamp(decision));
589
- // Extract preview (first 60 chars)
590
- const preview = decision.decision.length > 60 ? decision.decision.substring(0, 60) + '...' : decision.decision;
591
- // Extract files from trust_context or show generic
592
- let files = 'Multiple files';
593
- const trustCtx = typeof decision.trust_context === 'string'
594
- ? parseTrustContext(decision.trust_context)
595
- : decision.trust_context;
596
- if (trustCtx?.source?.file) {
597
- const fileStr = trustCtx.source.file;
598
- const fileList = fileStr.split(',').map((f) => f.trim());
599
- if (fileList.length === 1) {
600
- files = fileList[0];
601
- }
602
- else if (fileList.length === 2) {
603
- files = fileList.join(', ');
604
- }
605
- else {
606
- files = `${fileList[0]}, ${fileList[1]} (+${fileList.length - 2})`;
607
- }
608
- }
609
- const teaser = `
610
- 💡 MAMA has related info
611
-
612
- 📚 Topic: ${decision.topic}
613
- 📖 Preview: "${preview}"
614
- 📁 Files: ${files}
615
- ⏰ Updated: ${timeAgo}
616
-
617
- 🔍 Read more: mama.recall('${decision.topic}')
618
- `.trim();
619
- return teaser;
620
- }
621
499
  /**
622
500
  * Format mama.recall() results in readable format
623
501
  */
@@ -163,18 +163,6 @@ export declare function createEdgesFromReasoning(fromId: string, reasoning: stri
163
163
  created: number;
164
164
  failed: number;
165
165
  }>;
166
- /**
167
- * Get supersedes chain depth for a topic
168
- *
169
- * Story 2.2: Calculate how many times a topic has been superseded
170
- *
171
- * @param topic - Decision topic
172
- * @returns Chain depth and decision IDs
173
- */
174
- export declare function getSupersededChainDepth(topic: string): Promise<{
175
- depth: number;
176
- chain: string[];
177
- }>;
178
166
  /**
179
167
  * Learn Decision Function (Main API)
180
168
  *
@@ -25,7 +25,6 @@ exports.calculateCombinedConfidence = calculateCombinedConfidence;
25
25
  exports.detectRefinement = detectRefinement;
26
26
  exports.parseReasoningForRelationships = parseReasoningForRelationships;
27
27
  exports.createEdgesFromReasoning = createEdgesFromReasoning;
28
- exports.getSupersededChainDepth = getSupersededChainDepth;
29
28
  exports.learnDecision = learnDecision;
30
29
  exports.updateConfidence = updateConfidence;
31
30
  const debug_logger_js_1 = require("./debug-logger.js");
@@ -305,55 +304,6 @@ async function createEdgesFromReasoning(fromId, reasoning) {
305
304
  }
306
305
  return { created, failed };
307
306
  }
308
- /**
309
- * Get supersedes chain depth for a topic
310
- *
311
- * Story 2.2: Calculate how many times a topic has been superseded
312
- *
313
- * @param topic - Decision topic
314
- * @returns Chain depth and decision IDs
315
- */
316
- async function getSupersededChainDepth(topic) {
317
- const adapter = (0, memory_store_js_1.getAdapter)();
318
- const chain = [];
319
- try {
320
- // Start from the latest decision (superseded_by IS NULL)
321
- let stmt = adapter.prepare(`
322
- SELECT id, supersedes FROM decisions
323
- WHERE topic = ? AND superseded_by IS NULL
324
- ORDER BY created_at DESC
325
- LIMIT 1
326
- `);
327
- let current = stmt.get(topic);
328
- if (!current) {
329
- return { depth: 0, chain: [] };
330
- }
331
- chain.push(current.id);
332
- // Walk back through supersedes chain with cycle detection
333
- const visited = new Set([current.id]);
334
- const MAX_CHAIN_DEPTH = 1000; // Safety limit
335
- while (current && current.supersedes && chain.length < MAX_CHAIN_DEPTH) {
336
- // Cycle detection: stop if we've seen this ID before
337
- if (visited.has(current.supersedes)) {
338
- break;
339
- }
340
- stmt = adapter.prepare('SELECT id, supersedes FROM decisions WHERE id = ?');
341
- current = stmt.get(current.supersedes);
342
- if (current) {
343
- visited.add(current.id);
344
- chain.push(current.id);
345
- }
346
- }
347
- return {
348
- depth: chain.length - 1, // depth = number of supersedes edges
349
- chain: chain.reverse(), // oldest to newest
350
- };
351
- }
352
- catch (error) {
353
- const message = error instanceof Error ? error.message : String(error);
354
- throw new Error(`Failed to get supersedes chain: ${message}`);
355
- }
356
- }
357
307
  // ════════════════════════════════════════════════════════════════════════════
358
308
  // NOTE: Auto-link functions REMOVED in v1.2.0
359
309
  //
@@ -1,8 +1,7 @@
1
1
  import type { DatabaseAdapter } from '../db-manager.js';
2
- import type { ListVisibleTwinEdgesOptions, TwinEdgeRecord, TwinRef, TwinScopeRef, TwinVisibility } from './types.js';
2
+ import type { ListVisibleTwinEdgesOptions, TwinEdgeRecord, TwinRef, TwinVisibility } from './types.js';
3
3
  type TwinRefVisibilityAdapter = Pick<DatabaseAdapter, 'prepare'>;
4
4
  export declare function assertTwinRefsVisible(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], visibility?: TwinVisibility): void;
5
- export declare function assertTwinRefsVisibleToScopes(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], scopes?: TwinScopeRef[]): void;
6
5
  export declare function listVisibleTwinEdgesForRefs(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], options?: ListVisibleTwinEdgesOptions): TwinEdgeRecord[];
7
6
  export {};
8
7
  //# sourceMappingURL=ref-validation.d.ts.map
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertTwinRefsVisible = assertTwinRefsVisible;
4
- exports.assertTwinRefsVisibleToScopes = assertTwinRefsVisibleToScopes;
5
4
  exports.listVisibleTwinEdgesForRefs = listVisibleTwinEdgesForRefs;
6
5
  const store_js_1 = require("./store.js");
6
+ const channel_grant_js_1 = require("../context-compile/channel-grant.js");
7
7
  const TABLE_COLUMN_PRAGMAS = {
8
8
  decisions: 'PRAGMA table_info(decisions)',
9
9
  case_truth: 'PRAGMA table_info(case_truth)',
@@ -21,9 +21,6 @@ function hasScopes(scopes) {
21
21
  function hasProjectRefs(projectRefs) {
22
22
  return Array.isArray(projectRefs) && projectRefs.length > 0;
23
23
  }
24
- function visibilityFromScopes(scopes) {
25
- return { scopes: scopes ? [...scopes] : undefined };
26
- }
27
24
  function asOfMs(visibility) {
28
25
  return typeof visibility.asOfMs === 'number' ? visibility.asOfMs : null;
29
26
  }
@@ -177,6 +174,30 @@ function isCaseVisible(adapter, id, visibility) {
177
174
  }
178
175
  return false;
179
176
  }
177
+ /**
178
+ * The time bound, shared by both branches so a grant cannot skip it.
179
+ *
180
+ * DELIBERATELY STRICTER THAN THE READER, and a review flagged the difference as a
181
+ * divergence between two delegates of one rule. It is not. A row with no usable timestamp
182
+ * is refused here even when no bound is set, while the reader - whose clause is on
183
+ * `COALESCE(event_datetime, source_timestamp_ms)` - leaves such a row alone when there is
184
+ * no bound to apply.
185
+ *
186
+ * The direction is what makes it correct: this gate guards refs reached INDIRECTLY, through
187
+ * a seed the caller named or an edge the graph walked. Refusing what cannot be shown to sit
188
+ * inside any window keeps the indirect path no wider than the direct one, which is the
189
+ * invariant the whole design rests on. Relaxing it to match the reader would have made
190
+ * citation reach further than reading for exactly the rows whose position in time is
191
+ * unknown. `fails closed for raw endpoints with blank timestamps` states the intent.
192
+ */
193
+ function isRawWithinTime(row, visibility) {
194
+ const rawTs = row.event_datetime ?? row.source_timestamp_ms;
195
+ if (rawTs === null || rawTs === undefined || (typeof rawTs === 'string' && rawTs.trim() === '')) {
196
+ return false;
197
+ }
198
+ const eventTsMs = parseTimestamp(rawTs);
199
+ return eventTsMs !== null && eventTsMs >= 0 && isWithinVisibilityTime(eventTsMs, visibility);
200
+ }
180
201
  function isRawVisible(adapter, id, visibility) {
181
202
  const row = adapter
182
203
  .prepare('SELECT * FROM connector_event_index WHERE event_index_id = ? LIMIT 1')
@@ -188,6 +209,13 @@ function isRawVisible(adapter, id, visibility) {
188
209
  !visibility.connectors.includes(String(row.source_connector))) {
189
210
  return false;
190
211
  }
212
+ // The grant decides, and it decides the same way here as in the reader - one rule, taken
213
+ // from one place. The scope/project/tenant clauses below are the pre-grant rule and are
214
+ // skipped when a grant is present, exactly as the reader skips them, because applying
215
+ // both would make a cited ref satisfy a stricter test than a read one.
216
+ if (visibility.channels) {
217
+ return ((0, channel_grant_js_1.isChannelGranted)(String(row.source_connector), typeof row.channel === 'string' ? row.channel : null, visibility.channels) && isRawWithinTime(row, visibility));
218
+ }
191
219
  if (hasProjectRefs(visibility.projectRefs) &&
192
220
  !visibility.projectRefs.some((project) => project.id === row.project_id)) {
193
221
  return false;
@@ -197,12 +225,7 @@ function isRawVisible(adapter, id, visibility) {
197
225
  row.tenant_id !== visibility.tenantId) {
198
226
  return false;
199
227
  }
200
- const rawTs = row.event_datetime ?? row.source_timestamp_ms;
201
- if (rawTs === null || rawTs === undefined || (typeof rawTs === 'string' && rawTs.trim() === '')) {
202
- return false;
203
- }
204
- const eventTsMs = parseTimestamp(rawTs);
205
- if (eventTsMs === null || eventTsMs < 0 || !isWithinVisibilityTime(eventTsMs, visibility)) {
228
+ if (!isRawWithinTime(row, visibility)) {
206
229
  return false;
207
230
  }
208
231
  if (!hasScopes(visibility.scopes)) {
@@ -269,9 +292,6 @@ function assertTwinRefsVisible(adapter, refs, visibility = {}) {
269
292
  }
270
293
  }
271
294
  }
272
- function assertTwinRefsVisibleToScopes(adapter, refs, scopes) {
273
- assertTwinRefsVisible(adapter, refs, visibilityFromScopes(scopes));
274
- }
275
295
  function listVisibleTwinEdgesForRefs(adapter, refs, options = {}) {
276
296
  const edgeCache = new Map();
277
297
  const edgeTypes = normalizeEdgeTypes(options.edgeTypes);
@@ -1,10 +1,8 @@
1
1
  import type { DatabaseAdapter } from '../db-manager.js';
2
- import { type InsertTwinEdgeInput, type TwinEdgeRecord, type TwinRef } from './types.js';
2
+ import { type TwinEdgeRecord, type TwinRef } from './types.js';
3
3
  type TwinEdgeReadAdapter = Pick<DatabaseAdapter, 'prepare'>;
4
- type TwinEdgeAdapter = Pick<DatabaseAdapter, 'prepare' | 'transaction'>;
5
4
  export declare function mapTwinEdgeRow(row: Record<string, unknown>): TwinEdgeRecord;
6
5
  export declare function getTwinEdge(adapter: TwinEdgeReadAdapter, edgeId: string): TwinEdgeRecord | null;
7
6
  export declare function listTwinEdgesForRefs(adapter: TwinEdgeReadAdapter, refs: readonly TwinRef[]): TwinEdgeRecord[];
8
- export declare function insertTwinEdge(adapter: TwinEdgeAdapter, input: InsertTwinEdgeInput): TwinEdgeRecord;
9
7
  export {};
10
8
  //# sourceMappingURL=store.d.ts.map
@@ -3,31 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mapTwinEdgeRow = mapTwinEdgeRow;
4
4
  exports.getTwinEdge = getTwinEdge;
5
5
  exports.listTwinEdgesForRefs = listTwinEdgesForRefs;
6
- exports.insertTwinEdge = insertTwinEdge;
7
- const node_crypto_1 = require("node:crypto");
8
- const canonicalize_js_1 = require("../canonicalize.js");
9
6
  const types_js_1 = require("./types.js");
10
7
  const EDGE_TYPE_SET = new Set(types_js_1.TWIN_EDGE_TYPES);
11
8
  const REF_KIND_SET = new Set(types_js_1.TWIN_REF_KINDS);
12
9
  const SOURCE_SET = new Set(types_js_1.TWIN_EDGE_SOURCES);
13
- const HUMAN_ACTOR_ROLES = new Set(['commander', 'configurator_elevated']);
14
- const HUMAN_REASON_CLASSIFICATIONS = new Set([
15
- 'factual_correction',
16
- 'agent_inference_wrong',
17
- 'privacy_redaction',
18
- 'duplicate_merge',
19
- 'state_override',
20
- 'other',
21
- ]);
22
- function sha256Hex(input) {
23
- return (0, node_crypto_1.createHash)('sha256').update(input, 'utf8').digest('hex');
24
- }
25
- function sha256Buffer(input) {
26
- return (0, node_crypto_1.createHash)('sha256').update(input, 'utf8').digest();
27
- }
28
- function generatedEdgeId() {
29
- return `edge_${(0, node_crypto_1.randomUUID)().replace(/-/g, '')}`;
30
- }
31
10
  function nullableString(value) {
32
11
  return typeof value === 'string' && value.length > 0 ? value : null;
33
12
  }
@@ -61,68 +40,6 @@ function normalizeRef(ref, field) {
61
40
  id: requireNonEmptyString(ref.id, `${field}.id`),
62
41
  };
63
42
  }
64
- function assertSubjectKindAllowed(ref) {
65
- if (ref.kind === 'raw') {
66
- throw new Error('twin_edges.subject_ref.kind cannot be raw');
67
- }
68
- }
69
- function normalizeConfidence(value) {
70
- if (value === undefined || value === null) {
71
- return 1;
72
- }
73
- if (typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1) {
74
- return value;
75
- }
76
- throw new Error(`twin_edges.confidence must be between 0 and 1: ${String(value)}`);
77
- }
78
- function hasDeterministicRule(value) {
79
- return (value !== null &&
80
- typeof value === 'object' &&
81
- !Array.isArray(value) &&
82
- typeof value.deterministic_rule === 'string' &&
83
- value.deterministic_rule.length > 0);
84
- }
85
- function validateSourceMetadata(input, source) {
86
- if (source === 'agent') {
87
- requireNonEmptyString(input.agent_id, 'agent_id');
88
- requireNonEmptyString(input.model_run_id, 'model_run_id');
89
- requireNonEmptyString(input.envelope_hash, 'envelope_hash');
90
- return;
91
- }
92
- if (source === 'human') {
93
- requireNonEmptyString(input.human_actor_id, 'human_actor_id');
94
- const role = requireNonEmptyString(input.human_actor_role, 'human_actor_role');
95
- if (!HUMAN_ACTOR_ROLES.has(role)) {
96
- throw new Error(`Unsupported twin_edges.human_actor_role: ${role}`);
97
- }
98
- if (input.authority_scope_json === undefined || input.authority_scope_json === null) {
99
- throw new Error('twin_edges.authority_scope_json is required for human edges');
100
- }
101
- const classification = requireNonEmptyString(input.reason_classification, 'reason_classification');
102
- if (!HUMAN_REASON_CLASSIFICATIONS.has(classification)) {
103
- throw new Error(`Unsupported twin_edges.reason_classification: ${classification}`);
104
- }
105
- return;
106
- }
107
- if (!nullableString(input.reason_text) && !hasDeterministicRule(input.relation_attrs)) {
108
- throw new Error('twin_edges.reason_text or relation_attrs.deterministic_rule is required for code edges');
109
- }
110
- }
111
- function jsonField(value, field) {
112
- if (value === undefined || value === null) {
113
- return null;
114
- }
115
- try {
116
- if (typeof value === 'string') {
117
- return (0, canonicalize_js_1.canonicalizeJSON)(JSON.parse(value));
118
- }
119
- return (0, canonicalize_js_1.canonicalizeJSON)(value);
120
- }
121
- catch (error) {
122
- const message = error instanceof Error ? error.message : String(error);
123
- throw new Error(`Invalid twin_edges.${field}: ${message}`);
124
- }
125
- }
126
43
  function parseJsonField(value, field, edgeId) {
127
44
  if (value === null || value === undefined) {
128
45
  return null;
@@ -148,62 +65,6 @@ function toBuffer(value) {
148
65
  }
149
66
  throw new Error('twin_edges.content_hash must be a 32-byte Buffer');
150
67
  }
151
- function exists(adapter, table, column, id) {
152
- const row = adapter
153
- .prepare(`SELECT 1 AS ok FROM ${table} WHERE ${column} = ? LIMIT 1`)
154
- .get(id);
155
- return Boolean(row?.ok);
156
- }
157
- function validateRefExists(adapter, ref, field) {
158
- if (ref.kind === 'report') {
159
- throw new Error(`${field} ${ref.kind}:${ref.id} is not supported by twin_edges yet`);
160
- }
161
- const found = (ref.kind === 'memory' && exists(adapter, 'decisions', 'id', ref.id)) ||
162
- (ref.kind === 'case' && exists(adapter, 'case_truth', 'case_id', ref.id)) ||
163
- (ref.kind === 'entity' && exists(adapter, 'entity_nodes', 'id', ref.id)) ||
164
- (ref.kind === 'edge' && exists(adapter, 'twin_edges', 'edge_id', ref.id)) ||
165
- (ref.kind === 'raw' && exists(adapter, 'connector_event_index', 'event_index_id', ref.id));
166
- if (!found) {
167
- throw new Error(`${field} not found: ${ref.kind}:${ref.id}`);
168
- }
169
- }
170
- function contentHashInput(input) {
171
- return (0, canonicalize_js_1.canonicalizeJSON)(input);
172
- }
173
- function deriveEdgeIdempotencyKey(requestIdempotencyKey, contentHash) {
174
- return `reqedge_${sha256Hex((0, canonicalize_js_1.canonicalizeJSON)({
175
- request_idempotency_key: requestIdempotencyKey,
176
- content_hash: contentHash.toString('hex'),
177
- })).slice(0, 40)}`;
178
- }
179
- function selectByIdempotency(adapter, modelRunId, edgeIdempotencyKey) {
180
- if (!edgeIdempotencyKey) {
181
- return null;
182
- }
183
- if (!modelRunId) {
184
- const row = adapter
185
- .prepare(`
186
- SELECT *
187
- FROM twin_edges
188
- WHERE model_run_id IS NULL
189
- AND edge_idempotency_key = ?
190
- ORDER BY created_at ASC, edge_id ASC
191
- LIMIT 1
192
- `)
193
- .get(edgeIdempotencyKey);
194
- return row ? mapTwinEdgeRow(row) : null;
195
- }
196
- const row = adapter
197
- .prepare(`
198
- SELECT *
199
- FROM twin_edges
200
- WHERE model_run_id = ?
201
- AND edge_idempotency_key = ?
202
- LIMIT 1
203
- `)
204
- .get(modelRunId, edgeIdempotencyKey);
205
- return row ? mapTwinEdgeRow(row) : null;
206
- }
207
68
  function mapTwinEdgeRow(row) {
208
69
  const edgeId = String(row.edge_id);
209
70
  return {
@@ -265,79 +126,4 @@ function listTwinEdgesForRefs(adapter, refs) {
265
126
  .all(...params);
266
127
  return rows.map(mapTwinEdgeRow);
267
128
  }
268
- function insertTwinEdge(adapter, input) {
269
- const edgeType = normalizeEdgeType(input.edge_type);
270
- const subjectRef = normalizeRef(input.subject_ref, 'subject_ref');
271
- const objectRef = normalizeRef(input.object_ref, 'object_ref');
272
- assertSubjectKindAllowed(subjectRef);
273
- const source = normalizeSource(input.source);
274
- const confidence = normalizeConfidence(input.confidence);
275
- validateSourceMetadata(input, source);
276
- validateRefExists(adapter, subjectRef, 'subject_ref');
277
- validateRefExists(adapter, objectRef, 'object_ref');
278
- const relationAttrsJson = jsonField(input.relation_attrs, 'relation_attrs_json');
279
- const evidenceRefsJson = jsonField(input.evidence_refs, 'evidence_refs_json');
280
- const authorityScopeJson = jsonField(input.authority_scope_json, 'authority_scope_json');
281
- const agentId = nullableString(input.agent_id);
282
- const reasonText = nullableString(input.reason_text);
283
- const envelopeHash = nullableString(input.envelope_hash);
284
- const humanActorId = nullableString(input.human_actor_id);
285
- const humanActorRole = nullableString(input.human_actor_role);
286
- const reasonClassification = nullableString(input.reason_classification);
287
- const requestIdempotencyKey = nullableString(input.request_idempotency_key);
288
- const modelRunId = nullableString(input.model_run_id);
289
- const contentHash = sha256Buffer(contentHashInput({
290
- edge_type: edgeType,
291
- subject_ref: subjectRef,
292
- object_ref: objectRef,
293
- relation_attrs_json: relationAttrsJson,
294
- confidence,
295
- source,
296
- agent_id: agentId,
297
- model_run_id: modelRunId,
298
- envelope_hash: envelopeHash,
299
- human_actor_id: humanActorId,
300
- human_actor_role: humanActorRole,
301
- authority_scope_json: authorityScopeJson,
302
- reason_classification: reasonClassification,
303
- reason_text: reasonText,
304
- evidence_refs_json: evidenceRefsJson,
305
- }));
306
- const edgeIdempotencyKey = nullableString(input.edge_idempotency_key) ??
307
- (requestIdempotencyKey ? deriveEdgeIdempotencyKey(requestIdempotencyKey, contentHash) : null);
308
- const existing = selectByIdempotency(adapter, modelRunId, edgeIdempotencyKey);
309
- if (existing) {
310
- return existing;
311
- }
312
- const edgeId = nullableString(input.edge_id) ?? generatedEdgeId();
313
- const createdAt = Date.now();
314
- try {
315
- return adapter.transaction(() => {
316
- adapter
317
- .prepare(`
318
- INSERT INTO twin_edges (
319
- edge_id, edge_type, subject_kind, subject_id, object_kind, object_id,
320
- relation_attrs_json, confidence, source, agent_id, model_run_id, envelope_hash,
321
- human_actor_id, human_actor_role, authority_scope_json, reason_classification,
322
- reason_text, evidence_refs_json, request_idempotency_key, edge_idempotency_key,
323
- content_hash, created_at
324
- )
325
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
326
- `)
327
- .run(edgeId, edgeType, subjectRef.kind, subjectRef.id, objectRef.kind, objectRef.id, relationAttrsJson, confidence, source, agentId, modelRunId, envelopeHash, humanActorId, humanActorRole, authorityScopeJson, reasonClassification, reasonText, evidenceRefsJson, requestIdempotencyKey, edgeIdempotencyKey, contentHash, createdAt);
328
- const inserted = getTwinEdge(adapter, edgeId);
329
- if (!inserted) {
330
- throw new Error(`Failed to load inserted twin edge: ${edgeId}`);
331
- }
332
- return inserted;
333
- });
334
- }
335
- catch (error) {
336
- const duplicate = selectByIdempotency(adapter, modelRunId, edgeIdempotencyKey);
337
- if (duplicate) {
338
- return duplicate;
339
- }
340
- throw error;
341
- }
342
- }
343
129
  //# sourceMappingURL=store.js.map
@@ -29,6 +29,13 @@ export interface TwinVisibility {
29
29
  tenantId?: string | null;
30
30
  startMs?: number | null;
31
31
  asOfMs?: number | null;
32
+ /**
33
+ * Which channels of each connector may be read. When present it DECIDES raw visibility
34
+ * here exactly as it does in the reader, so a ref reached through an edge or named as a
35
+ * seed satisfies the same rule as a row the reader would have returned. Without it a
36
+ * caller could reach past the read path by citing what it could not have read.
37
+ */
38
+ channels?: Record<string, readonly string[]>;
32
39
  }
33
40
  export interface InsertTwinEdgeInput {
34
41
  edge_id?: string;
@@ -84,5 +91,8 @@ export interface ListVisibleTwinEdgesOptions {
84
91
  startMs?: number | null;
85
92
  asOfMs?: number | null;
86
93
  limit?: number;
94
+ /** Forwarded to the raw visibility rule. Declared so an injected implementation
95
+ * cannot silently drop the grant - it crossed this seam as an undeclared property. */
96
+ channels?: Record<string, readonly string[]>;
87
97
  }
88
98
  //# sourceMappingURL=types.d.ts.map
@@ -11,7 +11,6 @@
11
11
  *
12
12
  * @module embedding-client
13
13
  */
14
- import type { EmbeddingRole } from './embeddings.js';
15
14
  export declare const DEFAULT_PORT: number;
16
15
  export declare const HOST = "127.0.0.1";
17
16
  export declare const TIMEOUT_MS = 500;
@@ -26,20 +25,4 @@ export interface ServerStatus {
26
25
  * Get server port from port file or default
27
26
  */
28
27
  export declare function getServerPort(): number;
29
- /**
30
- * Check if embedding server is running
31
- */
32
- export declare function isServerRunning(): Promise<boolean>;
33
- /**
34
- * Generate embedding via HTTP server
35
- *
36
- * @param text - Text to embed
37
- * @param role - e5 role: 'passage' (default, stored text) or 'query' (search)
38
- * @returns Embedding or null if failed
39
- */
40
- export declare function getEmbeddingFromServer(text: string, role?: EmbeddingRole): Promise<Float32Array | null>;
41
- /**
42
- * Get server status
43
- */
44
- export declare function getServerStatus(): Promise<ServerStatus | null>;
45
28
  //# sourceMappingURL=embedding-client.d.ts.map