hippo-memory 1.17.0 → 1.18.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/bin/hippo.js +2 -2
- package/dist/api.d.ts +28 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +31 -7
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +105 -11
- package/dist/cli.js.map +1 -1
- package/dist/connectors/github/backfill.js +4 -4
- package/dist/connectors/github/cli-impl.js +6 -6
- package/dist/connectors/github/dlq.js +14 -14
- package/dist/connectors/slack/backfill.js +1 -1
- package/dist/connectors/slack/dlq.js +10 -10
- package/dist/connectors/slack/workspaces.js +4 -4
- package/dist/dag.js +6 -6
- package/dist/dashboard.js +7 -7
- package/dist/goals.d.ts +11 -0
- package/dist/goals.d.ts.map +1 -1
- package/dist/goals.js +61 -49
- package/dist/goals.js.map +1 -1
- package/dist/hooks.js +24 -24
- package/dist/physics-state.js +27 -27
- package/dist/predictions.js +67 -67
- package/dist/refine-llm.js +13 -13
- package/dist/search.d.ts +33 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -0
- package/dist/server.js.map +1 -1
- package/dist/src/api.js +31 -7
- package/dist/src/api.js.map +1 -1
- package/dist/src/cli.js +105 -11
- package/dist/src/cli.js.map +1 -1
- package/dist/src/connectors/github/backfill.js +4 -4
- package/dist/src/connectors/github/cli-impl.js +6 -6
- package/dist/src/connectors/github/dlq.js +14 -14
- package/dist/src/connectors/slack/backfill.js +1 -1
- package/dist/src/connectors/slack/dlq.js +10 -10
- package/dist/src/connectors/slack/workspaces.js +4 -4
- package/dist/src/dag.js +6 -6
- package/dist/src/dashboard.js +7 -7
- package/dist/src/goals.js +61 -49
- package/dist/src/goals.js.map +1 -1
- package/dist/src/hooks.js +24 -24
- package/dist/src/physics-state.js +27 -27
- package/dist/src/predictions.js +67 -67
- package/dist/src/refine-llm.js +13 -13
- package/dist/src/search.js.map +1 -1
- package/dist/src/server.js +7 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/store.js +260 -260
- package/dist/src/version.js +1 -1
- package/dist/src/working-memory.js +19 -19
- package/dist/store.js +260 -260
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.js +19 -19
- package/dist-ui/index.html +12 -12
- package/extensions/openclaw-plugin/index.ts +650 -650
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/benchmarks/e1.3/scenarios.json +0 -2587
package/dist/store.js
CHANGED
|
@@ -535,13 +535,13 @@ function loadSearchRows(db, query, limit, tenantId, scopeFilter) {
|
|
|
535
535
|
// F1 (v1.7.0): MEMORY_SEARCH_COLUMNS adds bm25_score as the trailing
|
|
536
536
|
// result column. Every other column is m.<col> AS <col> so rowToEntry
|
|
537
537
|
// sees the same shape it always has.
|
|
538
|
-
const rows = db.prepare(`
|
|
539
|
-
SELECT ${MEMORY_SEARCH_COLUMNS}
|
|
540
|
-
FROM memories m
|
|
541
|
-
JOIN memories_fts f ON f.id = m.id
|
|
542
|
-
WHERE memories_fts MATCH ?${tenantPredicate}${archivedClauseAlias}${scopeClauseAlias}
|
|
543
|
-
ORDER BY bm25(memories_fts), m.updated_at DESC
|
|
544
|
-
LIMIT ?
|
|
538
|
+
const rows = db.prepare(`
|
|
539
|
+
SELECT ${MEMORY_SEARCH_COLUMNS}
|
|
540
|
+
FROM memories m
|
|
541
|
+
JOIN memories_fts f ON f.id = m.id
|
|
542
|
+
WHERE memories_fts MATCH ?${tenantPredicate}${archivedClauseAlias}${scopeClauseAlias}
|
|
543
|
+
ORDER BY bm25(memories_fts), m.updated_at DESC
|
|
544
|
+
LIMIT ?
|
|
545
545
|
`).all(ftsQuery, ...tenantParams, ...scopeParams, limit);
|
|
546
546
|
if (rows.length > 0)
|
|
547
547
|
return rows;
|
|
@@ -556,12 +556,12 @@ function loadSearchRows(db, query, limit, tenantId, scopeFilter) {
|
|
|
556
556
|
const like = `%${escapeLike(term)}%`;
|
|
557
557
|
return [like, like];
|
|
558
558
|
});
|
|
559
|
-
const rows = db.prepare(`
|
|
560
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
561
|
-
FROM memories
|
|
562
|
-
WHERE (${where})${tenantPredicateNoAlias}${archivedClauseNoAlias}${scopeClauseNoAlias}
|
|
563
|
-
ORDER BY updated_at DESC, created DESC
|
|
564
|
-
LIMIT ?
|
|
559
|
+
const rows = db.prepare(`
|
|
560
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
561
|
+
FROM memories
|
|
562
|
+
WHERE (${where})${tenantPredicateNoAlias}${archivedClauseNoAlias}${scopeClauseNoAlias}
|
|
563
|
+
ORDER BY updated_at DESC, created DESC
|
|
564
|
+
LIMIT ?
|
|
565
565
|
`).all(...params, ...tenantParams, ...scopeParams, limit);
|
|
566
566
|
if (rows.length > 0)
|
|
567
567
|
return rows;
|
|
@@ -674,60 +674,60 @@ function loadLegacyStatsFile(hippoRoot) {
|
|
|
674
674
|
}
|
|
675
675
|
}
|
|
676
676
|
function upsertEntryRow(db, entry) {
|
|
677
|
-
db.prepare(`
|
|
678
|
-
INSERT INTO memories(
|
|
679
|
-
id, created, last_retrieved, retrieval_count, strength, half_life_days, layer,
|
|
680
|
-
tags_json, emotional_valence, schema_fit, source, outcome_score,
|
|
681
|
-
outcome_positive, outcome_negative,
|
|
682
|
-
conflicts_with_json, pinned, confidence, content,
|
|
683
|
-
parents_json, starred,
|
|
684
|
-
trace_outcome, source_session_id,
|
|
685
|
-
valid_from, superseded_by,
|
|
686
|
-
extracted_from,
|
|
687
|
-
dag_level, dag_parent_id,
|
|
688
|
-
kind, scope, owner, artifact_ref,
|
|
689
|
-
tenant_id,
|
|
690
|
-
descendant_count, earliest_at, latest_at,
|
|
691
|
-
dag_level_3_built_at,
|
|
692
|
-
updated_at
|
|
693
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
694
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
695
|
-
created = excluded.created,
|
|
696
|
-
last_retrieved = excluded.last_retrieved,
|
|
697
|
-
retrieval_count = excluded.retrieval_count,
|
|
698
|
-
strength = excluded.strength,
|
|
699
|
-
half_life_days = excluded.half_life_days,
|
|
700
|
-
layer = excluded.layer,
|
|
701
|
-
tags_json = excluded.tags_json,
|
|
702
|
-
emotional_valence = excluded.emotional_valence,
|
|
703
|
-
schema_fit = excluded.schema_fit,
|
|
704
|
-
source = excluded.source,
|
|
705
|
-
outcome_score = excluded.outcome_score,
|
|
706
|
-
outcome_positive = excluded.outcome_positive,
|
|
707
|
-
outcome_negative = excluded.outcome_negative,
|
|
708
|
-
conflicts_with_json = excluded.conflicts_with_json,
|
|
709
|
-
pinned = excluded.pinned,
|
|
710
|
-
confidence = excluded.confidence,
|
|
711
|
-
content = excluded.content,
|
|
712
|
-
parents_json = excluded.parents_json,
|
|
713
|
-
starred = excluded.starred,
|
|
714
|
-
trace_outcome = excluded.trace_outcome,
|
|
715
|
-
source_session_id = excluded.source_session_id,
|
|
716
|
-
valid_from = excluded.valid_from,
|
|
717
|
-
superseded_by = excluded.superseded_by,
|
|
718
|
-
extracted_from = excluded.extracted_from,
|
|
719
|
-
dag_level = excluded.dag_level,
|
|
720
|
-
dag_parent_id = excluded.dag_parent_id,
|
|
721
|
-
kind = excluded.kind,
|
|
722
|
-
scope = excluded.scope,
|
|
723
|
-
owner = excluded.owner,
|
|
724
|
-
artifact_ref = excluded.artifact_ref,
|
|
725
|
-
tenant_id = excluded.tenant_id,
|
|
726
|
-
descendant_count = excluded.descendant_count,
|
|
727
|
-
earliest_at = excluded.earliest_at,
|
|
728
|
-
latest_at = excluded.latest_at,
|
|
729
|
-
dag_level_3_built_at = excluded.dag_level_3_built_at,
|
|
730
|
-
updated_at = datetime('now')
|
|
677
|
+
db.prepare(`
|
|
678
|
+
INSERT INTO memories(
|
|
679
|
+
id, created, last_retrieved, retrieval_count, strength, half_life_days, layer,
|
|
680
|
+
tags_json, emotional_valence, schema_fit, source, outcome_score,
|
|
681
|
+
outcome_positive, outcome_negative,
|
|
682
|
+
conflicts_with_json, pinned, confidence, content,
|
|
683
|
+
parents_json, starred,
|
|
684
|
+
trace_outcome, source_session_id,
|
|
685
|
+
valid_from, superseded_by,
|
|
686
|
+
extracted_from,
|
|
687
|
+
dag_level, dag_parent_id,
|
|
688
|
+
kind, scope, owner, artifact_ref,
|
|
689
|
+
tenant_id,
|
|
690
|
+
descendant_count, earliest_at, latest_at,
|
|
691
|
+
dag_level_3_built_at,
|
|
692
|
+
updated_at
|
|
693
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
694
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
695
|
+
created = excluded.created,
|
|
696
|
+
last_retrieved = excluded.last_retrieved,
|
|
697
|
+
retrieval_count = excluded.retrieval_count,
|
|
698
|
+
strength = excluded.strength,
|
|
699
|
+
half_life_days = excluded.half_life_days,
|
|
700
|
+
layer = excluded.layer,
|
|
701
|
+
tags_json = excluded.tags_json,
|
|
702
|
+
emotional_valence = excluded.emotional_valence,
|
|
703
|
+
schema_fit = excluded.schema_fit,
|
|
704
|
+
source = excluded.source,
|
|
705
|
+
outcome_score = excluded.outcome_score,
|
|
706
|
+
outcome_positive = excluded.outcome_positive,
|
|
707
|
+
outcome_negative = excluded.outcome_negative,
|
|
708
|
+
conflicts_with_json = excluded.conflicts_with_json,
|
|
709
|
+
pinned = excluded.pinned,
|
|
710
|
+
confidence = excluded.confidence,
|
|
711
|
+
content = excluded.content,
|
|
712
|
+
parents_json = excluded.parents_json,
|
|
713
|
+
starred = excluded.starred,
|
|
714
|
+
trace_outcome = excluded.trace_outcome,
|
|
715
|
+
source_session_id = excluded.source_session_id,
|
|
716
|
+
valid_from = excluded.valid_from,
|
|
717
|
+
superseded_by = excluded.superseded_by,
|
|
718
|
+
extracted_from = excluded.extracted_from,
|
|
719
|
+
dag_level = excluded.dag_level,
|
|
720
|
+
dag_parent_id = excluded.dag_parent_id,
|
|
721
|
+
kind = excluded.kind,
|
|
722
|
+
scope = excluded.scope,
|
|
723
|
+
owner = excluded.owner,
|
|
724
|
+
artifact_ref = excluded.artifact_ref,
|
|
725
|
+
tenant_id = excluded.tenant_id,
|
|
726
|
+
descendant_count = excluded.descendant_count,
|
|
727
|
+
earliest_at = excluded.earliest_at,
|
|
728
|
+
latest_at = excluded.latest_at,
|
|
729
|
+
dag_level_3_built_at = excluded.dag_level_3_built_at,
|
|
730
|
+
updated_at = datetime('now')
|
|
731
731
|
`).run(entry.id, entry.created, entry.last_retrieved, entry.retrieval_count, entry.strength, entry.half_life_days, entry.layer, JSON.stringify(entry.tags ?? []), entry.emotional_valence, entry.schema_fit, entry.source, entry.outcome_score, entry.outcome_positive ?? 0, entry.outcome_negative ?? 0, JSON.stringify(entry.conflicts_with ?? []), entry.pinned ? 1 : 0, entry.confidence, entry.content, JSON.stringify(entry.parents ?? []), entry.starred ? 1 : 0, entry.trace_outcome ?? null, entry.source_session_id ?? null, entry.valid_from ?? entry.created, entry.superseded_by ?? null, entry.extracted_from ?? null, entry.dag_level ?? 0, entry.dag_parent_id ?? null, entry.kind ?? 'distilled', entry.scope ?? null, entry.owner ?? null, entry.artifact_ref ?? null, entry.tenantId ?? 'default', entry.descendant_count ?? 0, entry.earliest_at ?? null, entry.latest_at ?? null, entry.dag_level_3_built_at ?? null);
|
|
732
732
|
syncFtsRow(db, entry);
|
|
733
733
|
}
|
|
@@ -794,11 +794,11 @@ function syncMirrorFiles(hippoRoot, db) {
|
|
|
794
794
|
for (const entry of entries.map(rowToEntry)) {
|
|
795
795
|
writeMarkdownMirror(hippoRoot, entry);
|
|
796
796
|
}
|
|
797
|
-
const conflicts = db.prepare(`
|
|
798
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
799
|
-
FROM memory_conflicts
|
|
800
|
-
WHERE status = 'open'
|
|
801
|
-
ORDER BY updated_at DESC, id DESC
|
|
797
|
+
const conflicts = db.prepare(`
|
|
798
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
799
|
+
FROM memory_conflicts
|
|
800
|
+
WHERE status = 'open'
|
|
801
|
+
ORDER BY updated_at DESC, id DESC
|
|
802
802
|
`).all();
|
|
803
803
|
writeConflictMirrors(hippoRoot, conflicts.map(rowToMemoryConflict));
|
|
804
804
|
writeIndexMirror(hippoRoot, buildIndexFromDb(db));
|
|
@@ -1427,16 +1427,16 @@ export function saveActiveTaskSnapshot(hippoRoot, tenantId, snapshot) {
|
|
|
1427
1427
|
try {
|
|
1428
1428
|
db.exec('BEGIN');
|
|
1429
1429
|
db.prepare(`UPDATE task_snapshots SET status = 'superseded', updated_at = ? WHERE status = 'active' AND tenant_id = ?`).run(now, tenantId);
|
|
1430
|
-
const result = db.prepare(`
|
|
1431
|
-
INSERT INTO task_snapshots(task, summary, next_step, status, source, session_id, scope, tenant_id, created_at, updated_at)
|
|
1432
|
-
VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
|
|
1430
|
+
const result = db.prepare(`
|
|
1431
|
+
INSERT INTO task_snapshots(task, summary, next_step, status, source, session_id, scope, tenant_id, created_at, updated_at)
|
|
1432
|
+
VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
|
|
1433
1433
|
`).run(snapshot.task, snapshot.summary, snapshot.next_step, snapshot.source ?? 'cli', snapshot.session_id ?? null, snapshot.scope ?? null, tenantId, now, now);
|
|
1434
1434
|
db.exec('COMMIT');
|
|
1435
1435
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1436
|
-
const row = db.prepare(`
|
|
1437
|
-
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1438
|
-
FROM task_snapshots
|
|
1439
|
-
WHERE id = ?
|
|
1436
|
+
const row = db.prepare(`
|
|
1437
|
+
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1438
|
+
FROM task_snapshots
|
|
1439
|
+
WHERE id = ?
|
|
1440
1440
|
`).get(id);
|
|
1441
1441
|
if (!row) {
|
|
1442
1442
|
throw new Error('Failed to reload saved active task snapshot');
|
|
@@ -1463,12 +1463,12 @@ export function loadActiveTaskSnapshot(hippoRoot, tenantId) {
|
|
|
1463
1463
|
initStore(hippoRoot);
|
|
1464
1464
|
const db = openHippoDb(hippoRoot);
|
|
1465
1465
|
try {
|
|
1466
|
-
const row = db.prepare(`
|
|
1467
|
-
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1468
|
-
FROM task_snapshots
|
|
1469
|
-
WHERE status = 'active' AND tenant_id = ?
|
|
1470
|
-
ORDER BY updated_at DESC, id DESC
|
|
1471
|
-
LIMIT 1
|
|
1466
|
+
const row = db.prepare(`
|
|
1467
|
+
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1468
|
+
FROM task_snapshots
|
|
1469
|
+
WHERE status = 'active' AND tenant_id = ?
|
|
1470
|
+
ORDER BY updated_at DESC, id DESC
|
|
1471
|
+
LIMIT 1
|
|
1472
1472
|
`).get(tenantId);
|
|
1473
1473
|
if (!row) {
|
|
1474
1474
|
removeActiveTaskMirror(hippoRoot, tenantId);
|
|
@@ -1509,26 +1509,26 @@ export function appendSessionEvent(hippoRoot, tenantId, event) {
|
|
|
1509
1509
|
// v1.2: scope is wired through. Default-deny in api.recall + cmdRecall
|
|
1510
1510
|
// continuity reads applies to slack:private:* and 'unknown:legacy' rows.
|
|
1511
1511
|
try {
|
|
1512
|
-
const result = db.prepare(`
|
|
1513
|
-
INSERT INTO session_events(session_id, task, event_type, content, source, scope, metadata_json, tenant_id, created_at)
|
|
1514
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1512
|
+
const result = db.prepare(`
|
|
1513
|
+
INSERT INTO session_events(session_id, task, event_type, content, source, scope, metadata_json, tenant_id, created_at)
|
|
1514
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1515
1515
|
`).run(event.session_id, event.task ?? null, event.event_type, event.content, event.source ?? 'cli', event.scope ?? null, JSON.stringify(event.metadata ?? {}), tenantId, now);
|
|
1516
1516
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1517
|
-
const row = db.prepare(`
|
|
1518
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1519
|
-
FROM session_events
|
|
1520
|
-
WHERE id = ?
|
|
1517
|
+
const row = db.prepare(`
|
|
1518
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1519
|
+
FROM session_events
|
|
1520
|
+
WHERE id = ?
|
|
1521
1521
|
`).get(id);
|
|
1522
1522
|
if (!row) {
|
|
1523
1523
|
throw new Error('Failed to reload saved session event');
|
|
1524
1524
|
}
|
|
1525
1525
|
const loaded = rowToSessionEvent(row);
|
|
1526
|
-
const recentRows = db.prepare(`
|
|
1527
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1528
|
-
FROM session_events
|
|
1529
|
-
WHERE session_id = ? AND tenant_id = ?
|
|
1530
|
-
ORDER BY created_at DESC, id DESC
|
|
1531
|
-
LIMIT ?
|
|
1526
|
+
const recentRows = db.prepare(`
|
|
1527
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1528
|
+
FROM session_events
|
|
1529
|
+
WHERE session_id = ? AND tenant_id = ?
|
|
1530
|
+
ORDER BY created_at DESC, id DESC
|
|
1531
|
+
LIMIT ?
|
|
1532
1532
|
`).all(loaded.session_id, tenantId, 20);
|
|
1533
1533
|
const recent = recentRows.map(rowToSessionEvent).reverse();
|
|
1534
1534
|
writeRecentSessionMirror(hippoRoot, tenantId, recent);
|
|
@@ -1556,12 +1556,12 @@ export function listSessionEvents(hippoRoot, tenantId, options = {}) {
|
|
|
1556
1556
|
const limit = Math.max(1, Math.trunc(options.limit ?? 8));
|
|
1557
1557
|
params.push(limit);
|
|
1558
1558
|
const where = `WHERE ${clauses.join(' AND ')}`;
|
|
1559
|
-
const rows = db.prepare(`
|
|
1560
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1561
|
-
FROM session_events
|
|
1562
|
-
${where}
|
|
1563
|
-
ORDER BY created_at DESC, id DESC
|
|
1564
|
-
LIMIT ?
|
|
1559
|
+
const rows = db.prepare(`
|
|
1560
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1561
|
+
FROM session_events
|
|
1562
|
+
${where}
|
|
1563
|
+
ORDER BY created_at DESC, id DESC
|
|
1564
|
+
LIMIT ?
|
|
1565
1565
|
`).all(...params);
|
|
1566
1566
|
return rows.map(rowToSessionEvent).reverse();
|
|
1567
1567
|
}
|
|
@@ -1578,9 +1578,9 @@ export function findPromotableSessions(hippoRoot, tenantId, sinceMs) {
|
|
|
1578
1578
|
initStore(hippoRoot);
|
|
1579
1579
|
const db = openHippoDb(hippoRoot);
|
|
1580
1580
|
try {
|
|
1581
|
-
const rows = db.prepare(`
|
|
1582
|
-
SELECT DISTINCT session_id FROM session_events
|
|
1583
|
-
WHERE event_type = 'session_complete' AND created_at >= ? AND tenant_id = ?
|
|
1581
|
+
const rows = db.prepare(`
|
|
1582
|
+
SELECT DISTINCT session_id FROM session_events
|
|
1583
|
+
WHERE event_type = 'session_complete' AND created_at >= ? AND tenant_id = ?
|
|
1584
1584
|
`).all(new Date(sinceMs).toISOString(), tenantId);
|
|
1585
1585
|
return rows;
|
|
1586
1586
|
}
|
|
@@ -1597,10 +1597,10 @@ export function traceExistsForSession(hippoRoot, tenantId, session_id) {
|
|
|
1597
1597
|
initStore(hippoRoot);
|
|
1598
1598
|
const db = openHippoDb(hippoRoot);
|
|
1599
1599
|
try {
|
|
1600
|
-
const row = db.prepare(`
|
|
1601
|
-
SELECT 1 FROM memories
|
|
1602
|
-
WHERE source_session_id = ? AND layer = 'trace' AND tenant_id = ?
|
|
1603
|
-
LIMIT 1
|
|
1600
|
+
const row = db.prepare(`
|
|
1601
|
+
SELECT 1 FROM memories
|
|
1602
|
+
WHERE source_session_id = ? AND layer = 'trace' AND tenant_id = ?
|
|
1603
|
+
LIMIT 1
|
|
1604
1604
|
`).get(session_id, tenantId);
|
|
1605
1605
|
return !!row;
|
|
1606
1606
|
}
|
|
@@ -1623,38 +1623,38 @@ export function listMemoryConflicts(hippoRoot, status = 'open', tenantId) {
|
|
|
1623
1623
|
// each in-tenant, so neither a normal cross-tenant pair nor a stale
|
|
1624
1624
|
// pre-fix row surfaces (consistent with resolveConflict).
|
|
1625
1625
|
rows = allStatuses
|
|
1626
|
-
? db.prepare(`
|
|
1627
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1628
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1629
|
-
FROM memory_conflicts mc
|
|
1630
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1631
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1632
|
-
WHERE ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1633
|
-
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1626
|
+
? db.prepare(`
|
|
1627
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1628
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1629
|
+
FROM memory_conflicts mc
|
|
1630
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1631
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1632
|
+
WHERE ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1633
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1634
1634
|
`).all(tenantId, tenantId)
|
|
1635
|
-
: db.prepare(`
|
|
1636
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1637
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1638
|
-
FROM memory_conflicts mc
|
|
1639
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1640
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1641
|
-
WHERE mc.status = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1642
|
-
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1635
|
+
: db.prepare(`
|
|
1636
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1637
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1638
|
+
FROM memory_conflicts mc
|
|
1639
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1640
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1641
|
+
WHERE mc.status = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1642
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1643
1643
|
`).all(status, tenantId, tenantId);
|
|
1644
1644
|
}
|
|
1645
1645
|
else {
|
|
1646
1646
|
// Unscoped query — legacy direct-mode (CLI, tests, consolidate).
|
|
1647
1647
|
rows = allStatuses
|
|
1648
|
-
? db.prepare(`
|
|
1649
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1650
|
-
FROM memory_conflicts
|
|
1651
|
-
ORDER BY updated_at DESC, id DESC
|
|
1648
|
+
? db.prepare(`
|
|
1649
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1650
|
+
FROM memory_conflicts
|
|
1651
|
+
ORDER BY updated_at DESC, id DESC
|
|
1652
1652
|
`).all()
|
|
1653
|
-
: db.prepare(`
|
|
1654
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1655
|
-
FROM memory_conflicts
|
|
1656
|
-
WHERE status = ?
|
|
1657
|
-
ORDER BY updated_at DESC, id DESC
|
|
1653
|
+
: db.prepare(`
|
|
1654
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1655
|
+
FROM memory_conflicts
|
|
1656
|
+
WHERE status = ?
|
|
1657
|
+
ORDER BY updated_at DESC, id DESC
|
|
1658
1658
|
`).all(status);
|
|
1659
1659
|
}
|
|
1660
1660
|
return rows.map(rowToMemoryConflict);
|
|
@@ -1687,10 +1687,10 @@ export function replaceDetectedConflicts(hippoRoot, detected, detectedAt = new D
|
|
|
1687
1687
|
score: conflict.score,
|
|
1688
1688
|
}));
|
|
1689
1689
|
const detectedKeys = new Set(canonicalDetected.map((conflict) => `${conflict.memory_a_id}::${conflict.memory_b_id}`));
|
|
1690
|
-
const openRows = db.prepare(`
|
|
1691
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1692
|
-
FROM memory_conflicts
|
|
1693
|
-
WHERE status = 'open'
|
|
1690
|
+
const openRows = db.prepare(`
|
|
1691
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1692
|
+
FROM memory_conflicts
|
|
1693
|
+
WHERE status = 'open'
|
|
1694
1694
|
`).all();
|
|
1695
1695
|
for (const row of openRows) {
|
|
1696
1696
|
const key = `${row.memory_a_id}::${row.memory_b_id}`;
|
|
@@ -1709,20 +1709,20 @@ export function replaceDetectedConflicts(hippoRoot, detected, detectedAt = new D
|
|
|
1709
1709
|
// Skip cross-tenant pairs — never persist a conflict spanning tenants.
|
|
1710
1710
|
if (!sameTenant(conflict.memory_a_id, conflict.memory_b_id))
|
|
1711
1711
|
continue;
|
|
1712
|
-
db.prepare(`
|
|
1713
|
-
INSERT INTO memory_conflicts(memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at)
|
|
1714
|
-
VALUES (?, ?, ?, ?, 'open', ?, ?)
|
|
1715
|
-
ON CONFLICT(memory_a_id, memory_b_id) DO UPDATE SET
|
|
1716
|
-
reason = excluded.reason,
|
|
1717
|
-
score = excluded.score,
|
|
1718
|
-
status = 'open',
|
|
1719
|
-
updated_at = excluded.updated_at
|
|
1712
|
+
db.prepare(`
|
|
1713
|
+
INSERT INTO memory_conflicts(memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at)
|
|
1714
|
+
VALUES (?, ?, ?, ?, 'open', ?, ?)
|
|
1715
|
+
ON CONFLICT(memory_a_id, memory_b_id) DO UPDATE SET
|
|
1716
|
+
reason = excluded.reason,
|
|
1717
|
+
score = excluded.score,
|
|
1718
|
+
status = 'open',
|
|
1719
|
+
updated_at = excluded.updated_at
|
|
1720
1720
|
`).run(conflict.memory_a_id, conflict.memory_b_id, conflict.reason, conflict.score, detectedAt, detectedAt);
|
|
1721
1721
|
}
|
|
1722
|
-
const openConflicts = db.prepare(`
|
|
1723
|
-
SELECT memory_a_id, memory_b_id
|
|
1724
|
-
FROM memory_conflicts
|
|
1725
|
-
WHERE status = 'open'
|
|
1722
|
+
const openConflicts = db.prepare(`
|
|
1723
|
+
SELECT memory_a_id, memory_b_id
|
|
1724
|
+
FROM memory_conflicts
|
|
1725
|
+
WHERE status = 'open'
|
|
1726
1726
|
`).all();
|
|
1727
1727
|
const refMap = new Map();
|
|
1728
1728
|
for (const row of openConflicts) {
|
|
@@ -1776,17 +1776,17 @@ export function resolveConflict(hippoRoot, conflictId, keepId, forgetLoser = fal
|
|
|
1776
1776
|
const memArgs = tenantId !== undefined ? [tenantId] : [];
|
|
1777
1777
|
try {
|
|
1778
1778
|
const row = (tenantId !== undefined
|
|
1779
|
-
? db.prepare(`
|
|
1780
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1781
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1782
|
-
FROM memory_conflicts mc
|
|
1783
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1784
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1785
|
-
WHERE mc.id = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1779
|
+
? db.prepare(`
|
|
1780
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1781
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1782
|
+
FROM memory_conflicts mc
|
|
1783
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1784
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1785
|
+
WHERE mc.id = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1786
1786
|
`).get(conflictId, tenantId, tenantId)
|
|
1787
|
-
: db.prepare(`
|
|
1788
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1789
|
-
FROM memory_conflicts WHERE id = ?
|
|
1787
|
+
: db.prepare(`
|
|
1788
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1789
|
+
FROM memory_conflicts WHERE id = ?
|
|
1790
1790
|
`).get(conflictId));
|
|
1791
1791
|
if (!row)
|
|
1792
1792
|
return null;
|
|
@@ -1856,15 +1856,15 @@ export function saveSessionHandoff(hippoRoot, tenantId, handoff) {
|
|
|
1856
1856
|
// v1.2: scope is wired through. Read-side default-deny in api.recall +
|
|
1857
1857
|
// cmdRecall continuity excludes slack:private:* and 'unknown:legacy'.
|
|
1858
1858
|
try {
|
|
1859
|
-
const result = db.prepare(`
|
|
1860
|
-
INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at)
|
|
1861
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1859
|
+
const result = db.prepare(`
|
|
1860
|
+
INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at)
|
|
1861
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1862
1862
|
`).run(handoff.sessionId, handoff.repoRoot ?? null, handoff.taskId ?? null, handoff.summary, handoff.nextAction ?? null, JSON.stringify(handoff.artifacts ?? []), handoff.scope ?? null, tenantId, now);
|
|
1863
1863
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1864
|
-
const row = db.prepare(`
|
|
1865
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1866
|
-
FROM session_handoffs
|
|
1867
|
-
WHERE id = ?
|
|
1864
|
+
const row = db.prepare(`
|
|
1865
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1866
|
+
FROM session_handoffs
|
|
1867
|
+
WHERE id = ?
|
|
1868
1868
|
`).get(id);
|
|
1869
1869
|
if (!row) {
|
|
1870
1870
|
throw new Error('Failed to reload saved session handoff');
|
|
@@ -1885,21 +1885,21 @@ export function loadLatestHandoff(hippoRoot, tenantId, sessionId) {
|
|
|
1885
1885
|
try {
|
|
1886
1886
|
let row;
|
|
1887
1887
|
if (sessionId) {
|
|
1888
|
-
row = db.prepare(`
|
|
1889
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1890
|
-
FROM session_handoffs
|
|
1891
|
-
WHERE session_id = ? AND tenant_id = ?
|
|
1892
|
-
ORDER BY created_at DESC, id DESC
|
|
1893
|
-
LIMIT 1
|
|
1888
|
+
row = db.prepare(`
|
|
1889
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1890
|
+
FROM session_handoffs
|
|
1891
|
+
WHERE session_id = ? AND tenant_id = ?
|
|
1892
|
+
ORDER BY created_at DESC, id DESC
|
|
1893
|
+
LIMIT 1
|
|
1894
1894
|
`).get(sessionId, tenantId);
|
|
1895
1895
|
}
|
|
1896
1896
|
else {
|
|
1897
|
-
row = db.prepare(`
|
|
1898
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1899
|
-
FROM session_handoffs
|
|
1900
|
-
WHERE tenant_id = ?
|
|
1901
|
-
ORDER BY created_at DESC, id DESC
|
|
1902
|
-
LIMIT 1
|
|
1897
|
+
row = db.prepare(`
|
|
1898
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1899
|
+
FROM session_handoffs
|
|
1900
|
+
WHERE tenant_id = ?
|
|
1901
|
+
ORDER BY created_at DESC, id DESC
|
|
1902
|
+
LIMIT 1
|
|
1903
1903
|
`).get(tenantId);
|
|
1904
1904
|
}
|
|
1905
1905
|
return row ? rowToSessionHandoff(row) : null;
|
|
@@ -1916,10 +1916,10 @@ export function loadHandoffById(hippoRoot, tenantId, id) {
|
|
|
1916
1916
|
initStore(hippoRoot);
|
|
1917
1917
|
const db = openHippoDb(hippoRoot);
|
|
1918
1918
|
try {
|
|
1919
|
-
const row = db.prepare(`
|
|
1920
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1921
|
-
FROM session_handoffs
|
|
1922
|
-
WHERE id = ? AND tenant_id = ?
|
|
1919
|
+
const row = db.prepare(`
|
|
1920
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1921
|
+
FROM session_handoffs
|
|
1922
|
+
WHERE id = ? AND tenant_id = ?
|
|
1923
1923
|
`).get(id, tenantId);
|
|
1924
1924
|
return row ? rowToSessionHandoff(row) : null;
|
|
1925
1925
|
}
|
|
@@ -1949,13 +1949,13 @@ export function loadDirtySummaries(hippoRoot, tenantId) {
|
|
|
1949
1949
|
initStore(hippoRoot);
|
|
1950
1950
|
const db = openHippoDb(hippoRoot);
|
|
1951
1951
|
try {
|
|
1952
|
-
const rows = db.prepare(`
|
|
1953
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
1954
|
-
FROM memories
|
|
1955
|
-
WHERE summary_dirty = 1
|
|
1956
|
-
AND tenant_id = ?
|
|
1957
|
-
AND kind != 'archived'
|
|
1958
|
-
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
1952
|
+
const rows = db.prepare(`
|
|
1953
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
1954
|
+
FROM memories
|
|
1955
|
+
WHERE summary_dirty = 1
|
|
1956
|
+
AND tenant_id = ?
|
|
1957
|
+
AND kind != 'archived'
|
|
1958
|
+
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
1959
1959
|
`).all(tenantId);
|
|
1960
1960
|
return rows.map(rowToEntry);
|
|
1961
1961
|
}
|
|
@@ -1983,15 +1983,15 @@ export function markSummaryDirtyInTx(db, summaryId, tenantId, actor) {
|
|
|
1983
1983
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
1984
1984
|
// actual level in same round trip so audit metadata stays accurate without
|
|
1985
1985
|
// a SELECT-before-UPDATE extra DB op on this hot path (5 caller sites).
|
|
1986
|
-
const result = db.prepare(`
|
|
1987
|
-
UPDATE memories
|
|
1988
|
-
SET summary_dirty = 1
|
|
1989
|
-
WHERE id = ?
|
|
1990
|
-
AND tenant_id = ?
|
|
1991
|
-
AND dag_level IN (2, 3)
|
|
1992
|
-
AND summary_dirty = 0
|
|
1993
|
-
AND kind != 'archived'
|
|
1994
|
-
RETURNING dag_level
|
|
1986
|
+
const result = db.prepare(`
|
|
1987
|
+
UPDATE memories
|
|
1988
|
+
SET summary_dirty = 1
|
|
1989
|
+
WHERE id = ?
|
|
1990
|
+
AND tenant_id = ?
|
|
1991
|
+
AND dag_level IN (2, 3)
|
|
1992
|
+
AND summary_dirty = 0
|
|
1993
|
+
AND kind != 'archived'
|
|
1994
|
+
RETURNING dag_level
|
|
1995
1995
|
`).get(summaryId, tenantId);
|
|
1996
1996
|
if (result) {
|
|
1997
1997
|
audit(db, 'summary_marked_dirty', summaryId, { dag_level: result.dag_level, source: 'E2' }, actor, tenantId);
|
|
@@ -2017,15 +2017,15 @@ export function markSummaryDirty(hippoRoot, summaryId, tenantId, actor = 'cli')
|
|
|
2017
2017
|
try {
|
|
2018
2018
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
2019
2019
|
// actual level in same round trip.
|
|
2020
|
-
const result = db.prepare(`
|
|
2021
|
-
UPDATE memories
|
|
2022
|
-
SET summary_dirty = 1
|
|
2023
|
-
WHERE id = ?
|
|
2024
|
-
AND tenant_id = ?
|
|
2025
|
-
AND dag_level IN (2, 3)
|
|
2026
|
-
AND summary_dirty = 0
|
|
2027
|
-
AND kind != 'archived'
|
|
2028
|
-
RETURNING dag_level
|
|
2020
|
+
const result = db.prepare(`
|
|
2021
|
+
UPDATE memories
|
|
2022
|
+
SET summary_dirty = 1
|
|
2023
|
+
WHERE id = ?
|
|
2024
|
+
AND tenant_id = ?
|
|
2025
|
+
AND dag_level IN (2, 3)
|
|
2026
|
+
AND summary_dirty = 0
|
|
2027
|
+
AND kind != 'archived'
|
|
2028
|
+
RETURNING dag_level
|
|
2029
2029
|
`).get(summaryId, tenantId);
|
|
2030
2030
|
if (result) {
|
|
2031
2031
|
// audit() wraps appendAuditEvent in try/catch (v27 heal scenario).
|
|
@@ -2061,13 +2061,13 @@ export function loadAllL2Summaries(hippoRoot) {
|
|
|
2061
2061
|
initStore(hippoRoot);
|
|
2062
2062
|
const db = openHippoDb(hippoRoot);
|
|
2063
2063
|
try {
|
|
2064
|
-
const rows = db.prepare(`
|
|
2065
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2066
|
-
FROM memories
|
|
2067
|
-
WHERE dag_level = 2
|
|
2068
|
-
AND dag_parent_id IS NULL
|
|
2069
|
-
AND kind != 'archived'
|
|
2070
|
-
ORDER BY created ASC, id ASC
|
|
2064
|
+
const rows = db.prepare(`
|
|
2065
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2066
|
+
FROM memories
|
|
2067
|
+
WHERE dag_level = 2
|
|
2068
|
+
AND dag_parent_id IS NULL
|
|
2069
|
+
AND kind != 'archived'
|
|
2070
|
+
ORDER BY created ASC, id ASC
|
|
2071
2071
|
`).all();
|
|
2072
2072
|
return rows.map(rowToEntry);
|
|
2073
2073
|
}
|
|
@@ -2088,12 +2088,12 @@ export function loadAllDirtySummaries(hippoRoot) {
|
|
|
2088
2088
|
initStore(hippoRoot);
|
|
2089
2089
|
const db = openHippoDb(hippoRoot);
|
|
2090
2090
|
try {
|
|
2091
|
-
const rows = db.prepare(`
|
|
2092
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2093
|
-
FROM memories
|
|
2094
|
-
WHERE summary_dirty = 1
|
|
2095
|
-
AND kind != 'archived'
|
|
2096
|
-
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
2091
|
+
const rows = db.prepare(`
|
|
2092
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2093
|
+
FROM memories
|
|
2094
|
+
WHERE summary_dirty = 1
|
|
2095
|
+
AND kind != 'archived'
|
|
2096
|
+
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
2097
2097
|
`).all();
|
|
2098
2098
|
return rows.map(rowToEntry);
|
|
2099
2099
|
}
|
|
@@ -2113,13 +2113,13 @@ export function loadChildrenOfSummary(hippoRoot, summaryId, tenantId) {
|
|
|
2113
2113
|
initStore(hippoRoot);
|
|
2114
2114
|
const db = openHippoDb(hippoRoot);
|
|
2115
2115
|
try {
|
|
2116
|
-
const rows = db.prepare(`
|
|
2117
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2118
|
-
FROM memories
|
|
2119
|
-
WHERE dag_parent_id = ?
|
|
2120
|
-
AND tenant_id = ?
|
|
2121
|
-
AND kind != 'archived'
|
|
2122
|
-
ORDER BY created ASC
|
|
2116
|
+
const rows = db.prepare(`
|
|
2117
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2118
|
+
FROM memories
|
|
2119
|
+
WHERE dag_parent_id = ?
|
|
2120
|
+
AND tenant_id = ?
|
|
2121
|
+
AND kind != 'archived'
|
|
2122
|
+
ORDER BY created ASC
|
|
2123
2123
|
`).all(summaryId, tenantId);
|
|
2124
2124
|
return rows.map(rowToEntry);
|
|
2125
2125
|
}
|
|
@@ -2147,28 +2147,28 @@ export function applyRebuildResult(hippoRoot, summary, patch) {
|
|
|
2147
2147
|
// ONE prepared UPDATE per branch. Test #8 inspects the SQL string.
|
|
2148
2148
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3) on both branches.
|
|
2149
2149
|
const sql = patch.bumpRebuildCount
|
|
2150
|
-
? `UPDATE memories
|
|
2151
|
-
SET content = ?,
|
|
2152
|
-
descendant_count = ?,
|
|
2153
|
-
earliest_at = ?,
|
|
2154
|
-
latest_at = ?,
|
|
2155
|
-
last_rebuilt_at = ?,
|
|
2156
|
-
rebuild_count = COALESCE(rebuild_count, 0) + 1,
|
|
2157
|
-
summary_dirty = 0
|
|
2158
|
-
WHERE id = ?
|
|
2159
|
-
AND tenant_id = ?
|
|
2160
|
-
AND dag_level IN (2, 3)
|
|
2161
|
-
AND summary_dirty = 1
|
|
2150
|
+
? `UPDATE memories
|
|
2151
|
+
SET content = ?,
|
|
2152
|
+
descendant_count = ?,
|
|
2153
|
+
earliest_at = ?,
|
|
2154
|
+
latest_at = ?,
|
|
2155
|
+
last_rebuilt_at = ?,
|
|
2156
|
+
rebuild_count = COALESCE(rebuild_count, 0) + 1,
|
|
2157
|
+
summary_dirty = 0
|
|
2158
|
+
WHERE id = ?
|
|
2159
|
+
AND tenant_id = ?
|
|
2160
|
+
AND dag_level IN (2, 3)
|
|
2161
|
+
AND summary_dirty = 1
|
|
2162
2162
|
AND kind != 'archived'`
|
|
2163
|
-
: `UPDATE memories
|
|
2164
|
-
SET descendant_count = ?,
|
|
2165
|
-
earliest_at = ?,
|
|
2166
|
-
latest_at = ?,
|
|
2167
|
-
summary_dirty = 0
|
|
2168
|
-
WHERE id = ?
|
|
2169
|
-
AND tenant_id = ?
|
|
2170
|
-
AND dag_level IN (2, 3)
|
|
2171
|
-
AND summary_dirty = 1
|
|
2163
|
+
: `UPDATE memories
|
|
2164
|
+
SET descendant_count = ?,
|
|
2165
|
+
earliest_at = ?,
|
|
2166
|
+
latest_at = ?,
|
|
2167
|
+
summary_dirty = 0
|
|
2168
|
+
WHERE id = ?
|
|
2169
|
+
AND tenant_id = ?
|
|
2170
|
+
AND dag_level IN (2, 3)
|
|
2171
|
+
AND summary_dirty = 1
|
|
2172
2172
|
AND kind != 'archived'`;
|
|
2173
2173
|
const result = patch.bumpRebuildCount
|
|
2174
2174
|
? db.prepare(sql).run(patch.content, patch.descendant_count, patch.earliest_at, patch.latest_at, nowIso, summary.id, summary.tenantId)
|
|
@@ -2236,15 +2236,15 @@ export function clearSummaryDirtyAfterBuild(hippoRoot, summaryId, tenantId, acto
|
|
|
2236
2236
|
try {
|
|
2237
2237
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
2238
2238
|
// actual level so audit metadata stays accurate without an extra SELECT.
|
|
2239
|
-
const result = db.prepare(`
|
|
2240
|
-
UPDATE memories
|
|
2241
|
-
SET summary_dirty = 0
|
|
2242
|
-
WHERE id = ?
|
|
2243
|
-
AND tenant_id = ?
|
|
2244
|
-
AND dag_level IN (2, 3)
|
|
2245
|
-
AND summary_dirty = 1
|
|
2246
|
-
AND kind != 'archived'
|
|
2247
|
-
RETURNING dag_level
|
|
2239
|
+
const result = db.prepare(`
|
|
2240
|
+
UPDATE memories
|
|
2241
|
+
SET summary_dirty = 0
|
|
2242
|
+
WHERE id = ?
|
|
2243
|
+
AND tenant_id = ?
|
|
2244
|
+
AND dag_level IN (2, 3)
|
|
2245
|
+
AND summary_dirty = 1
|
|
2246
|
+
AND kind != 'archived'
|
|
2247
|
+
RETURNING dag_level
|
|
2248
2248
|
`).get(summaryId, tenantId);
|
|
2249
2249
|
if (result) {
|
|
2250
2250
|
// v0.30 / E5: source param distinguishes buildDag-clean (L2) from
|