hippo-memory 1.62.0 → 1.63.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/README.md +9 -0
- package/dist/agent-memories/apply.d.ts +2 -0
- package/dist/agent-memories/apply.js +23 -1
- package/dist/agent-memories/claude-code.d.ts +2 -1
- package/dist/agent-memories/claude-code.js +4 -4
- package/dist/agent-memories/report.d.ts +1 -0
- package/dist/agent-memories/report.js +2 -2
- package/dist/agent-memories/sync.js +37 -23
- package/dist/ambient-store.d.ts +4 -4
- package/dist/ambient-store.js +4 -3
- package/dist/api/assemble.d.ts +7 -10
- package/dist/api/assemble.js +7 -12
- package/dist/api/audit.d.ts +2 -2
- package/dist/api/audit.js +2 -2
- package/dist/api/auth.d.ts +6 -6
- package/dist/api/auth.js +5 -7
- package/dist/api/context-select.d.ts +4 -3
- package/dist/api/context-select.js +9 -11
- package/dist/api/context-types.d.ts +12 -17
- package/dist/api/context.d.ts +3 -2
- package/dist/api/context.js +20 -20
- package/dist/api/dormant.js +1 -1
- package/dist/api/drill-down.d.ts +4 -4
- package/dist/api/drill-down.js +22 -10
- package/dist/api/outcome.d.ts +8 -13
- package/dist/api/outcome.js +13 -17
- package/dist/api/promote.d.ts +5 -8
- package/dist/api/quarantine.js +3 -2
- package/dist/api/recall-types.d.ts +43 -55
- package/dist/api/recall.d.ts +3 -3
- package/dist/api/recall.js +7 -18
- package/dist/api/remember.d.ts +2 -2
- package/dist/api/sleep.d.ts +7 -35
- package/dist/api/sleep.js +3 -2
- package/dist/api/tokens.d.ts +2 -2
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +6 -10
- package/dist/api/types.js +2 -4
- package/dist/audit-prune.d.ts +4 -6
- package/dist/audit-prune.js +3 -5
- package/dist/audit.js +11 -33
- package/dist/auth.d.ts +8 -9
- package/dist/auth.js +5 -7
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +1 -1
- package/dist/availability.js +3 -5
- package/dist/capture/command.d.ts +5 -4
- package/dist/capture/command.js +8 -22
- package/dist/capture/compact.d.ts +1 -1
- package/dist/capture/compact.js +9 -13
- package/dist/capture/extract.js +37 -115
- package/dist/capture-error.d.ts +1 -1
- package/dist/capture-error.js +1 -1
- package/dist/churn-git.d.ts +1 -1
- package/dist/churn-git.js +1 -1
- package/dist/cli/audit.js +3 -4
- package/dist/cli/auth.js +3 -6
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +8 -24
- package/dist/cli/dag.js +5 -9
- package/dist/cli/decisions.js +10 -21
- package/dist/cli/explain.js +2 -1
- package/dist/cli/goals.js +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/playbooks.js +4 -9
- package/dist/cli/projects.js +3 -1
- package/dist/cli/recall.js +2 -1
- package/dist/cli/remember.js +6 -18
- package/dist/cli/session-hooks.js +21 -40
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +2 -6
- package/dist/cli/shared.js +3 -3
- package/dist/cli/slack.js +1 -1
- package/dist/cli/sleep.js +27 -1
- package/dist/cli/status.d.ts +4 -4
- package/dist/cli/status.js +7 -12
- package/dist/cli/transfer.js +8 -13
- package/dist/cli/usage.js +9 -6
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -9
- package/dist/compaction-record.d.ts +2 -0
- package/dist/compaction-record.js +89 -68
- package/dist/compare.d.ts +11 -16
- package/dist/compare.js +11 -16
- package/dist/config.d.ts +19 -18
- package/dist/config.js +90 -67
- package/dist/connectors/github/backfill.d.ts +2 -2
- package/dist/connectors/github/backfill.js +8 -15
- package/dist/connectors/github/cli-impl.js +3 -8
- package/dist/connectors/github/deletion.d.ts +5 -12
- package/dist/connectors/github/deletion.js +5 -12
- package/dist/connectors/github/dlq.d.ts +6 -9
- package/dist/connectors/github/dlq.js +2 -3
- package/dist/connectors/github/ingest.d.ts +5 -7
- package/dist/connectors/github/ingest.js +8 -12
- package/dist/connectors/github/octokit-client.d.ts +3 -5
- package/dist/connectors/github/octokit-client.js +5 -6
- package/dist/connectors/github/signature.d.ts +9 -39
- package/dist/connectors/github/signature.js +9 -39
- package/dist/connectors/github/tenant-routing.d.ts +1 -1
- package/dist/connectors/github/tenant-routing.js +1 -1
- package/dist/connectors/github/transform.js +2 -2
- package/dist/connectors/github/types.d.ts +2 -10
- package/dist/connectors/github/types.js +1 -3
- package/dist/connectors/slack/deletion.d.ts +3 -8
- package/dist/connectors/slack/deletion.js +3 -8
- package/dist/connectors/slack/dlq.d.ts +1 -1
- package/dist/connectors/slack/ingest.d.ts +1 -1
- package/dist/connectors/slack/ingest.js +7 -16
- package/dist/connectors/slack/signature.d.ts +1 -1
- package/dist/connectors/slack/tenant-routing.d.ts +3 -5
- package/dist/connectors/slack/tenant-routing.js +3 -5
- package/dist/connectors/slack/transform.d.ts +5 -6
- package/dist/connectors/slack/transform.js +5 -6
- package/dist/connectors/slack/types.d.ts +2 -6
- package/dist/connectors/slack/types.js +1 -3
- package/dist/connectors/slack/web-client.js +10 -3
- package/dist/connectors/slack/workspaces.d.ts +3 -5
- package/dist/connectors/slack/workspaces.js +3 -5
- package/dist/consolidate/conflicts.js +3 -14
- package/dist/consolidate/decay.js +9 -29
- package/dist/consolidate/llm-passes.js +4 -5
- package/dist/consolidate/merge.js +8 -23
- package/dist/consolidate/run.d.ts +1 -8
- package/dist/consolidate/run.js +3 -25
- package/dist/consolidate/sleep.js +5 -17
- package/dist/consolidate/traces.js +9 -21
- package/dist/customer-notes.d.ts +5 -7
- package/dist/customer-notes.js +6 -9
- package/dist/dag.d.ts +10 -21
- package/dist/dag.js +23 -73
- package/dist/db/continuity.js +2 -2
- package/dist/db/migrations/v14.js +1 -1
- package/dist/db/migrations/v15.js +1 -2
- package/dist/db/migrations/v16.js +3 -4
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +1 -1
- package/dist/db/migrations/v20.js +1 -1
- package/dist/db/migrations/v21.js +2 -6
- package/dist/db/migrations/v22.js +2 -4
- package/dist/db/migrations/v23.js +1 -1
- package/dist/db/migrations/v24.js +4 -6
- package/dist/db/migrations/v25.js +2 -3
- package/dist/db/migrations/v26.js +3 -3
- package/dist/db/migrations/v27.js +2 -10
- package/dist/db/migrations/v28.js +5 -8
- package/dist/db/migrations/v29.js +3 -4
- package/dist/db/migrations/v30.js +2 -2
- package/dist/db/migrations/v31.js +1 -1
- package/dist/db/migrations/v32.js +1 -1
- package/dist/db/migrations/v33.js +3 -3
- package/dist/db/migrations/v34.js +1 -1
- package/dist/db/migrations/v35.js +3 -4
- package/dist/db/migrations/v36.js +3 -4
- package/dist/db/migrations/v37.js +5 -5
- package/dist/db/migrations/v38.js +7 -8
- package/dist/db/migrations/v39.js +1 -1
- package/dist/db/migrations/v40.js +4 -16
- package/dist/db/migrations/v41.js +3 -4
- package/dist/db/migrations/v42.js +3 -4
- package/dist/db/migrations/v45.js +1 -1
- package/dist/db/migrations/v46.js +1 -1
- package/dist/db/migrations/v47.js +1 -1
- package/dist/db/migrations/v48.js +1 -1
- package/dist/decisions.d.ts +2 -2
- package/dist/decisions.js +6 -6
- package/dist/dedupe.js +86 -61
- package/dist/delivery-recorder.js +154 -135
- package/dist/doctor.js +119 -104
- package/dist/dormant.js +1 -4
- package/dist/embedding-provider.d.ts +4 -8
- package/dist/embedding-provider.js +4 -8
- package/dist/embeddings.js +55 -47
- package/dist/env.d.ts +1 -1
- package/dist/env.js +12 -12
- package/dist/escape.d.ts +5 -0
- package/dist/escape.js +10 -0
- package/dist/eval-stats.d.ts +1 -2
- package/dist/eval-stats.js +1 -2
- package/dist/eval-suite.js +27 -21
- package/dist/extract.js +4 -9
- package/dist/failure-log.d.ts +3 -3
- package/dist/failure-log.js +1 -1
- package/dist/forward-claim-detector.d.ts +2 -4
- package/dist/forward-claim-detector.js +6 -11
- package/dist/goals.d.ts +3 -3
- package/dist/goals.js +5 -6
- package/dist/graph/read.d.ts +2 -2
- package/dist/graph/read.js +5 -6
- package/dist/graph/types.d.ts +8 -8
- package/dist/graph/write.d.ts +7 -14
- package/dist/graph/write.js +16 -23
- package/dist/graph-extract.d.ts +7 -8
- package/dist/graph-extract.js +62 -72
- package/dist/graph-recall.d.ts +2 -2
- package/dist/graph-recall.js +55 -49
- package/dist/graph-stream.d.ts +5 -6
- package/dist/graph-stream.js +66 -57
- package/dist/graph-view.d.ts +2 -2
- package/dist/graph-view.js +7 -7
- package/dist/half-life-migration.d.ts +1 -2
- package/dist/half-life-migration.js +2 -3
- package/dist/hooks/codex-session.js +1 -1
- package/dist/hooks/codex-wrapper.d.ts +1 -1
- package/dist/hooks/codex-wrapper.js +3 -2
- package/dist/hooks/json-hooks.d.ts +2 -2
- package/dist/hooks/json-hooks.js +5 -4
- package/dist/hooks/opencode.d.ts +1 -1
- package/dist/hooks/opencode.js +5 -4
- package/dist/hooks/shared.d.ts +3 -7
- package/dist/hooks/shared.js +1 -8
- package/dist/http-util.d.ts +2 -3
- package/dist/http-util.js +3 -0
- package/dist/importers/core.d.ts +2 -9
- package/dist/importers/core.js +15 -30
- package/dist/importers/sources.js +2 -1
- package/dist/importers/vault.js +2 -20
- package/dist/incidents.d.ts +1 -1
- package/dist/incidents.js +1 -1
- package/dist/instruction-detect.d.ts +1 -1
- package/dist/instruction-detect.js +1 -1
- package/dist/invalidation.d.ts +3 -0
- package/dist/invalidation.js +160 -114
- package/dist/json.d.ts +5 -0
- package/dist/json.js +4 -0
- package/dist/judgment.js +1 -2
- package/dist/local-embedding.js +1 -1
- package/dist/mcp/admin-tools.js +7 -17
- package/dist/mcp/format.js +1 -1
- package/dist/mcp/framing.js +3 -6
- package/dist/mcp/protocol.d.ts +2 -5
- package/dist/mcp/protocol.js +1 -3
- package/dist/mcp/recall-tools.js +12 -15
- package/dist/mcp/request.js +4 -3
- package/dist/mcp/session-state.js +2 -3
- package/dist/mcp/stdio.js +2 -1
- package/dist/mcp/tools.js +9 -6
- package/dist/memory-value-weights.d.ts +5 -8
- package/dist/memory-value-weights.js +5 -8
- package/dist/memory-value.d.ts +13 -13
- package/dist/memory-value.js +26 -37
- package/dist/memory.d.ts +20 -22
- package/dist/memory.js +24 -48
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +3 -2
- package/dist/owner-validation.d.ts +4 -5
- package/dist/owner-validation.js +4 -5
- package/dist/physics.d.ts +4 -4
- package/dist/physics.js +7 -9
- package/dist/policies.d.ts +9 -10
- package/dist/policies.js +12 -14
- package/dist/postinstall.js +3 -6
- package/dist/predictions/planning-fallacy.d.ts +9 -14
- package/dist/predictions/planning-fallacy.js +10 -16
- package/dist/predictions/store.d.ts +15 -23
- package/dist/predictions/store.js +36 -33
- package/dist/processes.d.ts +2 -7
- package/dist/processes.js +3 -3
- package/dist/project-briefs.d.ts +2 -3
- package/dist/project-briefs.js +9 -13
- package/dist/project-identity.d.ts +22 -9
- package/dist/project-identity.js +47 -12
- package/dist/project-merge.d.ts +17 -2
- package/dist/project-merge.js +109 -27
- package/dist/project-remote.d.ts +12 -0
- package/dist/project-remote.js +138 -0
- package/dist/prompt-recall.js +1 -2
- package/dist/rate-limit.d.ts +1 -1
- package/dist/rate-limit.js +1 -1
- package/dist/raw-archive.d.ts +9 -0
- package/dist/raw-archive.js +70 -53
- package/dist/recall-history.d.ts +19 -20
- package/dist/recall-history.js +24 -42
- package/dist/recall-pipeline.js +4 -28
- package/dist/recall-scope.d.ts +7 -8
- package/dist/recall-scope.js +7 -8
- package/dist/recall-trace.d.ts +5 -9
- package/dist/recall-trace.js +6 -10
- package/dist/refine-llm.d.ts +1 -1
- package/dist/refine-llm.js +2 -2
- package/dist/reject-flow.d.ts +3 -4
- package/dist/reject-flow.js +122 -117
- package/dist/rejection.d.ts +5 -6
- package/dist/rejection.js +7 -15
- package/dist/rerankers/clef.d.ts +1 -1
- package/dist/rerankers/jev.d.ts +1 -2
- package/dist/rerankers/jev.js +4 -5
- package/dist/rerankers/llm.d.ts +1 -2
- package/dist/rerankers/llm.js +1 -2
- package/dist/rerankers/types.d.ts +1 -2
- package/dist/rrf.d.ts +2 -2
- package/dist/rrf.js +2 -2
- package/dist/search/bm25-search.d.ts +1 -1
- package/dist/search/bm25-search.js +2 -1
- package/dist/search/boosts.js +2 -1
- package/dist/search/hybrid.d.ts +1 -1
- package/dist/search/hybrid.js +2 -1
- package/dist/search/physics-search.d.ts +1 -1
- package/dist/search/physics-search.js +2 -1
- package/dist/search/types.d.ts +2 -0
- package/dist/search/types.js +3 -1
- package/dist/secret-detect.d.ts +4 -5
- package/dist/secret-detect.js +6 -10
- package/dist/server/auth.js +5 -5
- package/dist/server/client-ip.js +1 -1
- package/dist/server/cursor.js +2 -1
- package/dist/server/mcp-http.js +4 -4
- package/dist/server/request.d.ts +3 -6
- package/dist/server/request.js +6 -7
- package/dist/server/routes/admin.js +5 -4
- package/dist/server/routes/customer-notes.js +6 -5
- package/dist/server/routes/decisions.js +4 -3
- package/dist/server/routes/incidents.js +7 -5
- package/dist/server/routes/memories.js +7 -7
- package/dist/server/routes/policies.js +3 -2
- package/dist/server/routes/predictions.js +12 -15
- package/dist/server/routes/processes.js +3 -2
- package/dist/server/routes/project-briefs.js +8 -7
- package/dist/server/routes/recall.js +95 -93
- package/dist/server/routes/skills.js +6 -5
- package/dist/server/types.d.ts +1 -1
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +7 -14
- package/dist/server-detect.js +72 -58
- package/dist/server.d.ts +2 -2
- package/dist/server.js +131 -117
- package/dist/shared.d.ts +17 -17
- package/dist/shared.js +93 -97
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js +8 -8
- package/dist/store/audit-event.d.ts +2 -2
- package/dist/store/audit-event.js +1 -1
- package/dist/store/candidates.d.ts +2 -2
- package/dist/store/candidates.js +4 -3
- package/dist/store/conflicts.js +30 -22
- package/dist/store/delete-and-batch.d.ts +11 -14
- package/dist/store/delete-and-batch.js +40 -91
- package/dist/store/entry-reads.d.ts +17 -25
- package/dist/store/entry-reads.js +59 -40
- package/dist/store/entry-row.d.ts +6 -24
- package/dist/store/entry-row.js +6 -24
- package/dist/store/entry-writes.d.ts +6 -7
- package/dist/store/entry-writes.js +13 -11
- package/dist/store/handoffs.d.ts +1 -1
- package/dist/store/handoffs.js +7 -10
- package/dist/store/index-and-stats.d.ts +2 -6
- package/dist/store/index-and-stats.js +4 -10
- package/dist/store/mirrors.d.ts +6 -19
- package/dist/store/mirrors.js +14 -39
- package/dist/store/open.js +9 -31
- package/dist/store/rows.d.ts +5 -11
- package/dist/store/rows.js +6 -11
- package/dist/store/search-rows.d.ts +17 -34
- package/dist/store/search-rows.js +31 -59
- package/dist/store/sessions.d.ts +4 -5
- package/dist/store/sessions.js +5 -6
- package/dist/store/summaries.d.ts +13 -17
- package/dist/store/summaries.js +26 -70
- package/dist/support-bundle.js +4 -8
- package/dist/tenant.d.ts +1 -5
- package/dist/token-ledger.d.ts +1 -1
- package/dist/token-ledger.js +3 -5
- package/dist/trace.js +1 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.d.ts +1 -1
- 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/eval-suite.js
CHANGED
|
@@ -37,17 +37,13 @@ function mem(id, content, opts = {}) {
|
|
|
37
37
|
entry.created = opts.created;
|
|
38
38
|
return entry;
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const cases = [];
|
|
43
|
-
// =========================================================================
|
|
44
|
-
// 1. DIRECT RECALL — basic keyword matching
|
|
45
|
-
// =========================================================================
|
|
40
|
+
/** Direct recall: basic keyword matching. */
|
|
41
|
+
function addDirectRecall(entries, cases) {
|
|
46
42
|
entries.push(mem('dr-1', 'The PostgreSQL database migration failed because the users table had a NOT NULL constraint on the email column', { created: dateOffset(1), tags: ['topic:database'] }), mem('dr-2', 'React component rendering performance improved by 40% after memoizing the expensive computation in useMemo', { created: dateOffset(2), tags: ['topic:frontend'] }), mem('dr-3', 'The API rate limiter should use a sliding window algorithm instead of fixed window to prevent burst traffic', { created: dateOffset(3), tags: ['topic:api'] }), mem('dr-4', 'Docker container memory limits need to be set to 512MB for the worker service to prevent OOM kills', { created: dateOffset(4), tags: ['topic:devops'] }), mem('dr-5', 'The JWT token expiration was set to 24 hours but should be reduced to 1 hour for security compliance', { created: dateOffset(5), tags: ['topic:security'] }), mem('dr-6', 'Webpack bundle size grew to 2.3MB because lodash was imported as a whole instead of cherry-picking', { created: dateOffset(6), tags: ['topic:frontend'] }), mem('dr-7', 'The Redis cache TTL for user sessions should match the JWT expiration to prevent stale sessions', { created: dateOffset(7), tags: ['topic:caching'] }), mem('dr-8', 'GraphQL resolver for nested comments has N+1 query problem solved by DataLoader batching', { created: dateOffset(8), tags: ['topic:api'] }));
|
|
47
43
|
cases.push({ id: 'dr-q1', category: 'direct-recall', query: 'PostgreSQL migration NOT NULL constraint', expectedIds: ['dr-1'], description: 'exact keyword match on DB migration' }, { id: 'dr-q2', category: 'direct-recall', query: 'React useMemo performance memoizing', expectedIds: ['dr-2'], description: 'React performance optimization' }, { id: 'dr-q3', category: 'direct-recall', query: 'sliding window rate limiter API', expectedIds: ['dr-3'], description: 'API rate limiting approach' }, { id: 'dr-q4', category: 'direct-recall', query: 'Docker OOM memory limits worker', expectedIds: ['dr-4'], description: 'Docker memory config' }, { id: 'dr-q5', category: 'direct-recall', query: 'JWT token expiration security', expectedIds: ['dr-5'], description: 'JWT security setting' }, { id: 'dr-q6', category: 'direct-recall', query: 'webpack bundle size lodash', expectedIds: ['dr-6'], description: 'bundle size issue' }, { id: 'dr-q7', category: 'direct-recall', query: 'Redis cache TTL session expiration', expectedIds: ['dr-7'], description: 'cache TTL config' }, { id: 'dr-q8', category: 'direct-recall', query: 'GraphQL N+1 DataLoader batching', expectedIds: ['dr-8'], description: 'GraphQL N+1 fix' });
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
}
|
|
45
|
+
/** Extraction preference: extracted facts should rank above raw source. */
|
|
46
|
+
function addExtractionPreference(entries, cases) {
|
|
51
47
|
entries.push(mem('ep-src-1', 'speaker:Alice: So we had this big meeting yesterday about the deployment pipeline and Bob mentioned that the staging environment is using Kubernetes 1.28 and we should upgrade to 1.30 before the end of Q2 because of the security patches', {
|
|
52
48
|
created: dateOffset(10), tags: ['speaker:Alice', 'topic:infrastructure', 'session:meeting-1'],
|
|
53
49
|
}), mem('ep-ext-1', 'The staging environment runs Kubernetes 1.28 and needs to be upgraded to 1.30 before end of Q2 for security patches', {
|
|
@@ -65,9 +61,9 @@ export function buildSyntheticCorpus() {
|
|
|
65
61
|
extracted_from: 'ep-src-3',
|
|
66
62
|
}));
|
|
67
63
|
cases.push({ id: 'ep-q1', category: 'extraction-preference', query: 'Kubernetes upgrade staging environment', expectedIds: ['ep-ext-1'], description: 'extracted fact about K8s upgrade should rank above raw utterance' }, { id: 'ep-q2', category: 'extraction-preference', query: 'Datadog Grafana alerting migration', expectedIds: ['ep-ext-2'], description: 'extracted fact about monitoring switch' }, { id: 'ep-q3', category: 'extraction-preference', query: 'OAuth2 PKCE login page redesign', expectedIds: ['ep-ext-3'], description: 'extracted fact about auth work' });
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
}
|
|
65
|
+
/** Dag drill-down: summary nodes should surface children. */
|
|
66
|
+
function addDagDrilldown(entries, cases) {
|
|
71
67
|
entries.push(mem('dag-child-1', 'The API response time for /users endpoint degraded from 50ms to 300ms after adding the permissions check', {
|
|
72
68
|
created: dateOffset(15), layer: Layer.Semantic, tags: ['topic:api-performance', 'extracted'],
|
|
73
69
|
dag_level: 1,
|
|
@@ -86,14 +82,14 @@ export function buildSyntheticCorpus() {
|
|
|
86
82
|
child.dag_parent_id = 'dag-summary-1';
|
|
87
83
|
}
|
|
88
84
|
cases.push({ id: 'dag-q1', category: 'dag-drilldown', query: 'API performance problems latency', expectedIds: ['dag-child-1', 'dag-child-2', 'dag-child-3', 'dag-summary-1'], description: 'summary should drill down to all children' }, { id: 'dag-q2', category: 'dag-drilldown', query: 'endpoint response time degradation', expectedIds: ['dag-child-1', 'dag-child-2', 'dag-summary-1'], description: 'query matching summary should surface relevant children' });
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
}
|
|
86
|
+
/** Temporal: recency/oldest cues should affect ranking. */
|
|
87
|
+
function addTemporal(entries, cases) {
|
|
92
88
|
entries.push(mem('tmp-1', 'The team decided to use TypeScript for the new service', { created: dateOffset(-30), tags: ['topic:architecture'] }), mem('tmp-2', 'The team evaluated Rust as an alternative language for the service', { created: dateOffset(-20), tags: ['topic:architecture'] }), mem('tmp-3', 'The team added Go as a candidate language for the service rewrite', { created: dateOffset(-10), tags: ['topic:architecture'] }), mem('tmp-4', 'The team finalized the language choice as Go for the service rewrite', { created: dateOffset(-1), tags: ['topic:architecture'] }));
|
|
93
89
|
cases.push({ id: 'tmp-q1', category: 'temporal', query: 'what did the team recently decide about the service language', expectedIds: ['tmp-4'], description: 'recent cue should boost newest entry' }, { id: 'tmp-q2', category: 'temporal', query: 'what was the first language choice for the service', expectedIds: ['tmp-1'], description: 'oldest cue should boost earliest entry' }, { id: 'tmp-q3', category: 'temporal', query: 'latest update on the service rewrite language', expectedIds: ['tmp-4'], description: 'latest should boost most recent' }, { id: 'tmp-q4', category: 'temporal', query: 'original architecture decision for the service', expectedIds: ['tmp-1'], description: 'original should boost earliest' });
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
}
|
|
91
|
+
/** Noise resistance: relevant memories found despite noise. */
|
|
92
|
+
function addNoiseResistance(entries, cases) {
|
|
97
93
|
// Add 30 noise entries
|
|
98
94
|
const noiseTopics = [
|
|
99
95
|
'breakfast meeting catering ordered sandwiches', 'office temperature thermostat adjusted',
|
|
@@ -121,9 +117,9 @@ export function buildSyntheticCorpus() {
|
|
|
121
117
|
created: dateOffset(21), tags: ['topic:security', 'topic:s3'],
|
|
122
118
|
}));
|
|
123
119
|
cases.push({ id: 'nr-q1', category: 'noise-resistance', query: 'database connection pool exhausted max connections', expectedIds: ['nr-1'], description: 'find DB issue despite 30 noise entries' }, { id: 'nr-q2', category: 'noise-resistance', query: 'S3 bucket public access security misconfiguration', expectedIds: ['nr-2'], description: 'find S3 issue despite noise' }, { id: 'nr-q3', category: 'noise-resistance', query: 'PostgreSQL migration constraint', expectedIds: ['dr-1'], description: 'find earlier DB entry despite noise' }, { id: 'nr-q4', category: 'noise-resistance', query: 'JWT token security expiration', expectedIds: ['dr-5'], description: 'find security entry despite noise' });
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
}
|
|
121
|
+
/** Multi-hop: entity chaining across sessions. */
|
|
122
|
+
function addMultiHop(entries, cases) {
|
|
127
123
|
entries.push(mem('mh-1', 'speaker:Alice works on the payment gateway integration with Stripe. She found a webhook signature validation bug.', {
|
|
128
124
|
created: dateOffset(25), tags: ['speaker:Alice', 'topic:payments'],
|
|
129
125
|
}), mem('mh-2', 'speaker:Bob reviewed the Stripe webhook code and confirmed the signature validation uses the wrong secret key from the test environment.', {
|
|
@@ -134,6 +130,16 @@ export function buildSyntheticCorpus() {
|
|
|
134
130
|
created: dateOffset(28), tags: ['speaker:Carol', 'topic:billing'],
|
|
135
131
|
}));
|
|
136
132
|
cases.push({ id: 'mh-q1', category: 'multi-hop', query: 'Who fixed the Stripe webhook bug and what was the root cause?', expectedIds: ['mh-1', 'mh-2', 'mh-3'], description: 'chain Alice -> Stripe -> Bob -> fix' }, { id: 'mh-q2', category: 'multi-hop', query: 'What are all the payment-related issues the team discussed?', expectedIds: ['mh-1', 'mh-2', 'mh-3', 'mh-4'], description: 'find all payment topics across speakers' });
|
|
133
|
+
}
|
|
134
|
+
export function buildSyntheticCorpus() {
|
|
135
|
+
const entries = [];
|
|
136
|
+
const cases = [];
|
|
137
|
+
addDirectRecall(entries, cases);
|
|
138
|
+
addExtractionPreference(entries, cases);
|
|
139
|
+
addDagDrilldown(entries, cases);
|
|
140
|
+
addTemporal(entries, cases);
|
|
141
|
+
addNoiseResistance(entries, cases);
|
|
142
|
+
addMultiHop(entries, cases);
|
|
137
143
|
return { entries, cases };
|
|
138
144
|
}
|
|
139
145
|
// ---------------------------------------------------------------------------
|
package/dist/extract.js
CHANGED
|
@@ -6,9 +6,7 @@ import { redactSecretsStrict } from './secret-detect.js';
|
|
|
6
6
|
import { fetchWithRetry, llmTimeoutMs } from './http-retry.js';
|
|
7
7
|
import { neverAutoShareTags } from './shared.js';
|
|
8
8
|
import { log } from './log.js';
|
|
9
|
-
|
|
10
|
-
return typeof value === 'string';
|
|
11
|
-
}
|
|
9
|
+
import { isJsonString } from './json.js';
|
|
12
10
|
const EXTRACTION_PROMPT = `You are extracting factual statements from a conversation or memory entry. Extract 1-8 standalone factual statements that would be useful to remember later.
|
|
13
11
|
|
|
14
12
|
Rules:
|
|
@@ -101,15 +99,12 @@ export function storeExtractedFacts(hippoRoot, source, facts) {
|
|
|
101
99
|
source: source.source,
|
|
102
100
|
extracted_from: source.id,
|
|
103
101
|
scope: source.scope,
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// option stamps 'default' (memory.ts:535) regardless of the source
|
|
107
|
-
// entry's own tenant. Thread it through so extracted facts land in
|
|
108
|
-
// the same tenant as the episodic memory they were extracted from.
|
|
102
|
+
// Without it createMemory stamps 'default', and extracted facts leave
|
|
103
|
+
// the tenant of the episodic memory they were extracted from.
|
|
109
104
|
tenantId: source.tenantId,
|
|
110
105
|
baseHalfLifeDays,
|
|
111
106
|
}), origin_project: source.origin_project };
|
|
112
|
-
//
|
|
107
|
+
// A refusal is per-VALUE: one rejected fact must not
|
|
113
108
|
// drop the rest of this batch. writeEntry has already audited the
|
|
114
109
|
// refusal (reject_refusal) before rethrowing, so skip-and-count here.
|
|
115
110
|
try {
|
package/dist/failure-log.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Failure log
|
|
1
|
+
/** Failure log: every failed tool call the capture-error hook sees, stored or not. */
|
|
2
2
|
import type { CaptureErrorOutcome, RoutineRule } from './capture-error.js';
|
|
3
3
|
import type { DatabaseSyncLike } from './db.js';
|
|
4
4
|
/** Rows older than this are pruned on write, which also bounds how far back a repeat can be found. */
|
|
@@ -31,9 +31,9 @@ export interface SessionFailures {
|
|
|
31
31
|
/** Of those, failures whose signature another session hit first. */
|
|
32
32
|
repeats: number;
|
|
33
33
|
}
|
|
34
|
-
/** Rated failures per session since `sinceIso`, the input for repeat-error rate per arm
|
|
34
|
+
/** Rated failures per session since `sinceIso`, the input for repeat-error rate per arm. */
|
|
35
35
|
export declare function failuresBySession(db: DatabaseSyncLike, tenantId: string, sinceIso: string): SessionFailures[];
|
|
36
|
-
/** Failure log totals over a window, for {@link summarizeFailures}. Counts only: a rate needs a holdout arm
|
|
36
|
+
/** Failure log totals over a window, for {@link summarizeFailures}. Counts only: a rate needs a holdout arm. */
|
|
37
37
|
export interface FailureSummary {
|
|
38
38
|
/** ISO start of the window (inclusive). */
|
|
39
39
|
since: string;
|
package/dist/failure-log.js
CHANGED
|
@@ -11,7 +11,7 @@ export function recordFailure(db, event) {
|
|
|
11
11
|
const cutoff = new Date(Date.parse(now) - FAILURE_LOG_RETENTION_DAYS * 86_400_000).toISOString();
|
|
12
12
|
db.prepare(`DELETE FROM failure_log WHERE ts < ?`).run(cutoff);
|
|
13
13
|
}
|
|
14
|
-
/** Rated failures per session since `sinceIso`, the input for repeat-error rate per arm
|
|
14
|
+
/** Rated failures per session since `sinceIso`, the input for repeat-error rate per arm. */
|
|
15
15
|
export function failuresBySession(db, tenantId, sinceIso) {
|
|
16
16
|
// SAFETY: the SELECT names exactly these three TEXT columns.
|
|
17
17
|
const rows = db.prepare(`SELECT ts, session_id, sig_hash FROM failure_log
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Forward-claim detector: pure-function regex set + token extraction.
|
|
3
3
|
*
|
|
4
4
|
* No DB. No state. No dependencies beyond stdlib regex + String.
|
|
5
5
|
*
|
|
@@ -13,9 +13,7 @@
|
|
|
13
13
|
* Iteration signal: the `recall_autodebias_hint_no_class_match` audit op
|
|
14
14
|
* (emitted by computePlanningFallacyOutput when a phrase matches but no class
|
|
15
15
|
* resolves) is the telemetry channel for deciding whether to add an
|
|
16
|
-
* embedding-based detector
|
|
17
|
-
*
|
|
18
|
-
* Plan: docs/plans/2026-05-26-j32-auto-injection.md (Task 1).
|
|
16
|
+
* embedding-based detector.
|
|
19
17
|
*/
|
|
20
18
|
export interface ForwardClaimMatch {
|
|
21
19
|
/** The regex match snippet, e.g. "will take" or "~3 days". Surfaced
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Forward-claim detector: pure-function regex set + token extraction.
|
|
3
3
|
*
|
|
4
4
|
* No DB. No state. No dependencies beyond stdlib regex + String.
|
|
5
5
|
*
|
|
@@ -13,12 +13,10 @@
|
|
|
13
13
|
* Iteration signal: the `recall_autodebias_hint_no_class_match` audit op
|
|
14
14
|
* (emitted by computePlanningFallacyOutput when a phrase matches but no class
|
|
15
15
|
* resolves) is the telemetry channel for deciding whether to add an
|
|
16
|
-
* embedding-based detector
|
|
17
|
-
*
|
|
18
|
-
* Plan: docs/plans/2026-05-26-j32-auto-injection.md (Task 1).
|
|
16
|
+
* embedding-based detector.
|
|
19
17
|
*/
|
|
20
18
|
/**
|
|
21
|
-
*
|
|
19
|
+
* Each pattern is intentionally narrow:
|
|
22
20
|
* adding a pattern should require evidence from the
|
|
23
21
|
* `recall_autodebias_hint_no_class_match` audit channel that real forward-
|
|
24
22
|
* claims are slipping through, NOT speculative "this might match more".
|
|
@@ -29,8 +27,7 @@
|
|
|
29
27
|
*/
|
|
30
28
|
// Reused fragment for ALL duration-suffix patterns. Requires a digit + unit
|
|
31
29
|
// so 'will take ownership' / 'ship in Docker' (no time component) don't
|
|
32
|
-
// match
|
|
33
|
-
// on every-day non-estimate queries that happened to share a class-token.
|
|
30
|
+
// match: verb-only patterns fire on everyday non-estimate queries that share a class-token.
|
|
34
31
|
// Accepts `<N> unit` (3 days), `a/an unit` (a week — implicit 1), and
|
|
35
32
|
// `one unit` so natural English forward-claims aren't lost.
|
|
36
33
|
const DURATION_TAIL = String.raw `(?:about|around|~|≈)?\s*(?:\d+|a|an|one)\s*(?:day|week|month|hour|hr|min(?:ute)?|sec(?:ond)?)s?\b`;
|
|
@@ -51,8 +48,7 @@ const FORWARD_CLAIM_PATTERNS = [
|
|
|
51
48
|
// Lookbehind asserts start-of-string OR whitespace before the tilde
|
|
52
49
|
// because \b before ~ requires a word char immediately preceding (~ is
|
|
53
50
|
// not a word character), so /\b~/ would only match in 'foo~3 days'
|
|
54
|
-
// (malformed) and silently miss the legitimate cases.
|
|
55
|
-
// round 1 catch.
|
|
51
|
+
// (malformed) and silently miss the legitimate cases.
|
|
56
52
|
/(?<=^|\s)~\s*\d+\s*(?:day|week|month|hour)s?\b/i,
|
|
57
53
|
// Should + verb + duration tail. Same tightening as the leading 'will
|
|
58
54
|
// take' rule: 'should ship by EOD' must include a quantifier.
|
|
@@ -78,8 +74,7 @@ const STOP_WORDS = new Set([
|
|
|
78
74
|
// Duration units appear in every forward-claim phrase by design (the
|
|
79
75
|
// regex set REQUIRES a `<N> <unit>` quantifier after the verb). Letting
|
|
80
76
|
// them through to class resolution lets a class tag containing 'days'
|
|
81
|
-
// win or tie on the unit token instead of the domain token.
|
|
82
|
-
// 2 P3 catch.
|
|
77
|
+
// win or tie on the unit token instead of the domain token.
|
|
83
78
|
'day', 'days', 'week', 'weeks', 'month', 'months',
|
|
84
79
|
'hour', 'hours', 'hr', 'hrs',
|
|
85
80
|
'min', 'mins', 'minute', 'minutes', 'sec', 'secs', 'second', 'seconds',
|
package/dist/goals.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface PushGoalOpts {
|
|
|
60
60
|
}
|
|
61
61
|
export declare function pushGoal(hippoRoot: string, opts: PushGoalOpts): Goal;
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* Depth-cap enforcer shared by pushGoalWithDb and resumeGoal.
|
|
64
64
|
* If the (tenant, session) has >= MAX_ACTIVE_GOAL_DEPTH active goals,
|
|
65
65
|
* suspend the oldest `overflow` ones.
|
|
66
66
|
*
|
|
@@ -69,7 +69,7 @@ export declare function pushGoal(hippoRoot: string, opts: PushGoalOpts): Goal;
|
|
|
69
69
|
* is impossible to misread the contract at a call site. Both existing call
|
|
70
70
|
* sites (pushGoalWithDb, resumeGoal) wrap in `BEGIN IMMEDIATE` already.
|
|
71
71
|
*
|
|
72
|
-
* @internal
|
|
72
|
+
* @internal Internal goal-stack invariant. Subject to change.
|
|
73
73
|
*/
|
|
74
74
|
export declare function enforceDepthCapWithinTx(db: DatabaseSyncLike, tenantId: string, sessionId: string): void;
|
|
75
75
|
export declare function pushGoalWithDb(db: DatabaseSyncLike, opts: PushGoalOpts): Goal;
|
|
@@ -148,7 +148,7 @@ export declare function applyGoalStackBoost<R extends {
|
|
|
148
148
|
export interface CompleteGoalOpts {
|
|
149
149
|
outcomeScore?: number;
|
|
150
150
|
/**
|
|
151
|
-
*
|
|
151
|
+
* When true, skip the strength-multiplier propagation block.
|
|
152
152
|
* Default false (propagate). The goal's status still transitions to
|
|
153
153
|
* 'completed' and `outcome_score` is still recorded; only the side-effect
|
|
154
154
|
* on recalled memories' strength is suppressed.
|
package/dist/goals.js
CHANGED
|
@@ -29,7 +29,7 @@ export function pushGoal(hippoRoot, opts) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* Depth-cap enforcer shared by pushGoalWithDb and resumeGoal.
|
|
33
33
|
* If the (tenant, session) has >= MAX_ACTIVE_GOAL_DEPTH active goals,
|
|
34
34
|
* suspend the oldest `overflow` ones.
|
|
35
35
|
*
|
|
@@ -38,7 +38,7 @@ export function pushGoal(hippoRoot, opts) {
|
|
|
38
38
|
* is impossible to misread the contract at a call site. Both existing call
|
|
39
39
|
* sites (pushGoalWithDb, resumeGoal) wrap in `BEGIN IMMEDIATE` already.
|
|
40
40
|
*
|
|
41
|
-
* @internal
|
|
41
|
+
* @internal Internal goal-stack invariant. Subject to change.
|
|
42
42
|
*/
|
|
43
43
|
export function enforceDepthCapWithinTx(db, tenantId, sessionId) {
|
|
44
44
|
// SAFETY: the row comes from the SELECT above, which projects exactly one
|
|
@@ -291,9 +291,8 @@ export function computeGoalStackBoost(db, results, opts) {
|
|
|
291
291
|
if (matches.length === 0)
|
|
292
292
|
return r;
|
|
293
293
|
const multiplier = goalBoostMultiplier(r.entry, tags, matches, goalsByTag, policiesByGoalId);
|
|
294
|
-
//
|
|
295
|
-
// score is mutated, keyed by entry id
|
|
296
|
-
// mutation below is byte-identical to pre-A7.
|
|
294
|
+
// Recall-trace side-channel: record the goal-boost step BEFORE the
|
|
295
|
+
// score is mutated, keyed by entry id; a pure read of r.score.
|
|
297
296
|
if (trace) {
|
|
298
297
|
trace.set(r.entry.id, {
|
|
299
298
|
stage: 'goal-boost',
|
|
@@ -309,7 +308,7 @@ export function computeGoalStackBoost(db, results, opts) {
|
|
|
309
308
|
// still satisfies R's shape exactly.
|
|
310
309
|
return { ...r, score: r.score * multiplier };
|
|
311
310
|
})
|
|
312
|
-
//
|
|
311
|
+
// Deliberately a PLAIN stable score sort, no compareEntryIdentity
|
|
313
312
|
// tail -- a re-sort of an already deterministically-ordered ranking
|
|
314
313
|
// inherits its determinism via sort stability, and ties preserve the
|
|
315
314
|
// prior (meaningful) rank instead of reordering by content.
|
package/dist/graph/read.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare function loadRelations(hippoRoot: string, tenantId: string, opts?
|
|
|
16
16
|
limit?: number;
|
|
17
17
|
}, txDb?: GraphTxDb): Relation[];
|
|
18
18
|
/**
|
|
19
|
-
* Map consolidated source memory ids -> their graph entities. The SEED step of
|
|
19
|
+
* Map consolidated source memory ids -> their graph entities. The SEED step of
|
|
20
20
|
* multi-hop recall (recall result memory ids -> entities to traverse from). Tenant-
|
|
21
21
|
* scoped, read-only; chunks the IN-list under the SQLite variable cap.
|
|
22
22
|
*/
|
|
@@ -28,7 +28,7 @@ export declare function loadEntitiesByMemoryId(hippoRoot: string, tenantId: stri
|
|
|
28
28
|
export declare function loadEntitiesByIds(hippoRoot: string, tenantId: string, ids: number[], txDb?: GraphTxDb): Entity[];
|
|
29
29
|
/**
|
|
30
30
|
* All relations touching ANY of `entityIds` in EITHER direction (from OR to) — the
|
|
31
|
-
* per-hop neighbour query for
|
|
31
|
+
* per-hop neighbour query for multi-hop traversal. ONE query for the whole frontier
|
|
32
32
|
* (not one per node): this is the bidirectional read `loadRelations` (from-only) lacks,
|
|
33
33
|
* and avoids an N+1 across BFS frontier nodes. `limit` caps rows for the frontier and
|
|
34
34
|
* must be a non-negative integer (the raw `LIMIT ?` rejects a fractional value).
|
package/dist/graph/read.js
CHANGED
|
@@ -98,14 +98,14 @@ export function loadRelations(hippoRoot, tenantId, opts = {}, txDb) {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
// ---------------------------------------------------------------------------
|
|
101
|
-
//
|
|
101
|
+
// Multi-hop recall read helpers (SELECT-only; the check-graph-writes lint
|
|
102
102
|
// permits these here and in the read-only consumer src/graph-recall.ts).
|
|
103
103
|
// ---------------------------------------------------------------------------
|
|
104
104
|
/** Chunk size for IN-list queries: well under SQLite's 999-bound-variable default
|
|
105
105
|
* (leaves headroom for the tenant_id param + the doubled list in neighbour lookups). */
|
|
106
106
|
const IN_LIST_CHUNK = 400;
|
|
107
107
|
/**
|
|
108
|
-
* Map consolidated source memory ids -> their graph entities. The SEED step of
|
|
108
|
+
* Map consolidated source memory ids -> their graph entities. The SEED step of
|
|
109
109
|
* multi-hop recall (recall result memory ids -> entities to traverse from). Tenant-
|
|
110
110
|
* scoped, read-only; chunks the IN-list under the SQLite variable cap.
|
|
111
111
|
*/
|
|
@@ -119,8 +119,7 @@ export function loadEntitiesByMemoryId(hippoRoot, tenantId, memoryIds) {
|
|
|
119
119
|
for (let i = 0; i < memoryIds.length; i += IN_LIST_CHUNK) {
|
|
120
120
|
const slice = memoryIds.slice(i, i + IN_LIST_CHUNK);
|
|
121
121
|
const ph = slice.map(() => '?').join(',');
|
|
122
|
-
//
|
|
123
|
-
// makes it deterministic (entities.id is an autoincrement integer PK).
|
|
122
|
+
// id ASC so chunk-local scan order never decides ties (id is an autoincrement PK).
|
|
124
123
|
// SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
|
|
125
124
|
const rows = db.prepare(`
|
|
126
125
|
SELECT ${ENTITY_COLS} FROM entities
|
|
@@ -166,7 +165,7 @@ export function loadEntitiesByIds(hippoRoot, tenantId, ids, txDb) {
|
|
|
166
165
|
}
|
|
167
166
|
/**
|
|
168
167
|
* All relations touching ANY of `entityIds` in EITHER direction (from OR to) — the
|
|
169
|
-
* per-hop neighbour query for
|
|
168
|
+
* per-hop neighbour query for multi-hop traversal. ONE query for the whole frontier
|
|
170
169
|
* (not one per node): this is the bidirectional read `loadRelations` (from-only) lacks,
|
|
171
170
|
* and avoids an N+1 across BFS frontier nodes. `limit` caps rows for the frontier and
|
|
172
171
|
* must be a non-negative integer (the raw `LIMIT ?` rejects a fractional value).
|
|
@@ -183,7 +182,7 @@ export function loadNeighborRelations(hippoRoot, tenantId, entityIds, opts = {},
|
|
|
183
182
|
const db = txDb ?? ownDb;
|
|
184
183
|
try {
|
|
185
184
|
// `limit` is applied PER CHUNK; a frontier spanning >IN_LIST_CHUNK ids could return
|
|
186
|
-
// up to limit*chunks rows before the by-id dedup below. Harmless for
|
|
185
|
+
// up to limit*chunks rows before the by-id dedup below. Harmless for multi-hop recall (the
|
|
187
186
|
// frontier is bounded by maxNeighbors <= 200 << IN_LIST_CHUNK, so a single chunk,
|
|
188
187
|
// and the BFS re-enforces the per-hop fanout cap), but note the semantics if a
|
|
189
188
|
// tighter total cap is ever needed.
|
package/dist/graph/types.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ export type RelationType = 'owns' | 'supersedes' | 'depends-on' | 'blocked-by' |
|
|
|
8
8
|
export type GraphQueueStatus = 'pending' | 'processed' | 'skipped';
|
|
9
9
|
/** The consolidated source kinds the graph is permitted to index (never 'raw'). */
|
|
10
10
|
export type SourceKind = 'distilled' | 'superseded';
|
|
11
|
-
/** The authoritative
|
|
11
|
+
/** The authoritative first-class object types a graph row may be anchored to (the object
|
|
12
12
|
* provenance path, alongside the memory path). Maps to source_object_type. */
|
|
13
13
|
export type SourceObjectType = 'decision' | 'policy' | 'customer' | 'project';
|
|
14
|
-
/** A soft (type,id) pointer to the authoritative
|
|
14
|
+
/** A soft (type,id) pointer to the authoritative object row a graph row descends from.
|
|
15
15
|
* Survives a mirror memory forget/prune (memory_id may go NULL); the rebuild
|
|
16
16
|
* re-validates it (it is not a hard FK). */
|
|
17
17
|
export interface SourceObjectRef {
|
|
@@ -32,8 +32,8 @@ export interface Entity {
|
|
|
32
32
|
* its source_object provenance. */
|
|
33
33
|
memoryId: string | null;
|
|
34
34
|
sourceKind: SourceKind;
|
|
35
|
-
/** The authoritative
|
|
36
|
-
* Set for
|
|
35
|
+
/** The authoritative object this entity is anchored to (object-provenance path).
|
|
36
|
+
* Set for object-sourced entities; absent for memory-only (prose/NLP) entities. */
|
|
37
37
|
sourceObjectType?: SourceObjectType;
|
|
38
38
|
sourceObjectId?: number;
|
|
39
39
|
createdAt: string;
|
|
@@ -64,9 +64,9 @@ export interface InsertEntityOpts {
|
|
|
64
64
|
entityType: EntityType;
|
|
65
65
|
name: string;
|
|
66
66
|
/** A consolidated (distilled/superseded) memory; raw is rejected. NULL/omitted when
|
|
67
|
-
* the entity is anchored only to its
|
|
67
|
+
* the entity is anchored only to its source object (mirror forgotten/pruned). */
|
|
68
68
|
memoryId?: string | null;
|
|
69
|
-
/** The authoritative
|
|
69
|
+
/** The authoritative object this entity descends from. Required when memoryId is
|
|
70
70
|
* null; optional alongside a live memory (both paths may be set). */
|
|
71
71
|
sourceObject?: SourceObjectRef;
|
|
72
72
|
}
|
|
@@ -75,9 +75,9 @@ export interface InsertRelationOpts {
|
|
|
75
75
|
toEntityId: number;
|
|
76
76
|
relType: RelationType;
|
|
77
77
|
/** A consolidated (distilled/superseded) memory; raw is rejected. NULL/omitted when
|
|
78
|
-
* the relation is anchored only to its
|
|
78
|
+
* the relation is anchored only to its source object. */
|
|
79
79
|
memoryId?: string | null;
|
|
80
|
-
/** The authoritative
|
|
80
|
+
/** The authoritative object this relation descends from. */
|
|
81
81
|
sourceObject?: SourceObjectRef;
|
|
82
82
|
}
|
|
83
83
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/graph/write.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* (docs/plans/2026-06-01-e3-graph-guard.md).
|
|
2
|
+
* Graph layer over consolidated state - the graph-on-consolidated guard.
|
|
4
3
|
*
|
|
5
4
|
* A graph of canonical `entities` (person/project/customer/system/policy/decision) and
|
|
6
5
|
* `relations` (owns/supersedes/depends-on/blocked-by/references) sits ON TOP OF
|
|
@@ -11,11 +10,6 @@
|
|
|
11
10
|
* actual kind and enforce tenant-match - relations also reject cross-tenant edges), so
|
|
12
11
|
* the forbidden state is unrepresentable regardless of code path. These helpers
|
|
13
12
|
* surface the same guard as clear throws BEFORE hitting the trigger backstop.
|
|
14
|
-
*
|
|
15
|
-
* Scope (E3.3 first slice): the substrate + the guard + a thin insert/load/enqueue
|
|
16
|
-
* API. The `graph_extraction_queue` is the interface the deferred `hippo sleep`
|
|
17
|
-
* enqueue-hook + E3.1 entity extraction will call. No operator surface (CLI/HTTP/SDK)
|
|
18
|
-
* until E3.2 multi-hop recall.
|
|
19
13
|
*/
|
|
20
14
|
import { type GraphTxDb, type SourceObjectType, type Entity, type Relation, type GraphQueueItem, type InsertEntityOpts, type InsertRelationOpts } from './types.js';
|
|
21
15
|
/**
|
|
@@ -30,8 +24,7 @@ export declare function insertEntity(hippoRoot: string, tenantId: string, opts:
|
|
|
30
24
|
export declare function insertRelation(hippoRoot: string, tenantId: string, opts: InsertRelationOpts, txDb?: GraphTxDb): Relation;
|
|
31
25
|
/**
|
|
32
26
|
* Enqueue a consolidated memory for later graph extraction. Rejects a raw / missing /
|
|
33
|
-
* cross-tenant memory (the DB trigger is the backstop).
|
|
34
|
-
* `hippo sleep` is deferred (E3.1); this is the API it will call.
|
|
27
|
+
* cross-tenant memory (the DB trigger is the backstop).
|
|
35
28
|
*/
|
|
36
29
|
export declare function enqueueExtraction(hippoRoot: string, tenantId: string, memoryId: string): GraphQueueItem;
|
|
37
30
|
/**
|
|
@@ -46,7 +39,7 @@ export declare function markExtractionProcessed(hippoRoot: string, tenantId: str
|
|
|
46
39
|
* the number of entities deleted. The rebuild primitive for graph extraction: the
|
|
47
40
|
* deterministic graph is a pure derived function of the consolidated objects, so an
|
|
48
41
|
* extract clears then re-derives. Lives in graph.ts (the sole sanctioned graph
|
|
49
|
-
* writer), so the
|
|
42
|
+
* writer), so the CI lint permits this `DELETE FROM entities`. Does NOT touch
|
|
50
43
|
* graph_extraction_queue (the enqueue-hook's domain).
|
|
51
44
|
*/
|
|
52
45
|
export declare function clearGraph(hippoRoot: string, tenantId: string, txDb?: GraphTxDb): number;
|
|
@@ -63,19 +56,19 @@ export declare function runGraphRebuildTransaction<T>(hippoRoot: string, tenantI
|
|
|
63
56
|
/**
|
|
64
57
|
* Fail-soft producer hook: mark a tenant dirty for graph re-extraction by
|
|
65
58
|
* enqueuing its consolidated mirror memory. NEVER throws into the caller — a
|
|
66
|
-
* graph-dirty signal failing must not abort a core
|
|
59
|
+
* graph-dirty signal failing must not abort a core object write. Graph staleness is
|
|
67
60
|
* recoverable (next sleep / manual `graph extract`); a broken `hippo decide` is
|
|
68
|
-
* not. Called POST-COMMIT from the
|
|
61
|
+
* not. Called POST-COMMIT from the graph-source save/close mutations of
|
|
69
62
|
* decision, policy, customer_note and project_brief. A null memoryId (a
|
|
70
63
|
* forgotten mirror) is a no-op.
|
|
71
64
|
*/
|
|
72
65
|
export declare function markGraphDirty(hippoRoot: string, tenantId: string, memoryId: string | null): void;
|
|
73
66
|
/**
|
|
74
|
-
* Remove the graph rows sourced from one
|
|
67
|
+
* Remove the graph rows sourced from one first-class object, by its (type, id). Used when a
|
|
75
68
|
* MIRRORLESS object is closed: it has no mirror memory, so `markGraphDirty` cannot
|
|
76
69
|
* enqueue a rebuild (the queue is memory-keyed). Closing must still drop the object's
|
|
77
70
|
* now-stale entity + edges from the graph, so we remove them directly here. Fail-soft
|
|
78
|
-
* like `markGraphDirty` (never throws into the
|
|
71
|
+
* like `markGraphDirty` (never throws into the object close caller; graph staleness is
|
|
79
72
|
* recoverable). Deleting the entity cascade-deletes any relation where it is an endpoint
|
|
80
73
|
* (relations FK entities ON DELETE CASCADE); the explicit relations DELETE also covers a
|
|
81
74
|
* relation whose OWN provenance is this object (defensive — every such edge has the object
|
package/dist/graph/write.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* (docs/plans/2026-06-01-e3-graph-guard.md).
|
|
2
|
+
* Graph layer over consolidated state - the graph-on-consolidated guard.
|
|
4
3
|
*
|
|
5
4
|
* A graph of canonical `entities` (person/project/customer/system/policy/decision) and
|
|
6
5
|
* `relations` (owns/supersedes/depends-on/blocked-by/references) sits ON TOP OF
|
|
@@ -11,11 +10,6 @@
|
|
|
11
10
|
* actual kind and enforce tenant-match - relations also reject cross-tenant edges), so
|
|
12
11
|
* the forbidden state is unrepresentable regardless of code path. These helpers
|
|
13
12
|
* surface the same guard as clear throws BEFORE hitting the trigger backstop.
|
|
14
|
-
*
|
|
15
|
-
* Scope (E3.3 first slice): the substrate + the guard + a thin insert/load/enqueue
|
|
16
|
-
* API. The `graph_extraction_queue` is the interface the deferred `hippo sleep`
|
|
17
|
-
* enqueue-hook + E3.1 entity extraction will call. No operator surface (CLI/HTTP/SDK)
|
|
18
|
-
* until E3.2 multi-hop recall.
|
|
19
13
|
*/
|
|
20
14
|
import { openHippoDb, closeHippoDb } from '../db.js';
|
|
21
15
|
import { assertTenantId } from '../tenant.js';
|
|
@@ -37,9 +31,9 @@ function resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, label)
|
|
|
37
31
|
const row = db.prepare(`SELECT kind, tenant_id FROM memories WHERE id = ?`).get(memoryId);
|
|
38
32
|
if (!row) {
|
|
39
33
|
// Stale / forgotten mirror. Tolerate it IFF a valid source object provides provenance:
|
|
40
|
-
// graph-extract reads
|
|
41
|
-
// must NOT roll back the whole tenant rebuild - the active
|
|
42
|
-
//
|
|
34
|
+
// graph-extract reads object rows then inserts, and a mirror forgotten/pruned in that window
|
|
35
|
+
// must NOT roll back the whole tenant rebuild - the active object survives mirror loss.
|
|
36
|
+
// Anchor to the object; drop the dead memory pointer.
|
|
43
37
|
if (sourceObject == null) {
|
|
44
38
|
throw new Error(`${label}: source memory ${memoryId} not found`);
|
|
45
39
|
}
|
|
@@ -58,8 +52,8 @@ function resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, label)
|
|
|
58
52
|
memKind = row.kind;
|
|
59
53
|
}
|
|
60
54
|
}
|
|
61
|
-
// Validate the object pointer WHENEVER it is provided
|
|
62
|
-
//
|
|
55
|
+
// Validate the object pointer WHENEVER it is provided, not only when memory is null:
|
|
56
|
+
// a dual-set row whose object is wrong/closed/cross-tenant would become
|
|
63
57
|
// the active provenance after ON DELETE SET NULL and could then block the memory delete.
|
|
64
58
|
if (sourceObject != null) {
|
|
65
59
|
const table = SOURCE_OBJECT_TABLE[sourceObject.type];
|
|
@@ -79,7 +73,7 @@ function resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, label)
|
|
|
79
73
|
}
|
|
80
74
|
}
|
|
81
75
|
// source_kind is the memory's kind when a memory is present, else 'distilled' for an
|
|
82
|
-
// object-only row (
|
|
76
|
+
// object-only row (objects are consolidated by construction). All-null is rejected.
|
|
83
77
|
if (memKind != null)
|
|
84
78
|
return { sourceKind: memKind, memoryId: effectiveMemoryId };
|
|
85
79
|
if (sourceObject != null)
|
|
@@ -170,12 +164,11 @@ export function insertRelation(hippoRoot, tenantId, opts, txDb) {
|
|
|
170
164
|
}
|
|
171
165
|
}
|
|
172
166
|
// ---------------------------------------------------------------------------
|
|
173
|
-
// Extraction queue
|
|
167
|
+
// Extraction queue
|
|
174
168
|
// ---------------------------------------------------------------------------
|
|
175
169
|
/**
|
|
176
170
|
* Enqueue a consolidated memory for later graph extraction. Rejects a raw / missing /
|
|
177
|
-
* cross-tenant memory (the DB trigger is the backstop).
|
|
178
|
-
* `hippo sleep` is deferred (E3.1); this is the API it will call.
|
|
171
|
+
* cross-tenant memory (the DB trigger is the backstop).
|
|
179
172
|
*/
|
|
180
173
|
export function enqueueExtraction(hippoRoot, tenantId, memoryId) {
|
|
181
174
|
assertTenantId('enqueueExtraction', tenantId);
|
|
@@ -241,7 +234,7 @@ export function markExtractionProcessed(hippoRoot, tenantId, id, status = 'proce
|
|
|
241
234
|
* the number of entities deleted. The rebuild primitive for graph extraction: the
|
|
242
235
|
* deterministic graph is a pure derived function of the consolidated objects, so an
|
|
243
236
|
* extract clears then re-derives. Lives in graph.ts (the sole sanctioned graph
|
|
244
|
-
* writer), so the
|
|
237
|
+
* writer), so the CI lint permits this `DELETE FROM entities`. Does NOT touch
|
|
245
238
|
* graph_extraction_queue (the enqueue-hook's domain).
|
|
246
239
|
*/
|
|
247
240
|
export function clearGraph(hippoRoot, tenantId, txDb) {
|
|
@@ -292,14 +285,14 @@ export function runGraphRebuildTransaction(hippoRoot, tenantId, fn) {
|
|
|
292
285
|
}
|
|
293
286
|
}
|
|
294
287
|
// ---------------------------------------------------------------------------
|
|
295
|
-
//
|
|
288
|
+
// Sleep enqueue-hook: producer helper + drain support
|
|
296
289
|
// ---------------------------------------------------------------------------
|
|
297
290
|
/**
|
|
298
291
|
* Fail-soft producer hook: mark a tenant dirty for graph re-extraction by
|
|
299
292
|
* enqueuing its consolidated mirror memory. NEVER throws into the caller — a
|
|
300
|
-
* graph-dirty signal failing must not abort a core
|
|
293
|
+
* graph-dirty signal failing must not abort a core object write. Graph staleness is
|
|
301
294
|
* recoverable (next sleep / manual `graph extract`); a broken `hippo decide` is
|
|
302
|
-
* not. Called POST-COMMIT from the
|
|
295
|
+
* not. Called POST-COMMIT from the graph-source save/close mutations of
|
|
303
296
|
* decision, policy, customer_note and project_brief. A null memoryId (a
|
|
304
297
|
* forgotten mirror) is a no-op.
|
|
305
298
|
*/
|
|
@@ -311,16 +304,16 @@ export function markGraphDirty(hippoRoot, tenantId, memoryId) {
|
|
|
311
304
|
}
|
|
312
305
|
catch (err) {
|
|
313
306
|
// Logged (warn) so a SYSTEMATIC enqueue failure surfaces to operators, but
|
|
314
|
-
// swallowed so the already-committed
|
|
307
|
+
// swallowed so the already-committed object write is never rolled back.
|
|
315
308
|
log.warn(`markGraphDirty: enqueue failed for tenant=${tenantId} memory=${memoryId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
316
309
|
}
|
|
317
310
|
}
|
|
318
311
|
/**
|
|
319
|
-
* Remove the graph rows sourced from one
|
|
312
|
+
* Remove the graph rows sourced from one first-class object, by its (type, id). Used when a
|
|
320
313
|
* MIRRORLESS object is closed: it has no mirror memory, so `markGraphDirty` cannot
|
|
321
314
|
* enqueue a rebuild (the queue is memory-keyed). Closing must still drop the object's
|
|
322
315
|
* now-stale entity + edges from the graph, so we remove them directly here. Fail-soft
|
|
323
|
-
* like `markGraphDirty` (never throws into the
|
|
316
|
+
* like `markGraphDirty` (never throws into the object close caller; graph staleness is
|
|
324
317
|
* recoverable). Deleting the entity cascade-deletes any relation where it is an endpoint
|
|
325
318
|
* (relations FK entities ON DELETE CASCADE); the explicit relations DELETE also covers a
|
|
326
319
|
* relation whose OWN provenance is this object (defensive — every such edge has the object
|
package/dist/graph-extract.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* (docs/plans/2026-06-01-e3-deterministic-extraction.md).
|
|
2
|
+
* Deterministic entity extraction.
|
|
4
3
|
*
|
|
5
|
-
* Populates the
|
|
4
|
+
* Populates the graph from the already-structured consolidated first-class object tables -
|
|
6
5
|
* NO NLP, no precision gate for entities + supersedes. The graph is a pure derived
|
|
7
|
-
* function of the current
|
|
6
|
+
* function of the current object state, so `extractGraph` is an idempotent REBUILD: clear
|
|
8
7
|
* the tenant's graph, then re-derive entities + `supersedes` relations from decisions /
|
|
9
|
-
* policies / customer_notes / project_briefs (the four
|
|
8
|
+
* policies / customer_notes / project_briefs (the four object types whose kind maps to the
|
|
10
9
|
* `entity_type` enum). All writes go through the src/graph.ts consolidated-source guard
|
|
11
10
|
* (insertEntity / insertRelation / clearGraph); this module issues no raw SQL.
|
|
12
11
|
*
|
|
13
|
-
* Pass 3
|
|
12
|
+
* Pass 3 adds the
|
|
14
13
|
* first CROSS-OBJECT relations: a deterministic NAME-MATCH heuristic that emits a
|
|
15
14
|
* `references` edge when one consolidated object's text contains another entity's name.
|
|
16
15
|
* It is conservative (word-boundary, length-bounded, ambiguity-guarded, per-source
|
|
@@ -47,9 +46,9 @@ export interface ExtractResult {
|
|
|
47
46
|
truncated: string[];
|
|
48
47
|
}
|
|
49
48
|
/**
|
|
50
|
-
* Idempotent rebuild of the tenant's deterministic graph from its consolidated
|
|
49
|
+
* Idempotent rebuild of the tenant's deterministic graph from its consolidated first-class
|
|
51
50
|
* objects. Returns the entity/relation counts (+ which types were truncated at the
|
|
52
|
-
* per-type cap). Safe to re-run: output is a pure function of the current
|
|
51
|
+
* per-type cap). Safe to re-run: output is a pure function of the current object state.
|
|
53
52
|
*/
|
|
54
53
|
export declare function extractGraph(hippoRoot: string, tenantId: string): ExtractResult;
|
|
55
54
|
//# sourceMappingURL=graph-extract.d.ts.map
|