topos-node 1.3.7__tar.gz → 1.3.8__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.3.7/topos_node.egg-info → topos_node-1.3.8}/PKG-INFO +1 -1
- {topos_node-1.3.7 → topos_node-1.3.8}/pyproject.toml +1 -1
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/__version__.py +2 -2
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/tray.py +6 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/control_plane_client.py +20 -3
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/ingest.py +23 -13
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/state.py +22 -1
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/attention_triage_job.py +26 -6
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/dimension_summary_job.py +57 -24
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/entities_job.py +9 -1
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/statistics_job.py +43 -21
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/timeline_job.py +12 -3
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/orchestrator.py +71 -10
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/graph_refresh.py +32 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/canonical_pipeline.py +24 -9
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/ingest_helpers.py +87 -52
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/manager.py +109 -94
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/reprocess.py +32 -25
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/scope_registry.json +12 -4
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/runtime_update.py +65 -2
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/__init__.py +88 -1
- topos_node-1.3.8/topos/storage/db/write_gate.py +688 -0
- topos_node-1.3.8/topos/testing/lifespan.py +69 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/upgrades/manifests.json +9 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/upgrades/runner.py +10 -3
- {topos_node-1.3.7 → topos_node-1.3.8/topos_node.egg-info}/PKG-INFO +1 -1
- topos_node-1.3.7/topos/storage/db/write_gate.py +0 -336
- topos_node-1.3.7/topos/testing/lifespan.py +0 -22
- {topos_node-1.3.7 → topos_node-1.3.8}/LICENSE +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/MANIFEST.in +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/README.md +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/setup.cfg +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/shared/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/shared/filtering.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/shared/schema_registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/tests/test_extensions.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/tests/test_prewarm_first_run.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/tests/test_protocol_handled_types.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/tests/test_system_computer_name.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/profiles.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/query_engine.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/analytics/raw_queries.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/analytics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/app_registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/backup.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/compute_remote.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/conversation_context.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/data_commit.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/database_explorer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/db.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/device.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/engine_run.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/enrichment.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/enrichment_lab.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/facts_llm_config.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/filter_lab.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/health.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/home_chat.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/ingestion_api.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/ingestion_compat.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/ingestion_sources.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/intelligence_lifecycle.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/llm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/local_mcp.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/messenger_analytics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/privacy_disclose.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/query_api.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/shell.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/signal.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/signal_extraction_config.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/source_install.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/source_scrub.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/sources.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/sources_overview.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/sync.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/tool_index.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/ui_config.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/uma_data.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/upgrades.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/usage.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/api/user_identity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/app.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/auth.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/demo_mappers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/documents_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/models.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/canonicalization/resolver.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/__main__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/assets/topos_blk_rounded.png +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/assets/topos_white.png +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/commands.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/cli/reprocess_cmd.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/conversation_context_llm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/facts_llm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/model_packs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/settings.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/signal_extraction.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/config/uvicorn_logging.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/contacts/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/contacts/identity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/api_models.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/connection_resilience.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/device_helpers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/errors.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/events.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/common.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/complexity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/config.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/contacts_import.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/database_explorer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/device.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/enrichment.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/enrichment_lab.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/filter_lab.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/graph_query.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/home_chat.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/messages.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/messenger_analytics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/query.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/routines.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/signal_features.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/sources.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/timeline_daily.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/tool_index.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/handlers/uma.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/logging.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/metrics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/routine_access.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/startup_banner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/table_layers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/core/types.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/data_explorer_row_delete.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/data_explorer_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/canonical_writer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/content_policy.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/field_registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/privacy_layer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/disclosure/tier.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/generative_prompts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/generative_response.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/huggingface.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/ollama.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/openai.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/openai_compatible.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/redpill.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/backends/stub.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/client.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/engine.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/intake.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/memory_utils.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/model_cache.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/pipeline_memory.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/queue_manager.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/registration.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/result_formatter.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/router.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/scoped_token.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/tasks.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/transport.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/usage_guard.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/usage_observation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/engine/validator.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/catalog.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/derivation_recovery.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/derived_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/job_writer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/complexity_snapshot_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/model_overrides.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/models/manager.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/models/mvp_defaults.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/models/registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/pipeline_activity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/processor.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/registry_contract.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/signal_derivation_config.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/source_overrides.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/website_classifier.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/bundles.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/model_resolve.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/schema.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/service.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment_lab/worker.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/evals/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/evals/enrichment_eval.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/extensions.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/canonical.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/engine.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/entropy.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/focus.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/graph_metrics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/influence.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/projection.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/snapshots.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/topic_merge.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/topics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/topics_daily.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/complexity/volatility.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/affinity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/affinity_owner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/affinity_quality.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/consolidation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/context_vectors.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/cypher.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/declared_mappings.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/dossier.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/edges.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/fact_materializer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/graph_enrichers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/graph_search.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/linking.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/maintenance.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/reads.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/rebuild_subprocess.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/entities/resolver.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/extract.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/llm_extract.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/reads.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/facts/verdicts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/fit/evaluator.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/fit/opportunity_types.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/blackhole.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/blackhole_guard.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/blackhole_llm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/blackhole_rebuild.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/derived_scrub.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/exclusions.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/lifecycle/gc.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/provenance/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/provenance/posture.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/provenance/roles.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/brief_canonical_loader.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/brief_ontology.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/brief_renderer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/brief_schemas.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/chunking.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/cluster_labels.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/conversation_context.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/data_health.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/brief_ontologies.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/intentions.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/profile.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/relationships.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/time.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/definitions/work.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/derived_spec.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/dimension_briefs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/dimension_definition_loader.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/dimension_profiles.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/dimension_registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/embed_context.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/extraction/artifact_router.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/extraction/artifact_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/extraction/rule_extractors.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/graph_sanitize.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/hybrid_search.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/incremental_clustering.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/model_recommendations.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/query_embed_cache.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/schemas.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/service.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/signal_object_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/source_hydration.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/structured_signal.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/tool_index.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/topic_clustering.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/typed_stores/aggregates.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/typed_stores/commitments.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/typed_stores/rhythm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/vector_codec.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/vector_math.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/signal/vector_settings.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/stats/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/stats/definitions.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/stats/engine.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/stats/fold.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/stats/insights.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/timeline_projection.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/timeline_rollup.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/badges.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/daily.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/dashboard.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/instruments.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/intents.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/features/triage/readiness.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/bundles.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/schema.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/service.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/filter_lab/worker.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/home_chat/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/home_chat/schema.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/home_chat/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/hosted_pool_lease.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/inbox_crypto.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/inbox_drain.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/jobs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/journal_location_fanout.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/journal_time_log_normalize.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/local_sync.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/log_preview.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/documents_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/github_activity_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/parsers/voxterm_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/progress.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/state_machine.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/usage_inbox_dedupe.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/validation/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/lineage/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/lineage/provenance.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/lineage/tracker.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/llm_integrations_storage.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/observability/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/observability/alerts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/observability/metrics.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/observability/tracing.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/openai_client.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/audit.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/envelope.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/job_runner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/job_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/stages.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/pipeline/stub_enqueue.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/projections/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/projections/vector_index/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/protocol/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/protocol/handled_message_types.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/audit.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/cohort_resolvers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/ddr.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/disclosure.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/fingerprint.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/game_layer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/grant_cache.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/inference.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/intent.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/manifest.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/manifest_validation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/minimizer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/negotiation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/pipeline.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/planner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/retrieval.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/runtime.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/scope_registry_loader.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/session.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/session_utils.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/source_generation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/truth_facts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/truth_prompts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/turn_classifier.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/types.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/verify.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/query/verify_modes.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/rate_limit.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/routines/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/routines/schema.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/routines/store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/runtime_housekeeping.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/runtime_shutdown.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sanitization/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sanitization/nsfw_classifier.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sanitization/prewarm.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sanitization/privacy_filter.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/scope_resolution.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/container.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/embeddings/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/embeddings/local.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/embeddings/remote.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/interfaces.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/llm/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/llm/base.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/llm/openai.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/local.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/services/postgres.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/bundled_canonical_triples.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/canonical_signal_defaults.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/definitions.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/install_service.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/runtime_install.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/scrub_attribution.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sources/scrub_service.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/startup_banner.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/factory.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/fakes.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/postgres/stores.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/protocols.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/sqlite/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/sqlite/stores.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/adapters/sqlite/vector_search.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/activity_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/ai_chat/tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/canonical_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/conversations_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/mapping_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/canonical/postgres.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/client.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/connection_tuning.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/actor_role_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/affinity_pair_labels_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/attention_triage_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/attention_triage_v2.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/backup.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/complexity_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/conversation_context_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/documents_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/enrichment_spec_version_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_affinity_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_blackhole_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_context_vectors_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_context_vectors_v2.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/entity_mentions_authored_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/episodes_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/message_emotions_role_backfill_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/message_emotions_role_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/registry.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/registry_checksums.json +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/remediation_person_model.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/scope_source_generation.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_objects.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/signal_summaries_drop_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/paths.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/postgres.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/schema.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/db/storage_breakdown.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/oplog/decision.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/person/identity_resolver.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/projections/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/file_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/security/encryption.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/signal_identity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/source_settings.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/storage/user_identity.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sync/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sync/client.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/sync_handlers.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/testing/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/uma_filters.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/uma_resource_id.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/uma_rpt.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/upgrades/__init__.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/utils/base_object.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos/websocket_client.py +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos_node.egg-info/SOURCES.txt +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos_node.egg-info/entry_points.txt +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/topos_node.egg-info/requires.txt +0 -0
- {topos_node-1.3.7 → topos_node-1.3.8}/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.3.
|
|
7
|
+
version = "1.3.8"
|
|
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"
|
|
@@ -329,6 +329,8 @@ class ToposTray:
|
|
|
329
329
|
items.append("Show Logs")
|
|
330
330
|
if self.update.get("applying"):
|
|
331
331
|
items.append("Installing update…")
|
|
332
|
+
elif self.update.get("last_result") == "failed":
|
|
333
|
+
items.append("Update failed — click to retry")
|
|
332
334
|
elif self.update.get("last_result") == "success":
|
|
333
335
|
items.append("Update installed — restart to finish")
|
|
334
336
|
elif self.update.get("available"):
|
|
@@ -368,6 +370,10 @@ class ToposTray:
|
|
|
368
370
|
items.append(pystray.MenuItem("Show Logs", self._show_logs))
|
|
369
371
|
if self.update.get("applying"):
|
|
370
372
|
items.append(pystray.MenuItem("Installing update…", None, enabled=False))
|
|
373
|
+
elif self.update.get("last_result") == "failed":
|
|
374
|
+
# Clickable: a failed update that renders nothing is
|
|
375
|
+
# indistinguishable from a click that never registered.
|
|
376
|
+
items.append(pystray.MenuItem("Update failed — click to retry", self._apply_update))
|
|
371
377
|
elif self.update.get("last_result") == "success":
|
|
372
378
|
items.append(pystray.MenuItem("Update installed — restart to finish", None, enabled=False))
|
|
373
379
|
elif self.update.get("available"):
|
|
@@ -29,6 +29,12 @@ logger = logging.getLogger("topos.control_plane_client")
|
|
|
29
29
|
|
|
30
30
|
# Lightweight CP RPCs that must stay responsive while ingest/enrichment runs.
|
|
31
31
|
# UI-critical reads and scheduler ops only — no ingest/enrichment writes.
|
|
32
|
+
#: Keepalive. The control plane's own uvicorn pings at 30s with a 120s
|
|
33
|
+
#: deadline; the node pings faster so IT notices a dead link first and
|
|
34
|
+
#: reconnects, rather than waiting to be evicted.
|
|
35
|
+
PING_INTERVAL_SECONDS = 20.0
|
|
36
|
+
PING_TIMEOUT_SECONDS = 20.0
|
|
37
|
+
|
|
32
38
|
_FAST_INBOUND_MESSAGE_TYPES = frozenset(
|
|
33
39
|
{
|
|
34
40
|
"healthcheck",
|
|
@@ -297,9 +303,20 @@ class ControlPlaneClient:
|
|
|
297
303
|
self.control_plane_url,
|
|
298
304
|
additional_headers=headers,
|
|
299
305
|
ssl=ssl_context,
|
|
300
|
-
#
|
|
301
|
-
#
|
|
302
|
-
|
|
306
|
+
# A real pong deadline, restored once the client got its own
|
|
307
|
+
# thread and loop. It was disabled because handlers ran here
|
|
308
|
+
# and could block long enough to miss pongs — that reason is
|
|
309
|
+
# gone: handlers now marshal to the app loop, so this loop is
|
|
310
|
+
# always free to answer and to notice silence.
|
|
311
|
+
#
|
|
312
|
+
# Disabling it turned every silent connection death into a
|
|
313
|
+
# permanent wedge: `async for raw in ws` blocked forever, no
|
|
314
|
+
# exception fired, no reconnect was scheduled, and the node
|
|
315
|
+
# reported "connected" while the control plane had no socket
|
|
316
|
+
# at all. Observed live 2026-08-08 — 25 minutes wedged, with
|
|
317
|
+
# the web app correctly showing the Topos offline.
|
|
318
|
+
ping_interval=PING_INTERVAL_SECONDS,
|
|
319
|
+
ping_timeout=PING_TIMEOUT_SECONDS,
|
|
303
320
|
) as ws:
|
|
304
321
|
self._ws = ws
|
|
305
322
|
self._set_state("connected")
|
|
@@ -215,20 +215,30 @@ async def handle_app_ingest(message: Dict[str, Any]) -> Optional[Dict[str, Any]]
|
|
|
215
215
|
len(errors),
|
|
216
216
|
errors[0].get("error"),
|
|
217
217
|
)
|
|
218
|
-
|
|
219
|
-
if db_conn and user_id:
|
|
218
|
+
if user_id:
|
|
220
219
|
resource_id = (payload.get("resource_id") or "").strip() or f"dataset:{user_id}:{dataset_id or 'default'}"
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
|
|
221
|
+
def _record_app_ingest_uma() -> None:
|
|
222
|
+
# record_uma_request takes the write gate (and on first use runs
|
|
223
|
+
# the uma_access_requests ensure/migrate DDL) — keep it off the
|
|
224
|
+
# event-loop thread. Own connection: get_db_connection is
|
|
225
|
+
# thread-local.
|
|
226
|
+
own = hub.get_db_connection()
|
|
227
|
+
if own is None:
|
|
228
|
+
return
|
|
229
|
+
hub.record_uma_request(
|
|
230
|
+
own,
|
|
231
|
+
owner_user_id=user_id,
|
|
232
|
+
resource_id=resource_id,
|
|
233
|
+
request_type="write",
|
|
234
|
+
endpoint="app_ingest",
|
|
235
|
+
requesting_user_id=(payload.get("requesting_user_id") or None),
|
|
236
|
+
app_id=payload.get("app_id"),
|
|
237
|
+
requesting_user_email=(payload.get("requesting_user_email") or "").strip() or None,
|
|
238
|
+
access_channel=(payload.get("access_channel") or "internal").strip() or "internal",
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
await asyncio.to_thread(_record_app_ingest_uma)
|
|
232
242
|
response_payload = {
|
|
233
243
|
"records_processed": processed,
|
|
234
244
|
"records_total": records_total,
|
|
@@ -183,7 +183,9 @@ from ..storage.db.write_gate import ( # noqa: E402
|
|
|
183
183
|
batched_writes,
|
|
184
184
|
commit_connection,
|
|
185
185
|
db_write_lock,
|
|
186
|
+
register_connection,
|
|
186
187
|
sqlite_retry_busy,
|
|
188
|
+
unregister_connection,
|
|
187
189
|
with_db_write,
|
|
188
190
|
)
|
|
189
191
|
|
|
@@ -285,6 +287,7 @@ def _get_thread_db_connection(resolved_path: str) -> Optional[sqlite3.Connection
|
|
|
285
287
|
_ensure_row_factory(cached)
|
|
286
288
|
return cached
|
|
287
289
|
except (sqlite3.ProgrammingError, sqlite3.OperationalError):
|
|
290
|
+
unregister_connection(cached)
|
|
288
291
|
try:
|
|
289
292
|
cached.close()
|
|
290
293
|
except Exception: # noqa: BLE001
|
|
@@ -293,6 +296,7 @@ def _get_thread_db_connection(resolved_path: str) -> Optional[sqlite3.Connection
|
|
|
293
296
|
_thread_state.path = None
|
|
294
297
|
elif cached is not None:
|
|
295
298
|
# Path changed under us (tests re-point DATABASE_PATH).
|
|
299
|
+
unregister_connection(cached)
|
|
296
300
|
try:
|
|
297
301
|
cached.close()
|
|
298
302
|
except Exception: # noqa: BLE001
|
|
@@ -314,6 +318,7 @@ def _get_thread_db_connection(resolved_path: str) -> Optional[sqlite3.Connection
|
|
|
314
318
|
except Exception as exc: # noqa: BLE001 — tuning is an optimization, not a gate
|
|
315
319
|
logger.debug("Per-thread connection tuning skipped: %s", exc)
|
|
316
320
|
|
|
321
|
+
register_connection(conn)
|
|
317
322
|
_thread_state.conn = conn
|
|
318
323
|
_thread_state.path = resolved_path
|
|
319
324
|
logger.debug(
|
|
@@ -329,6 +334,7 @@ def close_thread_db_connection() -> None:
|
|
|
329
334
|
conn = getattr(_thread_state, "conn", None)
|
|
330
335
|
if conn is None:
|
|
331
336
|
return
|
|
337
|
+
unregister_connection(conn)
|
|
332
338
|
try:
|
|
333
339
|
conn.close()
|
|
334
340
|
except Exception: # noqa: BLE001
|
|
@@ -371,6 +377,7 @@ def _get_owner_db_connection() -> Optional[sqlite3.Connection]:
|
|
|
371
377
|
try:
|
|
372
378
|
db_conn.execute("SELECT 1")
|
|
373
379
|
except (sqlite3.ProgrammingError, sqlite3.OperationalError):
|
|
380
|
+
unregister_connection(db_conn)
|
|
374
381
|
db_conn = None
|
|
375
382
|
_db_conn_path = None
|
|
376
383
|
else:
|
|
@@ -398,7 +405,10 @@ def _get_owner_db_connection() -> Optional[sqlite3.Connection]:
|
|
|
398
405
|
# it across queries) — closing under them is the use-after-close
|
|
399
406
|
# that SIGBUSed on 2026-08-08. Dropping the reference lets the last
|
|
400
407
|
# user finish; the handle closes (rolling back any open
|
|
401
|
-
# transaction) when its refcount reaches zero.
|
|
408
|
+
# transaction) when its refcount reaches zero. The watchdog is told
|
|
409
|
+
# here for the same reason it holds no strong reference: it must
|
|
410
|
+
# not be what keeps this handle (or its stale record) around.
|
|
411
|
+
unregister_connection(db_conn)
|
|
402
412
|
db_conn = None
|
|
403
413
|
_db_conn_path = None
|
|
404
414
|
|
|
@@ -410,6 +420,7 @@ def _get_owner_db_connection() -> Optional[sqlite3.Connection]:
|
|
|
410
420
|
db_conn.row_factory = sqlite3.Row
|
|
411
421
|
return db_conn
|
|
412
422
|
except (sqlite3.ProgrammingError, sqlite3.OperationalError):
|
|
423
|
+
unregister_connection(db_conn)
|
|
413
424
|
db_conn = None
|
|
414
425
|
_db_conn_path = None
|
|
415
426
|
|
|
@@ -425,11 +436,13 @@ def _get_owner_db_connection() -> Optional[sqlite3.Connection]:
|
|
|
425
436
|
try:
|
|
426
437
|
db_conn.execute("SELECT 1")
|
|
427
438
|
except Exception:
|
|
439
|
+
unregister_connection(db_conn)
|
|
428
440
|
try:
|
|
429
441
|
db_conn.close()
|
|
430
442
|
except Exception: # noqa: BLE001
|
|
431
443
|
pass
|
|
432
444
|
else:
|
|
445
|
+
unregister_connection(new_conn)
|
|
433
446
|
try:
|
|
434
447
|
new_conn.close()
|
|
435
448
|
except Exception: # noqa: BLE001
|
|
@@ -467,6 +480,11 @@ def _open_owner_db_connection(db_path: Path) -> Optional[sqlite3.Connection]:
|
|
|
467
480
|
)
|
|
468
481
|
except Exception as tuning_exc: # noqa: BLE001
|
|
469
482
|
logger.warning("Connection tuning skipped: %s", tuning_exc)
|
|
483
|
+
# Registered before migrations run, not after: a migration that returns
|
|
484
|
+
# without committing wedges every writer behind it exactly like any
|
|
485
|
+
# other ungated write, and startup is when the database is least
|
|
486
|
+
# observable.
|
|
487
|
+
register_connection(conn)
|
|
470
488
|
try:
|
|
471
489
|
from ..storage.db.migrations import (
|
|
472
490
|
DowngradeGuardError,
|
|
@@ -478,6 +496,7 @@ def _open_owner_db_connection(db_path: Path) -> Optional[sqlite3.Connection]:
|
|
|
478
496
|
except (MigrationError, DowngradeGuardError) as migration_exc:
|
|
479
497
|
# Shape migrations must fail loud — serving a half-migrated DB corrupts data.
|
|
480
498
|
logger.error("Schema migration failed; refusing to open database: %s", migration_exc)
|
|
499
|
+
unregister_connection(conn)
|
|
481
500
|
try:
|
|
482
501
|
conn.close()
|
|
483
502
|
except Exception: # noqa: BLE001
|
|
@@ -490,6 +509,7 @@ def _open_owner_db_connection(db_path: Path) -> Optional[sqlite3.Connection]:
|
|
|
490
509
|
"Unexpected schema migration failure; refusing to open database: %s",
|
|
491
510
|
migration_exc,
|
|
492
511
|
)
|
|
512
|
+
unregister_connection(conn)
|
|
493
513
|
try:
|
|
494
514
|
conn.close()
|
|
495
515
|
except Exception: # noqa: BLE001
|
|
@@ -511,6 +531,7 @@ def _open_owner_db_connection(db_path: Path) -> Optional[sqlite3.Connection]:
|
|
|
511
531
|
raise
|
|
512
532
|
logger.warning("Failed to create database connection: %s", e)
|
|
513
533
|
if conn is not None:
|
|
534
|
+
unregister_connection(conn)
|
|
514
535
|
try:
|
|
515
536
|
conn.close()
|
|
516
537
|
except Exception: # noqa: BLE001
|
{topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/attention_triage_job.py
RENAMED
|
@@ -7,6 +7,7 @@ unchanged, so re-running a day is safe and cheap.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import asyncio
|
|
10
11
|
import logging
|
|
11
12
|
from typing import Any, Callable, Dict, List, Optional
|
|
12
13
|
|
|
@@ -34,8 +35,7 @@ class AttentionTriageJob(BaseEnrichmentJob):
|
|
|
34
35
|
canonical_messages: List[Dict[str, Any]],
|
|
35
36
|
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
36
37
|
) -> List[Dict[str, Any]]:
|
|
37
|
-
|
|
38
|
-
if conn is None:
|
|
38
|
+
if get_db_connection() is None:
|
|
39
39
|
return [{"_deferred": True, "error": "database_unavailable"}]
|
|
40
40
|
days = set()
|
|
41
41
|
for row in canonical_messages:
|
|
@@ -46,17 +46,37 @@ class AttentionTriageJob(BaseEnrichmentJob):
|
|
|
46
46
|
break
|
|
47
47
|
done = 0
|
|
48
48
|
for day_iso in sorted(days):
|
|
49
|
+
# A day's re-triage holds the write gate — a blocking OS lock — for
|
|
50
|
+
# its verdict upserts and signal objects. Held on the event loop it
|
|
51
|
+
# stalls every coroutine, including the control-plane keepalive, so
|
|
52
|
+
# each day runs on a worker thread against that thread's own
|
|
53
|
+
# connection. One day per hop also keeps progress incremental.
|
|
54
|
+
def _triage(_day: str = day_iso) -> Optional[Dict[str, Any]]:
|
|
55
|
+
conn = get_db_connection()
|
|
56
|
+
if conn is None:
|
|
57
|
+
return None
|
|
58
|
+
return run_daily_triage(conn, _day)
|
|
59
|
+
|
|
49
60
|
try:
|
|
50
|
-
summary =
|
|
51
|
-
|
|
61
|
+
summary = await asyncio.to_thread(_triage)
|
|
62
|
+
if summary is not None:
|
|
63
|
+
logger.info("attention_triage %s: %s", day_iso, summary.get("quadrants"))
|
|
52
64
|
except Exception: # one bad day must not sink the batch
|
|
53
65
|
logger.exception("attention_triage failed for %s", day_iso)
|
|
54
66
|
done += 1
|
|
55
67
|
if progress_callback:
|
|
56
68
|
progress_callback(done, len(days))
|
|
57
|
-
|
|
69
|
+
|
|
70
|
+
def _award() -> Optional[List[Any]]:
|
|
71
|
+
conn = get_db_connection()
|
|
72
|
+
if conn is None:
|
|
73
|
+
return None
|
|
58
74
|
from ....features.triage.badges import award_badges
|
|
59
|
-
|
|
75
|
+
|
|
76
|
+
return award_badges(conn)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
fresh = await asyncio.to_thread(_award)
|
|
60
80
|
if fresh:
|
|
61
81
|
logger.info("badges awarded: %s", fresh)
|
|
62
82
|
except Exception:
|
{topos_node-1.3.7 → topos_node-1.3.8}/topos/enrichment/jobs/canonical/dimension_summary_job.py
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
from typing import Any, Callable, Dict, List, Optional
|
|
5
6
|
|
|
@@ -120,26 +121,37 @@ class DimensionSummaryJob(BaseEnrichmentJob):
|
|
|
120
121
|
|
|
121
122
|
structured_result: Dict[str, Any] = {}
|
|
122
123
|
if structured_signal_enabled():
|
|
123
|
-
structured_result = enrich_structured_batch(
|
|
124
|
-
prepared,
|
|
125
|
-
source_id=str(source_id or "") or None,
|
|
126
|
-
only_dimension=only_dimension,
|
|
127
|
-
)
|
|
128
|
-
# Piggyback (badge-pass pattern): auto-tag new conversations as
|
|
129
|
-
# work/personal with the configured local model. Best-effort;
|
|
130
|
-
# owner-set tags are never touched.
|
|
131
|
-
try:
|
|
132
|
-
from ....features.signal.conversation_context import (
|
|
133
|
-
classify_untagged_conversations,
|
|
134
|
-
)
|
|
135
124
|
|
|
136
|
-
|
|
137
|
-
|
|
125
|
+
def _structured() -> Dict[str, Any]:
|
|
126
|
+
# Artifact routing, the gate aggregates and the scope
|
|
127
|
+
# materializer each take the write gate — a blocking OS lock
|
|
128
|
+
# that on the event loop stalls every coroutine, including the
|
|
129
|
+
# control-plane keepalive. enrich_structured_batch resolves its
|
|
130
|
+
# own connection, so on a worker thread it binds that thread's.
|
|
131
|
+
out = enrich_structured_batch(
|
|
132
|
+
prepared,
|
|
133
|
+
source_id=str(source_id or "") or None,
|
|
134
|
+
only_dimension=only_dimension,
|
|
138
135
|
)
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
# Piggyback (badge-pass pattern): auto-tag new conversations as
|
|
137
|
+
# work/personal with the configured local model. Best-effort;
|
|
138
|
+
# owner-set tags are never touched.
|
|
139
|
+
try:
|
|
140
|
+
from ....features.signal.conversation_context import (
|
|
141
|
+
classify_untagged_conversations,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
worker_conn = get_db_connection()
|
|
145
|
+
if worker_conn is not None:
|
|
146
|
+
out["conversation_context"] = classify_untagged_conversations(
|
|
147
|
+
worker_conn
|
|
148
|
+
)
|
|
149
|
+
except Exception as exc: # noqa: BLE001 — never blocks enrichment
|
|
150
|
+
logger.debug("conversation-context pass failed: %s", exc)
|
|
151
|
+
return out
|
|
152
|
+
|
|
153
|
+
structured_result = await asyncio.to_thread(_structured)
|
|
141
154
|
|
|
142
|
-
store = DimensionBriefStore(conn)
|
|
143
155
|
updated_dims: List[str] = []
|
|
144
156
|
|
|
145
157
|
for idx, dimension in enumerate(dimensions):
|
|
@@ -199,13 +211,34 @@ class DimensionSummaryJob(BaseEnrichmentJob):
|
|
|
199
211
|
continue
|
|
200
212
|
if not any(str(v or "").strip() for v in section_updates.values()):
|
|
201
213
|
continue
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
214
|
+
|
|
215
|
+
def _merge(
|
|
216
|
+
_dimension: str = dimension,
|
|
217
|
+
_updates: Dict[str, Optional[str]] = section_updates,
|
|
218
|
+
_model: Optional[str] = (
|
|
219
|
+
result.output.get("model")
|
|
220
|
+
if result.status == "completed" and result.output
|
|
221
|
+
else None
|
|
222
|
+
),
|
|
223
|
+
_provider: str = provider,
|
|
224
|
+
) -> None:
|
|
225
|
+
# merge_system_update ensures the brief head and appends a
|
|
226
|
+
# revision, both under the write gate — a blocking OS lock that
|
|
227
|
+
# on the event loop stalls every coroutine, including the
|
|
228
|
+
# control-plane keepalive. The store binds whichever connection
|
|
229
|
+
# it is built with, so build it on the worker thread.
|
|
230
|
+
worker_conn = get_db_connection()
|
|
231
|
+
if worker_conn is None:
|
|
232
|
+
return
|
|
233
|
+
DimensionBriefStore(worker_conn).merge_system_update(
|
|
234
|
+
_dimension,
|
|
235
|
+
_updates,
|
|
236
|
+
source_id=source_id,
|
|
237
|
+
model=_model,
|
|
238
|
+
provider=_provider,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
await asyncio.to_thread(_merge)
|
|
209
242
|
updated_dims.append(dimension)
|
|
210
243
|
if progress_callback:
|
|
211
244
|
progress_callback(idx + 1, len(dimensions))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
from typing import Any, Callable, Dict, List, Optional
|
|
@@ -169,7 +170,14 @@ class EntitiesJob(BaseEnrichmentJob):
|
|
|
169
170
|
|
|
170
171
|
if entity_spine_enabled() and results:
|
|
171
172
|
try:
|
|
172
|
-
|
|
173
|
+
# Spine resolution upserts entities, mentions, edges and
|
|
174
|
+
# dossiers under the write gate — a blocking OS lock that on
|
|
175
|
+
# the event loop stalls every coroutine, including the
|
|
176
|
+
# control-plane keepalive. It resolves its own connection, so
|
|
177
|
+
# on a worker thread it binds that thread's handle.
|
|
178
|
+
await asyncio.to_thread(
|
|
179
|
+
self._resolve_into_spine, results, canonical_messages
|
|
180
|
+
)
|
|
173
181
|
except Exception as exc:
|
|
174
182
|
logger.warning("entity spine resolution failed: %s", exc)
|
|
175
183
|
|
|
@@ -10,6 +10,7 @@ Gated by TOPOS_STATS (default on).
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import asyncio
|
|
13
14
|
import logging
|
|
14
15
|
import os
|
|
15
16
|
from typing import Any, Callable, Dict, List, Optional
|
|
@@ -44,24 +45,37 @@ class StatisticsJob(BaseEnrichmentJob):
|
|
|
44
45
|
canonical_messages: List[Dict[str, Any]],
|
|
45
46
|
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
46
47
|
) -> List[Dict[str, Any]]:
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
def _fold_and_promote() -> Optional[Dict[str, Any]]:
|
|
49
|
+
# Every step here takes the write gate — a blocking OS lock:
|
|
50
|
+
# StatsEngine's constructor seeds stat definitions, fold_batch
|
|
51
|
+
# holds it for the batch, and promotion runs migrations through
|
|
52
|
+
# AdapterFactory. On the event loop that stalls every coroutine,
|
|
53
|
+
# including the control-plane keepalive, so the whole stretch runs
|
|
54
|
+
# on a worker thread against that thread's own connection.
|
|
55
|
+
conn = get_db_connection()
|
|
56
|
+
if conn is None:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
from ....features.stats.engine import StatsEngine
|
|
60
|
+
|
|
61
|
+
engine = StatsEngine(conn)
|
|
62
|
+
folded = dict(engine.fold_batch(canonical_messages))
|
|
63
|
+
folded["promoted"] = 0
|
|
64
|
+
if self._should_promote(conn, folded["rows_folded"]):
|
|
65
|
+
try:
|
|
66
|
+
from ....storage.adapters.factory import AdapterFactory
|
|
67
|
+
|
|
68
|
+
bundle = AdapterFactory.create("local_database", conn=conn)
|
|
69
|
+
folded["promoted"] = engine.promote_insights(bundle)
|
|
70
|
+
self._record_promotion(conn)
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
logger.warning("stat insight promotion failed: %s", exc)
|
|
73
|
+
return folded
|
|
74
|
+
|
|
75
|
+
result = await asyncio.to_thread(_fold_and_promote)
|
|
76
|
+
if result is None:
|
|
49
77
|
return [{"_deferred": True, "error": "database_unavailable"}]
|
|
50
|
-
|
|
51
|
-
from ....features.stats.engine import StatsEngine
|
|
52
|
-
|
|
53
|
-
engine = StatsEngine(conn)
|
|
54
|
-
result = engine.fold_batch(canonical_messages)
|
|
55
|
-
promoted = 0
|
|
56
|
-
if self._should_promote(conn, result["rows_folded"]):
|
|
57
|
-
try:
|
|
58
|
-
from ....storage.adapters.factory import AdapterFactory
|
|
59
|
-
|
|
60
|
-
bundle = AdapterFactory.create("local_database", conn=conn)
|
|
61
|
-
promoted = engine.promote_insights(bundle)
|
|
62
|
-
self._record_promotion(conn)
|
|
63
|
-
except Exception as exc:
|
|
64
|
-
logger.warning("stat insight promotion failed: %s", exc)
|
|
78
|
+
promoted = result["promoted"]
|
|
65
79
|
|
|
66
80
|
if progress_callback:
|
|
67
81
|
progress_callback(len(canonical_messages), len(canonical_messages))
|
|
@@ -90,10 +104,18 @@ class StatisticsJob(BaseEnrichmentJob):
|
|
|
90
104
|
except (json.JSONDecodeError, TypeError, ValueError):
|
|
91
105
|
pending = 0
|
|
92
106
|
pending += rows_folded
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
# Gated AND committed. Ungated this counter update was still a write: it
|
|
108
|
+
# took SQLite's write lock at execute time on the event loop's
|
|
109
|
+
# connection and, with no commit anywhere after it, held that lock for
|
|
110
|
+
# the rest of the pipeline. Every other thread's first write then waited
|
|
111
|
+
# out the full 30s busy_timeout and failed "database is locked" — which
|
|
112
|
+
# is how this job lost its own fold on repeat ingests.
|
|
113
|
+
with with_db_write():
|
|
114
|
+
conn.execute(
|
|
115
|
+
"UPDATE stat_state SET state_json=? WHERE stat_id=? AND group_key='' AND bucket_date=''",
|
|
116
|
+
(json.dumps({"pending": pending}), _META_STAT_ID),
|
|
117
|
+
)
|
|
118
|
+
commit_connection(conn)
|
|
97
119
|
if pending >= _PROMOTE_EVERY_ROWS:
|
|
98
120
|
return True
|
|
99
121
|
stale = conn.execute(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import logging
|
|
6
7
|
from typing import Any, Callable, Dict, List, Optional
|
|
7
8
|
|
|
@@ -27,10 +28,18 @@ class TimelineJob(BaseEnrichmentJob):
|
|
|
27
28
|
canonical_messages: List[Dict[str, Any]],
|
|
28
29
|
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
29
30
|
) -> List[Dict[str, Any]]:
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
def _project():
|
|
32
|
+
# project_timeline_rows holds the write gate for the whole batch —
|
|
33
|
+
# a blocking OS lock — so it runs on a worker thread with that
|
|
34
|
+
# thread's own connection, never on the event loop.
|
|
35
|
+
conn = get_db_connection()
|
|
36
|
+
if conn is None:
|
|
37
|
+
return None
|
|
38
|
+
return project_timeline_rows(conn, canonical_messages)
|
|
39
|
+
|
|
40
|
+
result = await asyncio.to_thread(_project)
|
|
41
|
+
if result is None:
|
|
32
42
|
return [{"_deferred": True, "error": "database_unavailable"}]
|
|
33
|
-
result = project_timeline_rows(conn, canonical_messages)
|
|
34
43
|
if progress_callback:
|
|
35
44
|
progress_callback(len(canonical_messages), len(canonical_messages))
|
|
36
45
|
logger.debug(
|