topos-node 1.2.0__tar.gz → 1.2.1__tar.gz
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.
- {topos_node-1.2.0/topos_node.egg-info → topos_node-1.2.1}/PKG-INFO +1 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/pyproject.toml +1 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/__version__.py +2 -2
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/enrichment.py +10 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/signal.py +23 -0
- topos_node-1.2.1/topos/api/upgrades.py +30 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/app.py +15 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/control_plane_client.py +6 -2
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/config.py +14 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/signal_features.py +23 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/consolidation.py +98 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/fact_materializer.py +8 -3
- topos_node-1.2.1/topos/features/entities/graph_enrichers.py +393 -0
- topos_node-1.2.1/topos/features/entities/graph_refresh.py +145 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/resolver.py +23 -3
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/stats/definitions.py +5 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/canonical_pipeline.py +10 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/protocol/handled_message_types.json +2 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/retrieval.py +47 -13
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/scope_registry.json +3 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/__init__.py +6 -0
- topos_node-1.2.1/topos/storage/db/migrations/derivation_ledger_v1.py +44 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sync/client.py +6 -2
- topos_node-1.2.1/topos/upgrades/runner.py +339 -0
- {topos_node-1.2.0 → topos_node-1.2.1/topos_node.egg-info}/PKG-INFO +1 -1
- {topos_node-1.2.0 → topos_node-1.2.1}/topos_node.egg-info/SOURCES.txt +4 -0
- topos_node-1.2.0/topos/features/entities/graph_enrichers.py +0 -211
- {topos_node-1.2.0 → topos_node-1.2.1}/LICENSE +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/MANIFEST.in +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/README.md +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/setup.cfg +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/shared/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/shared/filtering.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/shared/schema_registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/tests/test_protocol_handled_types.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/profiles.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/query_engine.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/analytics/raw_queries.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/analytics.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/app_registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/backup.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/compute_remote.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/data_commit.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/database_explorer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/db.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/device.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/engine_run.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/enrichment_lab.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/filter_lab.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/health.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/home_chat.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/ingestion_api.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/ingestion_compat.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/ingestion_sources.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/intelligence_lifecycle.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/llm.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/local_mcp.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/messenger_analytics.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/privacy_disclose.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/query_api.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/signal_extraction_config.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/source_install.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/source_scrub.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/sources.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/sources_overview.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/sync.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/ui_config.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/uma_data.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/usage.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/api/user_identity.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/auth.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/demo_mappers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/models.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/canonicalization/resolver.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/cli/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/cli/__main__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/cli/commands.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/config/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/config/settings.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/config/signal_extraction.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/config/uvicorn_logging.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/contacts/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/contacts/identity.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/api_models.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/connection_resilience.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/device_helpers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/errors.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/events.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/common.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/contacts_import.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/database_explorer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/device.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/enrichment.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/enrichment_lab.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/filter_lab.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/home_chat.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/ingest.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/messages.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/messenger_analytics.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/query.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/routines.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/sources.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/handlers/uma.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/logging.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/metrics.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/routine_access.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/startup_banner.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/state.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/table_layers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/core/types.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/data_explorer_row_delete.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/data_explorer_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/canonical_writer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/content_policy.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/field_registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/privacy_layer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/disclosure/tier.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/generative_prompts.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/generative_response.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/huggingface.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/ollama.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/openai.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/openai_compatible.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/redpill.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/backends/stub.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/client.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/engine.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/intake.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/memory_utils.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/model_cache.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/pipeline_memory.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/queue_manager.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/registration.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/result_formatter.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/router.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/scoped_token.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/tasks.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/transport.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/usage_guard.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/usage_observation.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/engine/validator.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/catalog.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/derived_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/job_writer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/model_overrides.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/models/manager.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/models/mvp_defaults.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/models/registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/orchestrator.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/processor.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/registry_contract.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/signal_derivation_config.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/source_overrides.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment/website_classifier.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/bundles.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/model_resolve.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/schema.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/service.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/enrichment_lab/worker.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/evals/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/evals/enrichment_eval.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/dossier.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/edges.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/graph_search.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/linking.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/maintenance.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/entities/reads.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/facts/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/facts/extract.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/facts/llm_extract.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/facts/reads.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/facts/store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/fit/evaluator.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/fit/opportunity_types.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/lifecycle/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/lifecycle/derived_scrub.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/lifecycle/exclusions.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/lifecycle/gc.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/provenance/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/provenance/posture.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/provenance/roles.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/brief_canonical_loader.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/brief_ontology.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/brief_renderer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/brief_schemas.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/chunking.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/cluster_labels.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/data_health.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/brief_ontologies.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/intentions.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/profile.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/relationships.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/time.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/definitions/work.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/dimension_briefs.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/dimension_definition_loader.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/dimension_profiles.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/dimension_registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/embed_context.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/extraction/artifact_router.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/extraction/artifact_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/extraction/rule_extractors.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/graph_sanitize.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/hybrid_search.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/incremental_clustering.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/model_recommendations.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/query_embed_cache.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/schemas.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/service.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/signal_object_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/source_hydration.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/structured_signal.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/topic_clustering.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/typed_stores/aggregates.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/vector_codec.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/vector_math.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/signal/vector_settings.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/stats/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/stats/engine.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/stats/fold.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/features/stats/insights.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/bundles.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/schema.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/service.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/filter_lab/worker.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/home_chat/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/home_chat/schema.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/home_chat/store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/hosted_pool_lease.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/inbox_crypto.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/inbox_drain.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/ingest_helpers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/jobs.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/journal_location_fanout.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/journal_time_log_normalize.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/local_sync.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/log_preview.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/manager.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/github_activity_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/parsers/voxterm_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/progress.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/reprocess.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/state_machine.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/usage_inbox_dedupe.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/validation/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/lineage/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/lineage/provenance.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/lineage/tracker.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/llm_integrations_storage.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/observability/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/observability/alerts.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/observability/metrics.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/observability/tracing.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/openai_client.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/pipeline/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/pipeline/audit.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/pipeline/envelope.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/pipeline/stages.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/pipeline/stub_enqueue.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/projections/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/projections/vector_index/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/protocol/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/audit.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/ddr.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/disclosure.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/fingerprint.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/game_layer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/grant_cache.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/inference.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/intent.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/manifest.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/manifest_validation.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/minimizer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/negotiation.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/pipeline.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/planner.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/runtime.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/scope_registry_loader.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/session.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/session_utils.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/source_generation.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/turn_classifier.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/query/types.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/rate_limit.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/routines/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/routines/schema.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/routines/store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/runtime_update.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sanitization/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sanitization/nsfw_classifier.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sanitization/privacy_filter.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/scope_resolution.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/container.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/embeddings/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/embeddings/local.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/embeddings/remote.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/interfaces.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/llm/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/llm/base.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/llm/openai.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/local.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/services/postgres.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/bundled_canonical_triples.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/canonical_signal_defaults.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/definitions.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/install_service.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/registry.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/runtime_install.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/scrub_attribution.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sources/scrub_service.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/startup_banner.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/factory.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/fakes.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/postgres/stores.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/protocols.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/sqlite/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/sqlite/stores.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/adapters/sqlite/vector_search.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/activity_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/ai_chat/tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/canonical_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/conversations_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/mapping_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/canonical/postgres.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/client.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/connection_tuning.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/actor_role_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/episodes_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/remediation_person_model.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/scope_source_generation.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/signal_objects.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/paths.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/postgres.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/schema.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/db/storage_breakdown.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/oplog/decision.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/person/identity_resolver.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/projections/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/file_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/security/encryption.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/signal_identity.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/source_settings.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/storage/user_identity.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sync/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/sync_handlers.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/testing/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/testing/lifespan.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/uma_filters.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/uma_resource_id.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/uma_rpt.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/upgrades/__init__.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/upgrades/manifests.json +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/utils/base_object.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos/websocket_client.py +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos_node.egg-info/entry_points.txt +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos_node.egg-info/requires.txt +0 -0
- {topos_node-1.2.0 → topos_node-1.2.1}/topos_node.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "topos-node"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.1"
|
|
8
8
|
description = "Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -672,7 +672,7 @@ def _load_canonical_messages_for_enrichment(
|
|
|
672
672
|
if title:
|
|
673
673
|
rec["content"] = str(title)
|
|
674
674
|
if not rec.get("event_at"):
|
|
675
|
-
for key in ("occurred_at", "
|
|
675
|
+
for key in ("occurred_at", "starts_at", "entry_at", "posted_at", "visited_at"):
|
|
676
676
|
if rec.get(key):
|
|
677
677
|
rec["event_at"] = rec[key]
|
|
678
678
|
break
|
|
@@ -1056,6 +1056,15 @@ async def _process_enrichment_core(
|
|
|
1056
1056
|
progress_callback=progress_callback,
|
|
1057
1057
|
)
|
|
1058
1058
|
|
|
1059
|
+
# Canonical jobs changed the derived layers even when the signal lane is
|
|
1060
|
+
# skipped below — mark the graph for a debounced rebuild either way.
|
|
1061
|
+
try:
|
|
1062
|
+
from ..features.entities.graph_refresh import mark_graph_dirty
|
|
1063
|
+
|
|
1064
|
+
mark_graph_dirty()
|
|
1065
|
+
except Exception: # noqa: BLE001 — refresh must never break enrichment
|
|
1066
|
+
pass
|
|
1067
|
+
|
|
1059
1068
|
# Manual processing is the deliberate counterpart of the automatic ingest
|
|
1060
1069
|
# path, so it must also run the signal-derivation lane (embeddings,
|
|
1061
1070
|
# clusters, facts, ...) that the ingest path skips for manual sources.
|
|
@@ -388,6 +388,29 @@ async def dismiss_entity_review(review_id: str, _api_key: str = Depends(require_
|
|
|
388
388
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
389
389
|
|
|
390
390
|
|
|
391
|
+
class EntitySplitBody(BaseModel):
|
|
392
|
+
surface: str = Field(..., min_length=1, max_length=200)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
@router.post("/entities/{entity_id}/split")
|
|
396
|
+
async def split_entity_surface(
|
|
397
|
+
entity_id: str,
|
|
398
|
+
body: EntitySplitBody,
|
|
399
|
+
_api_key: str = Depends(require_api_key),
|
|
400
|
+
):
|
|
401
|
+
"""Owner unbind: split a surface's mentions out of this entity into a
|
|
402
|
+
fresh one, with a permanent no-bind guard so the resolver never re-merges
|
|
403
|
+
the pair (accidental-merge reversal; see consolidation.split_surface)."""
|
|
404
|
+
from ..features.entities.consolidation import split_surface
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
return split_surface(_entities_conn(), entity_id, body.surface)
|
|
408
|
+
except LookupError as exc:
|
|
409
|
+
raise HTTPException(status_code=404, detail=str(exc))
|
|
410
|
+
except ValueError as exc:
|
|
411
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
412
|
+
|
|
413
|
+
|
|
391
414
|
@router.post("/entities/{entity_id}/exclude")
|
|
392
415
|
async def exclude_entity_from_intelligence(
|
|
393
416
|
entity_id: str,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Upgrade status surface: what the runner + graph refresher are doing.
|
|
2
|
+
|
|
3
|
+
Read-only. The UI shows "Upgrading your intelligence…" instead of a
|
|
4
|
+
mysteriously thin graph while re-derivation runs.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
from fastapi import APIRouter, Depends
|
|
12
|
+
|
|
13
|
+
from ..auth import require_api_key
|
|
14
|
+
|
|
15
|
+
router = APIRouter()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _status_payload() -> Dict[str, Any]:
|
|
19
|
+
from ..core.state import get_db_connection
|
|
20
|
+
from ..features.entities.graph_refresh import status as refresh_status
|
|
21
|
+
from ..upgrades.runner import runner_status
|
|
22
|
+
|
|
23
|
+
conn = get_db_connection()
|
|
24
|
+
upgrade = runner_status(conn) if conn is not None else {"enabled": False, "error": "no database"}
|
|
25
|
+
return {"upgrade": upgrade, "graph_refresh": refresh_status()}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@router.get("/v1/upgrade/status", dependencies=[Depends(require_api_key)])
|
|
29
|
+
async def get_upgrade_status() -> Dict[str, Any]:
|
|
30
|
+
return _status_payload()
|
|
@@ -45,6 +45,7 @@ from .api import (
|
|
|
45
45
|
home_chat as home_chat_routes,
|
|
46
46
|
privacy_disclose as privacy_disclose_routes,
|
|
47
47
|
signal as signal_routes,
|
|
48
|
+
upgrades as upgrades_routes,
|
|
48
49
|
)
|
|
49
50
|
from .config.settings import settings
|
|
50
51
|
from .core.logging import align_uvicorn_loggers, configure_logging
|
|
@@ -93,6 +94,7 @@ app.add_middleware(
|
|
|
93
94
|
)
|
|
94
95
|
|
|
95
96
|
app.include_router(health_routes.router)
|
|
97
|
+
app.include_router(upgrades_routes.router)
|
|
96
98
|
app.include_router(local_mcp_routes.router)
|
|
97
99
|
app.include_router(llm_routes.router)
|
|
98
100
|
app.include_router(db_routes.router)
|
|
@@ -157,6 +159,19 @@ async def startup_event() -> None:
|
|
|
157
159
|
logger.info("Stage 9 migrations applied at startup: %d renames", len(result["applied"]))
|
|
158
160
|
except Exception as e:
|
|
159
161
|
logger.debug("Stage 9 migrations at startup (non-fatal): %s", e)
|
|
162
|
+
# Upgrade runner: compare the stamped derivation baseline against the
|
|
163
|
+
# shipped version and re-derive what this release invalidated (manifest in
|
|
164
|
+
# topos/upgrades). Heavy steps run in a daemon thread; the node serves
|
|
165
|
+
# stale derived data meanwhile. Fresh installs stamp-and-skip.
|
|
166
|
+
try:
|
|
167
|
+
from .core.state import get_db_connection as _get_conn_for_upgrades
|
|
168
|
+
from .upgrades.runner import start_background as _start_upgrades
|
|
169
|
+
|
|
170
|
+
_upgrade_conn = state.db_conn if state.db_conn is not None else _get_conn_for_upgrades()
|
|
171
|
+
if _upgrade_conn is not None:
|
|
172
|
+
_start_upgrades(_upgrade_conn)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.warning("Upgrade runner at startup failed (non-fatal): %s", e)
|
|
160
175
|
try:
|
|
161
176
|
from .sources import install_service
|
|
162
177
|
|
|
@@ -141,7 +141,8 @@ class ControlPlaneClient:
|
|
|
141
141
|
try:
|
|
142
142
|
await asyncio.wait_for(self._ready.wait(), timeout=max(0.1, timeout))
|
|
143
143
|
return True
|
|
144
|
-
except TimeoutError:
|
|
144
|
+
except (TimeoutError, asyncio.TimeoutError):
|
|
145
|
+
# Py3.10: asyncio.TimeoutError is not builtins.TimeoutError.
|
|
145
146
|
return False
|
|
146
147
|
|
|
147
148
|
async def stop(self) -> None:
|
|
@@ -253,7 +254,10 @@ class ControlPlaneClient:
|
|
|
253
254
|
async def _wait_for_stop_or_timeout(self, timeout_s: float) -> None:
|
|
254
255
|
try:
|
|
255
256
|
await asyncio.wait_for(self._stop.wait(), timeout=timeout_s)
|
|
256
|
-
except TimeoutError:
|
|
257
|
+
except (TimeoutError, asyncio.TimeoutError):
|
|
258
|
+
# Expected path: backoff elapsed. Must not escape — on Py3.10
|
|
259
|
+
# asyncio.TimeoutError is distinct from builtins.TimeoutError and
|
|
260
|
+
# would otherwise kill the reconnect loop task.
|
|
257
261
|
return
|
|
258
262
|
|
|
259
263
|
async def _schedule_inbound_message(self, ws, data: Dict[str, Any]) -> None:
|
|
@@ -349,6 +349,20 @@ async def handle_delete_signal_extraction_config(message: Dict[str, Any]) -> Opt
|
|
|
349
349
|
# ---- Exposure-profile visibility (P1.5): the owner's toggle for whether the
|
|
350
350
|
# labeled "what you've been exposed to" profile surfaces on interest/identity
|
|
351
351
|
# answers. Default ON; the engine read path is config.settings.exposure_profile_visible.
|
|
352
|
+
@handles("get_upgrade_status")
|
|
353
|
+
async def handle_get_upgrade_status(message):
|
|
354
|
+
"""Upgrade runner + graph-refresh status (read-only; UI progress banner)."""
|
|
355
|
+
req_id = message.get("id")
|
|
356
|
+
if not req_id:
|
|
357
|
+
return None
|
|
358
|
+
try:
|
|
359
|
+
from ...api.upgrades import _status_payload
|
|
360
|
+
|
|
361
|
+
return {"id": req_id, "status": "ok", "payload": _status_payload()}
|
|
362
|
+
except Exception as exc: # noqa: BLE001
|
|
363
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
364
|
+
|
|
365
|
+
|
|
352
366
|
@handles("get_exposure_profile_config")
|
|
353
367
|
async def handle_get_exposure_profile_config(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
354
368
|
req_id = message.get("id")
|
|
@@ -651,6 +651,29 @@ async def handle_signal_entity_review_action(message: Dict[str, Any]) -> Optiona
|
|
|
651
651
|
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
652
652
|
|
|
653
653
|
|
|
654
|
+
@handles("signal_entity_split")
|
|
655
|
+
async def handle_signal_entity_split(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
656
|
+
req_id = message.get("id")
|
|
657
|
+
if not req_id:
|
|
658
|
+
return None
|
|
659
|
+
payload = message.get("payload") or {}
|
|
660
|
+
entity_id = str(payload.get("entity_id") or "").strip()
|
|
661
|
+
surface = str(payload.get("surface") or "").strip()
|
|
662
|
+
if not entity_id or not surface:
|
|
663
|
+
return {"id": req_id, "status": "error", "error": "entity_id and surface required", "code": 400}
|
|
664
|
+
try:
|
|
665
|
+
from ...features.entities.consolidation import split_surface
|
|
666
|
+
|
|
667
|
+
conn = hub.get_db_connection()
|
|
668
|
+
return {"id": req_id, "status": "ok", "payload": split_surface(conn, entity_id, surface)}
|
|
669
|
+
except LookupError as exc:
|
|
670
|
+
return {"id": req_id, "status": "error", "error": str(exc), "code": 404}
|
|
671
|
+
except ValueError as exc:
|
|
672
|
+
return {"id": req_id, "status": "error", "error": str(exc), "code": 400}
|
|
673
|
+
except Exception as exc: # noqa: BLE001
|
|
674
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
675
|
+
|
|
676
|
+
|
|
654
677
|
@handles("signal_exclude_entity")
|
|
655
678
|
async def handle_signal_exclude_entity(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
656
679
|
req_id = message.get("id")
|
|
@@ -18,6 +18,7 @@ Dismissed pairs are never re-proposed.
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
import json
|
|
21
22
|
import logging
|
|
22
23
|
import sqlite3
|
|
23
24
|
import uuid
|
|
@@ -386,3 +387,100 @@ def resolve_review(
|
|
|
386
387
|
conn.commit()
|
|
387
388
|
refresh_dossiers(conn)
|
|
388
389
|
return {"review_id": review_id, "status": "approved", "kept": str(candidate_id), "absorbed": str(subject_id)}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def split_surface(conn: sqlite3.Connection, entity_id: str, surface: str) -> Dict[str, Any]:
|
|
393
|
+
"""Owner unbind: split a surface's mentions OUT of an entity, permanently.
|
|
394
|
+
|
|
395
|
+
The reverse of an accidental merge/bind (e.g. the resolver's unique-contact
|
|
396
|
+
tier binding "Claire" to the contact "Claire Duncombe"):
|
|
397
|
+
|
|
398
|
+
* mentions whose surface_text normalizes to ``surface`` move to a fresh
|
|
399
|
+
entity named after the surface (created only when mentions exist);
|
|
400
|
+
* a matching alias is removed from the source entity;
|
|
401
|
+
* a permanent ``no_bind`` guard row is written — the resolver consults it
|
|
402
|
+
so this surface can never resolve back to the source entity (token-
|
|
403
|
+
subset names score 1.0, so every tier would otherwise re-merge them);
|
|
404
|
+
* both mention counts recount. Edges/dossiers correct on the next graph
|
|
405
|
+
rebuild.
|
|
406
|
+
"""
|
|
407
|
+
from .resolver import EntityResolver, normalize_name
|
|
408
|
+
|
|
409
|
+
row = conn.execute(
|
|
410
|
+
"SELECT canonical_name, normalized_name, entity_type, aliases_json "
|
|
411
|
+
"FROM entities WHERE entity_id=?",
|
|
412
|
+
(str(entity_id),),
|
|
413
|
+
).fetchone()
|
|
414
|
+
if row is None:
|
|
415
|
+
raise LookupError(f"entity not found: {entity_id}")
|
|
416
|
+
canonical_name, normalized_name, entity_type, aliases_json = row
|
|
417
|
+
|
|
418
|
+
normalized = normalize_name(surface)
|
|
419
|
+
if not normalized:
|
|
420
|
+
raise ValueError(f"unresolvable surface: {surface!r}")
|
|
421
|
+
if normalized == str(normalized_name):
|
|
422
|
+
raise ValueError(
|
|
423
|
+
"surface is the entity's own name — use exclude to stop tracking it entirely"
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
# Move matching mentions to a fresh entity.
|
|
427
|
+
mention_rows = conn.execute(
|
|
428
|
+
"SELECT mention_id, surface_text FROM entity_mentions WHERE entity_id=?",
|
|
429
|
+
(str(entity_id),),
|
|
430
|
+
).fetchall()
|
|
431
|
+
moved_ids = [
|
|
432
|
+
str(mid) for mid, stext in mention_rows if normalize_name(str(stext or "")) == normalized
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
new_entity_id: Optional[str] = None
|
|
436
|
+
if moved_ids:
|
|
437
|
+
resolver = EntityResolver(conn)
|
|
438
|
+
new_entity_id = resolver._create_entity(str(surface).strip(), str(entity_type))
|
|
439
|
+
placeholders = ",".join("?" for _ in moved_ids)
|
|
440
|
+
conn.execute(
|
|
441
|
+
f"UPDATE entity_mentions SET entity_id=? WHERE mention_id IN ({placeholders})",
|
|
442
|
+
(new_entity_id, *moved_ids),
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Remove a matching alias from the source entity.
|
|
446
|
+
alias_removed = False
|
|
447
|
+
try:
|
|
448
|
+
aliases = [a for a in (json.loads(aliases_json or "[]")) if isinstance(a, str)]
|
|
449
|
+
except json.JSONDecodeError:
|
|
450
|
+
aliases = []
|
|
451
|
+
kept_aliases = [a for a in aliases if normalize_name(a) != normalized]
|
|
452
|
+
if len(kept_aliases) != len(aliases):
|
|
453
|
+
alias_removed = True
|
|
454
|
+
conn.execute(
|
|
455
|
+
"UPDATE entities SET aliases_json=?, updated_at=datetime('now') WHERE entity_id=?",
|
|
456
|
+
(json.dumps(kept_aliases), str(entity_id)),
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
# Permanent guard: this surface never binds to the source entity again.
|
|
460
|
+
conn.execute(
|
|
461
|
+
"""
|
|
462
|
+
INSERT INTO entity_review
|
|
463
|
+
(review_id, surface_text, candidate_entity_id, score, record_id,
|
|
464
|
+
status, created_at, kind, subject_entity_id, reason)
|
|
465
|
+
VALUES (?, ?, ?, 1.0, NULL, 'approved', datetime('now'), 'no_bind', ?, 'owner split')
|
|
466
|
+
""",
|
|
467
|
+
(f"rev_{uuid.uuid4().hex[:16]}", normalized, str(entity_id), new_entity_id),
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Recount both sides.
|
|
471
|
+
for eid in filter(None, [str(entity_id), new_entity_id]):
|
|
472
|
+
conn.execute(
|
|
473
|
+
"UPDATE entities SET mention_count = ("
|
|
474
|
+
" SELECT COUNT(*) FROM entity_mentions m WHERE m.entity_id = entities.entity_id"
|
|
475
|
+
"), updated_at=datetime('now') WHERE entity_id=?",
|
|
476
|
+
(eid,),
|
|
477
|
+
)
|
|
478
|
+
conn.commit()
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
"entity_id": str(entity_id),
|
|
482
|
+
"surface": str(surface).strip(),
|
|
483
|
+
"new_entity_id": new_entity_id,
|
|
484
|
+
"mentions_moved": len(moved_ids),
|
|
485
|
+
"alias_removed": alias_removed,
|
|
486
|
+
}
|
|
@@ -100,11 +100,14 @@ def _upsert_materialized_edge(
|
|
|
100
100
|
source_object_id: str,
|
|
101
101
|
asserted_by: Optional[str] = None,
|
|
102
102
|
actor_role: Optional[str] = None,
|
|
103
|
+
last_event_at: Optional[str] = None,
|
|
103
104
|
) -> None:
|
|
104
105
|
"""Idempotent directed edge with a materialized marker + carried validity.
|
|
105
106
|
|
|
106
107
|
``actor_role`` overrides the asserted_by-derived tier — used by enrichers
|
|
107
108
|
whose provenance isn't an assertion (presence, participation, witnessing).
|
|
109
|
+
``last_event_at`` defaults to valid_from — pass explicitly when the edge's
|
|
110
|
+
evidence spans a window (e.g. a goal recurring across months).
|
|
108
111
|
"""
|
|
109
112
|
if not src or not dst or src == dst:
|
|
110
113
|
return
|
|
@@ -126,6 +129,7 @@ def _upsert_materialized_edge(
|
|
|
126
129
|
""",
|
|
127
130
|
(src, dst, edge_type),
|
|
128
131
|
).fetchone()
|
|
132
|
+
effective_last = last_event_at or valid_from
|
|
129
133
|
if row is None:
|
|
130
134
|
conn.execute(
|
|
131
135
|
"""
|
|
@@ -137,17 +141,18 @@ def _upsert_materialized_edge(
|
|
|
137
141
|
(
|
|
138
142
|
f"fmz_{uuid.uuid4().hex[:16]}",
|
|
139
143
|
src, dst, edge_type, float(weight),
|
|
140
|
-
|
|
144
|
+
effective_last, valid_from or _now_iso(), valid_to, meta,
|
|
141
145
|
),
|
|
142
146
|
)
|
|
143
147
|
else:
|
|
144
148
|
conn.execute(
|
|
145
149
|
"""
|
|
146
150
|
UPDATE entity_edges
|
|
147
|
-
SET weight=?, valid_from=?, valid_to=?, metadata_json=?,
|
|
151
|
+
SET weight=?, valid_from=?, valid_to=?, last_event_at=?, metadata_json=?,
|
|
152
|
+
updated_at=datetime('now')
|
|
148
153
|
WHERE edge_id=?
|
|
149
154
|
""",
|
|
150
|
-
(float(weight), valid_from, valid_to, meta, row[0]),
|
|
155
|
+
(float(weight), valid_from, valid_to, effective_last, meta, row[0]),
|
|
151
156
|
)
|
|
152
157
|
|
|
153
158
|
|