@atomicmemory/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE +201 -0
- package/README.md +314 -0
- package/dist/app/bind-ephemeral.d.ts +18 -0
- package/dist/app/bind-ephemeral.js +22 -0
- package/dist/app/cors-headers.d.ts +12 -0
- package/dist/app/cors-headers.js +18 -0
- package/dist/app/create-app.d.ts +25 -0
- package/dist/app/create-app.js +156 -0
- package/dist/app/runtime-config-route-snapshot.d.ts +27 -0
- package/dist/app/runtime-config-route-snapshot.js +27 -0
- package/dist/app/runtime-container.d.ts +281 -0
- package/dist/app/runtime-container.js +297 -0
- package/dist/app/startup-checks.d.ts +28 -0
- package/dist/app/startup-checks.js +45 -0
- package/dist/bin.d.ts +17 -0
- package/dist/bin.js +128 -0
- package/dist/config.d.ts +680 -0
- package/dist/config.js +808 -0
- package/dist/db/agent-trust-repository.d.ts +49 -0
- package/dist/db/agent-trust-repository.js +66 -0
- package/dist/db/belief-edges-repository.d.ts +68 -0
- package/dist/db/belief-edges-repository.js +124 -0
- package/dist/db/claim-repository.d.ts +6 -0
- package/dist/db/claim-repository.js +4 -0
- package/dist/db/contradictions-repository.d.ts +56 -0
- package/dist/db/contradictions-repository.js +88 -0
- package/dist/db/document-chunk-repository.d.ts +48 -0
- package/dist/db/document-chunk-repository.js +145 -0
- package/dist/db/document-chunk-types.d.ts +35 -0
- package/dist/db/document-chunk-types.js +9 -0
- package/dist/db/document-list-cursor.d.ts +45 -0
- package/dist/db/document-list-cursor.js +111 -0
- package/dist/db/document-list-repository.d.ts +103 -0
- package/dist/db/document-list-repository.js +204 -0
- package/dist/db/entity-cards-repository.d.ts +37 -0
- package/dist/db/entity-cards-repository.js +46 -0
- package/dist/db/entity-values-repository.d.ts +26 -0
- package/dist/db/entity-values-repository.js +57 -0
- package/dist/db/link-repository.d.ts +30 -0
- package/dist/db/link-repository.js +54 -0
- package/dist/db/memory-repository.d.ts +163 -0
- package/dist/db/memory-repository.js +232 -0
- package/dist/db/migrate.d.ts +6 -0
- package/dist/db/migrate.js +36 -0
- package/dist/db/mmr.d.ts +14 -0
- package/dist/db/mmr.js +57 -0
- package/dist/db/passport-feed-repository.d.ts +91 -0
- package/dist/db/passport-feed-repository.js +198 -0
- package/dist/db/pg-episode-store.d.ts +19 -0
- package/dist/db/pg-episode-store.js +17 -0
- package/dist/db/pg-link-store.d.ts +17 -0
- package/dist/db/pg-link-store.js +14 -0
- package/dist/db/pg-memory-store.d.ts +68 -0
- package/dist/db/pg-memory-store.js +53 -0
- package/dist/db/pg-recap-store.d.ts +13 -0
- package/dist/db/pg-recap-store.js +19 -0
- package/dist/db/pg-representation-store.d.ts +17 -0
- package/dist/db/pg-representation-store.js +17 -0
- package/dist/db/pg-search-store.d.ts +29 -0
- package/dist/db/pg-search-store.js +47 -0
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +21 -0
- package/dist/db/ppr.d.ts +56 -0
- package/dist/db/ppr.js +178 -0
- package/dist/db/query-helpers.d.ts +44 -0
- package/dist/db/query-helpers.js +60 -0
- package/dist/db/raw-doc-artifact-sync.d.ts +128 -0
- package/dist/db/raw-doc-artifact-sync.js +259 -0
- package/dist/db/raw-document-blob-repository.d.ts +148 -0
- package/dist/db/raw-document-blob-repository.js +300 -0
- package/dist/db/raw-document-repository.d.ts +104 -0
- package/dist/db/raw-document-repository.js +410 -0
- package/dist/db/raw-document-status-repository.d.ts +122 -0
- package/dist/db/raw-document-status-repository.js +183 -0
- package/dist/db/raw-document-types.d.ts +236 -0
- package/dist/db/raw-document-types.js +10 -0
- package/dist/db/raw-storage-reconciliation-repository.d.ts +110 -0
- package/dist/db/raw-storage-reconciliation-repository.js +200 -0
- package/dist/db/reflection-jobs-repository.d.ts +33 -0
- package/dist/db/reflection-jobs-repository.js +48 -0
- package/dist/db/reflections-repository.d.ts +41 -0
- package/dist/db/reflections-repository.js +83 -0
- package/dist/db/repository-claims.d.ts +141 -0
- package/dist/db/repository-claims.js +376 -0
- package/dist/db/repository-deferred-audn.d.ts +33 -0
- package/dist/db/repository-deferred-audn.js +69 -0
- package/dist/db/repository-document-delete.d.ts +53 -0
- package/dist/db/repository-document-delete.js +156 -0
- package/dist/db/repository-entities.d.ts +114 -0
- package/dist/db/repository-entities.js +317 -0
- package/dist/db/repository-entity-attributes.d.ts +41 -0
- package/dist/db/repository-entity-attributes.js +65 -0
- package/dist/db/repository-entity-graph.d.ts +32 -0
- package/dist/db/repository-entity-graph.js +87 -0
- package/dist/db/repository-first-mentions.d.ts +41 -0
- package/dist/db/repository-first-mentions.js +79 -0
- package/dist/db/repository-lessons.d.ts +51 -0
- package/dist/db/repository-lessons.js +90 -0
- package/dist/db/repository-links.d.ts +26 -0
- package/dist/db/repository-links.js +105 -0
- package/dist/db/repository-observation.d.ts +26 -0
- package/dist/db/repository-observation.js +51 -0
- package/dist/db/repository-read.d.ts +56 -0
- package/dist/db/repository-read.js +271 -0
- package/dist/db/repository-recaps.d.ts +59 -0
- package/dist/db/repository-recaps.js +158 -0
- package/dist/db/repository-representations.d.ts +48 -0
- package/dist/db/repository-representations.js +162 -0
- package/dist/db/repository-temporal-state.d.ts +35 -0
- package/dist/db/repository-temporal-state.js +46 -0
- package/dist/db/repository-tll.d.ts +88 -0
- package/dist/db/repository-tll.js +179 -0
- package/dist/db/repository-types.d.ts +313 -0
- package/dist/db/repository-types.js +142 -0
- package/dist/db/repository-user-profiles.d.ts +17 -0
- package/dist/db/repository-user-profiles.js +28 -0
- package/dist/db/repository-vector-search.d.ts +33 -0
- package/dist/db/repository-vector-search.js +373 -0
- package/dist/db/repository-wipe.d.ts +34 -0
- package/dist/db/repository-wipe.js +94 -0
- package/dist/db/repository-write.d.ts +61 -0
- package/dist/db/repository-write.js +279 -0
- package/dist/db/schema.sql +1355 -0
- package/dist/db/storage-artifact-delete-tx.d.ts +56 -0
- package/dist/db/storage-artifact-delete-tx.js +123 -0
- package/dist/db/storage-artifact-providers.d.ts +21 -0
- package/dist/db/storage-artifact-providers.js +21 -0
- package/dist/db/storage-artifact-recovery-repository.d.ts +66 -0
- package/dist/db/storage-artifact-recovery-repository.js +58 -0
- package/dist/db/storage-artifact-repository.d.ts +329 -0
- package/dist/db/storage-artifact-repository.js +497 -0
- package/dist/db/stores.d.ts +220 -0
- package/dist/db/stores.js +12 -0
- package/dist/db/summaries-repository.d.ts +74 -0
- package/dist/db/summaries-repository.js +125 -0
- package/dist/eval/beam-10m-loader.d.ts +98 -0
- package/dist/eval/beam-10m-loader.js +128 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +17 -0
- package/dist/middleware/require-bearer.d.ts +27 -0
- package/dist/middleware/require-bearer.js +60 -0
- package/dist/middleware/validate-response.d.ts +33 -0
- package/dist/middleware/validate-response.js +55 -0
- package/dist/middleware/validate.d.ts +43 -0
- package/dist/middleware/validate.js +85 -0
- package/dist/routes/agents.d.ts +13 -0
- package/dist/routes/agents.js +89 -0
- package/dist/routes/document-response-formatters.d.ts +98 -0
- package/dist/routes/document-response-formatters.js +243 -0
- package/dist/routes/documents.d.ts +74 -0
- package/dist/routes/documents.js +425 -0
- package/dist/routes/memories.d.ts +29 -0
- package/dist/routes/memories.js +725 -0
- package/dist/routes/memory-response-formatters.d.ts +179 -0
- package/dist/routes/memory-response-formatters.js +210 -0
- package/dist/routes/public-raw-storage-metadata.d.ts +54 -0
- package/dist/routes/public-raw-storage-metadata.js +56 -0
- package/dist/routes/reflect.d.ts +14 -0
- package/dist/routes/reflect.js +19 -0
- package/dist/routes/response-schema-map.d.ts +14 -0
- package/dist/routes/response-schema-map.js +69 -0
- package/dist/routes/route-errors.d.ts +12 -0
- package/dist/routes/route-errors.js +30 -0
- package/dist/routes/storage-error-handlers.d.ts +34 -0
- package/dist/routes/storage-error-handlers.js +185 -0
- package/dist/routes/storage-response-formatters.d.ts +44 -0
- package/dist/routes/storage-response-formatters.js +155 -0
- package/dist/routes/storage.d.ts +38 -0
- package/dist/routes/storage.js +369 -0
- package/dist/routes/upstream-provider-errors.d.ts +19 -0
- package/dist/routes/upstream-provider-errors.js +95 -0
- package/dist/schemas/agents.d.ts +79 -0
- package/dist/schemas/agents.js +126 -0
- package/dist/schemas/common.d.ts +110 -0
- package/dist/schemas/common.js +190 -0
- package/dist/schemas/document-list-responses.d.ts +102 -0
- package/dist/schemas/document-list-responses.js +87 -0
- package/dist/schemas/document-list-schemas.d.ts +123 -0
- package/dist/schemas/document-list-schemas.js +174 -0
- package/dist/schemas/document-response-schemas.d.ts +610 -0
- package/dist/schemas/document-response-schemas.js +264 -0
- package/dist/schemas/document-status-envelope.d.ts +48 -0
- package/dist/schemas/document-status-envelope.js +54 -0
- package/dist/schemas/documents.d.ts +292 -0
- package/dist/schemas/documents.js +449 -0
- package/dist/schemas/errors.d.ts +75 -0
- package/dist/schemas/errors.js +105 -0
- package/dist/schemas/memories.d.ts +378 -0
- package/dist/schemas/memories.js +542 -0
- package/dist/schemas/openapi.d.ts +24 -0
- package/dist/schemas/openapi.js +1038 -0
- package/dist/schemas/response-scalars.d.ts +10 -0
- package/dist/schemas/response-scalars.js +10 -0
- package/dist/schemas/responses.d.ts +536 -0
- package/dist/schemas/responses.js +350 -0
- package/dist/schemas/search-response-parts.d.ts +97 -0
- package/dist/schemas/search-response-parts.js +103 -0
- package/dist/schemas/storage-schemas.d.ts +175 -0
- package/dist/schemas/storage-schemas.js +277 -0
- package/dist/schemas/zod-setup.d.ts +15 -0
- package/dist/schemas/zod-setup.js +17 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +57 -0
- package/dist/services/abstract-query-policy.d.ts +13 -0
- package/dist/services/abstract-query-policy.js +50 -0
- package/dist/services/affinity-clustering.d.ts +66 -0
- package/dist/services/affinity-clustering.js +125 -0
- package/dist/services/agentic-retrieval.d.ts +38 -0
- package/dist/services/agentic-retrieval.js +126 -0
- package/dist/services/answer-format.d.ts +56 -0
- package/dist/services/answer-format.js +118 -0
- package/dist/services/answer-rescue.d.ts +72 -0
- package/dist/services/answer-rescue.js +177 -0
- package/dist/services/answer-verifier.d.ts +24 -0
- package/dist/services/answer-verifier.js +73 -0
- package/dist/services/api-retry.d.ts +6 -0
- package/dist/services/api-retry.js +41 -0
- package/dist/services/assistant-turn-filter.d.ts +20 -0
- package/dist/services/assistant-turn-filter.js +69 -0
- package/dist/services/atomicmem-uri.d.ts +33 -0
- package/dist/services/atomicmem-uri.js +86 -0
- package/dist/services/audit-events.d.ts +54 -0
- package/dist/services/audit-events.js +56 -0
- package/dist/services/chunked-extraction.d.ts +21 -0
- package/dist/services/chunked-extraction.js +108 -0
- package/dist/services/claim-slotting.d.ts +27 -0
- package/dist/services/claim-slotting.js +38 -0
- package/dist/services/claude-code-llm.d.ts +19 -0
- package/dist/services/claude-code-llm.js +96 -0
- package/dist/services/composite-dedup.d.ts +50 -0
- package/dist/services/composite-dedup.js +153 -0
- package/dist/services/composite-grouping.d.ts +41 -0
- package/dist/services/composite-grouping.js +111 -0
- package/dist/services/composite-staleness.d.ts +20 -0
- package/dist/services/composite-staleness.js +50 -0
- package/dist/services/conciseness-preference.d.ts +14 -0
- package/dist/services/conciseness-preference.js +42 -0
- package/dist/services/conflict-policy.d.ts +20 -0
- package/dist/services/conflict-policy.js +335 -0
- package/dist/services/consensus-extraction.d.ts +39 -0
- package/dist/services/consensus-extraction.js +147 -0
- package/dist/services/consensus-validation.d.ts +52 -0
- package/dist/services/consensus-validation.js +206 -0
- package/dist/services/consolidation-service.d.ts +60 -0
- package/dist/services/consolidation-service.js +171 -0
- package/dist/services/content-detection.d.ts +18 -0
- package/dist/services/content-detection.js +25 -0
- package/dist/services/contradiction-surfacing.d.ts +62 -0
- package/dist/services/contradiction-surfacing.js +111 -0
- package/dist/services/cost-telemetry.d.ts +39 -0
- package/dist/services/cost-telemetry.js +58 -0
- package/dist/services/counter-evidence.d.ts +34 -0
- package/dist/services/counter-evidence.js +92 -0
- package/dist/services/current-state-ranking.d.ts +21 -0
- package/dist/services/current-state-ranking.js +152 -0
- package/dist/services/deferred-audn.d.ts +47 -0
- package/dist/services/deferred-audn.js +162 -0
- package/dist/services/document-chunker.d.ts +50 -0
- package/dist/services/document-chunker.js +153 -0
- package/dist/services/document-failure-markers.d.ts +91 -0
- package/dist/services/document-failure-markers.js +305 -0
- package/dist/services/document-indexer.d.ts +122 -0
- package/dist/services/document-indexer.js +405 -0
- package/dist/services/document-service.d.ts +245 -0
- package/dist/services/document-service.js +325 -0
- package/dist/services/document-upload-artifact-sync.d.ts +80 -0
- package/dist/services/document-upload-artifact-sync.js +162 -0
- package/dist/services/document-upload-beta2-recovery.d.ts +72 -0
- package/dist/services/document-upload-beta2-recovery.js +94 -0
- package/dist/services/document-upload.d.ts +44 -0
- package/dist/services/document-upload.js +353 -0
- package/dist/services/embedding.d.ts +57 -0
- package/dist/services/embedding.js +416 -0
- package/dist/services/entity-attribute-extractor.d.ts +34 -0
- package/dist/services/entity-attribute-extractor.js +117 -0
- package/dist/services/entity-card-synthesis.d.ts +54 -0
- package/dist/services/entity-card-synthesis.js +92 -0
- package/dist/services/entity-dedup.d.ts +9 -0
- package/dist/services/entity-dedup.js +14 -0
- package/dist/services/entity-graph.d.ts +17 -0
- package/dist/services/entity-graph.js +135 -0
- package/dist/services/entropy-gate.d.ts +52 -0
- package/dist/services/entropy-gate.js +56 -0
- package/dist/services/episode-fetcher.d.ts +47 -0
- package/dist/services/episode-fetcher.js +128 -0
- package/dist/services/event-anchor-facts.d.ts +8 -0
- package/dist/services/event-anchor-facts.js +205 -0
- package/dist/services/event-chain-detector.d.ts +52 -0
- package/dist/services/event-chain-detector.js +83 -0
- package/dist/services/extraction-cache.d.ts +9 -0
- package/dist/services/extraction-cache.js +54 -0
- package/dist/services/extraction-enrichment.d.ts +9 -0
- package/dist/services/extraction-enrichment.js +223 -0
- package/dist/services/extraction.d.ts +69 -0
- package/dist/services/extraction.js +596 -0
- package/dist/services/fact-normalization.d.ts +12 -0
- package/dist/services/fact-normalization.js +248 -0
- package/dist/services/filecoin-observability.d.ts +127 -0
- package/dist/services/filecoin-observability.js +200 -0
- package/dist/services/first-mention-service.d.ts +76 -0
- package/dist/services/first-mention-service.js +186 -0
- package/dist/services/hierarchical-retrieval.d.ts +49 -0
- package/dist/services/hierarchical-retrieval.js +50 -0
- package/dist/services/ingest-fact-pipeline.d.ts +32 -0
- package/dist/services/ingest-fact-pipeline.js +212 -0
- package/dist/services/ingest-post-write.d.ts +50 -0
- package/dist/services/ingest-post-write.js +117 -0
- package/dist/services/ingest-trace.d.ts +32 -0
- package/dist/services/ingest-trace.js +60 -0
- package/dist/services/input-sanitizer.d.ts +41 -0
- package/dist/services/input-sanitizer.js +135 -0
- package/dist/services/iterative-retrieval.d.ts +26 -0
- package/dist/services/iterative-retrieval.js +139 -0
- package/dist/services/keyword-expansion.d.ts +10 -0
- package/dist/services/keyword-expansion.js +26 -0
- package/dist/services/lesson-service.d.ts +68 -0
- package/dist/services/lesson-service.js +178 -0
- package/dist/services/literal-extractor.d.ts +16 -0
- package/dist/services/literal-extractor.js +74 -0
- package/dist/services/literal-list-protection.d.ts +17 -0
- package/dist/services/literal-list-protection.js +134 -0
- package/dist/services/literal-query-expansion.d.ts +20 -0
- package/dist/services/literal-query-expansion.js +181 -0
- package/dist/services/llm.d.ts +61 -0
- package/dist/services/llm.js +265 -0
- package/dist/services/memcell-projection.d.ts +17 -0
- package/dist/services/memcell-projection.js +41 -0
- package/dist/services/memory-audn.d.ts +43 -0
- package/dist/services/memory-audn.js +419 -0
- package/dist/services/memory-crud.d.ts +93 -0
- package/dist/services/memory-crud.js +255 -0
- package/dist/services/memory-ingest.d.ts +21 -0
- package/dist/services/memory-ingest.js +249 -0
- package/dist/services/memory-lifecycle.d.ts +75 -0
- package/dist/services/memory-lifecycle.js +108 -0
- package/dist/services/memory-lineage.d.ts +181 -0
- package/dist/services/memory-lineage.js +232 -0
- package/dist/services/memory-network.d.ts +40 -0
- package/dist/services/memory-network.js +75 -0
- package/dist/services/memory-search-types.d.ts +25 -0
- package/dist/services/memory-search-types.js +10 -0
- package/dist/services/memory-search.d.ts +48 -0
- package/dist/services/memory-search.js +505 -0
- package/dist/services/memory-service-types.d.ts +371 -0
- package/dist/services/memory-service-types.js +8 -0
- package/dist/services/memory-service.d.ts +152 -0
- package/dist/services/memory-service.js +225 -0
- package/dist/services/memory-storage.d.ts +33 -0
- package/dist/services/memory-storage.js +328 -0
- package/dist/services/msr-aggregator.d.ts +38 -0
- package/dist/services/msr-aggregator.js +97 -0
- package/dist/services/msr-detector.d.ts +35 -0
- package/dist/services/msr-detector.js +65 -0
- package/dist/services/namespace-retrieval.d.ts +60 -0
- package/dist/services/namespace-retrieval.js +180 -0
- package/dist/services/observation-date-extraction.d.ts +12 -0
- package/dist/services/observation-date-extraction.js +50 -0
- package/dist/services/observation-service.d.ts +27 -0
- package/dist/services/observation-service.js +84 -0
- package/dist/services/packaging-observability.d.ts +29 -0
- package/dist/services/packaging-observability.js +146 -0
- package/dist/services/query-expansion.d.ts +83 -0
- package/dist/services/query-expansion.js +242 -0
- package/dist/services/query-keyword-matches.d.ts +6 -0
- package/dist/services/query-keyword-matches.js +56 -0
- package/dist/services/query-term-visibility.d.ts +28 -0
- package/dist/services/query-term-visibility.js +100 -0
- package/dist/services/quick-extraction.d.ts +25 -0
- package/dist/services/quick-extraction.js +431 -0
- package/dist/services/quoted-entity-extraction.d.ts +10 -0
- package/dist/services/quoted-entity-extraction.js +161 -0
- package/dist/services/raw-storage-reconciler-backoff.d.ts +8 -0
- package/dist/services/raw-storage-reconciler-backoff.js +14 -0
- package/dist/services/raw-storage-reconciler-scheduler.d.ts +29 -0
- package/dist/services/raw-storage-reconciler-scheduler.js +43 -0
- package/dist/services/raw-storage-reconciler.d.ts +71 -0
- package/dist/services/raw-storage-reconciler.js +278 -0
- package/dist/services/recap-builder.d.ts +49 -0
- package/dist/services/recap-builder.js +157 -0
- package/dist/services/reflect-jobs.d.ts +23 -0
- package/dist/services/reflect-jobs.js +36 -0
- package/dist/services/reflect-prompts.d.ts +71 -0
- package/dist/services/reflect-prompts.js +99 -0
- package/dist/services/reflect-retrieval.d.ts +33 -0
- package/dist/services/reflect-retrieval.js +30 -0
- package/dist/services/reflect.d.ts +49 -0
- package/dist/services/reflect.js +84 -0
- package/dist/services/relative-temporal.d.ts +14 -0
- package/dist/services/relative-temporal.js +163 -0
- package/dist/services/relevance-policy.d.ts +37 -0
- package/dist/services/relevance-policy.js +109 -0
- package/dist/services/rerank.d.ts +32 -0
- package/dist/services/rerank.js +118 -0
- package/dist/services/reranker.d.ts +20 -0
- package/dist/services/reranker.js +99 -0
- package/dist/services/retrieval-channel-rules.d.ts +34 -0
- package/dist/services/retrieval-channel-rules.js +41 -0
- package/dist/services/retrieval-config-overlay.d.ts +36 -0
- package/dist/services/retrieval-config-overlay.js +44 -0
- package/dist/services/retrieval-format.d.ts +119 -0
- package/dist/services/retrieval-format.js +559 -0
- package/dist/services/retrieval-policy.d.ts +69 -0
- package/dist/services/retrieval-policy.js +275 -0
- package/dist/services/retrieval-profiles.d.ts +37 -0
- package/dist/services/retrieval-profiles.js +90 -0
- package/dist/services/retrieval-side-effects.d.ts +14 -0
- package/dist/services/retrieval-side-effects.js +26 -0
- package/dist/services/retrieval-trace.d.ts +108 -0
- package/dist/services/retrieval-trace.js +147 -0
- package/dist/services/rrf-fusion.d.ts +18 -0
- package/dist/services/rrf-fusion.js +34 -0
- package/dist/services/search-pipeline.d.ts +71 -0
- package/dist/services/search-pipeline.js +788 -0
- package/dist/services/session-date.d.ts +20 -0
- package/dist/services/session-date.js +61 -0
- package/dist/services/session-packaging.d.ts +53 -0
- package/dist/services/session-packaging.js +182 -0
- package/dist/services/session-summary-generator.d.ts +53 -0
- package/dist/services/session-summary-generator.js +134 -0
- package/dist/services/specialists/cr-specialist.d.ts +52 -0
- package/dist/services/specialists/cr-specialist.js +121 -0
- package/dist/services/specialists/dispatch.d.ts +53 -0
- package/dist/services/specialists/dispatch.js +102 -0
- package/dist/services/specialists/ie-ku-specialist.d.ts +37 -0
- package/dist/services/specialists/ie-ku-specialist.js +63 -0
- package/dist/services/specialists/msr-specialist.d.ts +61 -0
- package/dist/services/specialists/msr-specialist.js +162 -0
- package/dist/services/specialists/tr-specialist.d.ts +37 -0
- package/dist/services/specialists/tr-specialist.js +146 -0
- package/dist/services/storage-key-prefix.d.ts +42 -0
- package/dist/services/storage-key-prefix.js +45 -0
- package/dist/services/storage-put-recovery.d.ts +71 -0
- package/dist/services/storage-put-recovery.js +269 -0
- package/dist/services/storage-service-errors.d.ts +124 -0
- package/dist/services/storage-service-errors.js +189 -0
- package/dist/services/storage-service.d.ts +176 -0
- package/dist/services/storage-service.js +423 -0
- package/dist/services/subject-aware-ranking.d.ts +19 -0
- package/dist/services/subject-aware-ranking.js +161 -0
- package/dist/services/supplemental-extraction.d.ts +7 -0
- package/dist/services/supplemental-extraction.js +116 -0
- package/dist/services/tbc-execution.d.ts +49 -0
- package/dist/services/tbc-execution.js +284 -0
- package/dist/services/temporal-classifier.d.ts +56 -0
- package/dist/services/temporal-classifier.js +94 -0
- package/dist/services/temporal-endpoint-evidence.d.ts +12 -0
- package/dist/services/temporal-endpoint-evidence.js +313 -0
- package/dist/services/temporal-fingerprint.d.ts +6 -0
- package/dist/services/temporal-fingerprint.js +12 -0
- package/dist/services/temporal-format.d.ts +9 -0
- package/dist/services/temporal-format.js +21 -0
- package/dist/services/temporal-intent.d.ts +39 -0
- package/dist/services/temporal-intent.js +78 -0
- package/dist/services/temporal-query-constraints.d.ts +16 -0
- package/dist/services/temporal-query-constraints.js +107 -0
- package/dist/services/temporal-query-expansion.d.ts +14 -0
- package/dist/services/temporal-query-expansion.js +131 -0
- package/dist/services/temporal-rerank.d.ts +22 -0
- package/dist/services/temporal-rerank.js +47 -0
- package/dist/services/temporal-result-protection.d.ts +7 -0
- package/dist/services/temporal-result-protection.js +60 -0
- package/dist/services/temporal-state-write.d.ts +57 -0
- package/dist/services/temporal-state-write.js +45 -0
- package/dist/services/tiered-context.d.ts +87 -0
- package/dist/services/tiered-context.js +214 -0
- package/dist/services/tiered-loading.d.ts +88 -0
- package/dist/services/tiered-loading.js +263 -0
- package/dist/services/timeline-pack.d.ts +36 -0
- package/dist/services/timeline-pack.js +50 -0
- package/dist/services/timing.d.ts +13 -0
- package/dist/services/timing.js +72 -0
- package/dist/services/tll-augmentation.d.ts +20 -0
- package/dist/services/tll-augmentation.js +125 -0
- package/dist/services/tll-retrieval.d.ts +55 -0
- package/dist/services/tll-retrieval.js +101 -0
- package/dist/services/topic-abstraction.d.ts +36 -0
- package/dist/services/topic-abstraction.js +105 -0
- package/dist/services/trust-scoring.d.ts +43 -0
- package/dist/services/trust-scoring.js +89 -0
- package/dist/services/typed-belief-calculus.d.ts +126 -0
- package/dist/services/typed-belief-calculus.js +204 -0
- package/dist/services/upload-config.d.ts +34 -0
- package/dist/services/upload-config.js +23 -0
- package/dist/services/upload-decision.d.ts +65 -0
- package/dist/services/upload-decision.js +98 -0
- package/dist/services/upload-helpers.d.ts +107 -0
- package/dist/services/upload-helpers.js +148 -0
- package/dist/services/user-profile-builder.d.ts +22 -0
- package/dist/services/user-profile-builder.js +109 -0
- package/dist/services/voyage-embedding.d.ts +22 -0
- package/dist/services/voyage-embedding.js +77 -0
- package/dist/services/write-security.d.ts +31 -0
- package/dist/services/write-security.js +64 -0
- package/dist/storage/artifact-public-redaction.d.ts +34 -0
- package/dist/storage/artifact-public-redaction.js +83 -0
- package/dist/storage/cleanup.d.ts +103 -0
- package/dist/storage/cleanup.js +138 -0
- package/dist/storage/codec-factory.d.ts +17 -0
- package/dist/storage/codec-factory.js +33 -0
- package/dist/storage/codecs/aes-gcm-codec.d.ts +44 -0
- package/dist/storage/codecs/aes-gcm-codec.js +108 -0
- package/dist/storage/codecs/noop-codec.d.ts +16 -0
- package/dist/storage/codecs/noop-codec.js +23 -0
- package/dist/storage/factory.d.ts +44 -0
- package/dist/storage/factory.js +99 -0
- package/dist/storage/filecoin-cid-validation.d.ts +82 -0
- package/dist/storage/filecoin-cid-validation.js +122 -0
- package/dist/storage/filecoin-public-metadata.d.ts +73 -0
- package/dist/storage/filecoin-public-metadata.js +110 -0
- package/dist/storage/local-fs-store.d.ts +39 -0
- package/dist/storage/local-fs-store.js +145 -0
- package/dist/storage/pointer-uri-allowlist.d.ts +38 -0
- package/dist/storage/pointer-uri-allowlist.js +70 -0
- package/dist/storage/provider-metadata-projection.d.ts +27 -0
- package/dist/storage/provider-metadata-projection.js +68 -0
- package/dist/storage/providers/filecoin/backend.d.ts +42 -0
- package/dist/storage/providers/filecoin/backend.js +250 -0
- package/dist/storage/providers/filecoin/config.d.ts +70 -0
- package/dist/storage/providers/filecoin/config.js +275 -0
- package/dist/storage/providers/filecoin/errors.d.ts +45 -0
- package/dist/storage/providers/filecoin/errors.js +56 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.d.ts +78 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.js +155 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.d.ts +92 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.js +199 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.d.ts +58 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.js +103 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.d.ts +30 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.js +53 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.d.ts +111 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.js +87 -0
- package/dist/storage/providers/filecoin/hints.d.ts +71 -0
- package/dist/storage/providers/filecoin/hints.js +123 -0
- package/dist/storage/providers/filecoin/index.d.ts +51 -0
- package/dist/storage/providers/filecoin/index.js +103 -0
- package/dist/storage/providers/filecoin/ipfs-cid.d.ts +50 -0
- package/dist/storage/providers/filecoin/ipfs-cid.js +64 -0
- package/dist/storage/providers/filecoin/metadata.d.ts +72 -0
- package/dist/storage/providers/filecoin/metadata.js +137 -0
- package/dist/storage/providers/filecoin/piece-cid.d.ts +48 -0
- package/dist/storage/providers/filecoin/piece-cid.js +57 -0
- package/dist/storage/providers/filecoin/provider-client.d.ts +234 -0
- package/dist/storage/providers/filecoin/provider-client.js +27 -0
- package/dist/storage/providers/filecoin/readiness.d.ts +62 -0
- package/dist/storage/providers/filecoin/readiness.js +85 -0
- package/dist/storage/providers/filecoin/retriever.d.ts +82 -0
- package/dist/storage/providers/filecoin/retriever.js +63 -0
- package/dist/storage/providers/filecoin/skeleton-client.d.ts +36 -0
- package/dist/storage/providers/filecoin/skeleton-client.js +55 -0
- package/dist/storage/providers/filecoin/synapse-client.d.ts +169 -0
- package/dist/storage/providers/filecoin/synapse-client.js +343 -0
- package/dist/storage/providers/filecoin/synapse-construction.d.ts +26 -0
- package/dist/storage/providers/filecoin/synapse-construction.js +47 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.d.ts +23 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.js +49 -0
- package/dist/storage/providers/filecoin/synapse-readiness.d.ts +37 -0
- package/dist/storage/providers/filecoin/synapse-readiness.js +231 -0
- package/dist/storage/providers/filecoin/uri.d.ts +49 -0
- package/dist/storage/providers/filecoin/uri.js +84 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.d.ts +77 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.js +196 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.d.ts +54 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.js +81 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.d.ts +71 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.js +94 -0
- package/dist/storage/raw-content-codec.d.ts +89 -0
- package/dist/storage/raw-content-codec.js +47 -0
- package/dist/storage/raw-content-store-backend-adapter.d.ts +28 -0
- package/dist/storage/raw-content-store-backend-adapter.js +67 -0
- package/dist/storage/raw-content-store.d.ts +228 -0
- package/dist/storage/raw-content-store.js +27 -0
- package/dist/storage/s3-store.d.ts +42 -0
- package/dist/storage/s3-store.js +181 -0
- package/dist/storage/storage-backend-registry.d.ts +58 -0
- package/dist/storage/storage-backend-registry.js +56 -0
- package/dist/storage/storage-backend.d.ts +82 -0
- package/dist/storage/storage-backend.js +14 -0
- package/dist/storage/storage-capabilities.d.ts +56 -0
- package/dist/storage/storage-capabilities.js +170 -0
- package/dist/storage/store-registry.d.ts +67 -0
- package/dist/storage/store-registry.js +77 -0
- package/dist/vector-math.d.ts +15 -0
- package/dist/vector-math.js +31 -0
- package/dist/xml-escape.d.ts +5 -0
- package/dist/xml-escape.js +7 -0
- package/openapi.json +15395 -0
- package/openapi.yaml +10794 -0
- package/package.json +119 -0
|
@@ -0,0 +1,1355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* atomicmemory-core Schema — active memory projection plus contradiction-safe
|
|
3
|
+
* claim/version history. Idempotent: safe to re-run on every startup.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: This schema uses CREATE TABLE/INDEX IF NOT EXISTS so it can run
|
|
6
|
+
* on every app startup without data loss. Adding new columns to existing tables
|
|
7
|
+
* requires explicit ALTER TABLE ... ADD COLUMN IF NOT EXISTS statements — a
|
|
8
|
+
* plain column definition inside CREATE TABLE IF NOT EXISTS will be silently
|
|
9
|
+
* ignored if the table already exists.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
13
|
+
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS episodes (
|
|
16
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
17
|
+
user_id TEXT NOT NULL,
|
|
18
|
+
content TEXT NOT NULL,
|
|
19
|
+
source_site TEXT NOT NULL,
|
|
20
|
+
source_url TEXT NOT NULL DEFAULT '',
|
|
21
|
+
session_id TEXT,
|
|
22
|
+
workspace_id UUID DEFAULT NULL,
|
|
23
|
+
agent_id UUID DEFAULT NULL,
|
|
24
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_episodes_user_site ON episodes (user_id, source_site);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS canonical_memory_objects (
|
|
30
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
31
|
+
user_id TEXT NOT NULL,
|
|
32
|
+
object_family TEXT NOT NULL
|
|
33
|
+
CHECK (object_family IN ('ingested_fact')),
|
|
34
|
+
payload_format TEXT NOT NULL DEFAULT 'json',
|
|
35
|
+
canonical_payload JSONB NOT NULL,
|
|
36
|
+
provenance JSONB NOT NULL DEFAULT '{}',
|
|
37
|
+
observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
38
|
+
lineage JSONB NOT NULL DEFAULT '{}',
|
|
39
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_canonical_memory_objects_user_created
|
|
43
|
+
ON canonical_memory_objects (user_id, created_at DESC);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
46
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
47
|
+
user_id TEXT NOT NULL,
|
|
48
|
+
content TEXT NOT NULL,
|
|
49
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
50
|
+
memory_type TEXT NOT NULL DEFAULT 'semantic'
|
|
51
|
+
CHECK (memory_type IN ('episodic', 'semantic', 'procedural', 'composite')),
|
|
52
|
+
importance REAL NOT NULL DEFAULT 0.5
|
|
53
|
+
CHECK (importance >= 0.0 AND importance <= 1.0),
|
|
54
|
+
source_site TEXT NOT NULL,
|
|
55
|
+
source_url TEXT NOT NULL DEFAULT '',
|
|
56
|
+
episode_id UUID, -- FK to episodes removed: non-transactional writes with pgvector can't guarantee ordering
|
|
57
|
+
status TEXT NOT NULL DEFAULT 'active'
|
|
58
|
+
CHECK (status IN ('active', 'needs_clarification')),
|
|
59
|
+
metadata JSONB DEFAULT '{}',
|
|
60
|
+
keywords TEXT NOT NULL DEFAULT '',
|
|
61
|
+
namespace TEXT DEFAULT NULL,
|
|
62
|
+
summary TEXT NOT NULL DEFAULT '', -- L0: abstract/headline (~100 tokens)
|
|
63
|
+
overview TEXT NOT NULL DEFAULT '', -- L1: condensed overview (~1000 tokens)
|
|
64
|
+
trust_score REAL NOT NULL DEFAULT 1.0 -- Phase 3: source + content trust (0.0–1.0)
|
|
65
|
+
CHECK (trust_score >= 0.0 AND trust_score <= 1.0),
|
|
66
|
+
observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- when the conversation actually happened (vs created_at = DB insertion time)
|
|
67
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
68
|
+
last_accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
69
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
70
|
+
expired_at TIMESTAMPTZ DEFAULT NULL, -- Phase 4: set when superseded (temporal invalidation)
|
|
71
|
+
deleted_at TIMESTAMPTZ DEFAULT NULL,
|
|
72
|
+
-- Phase 7: 4-network memory separation (Hindsight-inspired)
|
|
73
|
+
network TEXT NOT NULL DEFAULT 'experience'
|
|
74
|
+
CHECK (network IN ('world', 'experience', 'opinion', 'observation')),
|
|
75
|
+
opinion_confidence REAL DEFAULT NULL
|
|
76
|
+
CHECK (opinion_confidence IS NULL OR (opinion_confidence >= 0.0 AND opinion_confidence <= 1.0)),
|
|
77
|
+
observation_subject TEXT DEFAULT NULL,
|
|
78
|
+
-- Phase 8: deferred AUDN reconciliation
|
|
79
|
+
deferred_audn BOOLEAN NOT NULL DEFAULT false,
|
|
80
|
+
audn_candidates JSONB DEFAULT NULL, -- serialized candidates for background reconciliation
|
|
81
|
+
-- Phase 9: workspace / multi-agent scoping
|
|
82
|
+
workspace_id UUID DEFAULT NULL,
|
|
83
|
+
agent_id UUID DEFAULT NULL,
|
|
84
|
+
visibility TEXT DEFAULT NULL
|
|
85
|
+
CHECK (visibility IS NULL OR visibility IN ('agent_only', 'restricted', 'workspace'))
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_memories_deferred_audn ON memories (user_id)
|
|
89
|
+
WHERE deferred_audn = true AND deleted_at IS NULL;
|
|
90
|
+
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_memories_user_site ON memories (user_id, source_site)
|
|
92
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_memories_user_created ON memories (user_id, created_at)
|
|
94
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
95
|
+
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_memories_embedding ON memories
|
|
97
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
98
|
+
WITH (m = 16, ef_construction = 200);
|
|
99
|
+
|
|
100
|
+
-- Full-text search: indexes both paraphrased content AND extracted keywords.
|
|
101
|
+
-- Keywords preserve proper nouns, dates, and project names that paraphrasing loses.
|
|
102
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS search_vector tsvector
|
|
103
|
+
GENERATED ALWAYS AS (
|
|
104
|
+
to_tsvector('english', content) || to_tsvector('simple', keywords)
|
|
105
|
+
) STORED;
|
|
106
|
+
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_memories_fts ON memories USING gin (search_vector)
|
|
108
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
109
|
+
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_memories_namespace ON memories (namespace)
|
|
111
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL AND namespace IS NOT NULL;
|
|
112
|
+
|
|
113
|
+
CREATE INDEX IF NOT EXISTS idx_memories_network ON memories (user_id, network)
|
|
114
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
115
|
+
|
|
116
|
+
CREATE INDEX IF NOT EXISTS idx_memories_workspace ON memories (workspace_id, agent_id)
|
|
117
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL AND workspace_id IS NOT NULL;
|
|
118
|
+
|
|
119
|
+
-- Visibility grants for restricted memories (workspace scoping)
|
|
120
|
+
CREATE TABLE IF NOT EXISTS memory_visibility_grants (
|
|
121
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
122
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
123
|
+
grantee_agent_id UUID NOT NULL,
|
|
124
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
125
|
+
UNIQUE (memory_id, grantee_agent_id)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_visibility_grants_memory ON memory_visibility_grants (memory_id);
|
|
129
|
+
CREATE INDEX IF NOT EXISTS idx_visibility_grants_agent ON memory_visibility_grants (grantee_agent_id);
|
|
130
|
+
|
|
131
|
+
CREATE INDEX IF NOT EXISTS idx_memories_observation_subject ON memories (user_id, observation_subject)
|
|
132
|
+
WHERE network = 'observation' AND deleted_at IS NULL AND expired_at IS NULL;
|
|
133
|
+
|
|
134
|
+
-- Workspace columns added via ALTER TABLE at the bottom of this file (Phase 5 Step 9).
|
|
135
|
+
CREATE TABLE IF NOT EXISTS memory_atomic_facts (
|
|
136
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
137
|
+
user_id TEXT NOT NULL,
|
|
138
|
+
parent_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
139
|
+
fact_text TEXT NOT NULL,
|
|
140
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
141
|
+
fact_type TEXT NOT NULL DEFAULT 'knowledge'
|
|
142
|
+
CHECK (fact_type IN ('preference', 'project', 'knowledge', 'person', 'plan')),
|
|
143
|
+
importance REAL NOT NULL DEFAULT 0.5
|
|
144
|
+
CHECK (importance >= 0.0 AND importance <= 1.0),
|
|
145
|
+
source_site TEXT NOT NULL,
|
|
146
|
+
source_url TEXT NOT NULL DEFAULT '',
|
|
147
|
+
episode_id UUID,
|
|
148
|
+
keywords TEXT NOT NULL DEFAULT '',
|
|
149
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
150
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
CREATE INDEX IF NOT EXISTS idx_memory_atomic_facts_parent ON memory_atomic_facts (parent_memory_id);
|
|
154
|
+
CREATE INDEX IF NOT EXISTS idx_memory_atomic_facts_user ON memory_atomic_facts (user_id, created_at DESC);
|
|
155
|
+
CREATE INDEX IF NOT EXISTS idx_memory_atomic_facts_embedding ON memory_atomic_facts
|
|
156
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
157
|
+
WITH (m = 16, ef_construction = 200);
|
|
158
|
+
|
|
159
|
+
ALTER TABLE memory_atomic_facts ADD COLUMN IF NOT EXISTS search_vector tsvector
|
|
160
|
+
GENERATED ALWAYS AS (
|
|
161
|
+
to_tsvector('english', fact_text) || to_tsvector('simple', keywords)
|
|
162
|
+
) STORED;
|
|
163
|
+
|
|
164
|
+
CREATE INDEX IF NOT EXISTS idx_memory_atomic_facts_fts ON memory_atomic_facts USING gin (search_vector);
|
|
165
|
+
|
|
166
|
+
-- Workspace columns added via ALTER TABLE at the bottom of this file (Phase 5 Step 9).
|
|
167
|
+
CREATE TABLE IF NOT EXISTS memory_foresight (
|
|
168
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
169
|
+
user_id TEXT NOT NULL,
|
|
170
|
+
parent_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
171
|
+
content TEXT NOT NULL,
|
|
172
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
173
|
+
foresight_type TEXT NOT NULL DEFAULT 'plan'
|
|
174
|
+
CHECK (foresight_type IN ('plan', 'goal', 'scheduled', 'expected_state')),
|
|
175
|
+
source_site TEXT NOT NULL,
|
|
176
|
+
source_url TEXT NOT NULL DEFAULT '',
|
|
177
|
+
episode_id UUID,
|
|
178
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
179
|
+
valid_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
180
|
+
valid_to TIMESTAMPTZ DEFAULT NULL,
|
|
181
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
CREATE INDEX IF NOT EXISTS idx_memory_foresight_parent ON memory_foresight (parent_memory_id);
|
|
185
|
+
CREATE INDEX IF NOT EXISTS idx_memory_foresight_user_valid ON memory_foresight (user_id, valid_from, valid_to);
|
|
186
|
+
CREATE INDEX IF NOT EXISTS idx_memory_foresight_embedding ON memory_foresight
|
|
187
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
188
|
+
WITH (m = 16, ef_construction = 200);
|
|
189
|
+
|
|
190
|
+
-- Observation regeneration trigger (async, decoupled from ingest)
|
|
191
|
+
CREATE TABLE IF NOT EXISTS observation_dirty (
|
|
192
|
+
user_id TEXT NOT NULL,
|
|
193
|
+
subject TEXT NOT NULL,
|
|
194
|
+
marked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
195
|
+
PRIMARY KEY (user_id, subject)
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
-- SCOPE_TODO: Claims are intentionally user-scoped — AUDN contradiction resolution
|
|
199
|
+
-- is cross-workspace. Workspace-scoped claims are a Phase 8+ concern.
|
|
200
|
+
CREATE TABLE IF NOT EXISTS memory_claims (
|
|
201
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
202
|
+
user_id TEXT NOT NULL,
|
|
203
|
+
claim_type TEXT NOT NULL DEFAULT 'fact',
|
|
204
|
+
status TEXT NOT NULL DEFAULT 'active'
|
|
205
|
+
CHECK (status IN ('active', 'deleted')),
|
|
206
|
+
current_version_id UUID DEFAULT NULL,
|
|
207
|
+
slot_key TEXT DEFAULT NULL,
|
|
208
|
+
subject_entity_id UUID DEFAULT NULL,
|
|
209
|
+
relation_type TEXT DEFAULT NULL
|
|
210
|
+
CHECK (relation_type IS NULL OR relation_type IN (
|
|
211
|
+
'uses', 'works_on', 'works_at', 'located_in', 'knows',
|
|
212
|
+
'prefers', 'created', 'belongs_to', 'studies', 'manages'
|
|
213
|
+
)),
|
|
214
|
+
object_entity_id UUID DEFAULT NULL,
|
|
215
|
+
valid_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
216
|
+
invalid_at TIMESTAMPTZ DEFAULT NULL,
|
|
217
|
+
invalidated_at TIMESTAMPTZ DEFAULT NULL,
|
|
218
|
+
invalidated_by_version_id UUID DEFAULT NULL,
|
|
219
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
220
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
221
|
+
CHECK (invalid_at IS NULL OR invalid_at >= valid_at)
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claims_user ON memory_claims (user_id);
|
|
225
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claims_user_valid
|
|
226
|
+
ON memory_claims (user_id, valid_at, invalid_at);
|
|
227
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claims_user_slot
|
|
228
|
+
ON memory_claims (user_id, slot_key)
|
|
229
|
+
WHERE slot_key IS NOT NULL;
|
|
230
|
+
|
|
231
|
+
-- SCOPE_TODO: Claim versions inherit user-scoped claim ownership — same rationale as memory_claims.
|
|
232
|
+
CREATE TABLE IF NOT EXISTS memory_claim_versions (
|
|
233
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
234
|
+
claim_id UUID NOT NULL REFERENCES memory_claims(id) ON DELETE CASCADE,
|
|
235
|
+
user_id TEXT NOT NULL,
|
|
236
|
+
memory_id UUID UNIQUE REFERENCES memories(id) ON DELETE SET NULL,
|
|
237
|
+
content TEXT NOT NULL,
|
|
238
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
239
|
+
importance REAL NOT NULL DEFAULT 0.5
|
|
240
|
+
CHECK (importance >= 0.0 AND importance <= 1.0),
|
|
241
|
+
source_site TEXT NOT NULL,
|
|
242
|
+
source_url TEXT NOT NULL DEFAULT '',
|
|
243
|
+
episode_id UUID /* REFERENCES episodes(id) ON DELETE SET NULL -- removed for non-transactional pgvector compat */,
|
|
244
|
+
valid_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
245
|
+
valid_to TIMESTAMPTZ DEFAULT NULL,
|
|
246
|
+
superseded_by_version_id UUID DEFAULT NULL,
|
|
247
|
+
mutation_type TEXT DEFAULT NULL
|
|
248
|
+
CHECK (mutation_type IS NULL OR mutation_type IN ('add', 'update', 'supersede', 'delete', 'clarify')),
|
|
249
|
+
mutation_reason TEXT DEFAULT NULL,
|
|
250
|
+
previous_version_id UUID DEFAULT NULL,
|
|
251
|
+
actor_model TEXT DEFAULT NULL,
|
|
252
|
+
contradiction_confidence REAL DEFAULT NULL,
|
|
253
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claim_versions_claim ON memory_claim_versions (claim_id);
|
|
257
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claim_versions_user_valid
|
|
258
|
+
ON memory_claim_versions (user_id, valid_from, valid_to);
|
|
259
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claim_versions_claim_valid
|
|
260
|
+
ON memory_claim_versions (claim_id, valid_from, valid_to);
|
|
261
|
+
|
|
262
|
+
CREATE INDEX IF NOT EXISTS idx_memory_claim_versions_embedding ON memory_claim_versions
|
|
263
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
264
|
+
WITH (m = 16, ef_construction = 200);
|
|
265
|
+
|
|
266
|
+
CREATE TABLE IF NOT EXISTS memory_evidence (
|
|
267
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
268
|
+
claim_version_id UUID NOT NULL
|
|
269
|
+
REFERENCES memory_claim_versions(id) ON DELETE CASCADE,
|
|
270
|
+
episode_id UUID /* REFERENCES episodes(id) ON DELETE SET NULL -- removed for non-transactional pgvector compat */,
|
|
271
|
+
memory_id UUID REFERENCES memories(id) ON DELETE SET NULL,
|
|
272
|
+
quote_text TEXT NOT NULL DEFAULT '',
|
|
273
|
+
speaker TEXT DEFAULT NULL,
|
|
274
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
CREATE INDEX IF NOT EXISTS idx_memory_evidence_version ON memory_evidence (claim_version_id);
|
|
278
|
+
|
|
279
|
+
-- Memory links for 1-hop link expansion (Phase 2, A-MEM style)
|
|
280
|
+
-- Bidirectional: stored as (source_id, target_id) where source_id < target_id
|
|
281
|
+
-- to avoid duplicate pairs. Query both directions at read time.
|
|
282
|
+
CREATE TABLE IF NOT EXISTS memory_links (
|
|
283
|
+
source_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
284
|
+
target_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
285
|
+
similarity REAL NOT NULL CHECK (similarity >= 0.0 AND similarity <= 1.0),
|
|
286
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
287
|
+
PRIMARY KEY (source_id, target_id)
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
CREATE INDEX IF NOT EXISTS idx_memory_links_target ON memory_links (target_id);
|
|
291
|
+
|
|
292
|
+
-- Phase 5: Entity graph — structured entities extracted from memories
|
|
293
|
+
-- SCOPE_TODO: Entities are user-global (entity dedup crosses workspace boundaries).
|
|
294
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
295
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
296
|
+
user_id TEXT NOT NULL,
|
|
297
|
+
name TEXT NOT NULL,
|
|
298
|
+
normalized_name TEXT NOT NULL,
|
|
299
|
+
entity_type TEXT NOT NULL
|
|
300
|
+
CHECK (entity_type IN ('person', 'tool', 'project', 'organization', 'place', 'concept')),
|
|
301
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
302
|
+
alias_names TEXT[] NOT NULL DEFAULT '{}',
|
|
303
|
+
normalized_alias_names TEXT[] NOT NULL DEFAULT '{}',
|
|
304
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
305
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
CREATE INDEX IF NOT EXISTS idx_entities_user ON entities (user_id);
|
|
309
|
+
CREATE INDEX IF NOT EXISTS idx_entities_user_type ON entities (user_id, entity_type);
|
|
310
|
+
CREATE INDEX IF NOT EXISTS idx_entities_user_normalized
|
|
311
|
+
ON entities (user_id, entity_type, normalized_name);
|
|
312
|
+
CREATE INDEX IF NOT EXISTS idx_entities_embedding ON entities
|
|
313
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
314
|
+
WITH (m = 16, ef_construction = 200);
|
|
315
|
+
|
|
316
|
+
-- Junction table: many memories ↔ many entities
|
|
317
|
+
CREATE TABLE IF NOT EXISTS memory_entities (
|
|
318
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
319
|
+
entity_id UUID NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
320
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
321
|
+
PRIMARY KEY (memory_id, entity_id)
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entities_entity ON memory_entities (entity_id);
|
|
325
|
+
|
|
326
|
+
-- Phase 4: Temporal Linkage List (TLL).
|
|
327
|
+
-- Per-entity sparse graph of event nodes with predecessor/successor edges.
|
|
328
|
+
-- Karpathy-minimal: append on ingest, traverse on EO/MSR/TR queries.
|
|
329
|
+
-- Targets the abilities Mem0 explicitly admits their architecture doesn't
|
|
330
|
+
-- crack at 10M (temporal reasoning, event ordering, multi-session reasoning).
|
|
331
|
+
-- The unique architectural primitive nobody has shipped publicly.
|
|
332
|
+
CREATE TABLE IF NOT EXISTS temporal_linkage_list (
|
|
333
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
334
|
+
user_id TEXT NOT NULL,
|
|
335
|
+
entity_id UUID NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
336
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
337
|
+
predecessor_memory_id UUID DEFAULT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
338
|
+
observation_date TIMESTAMPTZ NOT NULL,
|
|
339
|
+
position_in_chain INTEGER NOT NULL,
|
|
340
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
341
|
+
UNIQUE (user_id, entity_id, memory_id)
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
CREATE INDEX IF NOT EXISTS idx_tll_entity_chain
|
|
345
|
+
ON temporal_linkage_list (user_id, entity_id, position_in_chain);
|
|
346
|
+
CREATE INDEX IF NOT EXISTS idx_tll_memory
|
|
347
|
+
ON temporal_linkage_list (memory_id);
|
|
348
|
+
|
|
349
|
+
-- Defense-in-depth: unique (chain, position) so any future code path that
|
|
350
|
+
-- bypasses the advisory-lock append fails at the DB layer instead of
|
|
351
|
+
-- silently producing duplicate positions. Idempotent for fresh and
|
|
352
|
+
-- existing schemas.
|
|
353
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_tll_chain_position_unique
|
|
354
|
+
ON temporal_linkage_list (user_id, entity_id, position_in_chain);
|
|
355
|
+
|
|
356
|
+
-- Align predecessor FK with memory FK (CASCADE) so a hard-deleted memory
|
|
357
|
+
-- removes the dependent chain node instead of leaving a half-broken
|
|
358
|
+
-- predecessor pointer that breaks backward chain traversal. Idempotent:
|
|
359
|
+
-- re-applying the constraint overwrites any prior ON DELETE SET NULL
|
|
360
|
+
-- definition. Required for existing databases since the table-level
|
|
361
|
+
-- CREATE TABLE IF NOT EXISTS above does not update column constraints.
|
|
362
|
+
DO $$
|
|
363
|
+
BEGIN
|
|
364
|
+
IF EXISTS (
|
|
365
|
+
SELECT 1 FROM information_schema.table_constraints
|
|
366
|
+
WHERE table_name = 'temporal_linkage_list'
|
|
367
|
+
AND constraint_name = 'temporal_linkage_list_predecessor_memory_id_fkey'
|
|
368
|
+
) THEN
|
|
369
|
+
ALTER TABLE temporal_linkage_list
|
|
370
|
+
DROP CONSTRAINT temporal_linkage_list_predecessor_memory_id_fkey;
|
|
371
|
+
END IF;
|
|
372
|
+
ALTER TABLE temporal_linkage_list
|
|
373
|
+
ADD CONSTRAINT temporal_linkage_list_predecessor_memory_id_fkey
|
|
374
|
+
FOREIGN KEY (predecessor_memory_id) REFERENCES memories(id)
|
|
375
|
+
ON DELETE CASCADE;
|
|
376
|
+
END$$;
|
|
377
|
+
|
|
378
|
+
-- =====================================================================
|
|
379
|
+
-- First-mention events (chronological topic-introduction list)
|
|
380
|
+
-- =====================================================================
|
|
381
|
+
-- Per-user list of "the first time topic X was introduced in conversation."
|
|
382
|
+
-- Distinct from facts (which are atomic claims) and memories (which are
|
|
383
|
+
-- ingested chunks). The grain matches event-ordering rubrics:
|
|
384
|
+
-- "in what order did the user bring up these aspects."
|
|
385
|
+
--
|
|
386
|
+
-- Generated post-ingest by FirstMentionService via a single LLM call that
|
|
387
|
+
-- scans the full conversation and outputs a JSON array of first-mention
|
|
388
|
+
-- events. Idempotent on (user_id, memory_id) so re-running doesn't duplicate.
|
|
389
|
+
CREATE TABLE IF NOT EXISTS first_mention_events (
|
|
390
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
391
|
+
user_id TEXT NOT NULL,
|
|
392
|
+
topic TEXT NOT NULL,
|
|
393
|
+
turn_id INTEGER NOT NULL,
|
|
394
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
395
|
+
anchor_date TIMESTAMPTZ DEFAULT NULL,
|
|
396
|
+
position_in_conversation INTEGER NOT NULL,
|
|
397
|
+
source_site TEXT,
|
|
398
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
399
|
+
UNIQUE (user_id, memory_id)
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
CREATE INDEX IF NOT EXISTS idx_first_mention_user_position
|
|
403
|
+
ON first_mention_events (user_id, position_in_conversation);
|
|
404
|
+
|
|
405
|
+
CREATE INDEX IF NOT EXISTS idx_first_mention_user_topic
|
|
406
|
+
ON first_mention_events USING GIN (to_tsvector('english', topic));
|
|
407
|
+
|
|
408
|
+
-- Entity relations: typed, directed edges between entities with temporal validity
|
|
409
|
+
CREATE TABLE IF NOT EXISTS entity_relations (
|
|
410
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
411
|
+
user_id TEXT NOT NULL,
|
|
412
|
+
source_entity_id UUID NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
413
|
+
target_entity_id UUID NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
414
|
+
relation_type TEXT NOT NULL
|
|
415
|
+
CHECK (relation_type IN (
|
|
416
|
+
'uses', 'works_on', 'works_at', 'located_in', 'knows',
|
|
417
|
+
'prefers', 'created', 'belongs_to', 'studies', 'manages'
|
|
418
|
+
)),
|
|
419
|
+
source_memory_id UUID REFERENCES memories(id) ON DELETE SET NULL,
|
|
420
|
+
confidence REAL NOT NULL DEFAULT 1.0
|
|
421
|
+
CHECK (confidence >= 0.0 AND confidence <= 1.0),
|
|
422
|
+
valid_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
423
|
+
valid_to TIMESTAMPTZ DEFAULT NULL,
|
|
424
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
425
|
+
UNIQUE (source_entity_id, target_entity_id, relation_type)
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
CREATE INDEX IF NOT EXISTS idx_entity_relations_source ON entity_relations (source_entity_id);
|
|
429
|
+
CREATE INDEX IF NOT EXISTS idx_entity_relations_target ON entity_relations (target_entity_id);
|
|
430
|
+
CREATE INDEX IF NOT EXISTS idx_entity_relations_user ON entity_relations (user_id);
|
|
431
|
+
|
|
432
|
+
-- Phase 6: Lessons store — detected failure patterns for pre-action defense (A-MemGuard)
|
|
433
|
+
-- SCOPE_TODO: Lessons are user-global (failure patterns are personal, not per-workspace).
|
|
434
|
+
CREATE TABLE IF NOT EXISTS lessons (
|
|
435
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
436
|
+
user_id TEXT NOT NULL,
|
|
437
|
+
lesson_type TEXT NOT NULL
|
|
438
|
+
CHECK (lesson_type IN (
|
|
439
|
+
'injection_blocked', 'false_memory', 'contradiction_pattern',
|
|
440
|
+
'user_reported', 'consensus_violation', 'trust_violation'
|
|
441
|
+
)),
|
|
442
|
+
pattern TEXT NOT NULL,
|
|
443
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
444
|
+
source_memory_ids UUID[] NOT NULL DEFAULT '{}',
|
|
445
|
+
source_query TEXT DEFAULT NULL,
|
|
446
|
+
severity TEXT NOT NULL DEFAULT 'medium'
|
|
447
|
+
CHECK (severity IN ('low', 'medium', 'high', 'critical')),
|
|
448
|
+
active BOOLEAN NOT NULL DEFAULT true,
|
|
449
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
450
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
CREATE INDEX IF NOT EXISTS idx_lessons_user_active ON lessons (user_id) WHERE active = true;
|
|
454
|
+
CREATE INDEX IF NOT EXISTS idx_lessons_type ON lessons (user_id, lesson_type);
|
|
455
|
+
CREATE INDEX IF NOT EXISTS idx_lessons_embedding ON lessons
|
|
456
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
457
|
+
WITH (m = 16, ef_construction = 200);
|
|
458
|
+
|
|
459
|
+
-- Temporal metadata index (observed_at separates conversation time from DB insertion time)
|
|
460
|
+
CREATE INDEX IF NOT EXISTS idx_memories_user_observed ON memories (user_id, observed_at)
|
|
461
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
462
|
+
|
|
463
|
+
-- Agent trust levels for multi-agent conflict resolution (from hive-mind Phase 4)
|
|
464
|
+
CREATE TABLE IF NOT EXISTS agent_trust (
|
|
465
|
+
agent_id TEXT PRIMARY KEY,
|
|
466
|
+
user_id TEXT NOT NULL,
|
|
467
|
+
trust_level REAL NOT NULL DEFAULT 0.5
|
|
468
|
+
CHECK (trust_level >= 0.0 AND trust_level <= 1.0),
|
|
469
|
+
display_name TEXT DEFAULT NULL,
|
|
470
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
471
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
CREATE INDEX IF NOT EXISTS idx_agent_trust_user ON agent_trust (user_id);
|
|
475
|
+
|
|
476
|
+
-- Conflict tracking for CLARIFY escalation and auto-resolution
|
|
477
|
+
CREATE TABLE IF NOT EXISTS memory_conflicts (
|
|
478
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
479
|
+
user_id TEXT NOT NULL,
|
|
480
|
+
new_memory_id UUID REFERENCES memories(id) ON DELETE SET NULL,
|
|
481
|
+
existing_memory_id UUID REFERENCES memories(id) ON DELETE SET NULL,
|
|
482
|
+
new_agent_id TEXT DEFAULT NULL,
|
|
483
|
+
existing_agent_id TEXT DEFAULT NULL,
|
|
484
|
+
new_trust_level REAL DEFAULT NULL,
|
|
485
|
+
existing_trust_level REAL DEFAULT NULL,
|
|
486
|
+
contradiction_confidence REAL NOT NULL DEFAULT 0.5,
|
|
487
|
+
clarification_note TEXT DEFAULT NULL,
|
|
488
|
+
status TEXT NOT NULL DEFAULT 'open'
|
|
489
|
+
CHECK (status IN ('open', 'auto_resolved', 'resolved_new', 'resolved_existing', 'resolved_both')),
|
|
490
|
+
resolution_policy TEXT DEFAULT NULL,
|
|
491
|
+
resolved_at TIMESTAMPTZ DEFAULT NULL,
|
|
492
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
493
|
+
auto_resolve_after TIMESTAMPTZ DEFAULT NULL
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
CREATE INDEX IF NOT EXISTS idx_conflicts_user_status ON memory_conflicts (user_id, status)
|
|
497
|
+
WHERE status = 'open';
|
|
498
|
+
CREATE INDEX IF NOT EXISTS idx_conflicts_auto_resolve ON memory_conflicts (auto_resolve_after)
|
|
499
|
+
WHERE status = 'open' AND auto_resolve_after IS NOT NULL;
|
|
500
|
+
|
|
501
|
+
-- ---------------------------------------------------------------------------
|
|
502
|
+
-- Phase 5 Step 9: Add workspace scope columns to representation tables.
|
|
503
|
+
-- These are idempotent ALTER TABLE statements that run safely on every startup.
|
|
504
|
+
-- NULL means the row was created by user-scoped ingest (pre-Phase 5).
|
|
505
|
+
-- ---------------------------------------------------------------------------
|
|
506
|
+
|
|
507
|
+
ALTER TABLE memory_atomic_facts ADD COLUMN IF NOT EXISTS workspace_id UUID DEFAULT NULL;
|
|
508
|
+
ALTER TABLE memory_atomic_facts ADD COLUMN IF NOT EXISTS agent_id UUID DEFAULT NULL;
|
|
509
|
+
|
|
510
|
+
ALTER TABLE memory_foresight ADD COLUMN IF NOT EXISTS workspace_id UUID DEFAULT NULL;
|
|
511
|
+
ALTER TABLE memory_foresight ADD COLUMN IF NOT EXISTS agent_id UUID DEFAULT NULL;
|
|
512
|
+
|
|
513
|
+
CREATE INDEX IF NOT EXISTS idx_memory_atomic_facts_workspace
|
|
514
|
+
ON memory_atomic_facts (workspace_id) WHERE workspace_id IS NOT NULL;
|
|
515
|
+
CREATE INDEX IF NOT EXISTS idx_memory_foresight_workspace
|
|
516
|
+
ON memory_foresight (workspace_id) WHERE workspace_id IS NOT NULL;
|
|
517
|
+
|
|
518
|
+
-- ---------------------------------------------------------------------------
|
|
519
|
+
-- TBC Phase 3 (2026-05-06): Typed Belief Calculus first-class storage.
|
|
520
|
+
-- Promotes belief state from `memories.metadata` JSONB into typed columns +
|
|
521
|
+
-- a new `belief_edges` table. All additions are idempotent (IF NOT EXISTS).
|
|
522
|
+
-- Pre-migration databases stay queryable; tbc-execution.ts dual-writes
|
|
523
|
+
-- during the migration window. Design doc: docs/tbc-phase-3-schema.md.
|
|
524
|
+
-- Activated only when TBC_ENABLED=true; defaults preserve existing behavior.
|
|
525
|
+
-- ---------------------------------------------------------------------------
|
|
526
|
+
|
|
527
|
+
-- Belief confidence in [0,1]; default 1.0 = "fully believed" (matches AUDN's
|
|
528
|
+
-- no-confidence-tracking baseline).
|
|
529
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS confidence REAL DEFAULT 1.0
|
|
530
|
+
CHECK (confidence >= 0.0 AND confidence <= 1.0);
|
|
531
|
+
|
|
532
|
+
-- Belief tier — controls how the claim influences answer generation.
|
|
533
|
+
-- standard: default tier; normal weight in retrieval
|
|
534
|
+
-- directive: promoted; injected as a "must follow" rule in answer prompt
|
|
535
|
+
-- demoted: challenged; lower weight + flagged for re-evaluation
|
|
536
|
+
-- retracted: believed false; excluded from default retrieval
|
|
537
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS belief_tier TEXT DEFAULT 'standard'
|
|
538
|
+
CHECK (belief_tier IN ('standard', 'directive', 'demoted', 'retracted'));
|
|
539
|
+
|
|
540
|
+
-- The TBC operator that most recently mutated this memory.
|
|
541
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS mutation_type TEXT DEFAULT NULL
|
|
542
|
+
CHECK (mutation_type IS NULL OR mutation_type IN (
|
|
543
|
+
'AFFIRM', 'UPDATE', 'RETRACT', 'SUPERSEDE',
|
|
544
|
+
'PROMOTE', 'DEMOTE', 'EVIDENCE_FOR', 'COUNTER'
|
|
545
|
+
));
|
|
546
|
+
|
|
547
|
+
-- Tier-aware retrieval index (directives surface fast, retracted excluded).
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_memories_belief_tier
|
|
549
|
+
ON memories (user_id, belief_tier)
|
|
550
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL AND belief_tier != 'standard';
|
|
551
|
+
|
|
552
|
+
-- Confidence-weighted retrieval index (low-confidence demotion).
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_memories_confidence
|
|
554
|
+
ON memories (user_id, confidence DESC)
|
|
555
|
+
WHERE deleted_at IS NULL AND expired_at IS NULL;
|
|
556
|
+
|
|
557
|
+
-- belief_edges: typed belief graph between claims.
|
|
558
|
+
-- evidence_for: source supports target's confidence (positive weight)
|
|
559
|
+
-- counter: source contradicts target's confidence (negative weight)
|
|
560
|
+
-- supersedes: source replaces target (more specific or general)
|
|
561
|
+
-- promotes: source promoted target to directive tier
|
|
562
|
+
-- demotes: source challenged target without retracting
|
|
563
|
+
CREATE TABLE IF NOT EXISTS belief_edges (
|
|
564
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
565
|
+
user_id TEXT NOT NULL,
|
|
566
|
+
source_id UUID NOT NULL,
|
|
567
|
+
target_id UUID NOT NULL,
|
|
568
|
+
edge_type TEXT NOT NULL CHECK (edge_type IN (
|
|
569
|
+
'evidence_for', 'counter', 'supersedes', 'promotes', 'demotes'
|
|
570
|
+
)),
|
|
571
|
+
weight REAL NOT NULL DEFAULT 0.0
|
|
572
|
+
CHECK (weight >= -1.0 AND weight <= 1.0),
|
|
573
|
+
rationale TEXT NOT NULL DEFAULT '',
|
|
574
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
575
|
+
workspace_id UUID DEFAULT NULL,
|
|
576
|
+
agent_id UUID DEFAULT NULL
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
-- For "all evidence pointing at this claim" queries (queryable belief state).
|
|
580
|
+
CREATE INDEX IF NOT EXISTS idx_belief_edges_target
|
|
581
|
+
ON belief_edges (target_id, edge_type, created_at DESC);
|
|
582
|
+
|
|
583
|
+
-- For "all claims this evidence supports/counters" queries.
|
|
584
|
+
CREATE INDEX IF NOT EXISTS idx_belief_edges_source
|
|
585
|
+
ON belief_edges (source_id, edge_type);
|
|
586
|
+
|
|
587
|
+
-- User-scoped traversal (multi-tenant safety).
|
|
588
|
+
CREATE INDEX IF NOT EXISTS idx_belief_edges_user_target
|
|
589
|
+
ON belief_edges (user_id, target_id);
|
|
590
|
+
|
|
591
|
+
-- ---------------------------------------------------------------------------
|
|
592
|
+
-- Hierarchical Retrieval (2026-05-07): three-level memory hierarchy for
|
|
593
|
+
-- BEAM-10M scale (10 conversations × ~1.4M tokens each = ~14M total context).
|
|
594
|
+
-- session_summaries + conv_summaries indexed via HNSW on summary_embedding.
|
|
595
|
+
-- Activated only when HIERARCHICAL_RETRIEVAL_ENABLED=true; defaults preserve
|
|
596
|
+
-- existing flat-retrieval behavior. Design doc: docs/hierarchical-retrieval.md.
|
|
597
|
+
-- ---------------------------------------------------------------------------
|
|
598
|
+
|
|
599
|
+
CREATE TABLE IF NOT EXISTS session_summaries (
|
|
600
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
601
|
+
user_id TEXT NOT NULL,
|
|
602
|
+
session_id TEXT NOT NULL,
|
|
603
|
+
conversation_id TEXT NOT NULL,
|
|
604
|
+
session_index INTEGER NOT NULL,
|
|
605
|
+
summary_text TEXT NOT NULL,
|
|
606
|
+
summary_embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
607
|
+
topics TEXT[] NOT NULL DEFAULT '{}',
|
|
608
|
+
fact_count INTEGER NOT NULL DEFAULT 0,
|
|
609
|
+
occurred_start TIMESTAMPTZ DEFAULT NULL,
|
|
610
|
+
occurred_end TIMESTAMPTZ DEFAULT NULL,
|
|
611
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
612
|
+
workspace_id UUID DEFAULT NULL,
|
|
613
|
+
agent_id UUID DEFAULT NULL
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
CREATE TABLE IF NOT EXISTS conv_summaries (
|
|
617
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
618
|
+
user_id TEXT NOT NULL,
|
|
619
|
+
conversation_id TEXT NOT NULL,
|
|
620
|
+
summary_text TEXT NOT NULL,
|
|
621
|
+
summary_embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
622
|
+
session_count INTEGER NOT NULL DEFAULT 0,
|
|
623
|
+
fact_count INTEGER NOT NULL DEFAULT 0,
|
|
624
|
+
occurred_start TIMESTAMPTZ DEFAULT NULL,
|
|
625
|
+
occurred_end TIMESTAMPTZ DEFAULT NULL,
|
|
626
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
627
|
+
workspace_id UUID DEFAULT NULL,
|
|
628
|
+
agent_id UUID DEFAULT NULL
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
-- Stage-1 retrieval: top-K conversations by summary similarity.
|
|
632
|
+
CREATE INDEX IF NOT EXISTS idx_conv_summaries_embedding
|
|
633
|
+
ON conv_summaries USING hnsw (summary_embedding vector_cosine_ops)
|
|
634
|
+
WITH (m = 16, ef_construction = 200);
|
|
635
|
+
|
|
636
|
+
-- Stage-2 retrieval: top-K sessions within selected conversations.
|
|
637
|
+
CREATE INDEX IF NOT EXISTS idx_session_summaries_embedding
|
|
638
|
+
ON session_summaries USING hnsw (summary_embedding vector_cosine_ops)
|
|
639
|
+
WITH (m = 16, ef_construction = 200);
|
|
640
|
+
|
|
641
|
+
-- User-scoped lookups for both summary tables.
|
|
642
|
+
CREATE INDEX IF NOT EXISTS idx_session_summaries_user_conv
|
|
643
|
+
ON session_summaries (user_id, conversation_id, session_index);
|
|
644
|
+
|
|
645
|
+
CREATE INDEX IF NOT EXISTS idx_conv_summaries_user
|
|
646
|
+
ON conv_summaries (user_id, conversation_id);
|
|
647
|
+
|
|
648
|
+
-- ---------------------------------------------------------------------------
|
|
649
|
+
-- Sprint 3 (2026-05-10): Topic-abstraction layer for the EO experiment.
|
|
650
|
+
-- Per-memory conceptual topic (3-7 word LLM summary at higher abstraction
|
|
651
|
+
-- than raw facts) + its embedding. Surfaced via a dedicated RRF channel at
|
|
652
|
+
-- retrieval. Activated only when TOPIC_ABSTRACTION_ENABLED=true; defaults
|
|
653
|
+
-- preserve existing behavior on un-migrated rows. Design doc:
|
|
654
|
+
-- benchmarks-sprint3/2026-05-10-am-baseline-and-rerank-design.md.
|
|
655
|
+
-- ---------------------------------------------------------------------------
|
|
656
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS topic_abstraction TEXT NOT NULL DEFAULT '';
|
|
657
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS topic_embedding vector({{EMBEDDING_DIMENSIONS}}) DEFAULT NULL;
|
|
658
|
+
-- Pointer to the recap this memory has been consolidated into (NULL until
|
|
659
|
+
-- the Recap-layer builder runs). Used to filter out already-consolidated
|
|
660
|
+
-- memories from future recap-cluster candidates.
|
|
661
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS recap_id UUID DEFAULT NULL;
|
|
662
|
+
|
|
663
|
+
CREATE INDEX IF NOT EXISTS idx_memories_topic_embedding
|
|
664
|
+
ON memories USING hnsw (topic_embedding vector_cosine_ops)
|
|
665
|
+
WITH (m = 16, ef_construction = 200)
|
|
666
|
+
WHERE topic_embedding IS NOT NULL AND deleted_at IS NULL AND expired_at IS NULL;
|
|
667
|
+
|
|
668
|
+
-- ---------------------------------------------------------------------------
|
|
669
|
+
-- Sprint 3 (2026-05-10): Recap layer for cross-session synthesis.
|
|
670
|
+
-- A Recap is an LLM-synthesized narrative aggregating N memories that share
|
|
671
|
+
-- a conceptual topic. Surfaced via its own RRF channel at retrieval. Cog-sci
|
|
672
|
+
-- analogue: hippocampal consolidation. Three of the four next-gen memory
|
|
673
|
+
-- systems converge on this primitive (Hindsight observations, Honcho
|
|
674
|
+
-- dreaming, X-Mem Episodes, EverMemOS multi-pass restructuring). Activated
|
|
675
|
+
-- only when RECAP_LAYER_ENABLED=true.
|
|
676
|
+
-- ---------------------------------------------------------------------------
|
|
677
|
+
CREATE TABLE IF NOT EXISTS recaps (
|
|
678
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
679
|
+
user_id TEXT NOT NULL,
|
|
680
|
+
recap_text TEXT NOT NULL,
|
|
681
|
+
recap_embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
682
|
+
topic TEXT NOT NULL DEFAULT '',
|
|
683
|
+
member_memory_ids UUID[] NOT NULL DEFAULT '{}',
|
|
684
|
+
member_count INTEGER NOT NULL DEFAULT 0,
|
|
685
|
+
time_range_start TIMESTAMPTZ DEFAULT NULL,
|
|
686
|
+
time_range_end TIMESTAMPTZ DEFAULT NULL,
|
|
687
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
688
|
+
workspace_id UUID DEFAULT NULL
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
CREATE INDEX IF NOT EXISTS idx_recaps_user_topic
|
|
692
|
+
ON recaps (user_id, topic) WHERE workspace_id IS NULL;
|
|
693
|
+
|
|
694
|
+
CREATE INDEX IF NOT EXISTS idx_recaps_embedding
|
|
695
|
+
ON recaps USING hnsw (recap_embedding vector_cosine_ops)
|
|
696
|
+
WITH (m = 16, ef_construction = 200);
|
|
697
|
+
|
|
698
|
+
-- ---------------------------------------------------------------------------
|
|
699
|
+
-- Sprint 3 v1.5 (2026-05-11): user-profile channel (H2 from haiku-080).
|
|
700
|
+
-- One row per user holds the synthesized profile that is pinned to every
|
|
701
|
+
-- answer prompt. Updated by user-profile-builder.ts after each ingest
|
|
702
|
+
-- that stores >= 3 new facts. See also:
|
|
703
|
+
-- src/db/migrations/20260511_user_profiles.sql (migration provenance copy)
|
|
704
|
+
-- ---------------------------------------------------------------------------
|
|
705
|
+
CREATE TABLE IF NOT EXISTS user_profiles (
|
|
706
|
+
user_id TEXT PRIMARY KEY,
|
|
707
|
+
profile_text TEXT NOT NULL,
|
|
708
|
+
source_memory_ids TEXT[] NOT NULL,
|
|
709
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
CREATE INDEX IF NOT EXISTS user_profiles_updated_at_idx
|
|
713
|
+
ON user_profiles (updated_at DESC);
|
|
714
|
+
|
|
715
|
+
-- ---------------------------------------------------------------------------
|
|
716
|
+
-- Sprint 4 (2026-05-11): Entity-Attribute Index (EAI).
|
|
717
|
+
-- Stores (entity, attribute, value) triples extracted at ingest time, indexed
|
|
718
|
+
-- for fast lookup by entity name and/or attribute key on queries like
|
|
719
|
+
-- "how many X did I do?" or "what is my Y?". Distinct from the entity graph
|
|
720
|
+
-- (entities, entity_relations) which captures structural relations.
|
|
721
|
+
-- See also: src/db/migrations/20260511_entity_attributes.sql.
|
|
722
|
+
-- Activated only when ENTITY_ATTRIBUTES_ENABLED=true.
|
|
723
|
+
-- ---------------------------------------------------------------------------
|
|
724
|
+
CREATE TABLE IF NOT EXISTS entity_attributes (
|
|
725
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
726
|
+
user_id TEXT NOT NULL,
|
|
727
|
+
entity_name TEXT NOT NULL,
|
|
728
|
+
attribute_key TEXT NOT NULL,
|
|
729
|
+
attribute_value TEXT NOT NULL,
|
|
730
|
+
value_type TEXT NOT NULL CHECK (value_type IN ('number','string','list','boolean','date')),
|
|
731
|
+
source_memory_id UUID,
|
|
732
|
+
observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
733
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
CREATE INDEX IF NOT EXISTS idx_entity_attributes_user_entity
|
|
737
|
+
ON entity_attributes (user_id, lower(entity_name));
|
|
738
|
+
CREATE INDEX IF NOT EXISTS idx_entity_attributes_user_attribute
|
|
739
|
+
ON entity_attributes (user_id, lower(attribute_key));
|
|
740
|
+
CREATE INDEX IF NOT EXISTS idx_entity_attributes_observed
|
|
741
|
+
ON entity_attributes (user_id, observed_at DESC);
|
|
742
|
+
|
|
743
|
+
-- ---------------------------------------------------------------------------
|
|
744
|
+
-- BEAM-0.85 Phase 2 (2026-05-12): Literal value extraction for IE/KU.
|
|
745
|
+
-- Captures exact (entity, attribute, value) triples from ingested facts so
|
|
746
|
+
-- specialist lookup can answer literal factual questions via SQL.
|
|
747
|
+
-- See also: src/db/migrations/20260512_entity_values.sql.
|
|
748
|
+
-- ---------------------------------------------------------------------------
|
|
749
|
+
CREATE TABLE IF NOT EXISTS entity_values (
|
|
750
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
751
|
+
user_id TEXT NOT NULL,
|
|
752
|
+
entity TEXT NOT NULL,
|
|
753
|
+
attribute TEXT NOT NULL,
|
|
754
|
+
value TEXT NOT NULL,
|
|
755
|
+
value_type TEXT NOT NULL CHECK (value_type IN ('date', 'number', 'string', 'duration', 'list')),
|
|
756
|
+
observed_at TIMESTAMPTZ NOT NULL,
|
|
757
|
+
fact_id UUID NOT NULL,
|
|
758
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
CREATE INDEX IF NOT EXISTS ix_entity_values_lookup
|
|
762
|
+
ON entity_values (user_id, lower(entity), lower(attribute), observed_at DESC);
|
|
763
|
+
|
|
764
|
+
CREATE INDEX IF NOT EXISTS ix_entity_values_fact
|
|
765
|
+
ON entity_values (fact_id);
|
|
766
|
+
|
|
767
|
+
-- ---------------------------------------------------------------------------
|
|
768
|
+
-- BEAM-0.85 (2026-05-12): Async Reflect step storage.
|
|
769
|
+
-- Stores synthesized observations per (user_id, conversation_id), plus the
|
|
770
|
+
-- Postgres-backed queue used by the reflect worker.
|
|
771
|
+
-- See also: src/db/migrations/20260512_session_reflections.sql.
|
|
772
|
+
-- ---------------------------------------------------------------------------
|
|
773
|
+
CREATE TABLE IF NOT EXISTS session_reflections (
|
|
774
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
775
|
+
user_id TEXT NOT NULL,
|
|
776
|
+
conversation_id TEXT NOT NULL,
|
|
777
|
+
observation TEXT NOT NULL,
|
|
778
|
+
observation_type TEXT NOT NULL CHECK (observation_type IN (
|
|
779
|
+
'entity_state', 'event_summary', 'preference',
|
|
780
|
+
'contradiction', 'decision', 'numeric_value'
|
|
781
|
+
)),
|
|
782
|
+
evidence_memory_ids TEXT[] NOT NULL,
|
|
783
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}),
|
|
784
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
CREATE INDEX IF NOT EXISTS ix_session_reflections_user_conv
|
|
788
|
+
ON session_reflections (user_id, conversation_id);
|
|
789
|
+
|
|
790
|
+
CREATE INDEX IF NOT EXISTS ix_session_reflections_embedding
|
|
791
|
+
ON session_reflections USING hnsw (embedding vector_cosine_ops);
|
|
792
|
+
|
|
793
|
+
CREATE TABLE IF NOT EXISTS reflection_jobs (
|
|
794
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
795
|
+
user_id TEXT NOT NULL,
|
|
796
|
+
conversation_id TEXT NOT NULL,
|
|
797
|
+
status TEXT NOT NULL DEFAULT 'pending'
|
|
798
|
+
CHECK (status IN ('pending', 'in_progress', 'completed', 'failed')),
|
|
799
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
800
|
+
last_error TEXT,
|
|
801
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
802
|
+
last_tried_at TIMESTAMPTZ
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ix_reflection_jobs_pending_unique
|
|
806
|
+
ON reflection_jobs (user_id, conversation_id)
|
|
807
|
+
WHERE status IN ('pending', 'in_progress');
|
|
808
|
+
|
|
809
|
+
CREATE INDEX IF NOT EXISTS ix_reflection_jobs_status_created
|
|
810
|
+
ON reflection_jobs (status, created_at);
|
|
811
|
+
|
|
812
|
+
-- ---------------------------------------------------------------------------
|
|
813
|
+
-- BEAM-0.85 (2026-05-12): Always-on per-entity ENTITY_CARD channel.
|
|
814
|
+
-- Mirrors Honcho's "peer card" pattern. The Reflect worker (Sonnet 4.5)
|
|
815
|
+
-- maintains one card per (user_id, conversation_id, entity_name); the
|
|
816
|
+
-- search pipeline injects all cards for the active conversation at the top
|
|
817
|
+
-- of every answer-LLM prompt under the `## ENTITY_STATE` heading.
|
|
818
|
+
-- See also: src/db/migrations/20260512_entity_cards.sql.
|
|
819
|
+
-- Activated only when ENTITY_CARD_ENABLED=true.
|
|
820
|
+
-- ---------------------------------------------------------------------------
|
|
821
|
+
CREATE TABLE IF NOT EXISTS entity_cards (
|
|
822
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
823
|
+
user_id TEXT NOT NULL,
|
|
824
|
+
conversation_id TEXT NOT NULL,
|
|
825
|
+
entity_name TEXT NOT NULL,
|
|
826
|
+
card_text TEXT NOT NULL,
|
|
827
|
+
source_observation_ids TEXT[] NOT NULL DEFAULT '{}',
|
|
828
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
829
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
830
|
+
);
|
|
831
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ix_entity_cards_unique
|
|
832
|
+
ON entity_cards (user_id, conversation_id, entity_name);
|
|
833
|
+
CREATE INDEX IF NOT EXISTS ix_entity_cards_user_conv
|
|
834
|
+
ON entity_cards (user_id, conversation_id);
|
|
835
|
+
|
|
836
|
+
-- ---------------------------------------------------------------------------
|
|
837
|
+
-- BEAM CR fix (2026-05-12): AUDN bilateral preservation for contradictions.
|
|
838
|
+
-- When the flag-gated bilateral path fires instead of DELETE/SUPERSEDE,
|
|
839
|
+
-- both prior + new memory remain in `memories` with `contradiction_active=true`
|
|
840
|
+
-- and `contradicts_memory_id` pointing at the counterpart. A row in
|
|
841
|
+
-- `memory_contradictions` records the conflict with both summaries verbatim
|
|
842
|
+
-- so retrieval can quote BOTH sides for CR-style questions.
|
|
843
|
+
-- See also: src/db/migrations/20260512_audn_bilateral.sql.
|
|
844
|
+
-- Activated only when CONTRADICTION_PRESERVATION_ENABLED=true.
|
|
845
|
+
-- ---------------------------------------------------------------------------
|
|
846
|
+
ALTER TABLE memories
|
|
847
|
+
ADD COLUMN IF NOT EXISTS contradicts_memory_id UUID REFERENCES memories(id) ON DELETE SET NULL,
|
|
848
|
+
ADD COLUMN IF NOT EXISTS contradiction_active BOOLEAN NOT NULL DEFAULT false;
|
|
849
|
+
|
|
850
|
+
CREATE INDEX IF NOT EXISTS ix_memories_contradiction_active
|
|
851
|
+
ON memories (user_id, contradiction_active) WHERE contradiction_active = true;
|
|
852
|
+
|
|
853
|
+
CREATE TABLE IF NOT EXISTS memory_contradictions (
|
|
854
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
855
|
+
user_id TEXT NOT NULL,
|
|
856
|
+
conversation_id TEXT,
|
|
857
|
+
left_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
858
|
+
right_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
859
|
+
left_summary TEXT NOT NULL,
|
|
860
|
+
right_summary TEXT NOT NULL,
|
|
861
|
+
resolved BOOLEAN NOT NULL DEFAULT false,
|
|
862
|
+
resolution_note TEXT,
|
|
863
|
+
detected_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
CREATE INDEX IF NOT EXISTS ix_memory_contradictions_user
|
|
867
|
+
ON memory_contradictions (user_id, conversation_id);
|
|
868
|
+
CREATE INDEX IF NOT EXISTS ix_memory_contradictions_left
|
|
869
|
+
ON memory_contradictions (left_memory_id);
|
|
870
|
+
CREATE INDEX IF NOT EXISTS ix_memory_contradictions_right
|
|
871
|
+
ON memory_contradictions (right_memory_id);
|
|
872
|
+
|
|
873
|
+
-- ---------------------------------------------------------------------------
|
|
874
|
+
-- BEAM v38 (2026-05-12): Temporal state layer — focused Mem0
|
|
875
|
+
-- temporal-reasoning subset for KU lift.
|
|
876
|
+
--
|
|
877
|
+
-- Adds three columns on `memories` describing an evolving fact:
|
|
878
|
+
-- state_key stable identifier for an evolving fact ("user:1:location")
|
|
879
|
+
-- event_start when the fact became true
|
|
880
|
+
-- event_end when the fact stopped being true (NULL = still active)
|
|
881
|
+
--
|
|
882
|
+
-- See also: src/db/migrations/20260512_temporal_state.sql.
|
|
883
|
+
-- Activated only when TEMPORAL_STATE_ENABLED=true.
|
|
884
|
+
-- ---------------------------------------------------------------------------
|
|
885
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS state_key TEXT DEFAULT NULL;
|
|
886
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS event_start TIMESTAMPTZ DEFAULT NULL;
|
|
887
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS event_end TIMESTAMPTZ DEFAULT NULL;
|
|
888
|
+
|
|
889
|
+
CREATE INDEX IF NOT EXISTS idx_memories_state_key_active
|
|
890
|
+
ON memories (user_id, state_key)
|
|
891
|
+
WHERE event_end IS NULL
|
|
892
|
+
AND state_key IS NOT NULL
|
|
893
|
+
AND deleted_at IS NULL;
|
|
894
|
+
|
|
895
|
+
CREATE INDEX IF NOT EXISTS idx_memories_state_key_all
|
|
896
|
+
ON memories (user_id, state_key)
|
|
897
|
+
WHERE state_key IS NOT NULL
|
|
898
|
+
AND deleted_at IS NULL;
|
|
899
|
+
-- Document pipeline (Phase 1 of the large-file ingestion plan).
|
|
900
|
+
--
|
|
901
|
+
-- See `Atomicmemory-research/docs/core-repo/design/large-file-ingestion-and-raw-storage-plan-2026-05-08.md`.
|
|
902
|
+
--
|
|
903
|
+
-- Phase 1 ships the pointer-only document registry: `raw_sources` is a
|
|
904
|
+
-- per-(user, source_site, provider, account) namespace; `raw_documents`
|
|
905
|
+
-- represents one registered upstream object. The CHECK constraints on
|
|
906
|
+
-- `storage_mode` / `registration_status` / `raw_storage_status` accept the
|
|
907
|
+
-- full enum that later phases will populate (managed_blob, inline_text_stored,
|
|
908
|
+
-- blob_stored) so Phase 3 doesn't need a CHECK migration. The service layer
|
|
909
|
+
-- enforces `storage_mode = 'pointer_only'` until Phase 3 lands.
|
|
910
|
+
-- ---------------------------------------------------------------------------
|
|
911
|
+
|
|
912
|
+
CREATE TABLE IF NOT EXISTS raw_sources (
|
|
913
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
914
|
+
user_id TEXT NOT NULL,
|
|
915
|
+
source_site TEXT NOT NULL,
|
|
916
|
+
provider TEXT NOT NULL,
|
|
917
|
+
account_id TEXT,
|
|
918
|
+
storage_mode TEXT NOT NULL DEFAULT 'pointer_only'
|
|
919
|
+
CHECK (storage_mode IN ('pointer_only', 'managed_blob', 'inline_small_text')),
|
|
920
|
+
retention_policy JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
921
|
+
consent_policy JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
922
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
923
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
-- COALESCE(account_id, '') keeps NULL account_ids in a single namespace slot
|
|
927
|
+
-- (Postgres treats NULLs as distinct in plain unique indexes, which would let
|
|
928
|
+
-- two rows with the same user/source/provider but different consent contexts
|
|
929
|
+
-- collide).
|
|
930
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_raw_sources_namespace
|
|
931
|
+
ON raw_sources (user_id, source_site, provider, COALESCE(account_id, ''));
|
|
932
|
+
CREATE INDEX IF NOT EXISTS idx_raw_sources_user
|
|
933
|
+
ON raw_sources (user_id);
|
|
934
|
+
|
|
935
|
+
CREATE TABLE IF NOT EXISTS raw_documents (
|
|
936
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
937
|
+
user_id TEXT NOT NULL,
|
|
938
|
+
raw_source_id UUID NOT NULL REFERENCES raw_sources(id) ON DELETE CASCADE,
|
|
939
|
+
external_id TEXT NOT NULL,
|
|
940
|
+
external_uri TEXT,
|
|
941
|
+
display_name TEXT,
|
|
942
|
+
mime_type TEXT,
|
|
943
|
+
size_bytes BIGINT,
|
|
944
|
+
content_hash TEXT,
|
|
945
|
+
provider_version TEXT,
|
|
946
|
+
source_modified_at TIMESTAMPTZ,
|
|
947
|
+
storage_mode TEXT NOT NULL DEFAULT 'pointer_only'
|
|
948
|
+
CHECK (storage_mode IN ('pointer_only', 'managed_blob', 'inline_small_text')),
|
|
949
|
+
-- storage_uri / storage_provider stay NULL in Phase 1 (no managed blob).
|
|
950
|
+
storage_uri TEXT,
|
|
951
|
+
storage_provider TEXT,
|
|
952
|
+
registration_status TEXT NOT NULL DEFAULT 'registered'
|
|
953
|
+
CHECK (registration_status IN ('registered', 'registration_failed')),
|
|
954
|
+
raw_storage_status TEXT NOT NULL DEFAULT 'pointer_recorded'
|
|
955
|
+
CHECK (raw_storage_status IN
|
|
956
|
+
('pointer_recorded', 'blob_stored', 'inline_text_stored', 'raw_storage_failed', 'blob_deleted')),
|
|
957
|
+
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
958
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
959
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
960
|
+
deleted_at TIMESTAMPTZ
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
-- Phase 3 broadened the `raw_storage_status` CHECK to include
|
|
964
|
+
-- `blob_deleted` (terminal post-cleanup state for tombstoned managed-blob
|
|
965
|
+
-- rows). The Filecoin raw-content-store lifecycle refactor (Slice 2)
|
|
966
|
+
-- further broadens it to include the eventual-provider states:
|
|
967
|
+
-- * `blob_pending` — provider accepted the upload but storage /
|
|
968
|
+
-- retrievability is not yet confirmed (e.g. a Filecoin onramp
|
|
969
|
+
-- that returns before the deal is sealed). Slice 3 writes this
|
|
970
|
+
-- when `put()` returns `status: 'pending'`.
|
|
971
|
+
-- * `blob_available` — schema-reserved for the Phase 3 reconciliation
|
|
972
|
+
-- worker that promotes `blob_pending` rows once `head()` confirms
|
|
973
|
+
-- retrievability. No Phase-1 writer.
|
|
974
|
+
-- * `blob_archival_failed` — schema-reserved for the Phase 3
|
|
975
|
+
-- reconciler's permanent-failure path. No Phase-1 writer.
|
|
976
|
+
-- * `blob_tombstoned` — schema-reserved for Phase 2 Filecoin
|
|
977
|
+
-- deletes when the provider supports unpin-only semantics. No
|
|
978
|
+
-- Phase-1 writer.
|
|
979
|
+
-- * `blob_uploading` (Phase 5) — transient state during the upload
|
|
980
|
+
-- pipeline's α/β/β2/γ split. Phase α writes this with a claim_id
|
|
981
|
+
-- after seizing the slot; Phase γ flips it to the final terminal
|
|
982
|
+
-- state after the adapter returns. A row that stays in
|
|
983
|
+
-- `blob_uploading` past a process restart is recoverable via
|
|
984
|
+
-- same-bytes idempotent retry of `uploadRaw` — the reconciler
|
|
985
|
+
-- does NOT process `blob_uploading` rows.
|
|
986
|
+
-- Idempotent ALTER so the new values are accepted on existing test
|
|
987
|
+
-- DBs whose CREATE TABLE IF NOT EXISTS already locked in the prior CHECK.
|
|
988
|
+
ALTER TABLE raw_documents
|
|
989
|
+
DROP CONSTRAINT IF EXISTS raw_documents_raw_storage_status_check;
|
|
990
|
+
ALTER TABLE raw_documents
|
|
991
|
+
ADD CONSTRAINT raw_documents_raw_storage_status_check
|
|
992
|
+
CHECK (raw_storage_status IN
|
|
993
|
+
('pointer_recorded', 'blob_stored', 'inline_text_stored', 'raw_storage_failed', 'blob_deleted',
|
|
994
|
+
'blob_pending', 'blob_available', 'blob_archival_failed', 'blob_tombstoned',
|
|
995
|
+
'blob_uploading'));
|
|
996
|
+
|
|
997
|
+
-- Filecoin lifecycle refactor (Phase 5) — typed claim + scheduling
|
|
998
|
+
-- columns moved out of JSONB. The upload pipeline's α/β/β2/γ split
|
|
999
|
+
-- writes a per-row claim_id when seizing the slot; the Phase 6
|
|
1000
|
+
-- reconciler claims `blob_pending` rows on the same columns and
|
|
1001
|
+
-- advances `next_check_at` via exponential backoff. `pending_since`
|
|
1002
|
+
-- is the durable "row entered blob_pending at" timestamp the
|
|
1003
|
+
-- observability layer reads for the `pending_age_seconds` metric.
|
|
1004
|
+
ALTER TABLE raw_documents
|
|
1005
|
+
ADD COLUMN IF NOT EXISTS raw_storage_claim_id TEXT,
|
|
1006
|
+
ADD COLUMN IF NOT EXISTS raw_storage_claimed_at TIMESTAMPTZ,
|
|
1007
|
+
ADD COLUMN IF NOT EXISTS raw_storage_last_checked_at TIMESTAMPTZ,
|
|
1008
|
+
ADD COLUMN IF NOT EXISTS raw_storage_next_check_at TIMESTAMPTZ,
|
|
1009
|
+
ADD COLUMN IF NOT EXISTS raw_storage_reconcile_attempts INTEGER NOT NULL DEFAULT 0,
|
|
1010
|
+
ADD COLUMN IF NOT EXISTS raw_storage_pending_since TIMESTAMPTZ;
|
|
1011
|
+
|
|
1012
|
+
-- Provider-side metadata for the managed blob (CID, piece CID, deal
|
|
1013
|
+
-- id, onramp request id, gateway URL, etc.). Opaque to the upload
|
|
1014
|
+
-- pipeline; the adapter's `put()` returns the shape and the row
|
|
1015
|
+
-- formatter forwards it verbatim. Default `'{}'` so existing rows
|
|
1016
|
+
-- and the pointer-only path stay schema-clean.
|
|
1017
|
+
ALTER TABLE raw_documents
|
|
1018
|
+
ADD COLUMN IF NOT EXISTS raw_storage_metadata JSONB NOT NULL DEFAULT '{}'::jsonb;
|
|
1019
|
+
|
|
1020
|
+
-- Phase 2 indexing fingerprint. Distinct from `content_hash` (which is
|
|
1021
|
+
-- the upstream/provider-supplied raw-content hash) so that indexing
|
|
1022
|
+
-- never overwrites caller-provided metadata. NULL means "not yet
|
|
1023
|
+
-- indexed under the current chunker_version"; the indexer's idempotency
|
|
1024
|
+
-- check compares the input text's hash against this column.
|
|
1025
|
+
ALTER TABLE raw_documents ADD COLUMN IF NOT EXISTS indexed_content_hash TEXT;
|
|
1026
|
+
ALTER TABLE raw_documents ADD COLUMN IF NOT EXISTS indexed_at TIMESTAMPTZ;
|
|
1027
|
+
|
|
1028
|
+
-- Phase B (document-ingest hardening) — per-layer status + last_error.
|
|
1029
|
+
--
|
|
1030
|
+
-- The audit at `Atomicmemory-research/docs/core-repo/design/document-ingest-audit.md`
|
|
1031
|
+
-- and the rev-18 hardening plan call for durable, observable
|
|
1032
|
+
-- per-layer status so the UI/API stops pretending indexing is
|
|
1033
|
+
-- instant and partial failures stop creating silent orphans.
|
|
1034
|
+
--
|
|
1035
|
+
-- * extraction_status — text-extraction layer: 'not_required'
|
|
1036
|
+
-- (e.g. URL pointer with no body), 'pending' (registered, awaiting
|
|
1037
|
+
-- extraction), 'running' (in-flight), 'complete', 'unsupported'
|
|
1038
|
+
-- (`.parquet`, etc.), 'failed'.
|
|
1039
|
+
-- * semantic_index_status — chunk + embed + index pipeline:
|
|
1040
|
+
-- 'not_required', 'pending', 'running', 'complete', 'failed',
|
|
1041
|
+
-- 'stale' (re-index needed; reserved).
|
|
1042
|
+
-- * last_error — JSONB envelope `{ layer, code, message, occurred_at }`
|
|
1043
|
+
-- scoped to the most-recent failure for any layer; cleared on the
|
|
1044
|
+
-- next successful transition for that layer.
|
|
1045
|
+
--
|
|
1046
|
+
-- Cross-walk to spec naming (`Atomicmemory-research/docs/core-repo/design/ingestion-variations-supported-2026-05-09.md`):
|
|
1047
|
+
-- `raw_storage_status` retains its prior values
|
|
1048
|
+
-- (`pointer_recorded` / `blob_stored` / `inline_text_stored` /
|
|
1049
|
+
-- `raw_storage_failed` / `blob_deleted`); rename can land later if
|
|
1050
|
+
-- the migration is worth the churn.
|
|
1051
|
+
ALTER TABLE raw_documents
|
|
1052
|
+
ADD COLUMN IF NOT EXISTS extraction_status TEXT NOT NULL DEFAULT 'not_required';
|
|
1053
|
+
ALTER TABLE raw_documents
|
|
1054
|
+
ADD COLUMN IF NOT EXISTS semantic_index_status TEXT NOT NULL DEFAULT 'not_required';
|
|
1055
|
+
ALTER TABLE raw_documents ADD COLUMN IF NOT EXISTS last_error JSONB;
|
|
1056
|
+
|
|
1057
|
+
ALTER TABLE raw_documents
|
|
1058
|
+
DROP CONSTRAINT IF EXISTS raw_documents_extraction_status_check;
|
|
1059
|
+
ALTER TABLE raw_documents
|
|
1060
|
+
ADD CONSTRAINT raw_documents_extraction_status_check
|
|
1061
|
+
CHECK (extraction_status IN
|
|
1062
|
+
('not_required', 'pending', 'running', 'complete', 'unsupported', 'failed'));
|
|
1063
|
+
|
|
1064
|
+
ALTER TABLE raw_documents
|
|
1065
|
+
DROP CONSTRAINT IF EXISTS raw_documents_semantic_index_status_check;
|
|
1066
|
+
ALTER TABLE raw_documents
|
|
1067
|
+
ADD CONSTRAINT raw_documents_semantic_index_status_check
|
|
1068
|
+
CHECK (semantic_index_status IN
|
|
1069
|
+
('not_required', 'pending', 'running', 'complete', 'failed', 'stale'));
|
|
1070
|
+
|
|
1071
|
+
-- Recovery-relevant rows: documents with at least one layer in a
|
|
1072
|
+
-- failure state. Partial index keeps it small on healthy deployments.
|
|
1073
|
+
CREATE INDEX IF NOT EXISTS idx_raw_documents_status_failed
|
|
1074
|
+
ON raw_documents (user_id)
|
|
1075
|
+
WHERE deleted_at IS NULL
|
|
1076
|
+
AND (
|
|
1077
|
+
extraction_status = 'failed'
|
|
1078
|
+
OR semantic_index_status = 'failed'
|
|
1079
|
+
OR raw_storage_status = 'raw_storage_failed'
|
|
1080
|
+
);
|
|
1081
|
+
|
|
1082
|
+
-- Active-row idempotency: at most one live registration per
|
|
1083
|
+
-- (user, source, external_id, version). Soft-deleted rows are excluded so
|
|
1084
|
+
-- a re-registration after deletion creates a fresh row instead of colliding.
|
|
1085
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_raw_documents_active_unique
|
|
1086
|
+
ON raw_documents (user_id, raw_source_id, external_id, COALESCE(provider_version, ''))
|
|
1087
|
+
WHERE deleted_at IS NULL;
|
|
1088
|
+
CREATE INDEX IF NOT EXISTS idx_raw_documents_user
|
|
1089
|
+
ON raw_documents (user_id) WHERE deleted_at IS NULL;
|
|
1090
|
+
CREATE INDEX IF NOT EXISTS idx_raw_documents_source
|
|
1091
|
+
ON raw_documents (raw_source_id) WHERE deleted_at IS NULL;
|
|
1092
|
+
|
|
1093
|
+
-- Memory provenance to documents/chunks. document_chunk_id is unused in
|
|
1094
|
+
-- Phase 1 (chunks ship in Phase 2) but the column lands now so memories
|
|
1095
|
+
-- created during the Phase 1 → 2 transition don't need a backfill migration.
|
|
1096
|
+
-- No FK constraint yet — added once raw_documents/document_chunks deletion
|
|
1097
|
+
-- semantics are reviewed alongside the chunk table in Phase 2.
|
|
1098
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS raw_document_id UUID DEFAULT NULL;
|
|
1099
|
+
ALTER TABLE memories ADD COLUMN IF NOT EXISTS document_chunk_id UUID DEFAULT NULL;
|
|
1100
|
+
|
|
1101
|
+
CREATE INDEX IF NOT EXISTS idx_memories_raw_document
|
|
1102
|
+
ON memories (user_id, raw_document_id)
|
|
1103
|
+
WHERE raw_document_id IS NOT NULL AND deleted_at IS NULL;
|
|
1104
|
+
CREATE INDEX IF NOT EXISTS idx_memories_document_chunk
|
|
1105
|
+
ON memories (user_id, document_chunk_id)
|
|
1106
|
+
WHERE document_chunk_id IS NOT NULL AND deleted_at IS NULL;
|
|
1107
|
+
|
|
1108
|
+
-- Phase D — passport-feed grouped query support (rev 18).
|
|
1109
|
+
-- The `GROUP BY raw_document_id` + `ARRAY_AGG(... ORDER BY created_at
|
|
1110
|
+
-- DESC, id DESC)[1]` pattern in `passport-feed-repository.ts` lifts
|
|
1111
|
+
-- (created_at DESC, id DESC) inside each (user_id, raw_document_id)
|
|
1112
|
+
-- partition. A composite partial index on those four columns lets
|
|
1113
|
+
-- Postgres skip the secondary sort entirely on the grouped branch
|
|
1114
|
+
-- under real volume; the partial WHERE clause keeps the index lean
|
|
1115
|
+
-- (memory rows that aren't document-backed or are tombstoned never
|
|
1116
|
+
-- enter the hot path).
|
|
1117
|
+
CREATE INDEX IF NOT EXISTS idx_memories_passport_grouped
|
|
1118
|
+
ON memories (user_id, raw_document_id, created_at DESC, id DESC)
|
|
1119
|
+
WHERE raw_document_id IS NOT NULL AND deleted_at IS NULL;
|
|
1120
|
+
|
|
1121
|
+
-- Phase D — passport-feed standalone branch support (rev 18).
|
|
1122
|
+
-- The standalone-memory branch of the UNION ALL pages by
|
|
1123
|
+
-- `(created_at DESC, id DESC)` filtered to memories with
|
|
1124
|
+
-- `raw_document_id IS NULL`. The pre-existing
|
|
1125
|
+
-- `idx_memories_user_created` is the wrong shape (no IS NULL
|
|
1126
|
+
-- partial, no `id` tie-breaker). This partial index matches the
|
|
1127
|
+
-- exact predicate the cursor walks.
|
|
1128
|
+
CREATE INDEX IF NOT EXISTS idx_memories_passport_standalone
|
|
1129
|
+
ON memories (user_id, created_at DESC, id DESC)
|
|
1130
|
+
WHERE raw_document_id IS NULL AND deleted_at IS NULL;
|
|
1131
|
+
|
|
1132
|
+
-- ---------------------------------------------------------------------------
|
|
1133
|
+
-- Document chunks (Phase 2 of the large-file ingestion plan).
|
|
1134
|
+
--
|
|
1135
|
+
-- One row per deterministic chunk derived from a registered document.
|
|
1136
|
+
-- Chunks store their own embedding (so the chunk-level vector store
|
|
1137
|
+
-- supports raw chunk lookup / debug / re-index without touching memories)
|
|
1138
|
+
-- AND each chunk creates a sibling row in `memories` with
|
|
1139
|
+
-- raw_document_id + document_chunk_id provenance — that's the surface
|
|
1140
|
+
-- the existing /v1/memories/search retrieval pipeline finds.
|
|
1141
|
+
--
|
|
1142
|
+
-- (parser_version, chunker_version) pair lets a future code change
|
|
1143
|
+
-- re-chunk a document without colliding with the prior generation —
|
|
1144
|
+
-- the partial unique index keys on chunker_version, so a bumped
|
|
1145
|
+
-- chunker_version causes fresh inserts to coexist with the old soft-
|
|
1146
|
+
-- deleted rows. Phase 2 only ships chunker_version='phase2-fixed-v1'
|
|
1147
|
+
-- and parser_version='phase2-text-v1'; future phases bump.
|
|
1148
|
+
-- ---------------------------------------------------------------------------
|
|
1149
|
+
|
|
1150
|
+
CREATE TABLE IF NOT EXISTS document_chunks (
|
|
1151
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1152
|
+
user_id TEXT NOT NULL,
|
|
1153
|
+
raw_document_id UUID NOT NULL REFERENCES raw_documents(id) ON DELETE CASCADE,
|
|
1154
|
+
chunk_index INTEGER NOT NULL CHECK (chunk_index >= 0),
|
|
1155
|
+
content TEXT NOT NULL,
|
|
1156
|
+
content_hash TEXT NOT NULL,
|
|
1157
|
+
char_start INTEGER NOT NULL CHECK (char_start >= 0),
|
|
1158
|
+
char_end INTEGER NOT NULL CHECK (char_end >= char_start),
|
|
1159
|
+
token_count INTEGER NOT NULL CHECK (token_count >= 0),
|
|
1160
|
+
embedding vector({{EMBEDDING_DIMENSIONS}}) NOT NULL,
|
|
1161
|
+
parser_version TEXT NOT NULL,
|
|
1162
|
+
chunker_version TEXT NOT NULL,
|
|
1163
|
+
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
1164
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1165
|
+
deleted_at TIMESTAMPTZ
|
|
1166
|
+
);
|
|
1167
|
+
|
|
1168
|
+
-- Active-row uniqueness on (raw_document_id, chunk_index, chunker_version).
|
|
1169
|
+
-- Soft-deleted rows are excluded so a re-index after a previous chunker
|
|
1170
|
+
-- run leaves audit history intact while letting the new run succeed.
|
|
1171
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_document_chunks_active_unique
|
|
1172
|
+
ON document_chunks (raw_document_id, chunk_index, chunker_version)
|
|
1173
|
+
WHERE deleted_at IS NULL;
|
|
1174
|
+
|
|
1175
|
+
CREATE INDEX IF NOT EXISTS idx_document_chunks_document
|
|
1176
|
+
ON document_chunks (raw_document_id)
|
|
1177
|
+
WHERE deleted_at IS NULL;
|
|
1178
|
+
CREATE INDEX IF NOT EXISTS idx_document_chunks_user
|
|
1179
|
+
ON document_chunks (user_id)
|
|
1180
|
+
WHERE deleted_at IS NULL;
|
|
1181
|
+
CREATE INDEX IF NOT EXISTS idx_document_chunks_embedding
|
|
1182
|
+
ON document_chunks USING hnsw (embedding vector_cosine_ops)
|
|
1183
|
+
WITH (m = 16, ef_construction = 200);
|
|
1184
|
+
|
|
1185
|
+
-- ---------------------------------------------------------------------------
|
|
1186
|
+
-- Storage artifacts (Step 4 of the storage-sibling plan).
|
|
1187
|
+
--
|
|
1188
|
+
-- One row per artifact tracked by the direct storage API, independent
|
|
1189
|
+
-- of `raw_documents`. Pointer-mode rows carry a registered URI and
|
|
1190
|
+
-- never persist bytes (the server NEVER fetches the URI itself);
|
|
1191
|
+
-- managed-mode rows carry the adapter-returned URI plus the usual
|
|
1192
|
+
-- pending → available / deleting → deleted/delete_failed lifecycle.
|
|
1193
|
+
--
|
|
1194
|
+
-- Owner scoping lives on `user_id`. `org_id` / `project_id` are
|
|
1195
|
+
-- reserved for future multi-tenancy and stay NULL in v1.
|
|
1196
|
+
--
|
|
1197
|
+
-- Internal-only columns:
|
|
1198
|
+
-- * `plaintext_hash` — SHA-256 of caller bytes; never on the wire
|
|
1199
|
+
-- by default. The Step-5 response formatter exposes it only when
|
|
1200
|
+
-- the row's `disclose_content_hash = true` AND the caller opted in
|
|
1201
|
+
-- at put time.
|
|
1202
|
+
-- * `stored_hash` — SHA-256 of the bytes the adapter actually wrote;
|
|
1203
|
+
-- never on the wire under any condition.
|
|
1204
|
+
-- * `last_error` — internal failure envelope for delete retries.
|
|
1205
|
+
-- Step 5 is responsible for projecting the wire shape; this PR is
|
|
1206
|
+
-- DB-only and is allowed to keep the internal columns visible in the
|
|
1207
|
+
-- repository's row type.
|
|
1208
|
+
--
|
|
1209
|
+
-- FK direction: `raw_documents.storage_artifact_id REFERENCES
|
|
1210
|
+
-- storage_artifacts(id)`. Step 7 wires the document-ingestion paths
|
|
1211
|
+
-- to populate this column; Step 4 just defines the persistence
|
|
1212
|
+
-- surface and the reverse-lookup index.
|
|
1213
|
+
-- ---------------------------------------------------------------------------
|
|
1214
|
+
|
|
1215
|
+
CREATE TABLE IF NOT EXISTS storage_artifacts (
|
|
1216
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1217
|
+
user_id TEXT NOT NULL,
|
|
1218
|
+
org_id TEXT,
|
|
1219
|
+
project_id TEXT,
|
|
1220
|
+
provider TEXT NOT NULL,
|
|
1221
|
+
mode TEXT NOT NULL CHECK (mode IN ('pointer', 'managed')),
|
|
1222
|
+
-- Nullable while the row is in `pending` (managed put before
|
|
1223
|
+
-- backend.put has returned a URI); set to the adapter URI on
|
|
1224
|
+
-- success, stays NULL on `failed`. `pointer` rows always supply
|
|
1225
|
+
-- the URI at insert time. The partial unique index below covers
|
|
1226
|
+
-- the post-set side of the contract.
|
|
1227
|
+
uri TEXT,
|
|
1228
|
+
status TEXT NOT NULL
|
|
1229
|
+
CHECK (status IN
|
|
1230
|
+
('stored', 'pending', 'available', 'unavailable',
|
|
1231
|
+
'deleting', 'deleted', 'delete_failed', 'failed')),
|
|
1232
|
+
size_bytes BIGINT,
|
|
1233
|
+
content_type TEXT,
|
|
1234
|
+
-- Internal; never on the wire by default.
|
|
1235
|
+
plaintext_hash TEXT,
|
|
1236
|
+
-- Internal; never on the wire ever.
|
|
1237
|
+
stored_hash TEXT,
|
|
1238
|
+
content_encoding TEXT NOT NULL DEFAULT 'identity'
|
|
1239
|
+
CHECK (content_encoding IN ('identity', 'aes_gcm')),
|
|
1240
|
+
disclose_content_hash BOOLEAN NOT NULL DEFAULT FALSE,
|
|
1241
|
+
identifiers JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
1242
|
+
lifecycle JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
1243
|
+
replication JSONB,
|
|
1244
|
+
verification JSONB,
|
|
1245
|
+
retrieval JSONB,
|
|
1246
|
+
provider_details JSONB,
|
|
1247
|
+
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
1248
|
+
last_error JSONB,
|
|
1249
|
+
-- CAS token for the upload pipeline (pending-row-first put). Held
|
|
1250
|
+
-- by `claimPendingArtifact`, cleared by `recordUploadedArtifact` /
|
|
1251
|
+
-- `markPutFailed`. Distinct from `delete_attempt_id` so the two
|
|
1252
|
+
-- lifecycle phases never collide.
|
|
1253
|
+
put_attempt_id UUID,
|
|
1254
|
+
delete_attempt_id UUID,
|
|
1255
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1256
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1257
|
+
deleted_at TIMESTAMPTZ
|
|
1258
|
+
);
|
|
1259
|
+
|
|
1260
|
+
-- Forward-compat migration for deployments that already created
|
|
1261
|
+
-- `storage_artifacts` with `uri NOT NULL`. Idempotent: only fires
|
|
1262
|
+
-- the ALTER when information_schema reports the column as still
|
|
1263
|
+
-- NOT NULL, so a re-run against a freshly upgraded DB is a no-op
|
|
1264
|
+
-- without relying on `EXCEPTION WHEN OTHERS` (workspace rule
|
|
1265
|
+
-- forbids silent error swallowing).
|
|
1266
|
+
DO $$
|
|
1267
|
+
BEGIN
|
|
1268
|
+
IF EXISTS (
|
|
1269
|
+
SELECT 1 FROM information_schema.columns
|
|
1270
|
+
WHERE table_name = 'storage_artifacts'
|
|
1271
|
+
AND column_name = 'uri'
|
|
1272
|
+
AND is_nullable = 'NO'
|
|
1273
|
+
) THEN
|
|
1274
|
+
ALTER TABLE storage_artifacts ALTER COLUMN uri DROP NOT NULL;
|
|
1275
|
+
END IF;
|
|
1276
|
+
END $$;
|
|
1277
|
+
ALTER TABLE storage_artifacts
|
|
1278
|
+
ADD COLUMN IF NOT EXISTS put_attempt_id UUID;
|
|
1279
|
+
|
|
1280
|
+
-- Concurrent `putManaged` callers must not produce two rows whose
|
|
1281
|
+
-- adapter URI collides. The unique index is partial: only managed
|
|
1282
|
+
-- rows with a URI set and not soft-deleted participate. Pointer
|
|
1283
|
+
-- rows are exempt — a single user legitimately has multiple
|
|
1284
|
+
-- pointer rows for the same caller-supplied URI (e.g. one created
|
|
1285
|
+
-- by `putPointer` against the active backend, another auto-paired
|
|
1286
|
+
-- to a document registration via `EXTERNAL_POINTER_PROVIDER`).
|
|
1287
|
+
-- `pending` / `failed` rows carry `uri IS NULL` and also fall out
|
|
1288
|
+
-- of the constraint naturally.
|
|
1289
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uniq_storage_artifacts_user_managed_uri
|
|
1290
|
+
ON storage_artifacts (user_id, uri)
|
|
1291
|
+
WHERE uri IS NOT NULL AND deleted_at IS NULL AND mode = 'managed';
|
|
1292
|
+
|
|
1293
|
+
-- One-time cleanup: drop the over-broad index from an earlier rev
|
|
1294
|
+
-- of this migration. Idempotent.
|
|
1295
|
+
DROP INDEX IF EXISTS uniq_storage_artifacts_user_uri;
|
|
1296
|
+
|
|
1297
|
+
CREATE INDEX IF NOT EXISTS idx_storage_artifacts_user_status
|
|
1298
|
+
ON storage_artifacts (user_id, status) WHERE deleted_at IS NULL;
|
|
1299
|
+
CREATE INDEX IF NOT EXISTS idx_storage_artifacts_user_provider
|
|
1300
|
+
ON storage_artifacts (user_id, provider) WHERE deleted_at IS NULL;
|
|
1301
|
+
-- Cursor pagination keyed on (created_at DESC, id DESC) within a
|
|
1302
|
+
-- user. Partial index keeps it lean for healthy deployments.
|
|
1303
|
+
CREATE INDEX IF NOT EXISTS idx_storage_artifacts_user_created
|
|
1304
|
+
ON storage_artifacts (user_id, created_at DESC, id DESC)
|
|
1305
|
+
WHERE deleted_at IS NULL;
|
|
1306
|
+
|
|
1307
|
+
-- Non-partial unique index on (id, user_id). `id` alone is already the
|
|
1308
|
+
-- primary key; the composite uniqueness exists so the owner-scoped
|
|
1309
|
+
-- composite foreign key on raw_documents below has a valid target.
|
|
1310
|
+
-- Postgres accepts a non-partial unique index as an FK target, and
|
|
1311
|
+
-- this is the only place we need the (id, user_id) pair indexed.
|
|
1312
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_storage_artifacts_id_user
|
|
1313
|
+
ON storage_artifacts (id, user_id);
|
|
1314
|
+
|
|
1315
|
+
-- Reverse pointer from documents to their backing artifact. The FK is
|
|
1316
|
+
-- COMPOSITE on (storage_artifact_id, user_id) so the schema itself
|
|
1317
|
+
-- makes a USER_B raw_document pointing at USER_A's artifact
|
|
1318
|
+
-- impossible — the row would have to match BOTH columns of the
|
|
1319
|
+
-- referenced storage_artifacts row, and the artifact's `user_id`
|
|
1320
|
+
-- column carries the canonical owner. Populated in Step 7.
|
|
1321
|
+
--
|
|
1322
|
+
-- NULL `storage_artifact_id` is legitimate for rows registered
|
|
1323
|
+
-- without an `external_uri` (pointer-only registration stub) or rows
|
|
1324
|
+
-- that pre-date Step 7.
|
|
1325
|
+
ALTER TABLE raw_documents
|
|
1326
|
+
ADD COLUMN IF NOT EXISTS storage_artifact_id UUID NULL;
|
|
1327
|
+
-- This file is reapplied on every startup (`migrate.ts` runs schema.sql
|
|
1328
|
+
-- against the configured DB). The composite FK is therefore added
|
|
1329
|
+
-- only when it doesn't already exist, so repeated boots don't take
|
|
1330
|
+
-- ACCESS EXCLUSIVE on raw_documents to revalidate the same constraint.
|
|
1331
|
+
-- The legacy single-column FK is dropped the same way for one-time
|
|
1332
|
+
-- cleanup against any dev/test DB that applied the earlier shape.
|
|
1333
|
+
DO $$
|
|
1334
|
+
BEGIN
|
|
1335
|
+
IF EXISTS (
|
|
1336
|
+
SELECT 1 FROM pg_constraint
|
|
1337
|
+
WHERE conname = 'raw_documents_storage_artifact_id_fkey'
|
|
1338
|
+
AND conrelid = 'raw_documents'::regclass
|
|
1339
|
+
) THEN
|
|
1340
|
+
ALTER TABLE raw_documents
|
|
1341
|
+
DROP CONSTRAINT raw_documents_storage_artifact_id_fkey;
|
|
1342
|
+
END IF;
|
|
1343
|
+
IF NOT EXISTS (
|
|
1344
|
+
SELECT 1 FROM pg_constraint
|
|
1345
|
+
WHERE conname = 'raw_documents_storage_artifact_owner_fkey'
|
|
1346
|
+
AND conrelid = 'raw_documents'::regclass
|
|
1347
|
+
) THEN
|
|
1348
|
+
ALTER TABLE raw_documents
|
|
1349
|
+
ADD CONSTRAINT raw_documents_storage_artifact_owner_fkey
|
|
1350
|
+
FOREIGN KEY (storage_artifact_id, user_id)
|
|
1351
|
+
REFERENCES storage_artifacts (id, user_id);
|
|
1352
|
+
END IF;
|
|
1353
|
+
END $$;
|
|
1354
|
+
CREATE INDEX IF NOT EXISTS idx_raw_documents_storage_artifact
|
|
1355
|
+
ON raw_documents (storage_artifact_id) WHERE storage_artifact_id IS NOT NULL;
|