topos-node 1.3.7__tar.gz → 1.3.9__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.
Files changed (622) hide show
  1. {topos_node-1.3.7/topos_node.egg-info → topos_node-1.3.9}/PKG-INFO +1 -1
  2. {topos_node-1.3.7 → topos_node-1.3.9}/pyproject.toml +1 -1
  3. {topos_node-1.3.7 → topos_node-1.3.9}/topos/__version__.py +2 -2
  4. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/tray.py +6 -0
  5. {topos_node-1.3.7 → topos_node-1.3.9}/topos/control_plane_client.py +20 -3
  6. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/ingest.py +23 -13
  7. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/state.py +22 -1
  8. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/derivation_recovery.py +141 -55
  9. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/attention_triage_job.py +26 -6
  10. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/dimension_summary_job.py +57 -24
  11. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/entities_job.py +9 -1
  12. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/statistics_job.py +43 -21
  13. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/timeline_job.py +12 -3
  14. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/orchestrator.py +71 -10
  15. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/graph_refresh.py +32 -0
  16. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/canonical_pipeline.py +24 -9
  17. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/ingest_helpers.py +87 -52
  18. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/manager.py +109 -94
  19. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/reprocess.py +32 -25
  20. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/job_runner.py +32 -2
  21. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/job_store.py +23 -0
  22. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/scope_registry.json +12 -4
  23. {topos_node-1.3.7 → topos_node-1.3.9}/topos/runtime_update.py +65 -2
  24. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/__init__.py +88 -1
  25. topos_node-1.3.9/topos/storage/db/write_gate.py +688 -0
  26. topos_node-1.3.9/topos/testing/lifespan.py +69 -0
  27. {topos_node-1.3.7 → topos_node-1.3.9}/topos/upgrades/manifests.json +33 -0
  28. {topos_node-1.3.7 → topos_node-1.3.9}/topos/upgrades/runner.py +29 -3
  29. {topos_node-1.3.7 → topos_node-1.3.9/topos_node.egg-info}/PKG-INFO +1 -1
  30. topos_node-1.3.7/topos/storage/db/write_gate.py +0 -336
  31. topos_node-1.3.7/topos/testing/lifespan.py +0 -22
  32. {topos_node-1.3.7 → topos_node-1.3.9}/LICENSE +0 -0
  33. {topos_node-1.3.7 → topos_node-1.3.9}/MANIFEST.in +0 -0
  34. {topos_node-1.3.7 → topos_node-1.3.9}/README.md +0 -0
  35. {topos_node-1.3.7 → topos_node-1.3.9}/setup.cfg +0 -0
  36. {topos_node-1.3.7 → topos_node-1.3.9}/shared/__init__.py +0 -0
  37. {topos_node-1.3.7 → topos_node-1.3.9}/shared/filtering.py +0 -0
  38. {topos_node-1.3.7 → topos_node-1.3.9}/shared/schema_registry.py +0 -0
  39. {topos_node-1.3.7 → topos_node-1.3.9}/tests/test_extensions.py +0 -0
  40. {topos_node-1.3.7 → topos_node-1.3.9}/tests/test_llm_integrations_storage.py +0 -0
  41. {topos_node-1.3.7 → topos_node-1.3.9}/tests/test_prewarm_first_run.py +0 -0
  42. {topos_node-1.3.7 → topos_node-1.3.9}/tests/test_protocol_handled_types.py +0 -0
  43. {topos_node-1.3.7 → topos_node-1.3.9}/tests/test_system_computer_name.py +0 -0
  44. {topos_node-1.3.7 → topos_node-1.3.9}/topos/__init__.py +0 -0
  45. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/__init__.py +0 -0
  46. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/duckdb_adapter.py +0 -0
  47. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/messenger_communities.py +0 -0
  48. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/messenger_graph.py +0 -0
  49. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/messenger_labels.py +0 -0
  50. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/profiles.py +0 -0
  51. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/query_engine.py +0 -0
  52. {topos_node-1.3.7 → topos_node-1.3.9}/topos/analytics/raw_queries.py +0 -0
  53. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/__init__.py +0 -0
  54. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/analytics.py +0 -0
  55. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/app_registry.py +0 -0
  56. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/backup.py +0 -0
  57. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/compute_remote.py +0 -0
  58. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/conversation_context.py +0 -0
  59. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/data_commit.py +0 -0
  60. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/data_explorer_table_prefs.py +0 -0
  61. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/database_explorer.py +0 -0
  62. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/db.py +0 -0
  63. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/device.py +0 -0
  64. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/engine_run.py +0 -0
  65. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/enrichment.py +0 -0
  66. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/enrichment_lab.py +0 -0
  67. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/facts_llm_config.py +0 -0
  68. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/filter_lab.py +0 -0
  69. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/health.py +0 -0
  70. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/home_chat.py +0 -0
  71. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/ingestion_api.py +0 -0
  72. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/ingestion_compat.py +0 -0
  73. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/ingestion_sources.py +0 -0
  74. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/intelligence_lifecycle.py +0 -0
  75. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/llm.py +0 -0
  76. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/local_mcp.py +0 -0
  77. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/messenger_analytics.py +0 -0
  78. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/privacy_disclose.py +0 -0
  79. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/query_api.py +0 -0
  80. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/runtime_bootstrap.py +0 -0
  81. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/sanitization_ollama_config.py +0 -0
  82. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/shell.py +0 -0
  83. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/signal.py +0 -0
  84. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/signal_extraction_config.py +0 -0
  85. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/source_install.py +0 -0
  86. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/source_scrub.py +0 -0
  87. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/sources.py +0 -0
  88. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/sources_overview.py +0 -0
  89. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/sync.py +0 -0
  90. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/tool_index.py +0 -0
  91. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/ui_config.py +0 -0
  92. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/uma_data.py +0 -0
  93. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/upgrades.py +0 -0
  94. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/usage.py +0 -0
  95. {topos_node-1.3.7 → topos_node-1.3.9}/topos/api/user_identity.py +0 -0
  96. {topos_node-1.3.7 → topos_node-1.3.9}/topos/app.py +0 -0
  97. {topos_node-1.3.7 → topos_node-1.3.9}/topos/auth.py +0 -0
  98. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/__init__.py +0 -0
  99. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/__init__.py +0 -0
  100. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/base.py +0 -0
  101. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
  102. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
  103. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/demo_mappers.py +0 -0
  104. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/documents_mapper.py +0 -0
  105. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
  106. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
  107. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  108. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
  109. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/models.py +0 -0
  110. {topos_node-1.3.7 → topos_node-1.3.9}/topos/canonicalization/resolver.py +0 -0
  111. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/__init__.py +0 -0
  112. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/__main__.py +0 -0
  113. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/assets/topos_blk_rounded.png +0 -0
  114. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/assets/topos_white.png +0 -0
  115. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/commands.py +0 -0
  116. {topos_node-1.3.7 → topos_node-1.3.9}/topos/cli/reprocess_cmd.py +0 -0
  117. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/__init__.py +0 -0
  118. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/conversation_context_llm.py +0 -0
  119. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/facts_llm.py +0 -0
  120. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/model_packs.py +0 -0
  121. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/sanitization_ollama.py +0 -0
  122. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/settings.py +0 -0
  123. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/signal_extraction.py +0 -0
  124. {topos_node-1.3.7 → topos_node-1.3.9}/topos/config/uvicorn_logging.json +0 -0
  125. {topos_node-1.3.7 → topos_node-1.3.9}/topos/contacts/__init__.py +0 -0
  126. {topos_node-1.3.7 → topos_node-1.3.9}/topos/contacts/identity.py +0 -0
  127. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/__init__.py +0 -0
  128. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/api_models.py +0 -0
  129. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/connection_resilience.py +0 -0
  130. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/device_helpers.py +0 -0
  131. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/errors.py +0 -0
  132. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/events.py +0 -0
  133. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/__init__.py +0 -0
  134. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/common.py +0 -0
  135. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/complexity.py +0 -0
  136. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/config.py +0 -0
  137. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/contacts_import.py +0 -0
  138. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/database_explorer.py +0 -0
  139. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/device.py +0 -0
  140. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/enrichment.py +0 -0
  141. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/enrichment_lab.py +0 -0
  142. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/filter_lab.py +0 -0
  143. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/graph_query.py +0 -0
  144. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/home_chat.py +0 -0
  145. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/messages.py +0 -0
  146. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/messenger_analytics.py +0 -0
  147. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/query.py +0 -0
  148. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/registry.py +0 -0
  149. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/routines.py +0 -0
  150. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/signal_features.py +0 -0
  151. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/sources.py +0 -0
  152. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/timeline_daily.py +0 -0
  153. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/tool_index.py +0 -0
  154. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/handlers/uma.py +0 -0
  155. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/logging.py +0 -0
  156. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/metrics.py +0 -0
  157. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/routine_access.py +0 -0
  158. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/startup_banner.py +0 -0
  159. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/table_layers.py +0 -0
  160. {topos_node-1.3.7 → topos_node-1.3.9}/topos/core/types.py +0 -0
  161. {topos_node-1.3.7 → topos_node-1.3.9}/topos/data_explorer_row_delete.py +0 -0
  162. {topos_node-1.3.7 → topos_node-1.3.9}/topos/data_explorer_table_prefs.py +0 -0
  163. {topos_node-1.3.7 → topos_node-1.3.9}/topos/data_explorer_tables.py +0 -0
  164. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/__init__.py +0 -0
  165. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/canonical_writer.py +0 -0
  166. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/content_policy.py +0 -0
  167. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/field_registry.py +0 -0
  168. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/privacy_layer.py +0 -0
  169. {topos_node-1.3.7 → topos_node-1.3.9}/topos/disclosure/tier.py +0 -0
  170. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/__init__.py +0 -0
  171. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/__init__.py +0 -0
  172. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/base.py +0 -0
  173. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/generative_prompts.py +0 -0
  174. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/generative_response.py +0 -0
  175. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/huggingface.py +0 -0
  176. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/ollama.py +0 -0
  177. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/openai.py +0 -0
  178. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/openai_compatible.py +0 -0
  179. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/redpill.py +0 -0
  180. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/backends/stub.py +0 -0
  181. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/client.py +0 -0
  182. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/engine.py +0 -0
  183. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/intake.py +0 -0
  184. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/memory_utils.py +0 -0
  185. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/model_cache.py +0 -0
  186. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/pipeline_memory.py +0 -0
  187. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/queue_manager.py +0 -0
  188. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/registration.py +0 -0
  189. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/result_formatter.py +0 -0
  190. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/router.py +0 -0
  191. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/scoped_token.py +0 -0
  192. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/tasks.py +0 -0
  193. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/transport.py +0 -0
  194. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/usage_guard.py +0 -0
  195. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/usage_observation.py +0 -0
  196. {topos_node-1.3.7 → topos_node-1.3.9}/topos/engine/validator.py +0 -0
  197. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/__init__.py +0 -0
  198. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/catalog.py +0 -0
  199. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/derived_tables.py +0 -0
  200. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/job_writer.py +0 -0
  201. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/__init__.py +0 -0
  202. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/base.py +0 -0
  203. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  204. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
  205. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
  206. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
  207. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
  208. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/complexity_snapshot_job.py +0 -0
  209. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
  210. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
  211. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
  212. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
  213. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
  214. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
  215. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
  216. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
  217. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
  218. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
  219. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
  220. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
  221. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/raw/__init__.py +0 -0
  222. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  223. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/raw/language_job.py +0 -0
  224. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  225. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  226. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/model_overrides.py +0 -0
  227. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/models/__init__.py +0 -0
  228. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/models/manager.py +0 -0
  229. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/models/mvp_defaults.py +0 -0
  230. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/models/registry.py +0 -0
  231. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/models/versioning.py +0 -0
  232. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/pipeline_activity.py +0 -0
  233. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/processor.py +0 -0
  234. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/progress_bar.py +0 -0
  235. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/registry_contract.py +0 -0
  236. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/signal_derivation_config.json +0 -0
  237. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/source_overrides.py +0 -0
  238. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment/website_classifier.py +0 -0
  239. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/__init__.py +0 -0
  240. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/bundles.py +0 -0
  241. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/model_resolve.py +0 -0
  242. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/schema.py +0 -0
  243. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/service.py +0 -0
  244. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/store.py +0 -0
  245. {topos_node-1.3.7 → topos_node-1.3.9}/topos/enrichment_lab/worker.py +0 -0
  246. {topos_node-1.3.7 → topos_node-1.3.9}/topos/evals/__init__.py +0 -0
  247. {topos_node-1.3.7 → topos_node-1.3.9}/topos/evals/enrichment_eval.py +0 -0
  248. {topos_node-1.3.7 → topos_node-1.3.9}/topos/extensions.py +0 -0
  249. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/__init__.py +0 -0
  250. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/canonical.py +0 -0
  251. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/engine.py +0 -0
  252. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/entropy.py +0 -0
  253. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/focus.py +0 -0
  254. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/graph_metrics.py +0 -0
  255. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/influence.py +0 -0
  256. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/projection.py +0 -0
  257. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/snapshots.py +0 -0
  258. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/store.py +0 -0
  259. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/topic_merge.py +0 -0
  260. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/topics.py +0 -0
  261. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/topics_daily.py +0 -0
  262. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/complexity/volatility.py +0 -0
  263. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/__init__.py +0 -0
  264. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/affinity.py +0 -0
  265. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/affinity_owner.py +0 -0
  266. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/affinity_quality.py +0 -0
  267. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/consolidation.py +0 -0
  268. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/context_vectors.py +0 -0
  269. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/cypher.py +0 -0
  270. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/declared_mappings.py +0 -0
  271. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/dossier.py +0 -0
  272. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/edges.py +0 -0
  273. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/fact_materializer.py +0 -0
  274. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/graph_enrichers.py +0 -0
  275. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/graph_search.py +0 -0
  276. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/linking.py +0 -0
  277. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/maintenance.py +0 -0
  278. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/reads.py +0 -0
  279. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/rebuild_subprocess.py +0 -0
  280. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/entities/resolver.py +0 -0
  281. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/__init__.py +0 -0
  282. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/extract.py +0 -0
  283. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/llm_extract.py +0 -0
  284. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/reads.py +0 -0
  285. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/store.py +0 -0
  286. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/facts/verdicts.py +0 -0
  287. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/fit/evaluator.py +0 -0
  288. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/fit/opportunity_types.json +0 -0
  289. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/__init__.py +0 -0
  290. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/blackhole.py +0 -0
  291. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/blackhole_guard.py +0 -0
  292. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/blackhole_llm.py +0 -0
  293. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/blackhole_rebuild.py +0 -0
  294. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/derived_scrub.py +0 -0
  295. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/exclusions.py +0 -0
  296. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/lifecycle/gc.py +0 -0
  297. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/provenance/__init__.py +0 -0
  298. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/provenance/posture.py +0 -0
  299. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/provenance/roles.py +0 -0
  300. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/__init__.py +0 -0
  301. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/brief_canonical_loader.py +0 -0
  302. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/brief_ontology.py +0 -0
  303. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/brief_renderer.py +0 -0
  304. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/brief_schemas.py +0 -0
  305. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/chunking.py +0 -0
  306. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/cluster_labels.py +0 -0
  307. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/conversation_context.py +0 -0
  308. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/data_health.py +0 -0
  309. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/brief_ontologies.json +0 -0
  310. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/intentions.json +0 -0
  311. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/profile.json +0 -0
  312. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/relationships.json +0 -0
  313. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
  314. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/time.json +0 -0
  315. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/definitions/work.json +0 -0
  316. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/derived_spec.py +0 -0
  317. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/dimension_briefs.py +0 -0
  318. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/dimension_definition_loader.py +0 -0
  319. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/dimension_profiles.py +0 -0
  320. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/dimension_registry.py +0 -0
  321. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/embed_context.py +0 -0
  322. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/extraction/artifact_router.py +0 -0
  323. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/extraction/artifact_store.py +0 -0
  324. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/extraction/rule_extractors.py +0 -0
  325. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/graph_sanitize.py +0 -0
  326. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/hybrid_search.py +0 -0
  327. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/incremental_clustering.py +0 -0
  328. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/model_recommendations.py +0 -0
  329. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/query_embed_cache.py +0 -0
  330. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/schemas.py +0 -0
  331. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/service.py +0 -0
  332. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/signal_object_store.py +0 -0
  333. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/source_hydration.py +0 -0
  334. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/structured_signal.py +0 -0
  335. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/tool_index.py +0 -0
  336. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/topic_clustering.py +0 -0
  337. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/typed_stores/aggregates.py +0 -0
  338. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/typed_stores/commitments.py +0 -0
  339. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/typed_stores/rhythm.py +0 -0
  340. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
  341. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/vector_codec.py +0 -0
  342. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/vector_math.py +0 -0
  343. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/signal/vector_settings.py +0 -0
  344. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/stats/__init__.py +0 -0
  345. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/stats/definitions.py +0 -0
  346. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/stats/engine.py +0 -0
  347. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/stats/fold.py +0 -0
  348. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/stats/insights.py +0 -0
  349. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/timeline_projection.py +0 -0
  350. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/timeline_rollup.py +0 -0
  351. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/__init__.py +0 -0
  352. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/badges.py +0 -0
  353. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/daily.py +0 -0
  354. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/dashboard.py +0 -0
  355. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/instruments.py +0 -0
  356. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/intents.py +0 -0
  357. {topos_node-1.3.7 → topos_node-1.3.9}/topos/features/triage/readiness.py +0 -0
  358. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/__init__.py +0 -0
  359. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/bundles.py +0 -0
  360. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/schema.py +0 -0
  361. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/service.py +0 -0
  362. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/store.py +0 -0
  363. {topos_node-1.3.7 → topos_node-1.3.9}/topos/filter_lab/worker.py +0 -0
  364. {topos_node-1.3.7 → topos_node-1.3.9}/topos/home_chat/__init__.py +0 -0
  365. {topos_node-1.3.7 → topos_node-1.3.9}/topos/home_chat/schema.py +0 -0
  366. {topos_node-1.3.7 → topos_node-1.3.9}/topos/home_chat/store.py +0 -0
  367. {topos_node-1.3.7 → topos_node-1.3.9}/topos/hosted_pool_lease.py +0 -0
  368. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/__init__.py +0 -0
  369. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/checkpoints/__init__.py +0 -0
  370. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  371. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  372. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/inbox_crypto.py +0 -0
  373. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/inbox_drain.py +0 -0
  374. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/jobs.py +0 -0
  375. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/journal_location_fanout.py +0 -0
  376. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/journal_time_log_normalize.py +0 -0
  377. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/local_sync.py +0 -0
  378. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/log_preview.py +0 -0
  379. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parser.py +0 -0
  380. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/__init__.py +0 -0
  381. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/base.py +0 -0
  382. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/browser_parser.py +0 -0
  383. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/calendar_parser.py +0 -0
  384. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  385. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  386. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
  387. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/documents_parser.py +0 -0
  388. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/github_activity_parser.py +0 -0
  389. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
  390. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/grok_parser.py +0 -0
  391. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/messenger_parser.py +0 -0
  392. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/parsers/voxterm_parser.py +0 -0
  393. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/progress.py +0 -0
  394. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/__init__.py +0 -0
  395. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/base.py +0 -0
  396. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/calendar.py +0 -0
  397. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/chatgpt.py +0 -0
  398. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/contact_importers.py +0 -0
  399. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/grok.py +0 -0
  400. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/imessage_reader.py +0 -0
  401. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/signal_export_parser.py +0 -0
  402. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/sources/signal_reader.py +0 -0
  403. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/state_machine.py +0 -0
  404. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/triggers/__init__.py +0 -0
  405. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/triggers/file_trigger.py +0 -0
  406. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  407. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/usage_inbox_dedupe.py +0 -0
  408. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/validation/__init__.py +0 -0
  409. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/validation/base.py +0 -0
  410. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/validation/schema_registry.py +0 -0
  411. {topos_node-1.3.7 → topos_node-1.3.9}/topos/ingestion/validation/schema_validator.py +0 -0
  412. {topos_node-1.3.7 → topos_node-1.3.9}/topos/lineage/__init__.py +0 -0
  413. {topos_node-1.3.7 → topos_node-1.3.9}/topos/lineage/provenance.py +0 -0
  414. {topos_node-1.3.7 → topos_node-1.3.9}/topos/lineage/tracker.py +0 -0
  415. {topos_node-1.3.7 → topos_node-1.3.9}/topos/llm_integrations_storage.py +0 -0
  416. {topos_node-1.3.7 → topos_node-1.3.9}/topos/mcp_stdio_proxy.py +0 -0
  417. {topos_node-1.3.7 → topos_node-1.3.9}/topos/observability/__init__.py +0 -0
  418. {topos_node-1.3.7 → topos_node-1.3.9}/topos/observability/alerts.py +0 -0
  419. {topos_node-1.3.7 → topos_node-1.3.9}/topos/observability/metrics.py +0 -0
  420. {topos_node-1.3.7 → topos_node-1.3.9}/topos/observability/tracing.py +0 -0
  421. {topos_node-1.3.7 → topos_node-1.3.9}/topos/openai_client.py +0 -0
  422. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/__init__.py +0 -0
  423. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/audit.py +0 -0
  424. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/envelope.py +0 -0
  425. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/stages.py +0 -0
  426. {topos_node-1.3.7 → topos_node-1.3.9}/topos/pipeline/stub_enqueue.py +0 -0
  427. {topos_node-1.3.7 → topos_node-1.3.9}/topos/projections/__init__.py +0 -0
  428. {topos_node-1.3.7 → topos_node-1.3.9}/topos/projections/vector_index/__init__.py +0 -0
  429. {topos_node-1.3.7 → topos_node-1.3.9}/topos/projections/vector_index/base.py +0 -0
  430. {topos_node-1.3.7 → topos_node-1.3.9}/topos/projections/vector_index/builders.py +0 -0
  431. {topos_node-1.3.7 → topos_node-1.3.9}/topos/projections/vector_index/health_checks.py +0 -0
  432. {topos_node-1.3.7 → topos_node-1.3.9}/topos/protocol/__init__.py +0 -0
  433. {topos_node-1.3.7 → topos_node-1.3.9}/topos/protocol/handled_message_types.json +0 -0
  434. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/__init__.py +0 -0
  435. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/audit.py +0 -0
  436. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/cohort_resolvers.py +0 -0
  437. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/ddr.py +0 -0
  438. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/disclosure.py +0 -0
  439. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/fingerprint.py +0 -0
  440. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/game_layer.py +0 -0
  441. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/grant_cache.py +0 -0
  442. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/inference.py +0 -0
  443. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/intent.py +0 -0
  444. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/manifest.py +0 -0
  445. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/manifest_validation.py +0 -0
  446. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/minimizer.py +0 -0
  447. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/negotiation.py +0 -0
  448. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/pipeline.py +0 -0
  449. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/planner.py +0 -0
  450. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/retrieval.py +0 -0
  451. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/runtime.py +0 -0
  452. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/scope_registry_loader.py +0 -0
  453. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/session.py +0 -0
  454. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/session_utils.py +0 -0
  455. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/source_generation.py +0 -0
  456. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/truth_facts.py +0 -0
  457. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/truth_prompts.py +0 -0
  458. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/turn_classifier.py +0 -0
  459. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/types.py +0 -0
  460. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/verify.py +0 -0
  461. {topos_node-1.3.7 → topos_node-1.3.9}/topos/query/verify_modes.py +0 -0
  462. {topos_node-1.3.7 → topos_node-1.3.9}/topos/rate_limit.py +0 -0
  463. {topos_node-1.3.7 → topos_node-1.3.9}/topos/routines/__init__.py +0 -0
  464. {topos_node-1.3.7 → topos_node-1.3.9}/topos/routines/schema.py +0 -0
  465. {topos_node-1.3.7 → topos_node-1.3.9}/topos/routines/store.py +0 -0
  466. {topos_node-1.3.7 → topos_node-1.3.9}/topos/runtime_housekeeping.py +0 -0
  467. {topos_node-1.3.7 → topos_node-1.3.9}/topos/runtime_shutdown.py +0 -0
  468. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sanitization/__init__.py +0 -0
  469. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sanitization/nsfw_classifier.py +0 -0
  470. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sanitization/ollama_transforms.py +0 -0
  471. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sanitization/prewarm.py +0 -0
  472. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sanitization/privacy_filter.py +0 -0
  473. {topos_node-1.3.7 → topos_node-1.3.9}/topos/scope_resolution.py +0 -0
  474. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/__init__.py +0 -0
  475. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/container.py +0 -0
  476. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/embeddings/__init__.py +0 -0
  477. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/embeddings/base.py +0 -0
  478. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/embeddings/local.py +0 -0
  479. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/embeddings/remote.py +0 -0
  480. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/interfaces.py +0 -0
  481. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/llm/__init__.py +0 -0
  482. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/llm/base.py +0 -0
  483. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/llm/openai.py +0 -0
  484. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/local.py +0 -0
  485. {topos_node-1.3.7 → topos_node-1.3.9}/topos/services/postgres.py +0 -0
  486. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/__init__.py +0 -0
  487. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/bundled_canonical_triples.py +0 -0
  488. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/canonical_signal_defaults.py +0 -0
  489. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/definitions.py +0 -0
  490. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/install_service.py +0 -0
  491. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/registry.py +0 -0
  492. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/runtime_install.py +0 -0
  493. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/scrub_attribution.py +0 -0
  494. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sources/scrub_service.py +0 -0
  495. {topos_node-1.3.7 → topos_node-1.3.9}/topos/startup_banner.py +0 -0
  496. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/__init__.py +0 -0
  497. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/__init__.py +0 -0
  498. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/factory.py +0 -0
  499. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/fakes.py +0 -0
  500. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/postgres/stores.py +0 -0
  501. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/protocols.py +0 -0
  502. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/sqlite/__init__.py +0 -0
  503. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/sqlite/stores.py +0 -0
  504. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/adapters/sqlite/vector_search.py +0 -0
  505. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/__init__.py +0 -0
  506. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/activity_tables.py +0 -0
  507. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  508. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
  509. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  510. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/ai_chat/model.py +0 -0
  511. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/ai_chat/tables.py +0 -0
  512. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
  513. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/canonical_store.py +0 -0
  514. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/conversations_tables.py +0 -0
  515. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/mapping_store.py +0 -0
  516. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/canonical/postgres.py +0 -0
  517. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/__init__.py +0 -0
  518. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/client.py +0 -0
  519. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/connection_tuning.py +0 -0
  520. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
  521. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/actor_role_v1.py +0 -0
  522. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/affinity_pair_labels_v1.py +0 -0
  523. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/attention_triage_v1.py +0 -0
  524. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/attention_triage_v2.py +0 -0
  525. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/backup.py +0 -0
  526. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
  527. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
  528. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
  529. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
  530. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/complexity_v1.py +0 -0
  531. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/conversation_context_v1.py +0 -0
  532. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
  533. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/documents_v1.py +0 -0
  534. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/enrichment_spec_version_v1.py +0 -0
  535. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_affinity_v1.py +0 -0
  536. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_blackhole_v1.py +0 -0
  537. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_context_vectors_v1.py +0 -0
  538. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_context_vectors_v2.py +0 -0
  539. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
  540. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/entity_mentions_authored_v1.py +0 -0
  541. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/episodes_v1.py +0 -0
  542. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
  543. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
  544. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
  545. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
  546. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
  547. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
  548. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/message_emotions_role_backfill_v1.py +0 -0
  549. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/message_emotions_role_v1.py +0 -0
  550. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
  551. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/registry.py +0 -0
  552. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/registry_checksums.json +0 -0
  553. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/remediation_person_model.py +0 -0
  554. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/scope_source_generation.py +0 -0
  555. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
  556. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
  557. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_objects.py +0 -0
  558. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
  559. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
  560. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/signal_summaries_drop_v1.py +0 -0
  561. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  562. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
  563. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
  564. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
  565. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
  566. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
  567. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
  568. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
  569. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
  570. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
  571. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
  572. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
  573. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
  574. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
  575. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
  576. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
  577. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
  578. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
  579. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
  580. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/paths.py +0 -0
  581. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/postgres.py +0 -0
  582. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/schema.py +0 -0
  583. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/db/storage_breakdown.py +0 -0
  584. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/enrichment/__init__.py +0 -0
  585. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  586. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  587. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/normalized/__init__.py +0 -0
  588. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/normalized/normalized_store.py +0 -0
  589. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/oplog/__init__.py +0 -0
  590. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/oplog/decision.py +0 -0
  591. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/oplog/oplog_store.py +0 -0
  592. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/oplog/postgres.py +0 -0
  593. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/person/identity_resolver.py +0 -0
  594. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/projections/__init__.py +0 -0
  595. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/projections/index_ops_store.py +0 -0
  596. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/projections/vector_index_store.py +0 -0
  597. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/__init__.py +0 -0
  598. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/browser_flat_tables.py +0 -0
  599. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/file_store.py +0 -0
  600. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/raw_store.py +0 -0
  601. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/raw_tables_manager.py +0 -0
  602. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/raw/sqlite_raw_store.py +0 -0
  603. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/security/encryption.py +0 -0
  604. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/signal_identity.py +0 -0
  605. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/source_settings.py +0 -0
  606. {topos_node-1.3.7 → topos_node-1.3.9}/topos/storage/user_identity.py +0 -0
  607. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sync/__init__.py +0 -0
  608. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sync/client.py +0 -0
  609. {topos_node-1.3.7 → topos_node-1.3.9}/topos/sync_handlers.py +0 -0
  610. {topos_node-1.3.7 → topos_node-1.3.9}/topos/testing/__init__.py +0 -0
  611. {topos_node-1.3.7 → topos_node-1.3.9}/topos/uma_contact_enrichment.py +0 -0
  612. {topos_node-1.3.7 → topos_node-1.3.9}/topos/uma_filters.py +0 -0
  613. {topos_node-1.3.7 → topos_node-1.3.9}/topos/uma_resource_id.py +0 -0
  614. {topos_node-1.3.7 → topos_node-1.3.9}/topos/uma_rpt.py +0 -0
  615. {topos_node-1.3.7 → topos_node-1.3.9}/topos/upgrades/__init__.py +0 -0
  616. {topos_node-1.3.7 → topos_node-1.3.9}/topos/utils/base_object.py +0 -0
  617. {topos_node-1.3.7 → topos_node-1.3.9}/topos/websocket_client.py +0 -0
  618. {topos_node-1.3.7 → topos_node-1.3.9}/topos_node.egg-info/SOURCES.txt +0 -0
  619. {topos_node-1.3.7 → topos_node-1.3.9}/topos_node.egg-info/dependency_links.txt +0 -0
  620. {topos_node-1.3.7 → topos_node-1.3.9}/topos_node.egg-info/entry_points.txt +0 -0
  621. {topos_node-1.3.7 → topos_node-1.3.9}/topos_node.egg-info/requires.txt +0 -0
  622. {topos_node-1.3.7 → topos_node-1.3.9}/topos_node.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topos-node
3
- Version: 1.3.7
3
+ Version: 1.3.9
4
4
  Summary: Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://topos.dialogues.ai
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "topos-node"
7
- version = "1.3.7"
7
+ version = "1.3.9"
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"
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "1.3.7"
4
- __version_info__ = (1, 3, 7)
3
+ __version__ = "1.3.9"
4
+ __version_info__ = (1, 3, 9)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -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
- # Transform-heavy requests can block the event loop in the handler path long enough
301
- # to miss pong deadlines; disable pong timeout-driven disconnects.
302
- ping_timeout=None,
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
- db_conn = hub.get_db_connection()
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
- hub.record_uma_request(
222
- db_conn,
223
- owner_user_id=user_id,
224
- resource_id=resource_id,
225
- request_type="write",
226
- endpoint="app_ingest",
227
- requesting_user_id=(payload.get("requesting_user_id") or None),
228
- app_id=payload.get("app_id"),
229
- requesting_user_email=(payload.get("requesting_user_email") or "").strip() or None,
230
- access_channel=(payload.get("access_channel") or "internal").strip() or "internal",
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
@@ -240,6 +240,70 @@ def list_pending_derivation_retries(
240
240
  return out
241
241
 
242
242
 
243
+ async def retry_single_derivation(
244
+ conn: sqlite3.Connection,
245
+ *,
246
+ source_id: str,
247
+ sync_batch_id: str,
248
+ job_name: str,
249
+ record_ids: Optional[Sequence[str]] = None,
250
+ ) -> Dict[str, Any]:
251
+ """Re-run exactly one recorded derivation debt.
252
+
253
+ Reloads the debt's canonical records and re-runs ONLY the job that failed,
254
+ so a retry cannot disturb jobs that already succeeded. Jobs are idempotent
255
+ per (batch, job) at the ledger level; a retry that fails again simply leaves
256
+ the debt in place for the next attempt.
257
+
258
+ Returns ``{"outcome": "recovered" | "still_failing" | "skipped", ...}``.
259
+ "skipped" means the debt cannot be re-run mechanically (unknown source, no
260
+ surviving records) — the caller decides whether that discharges it.
261
+ """
262
+ if not job_name or not source_id:
263
+ return {"outcome": "skipped", "reason": "incomplete record"}
264
+ try:
265
+ from ..ingestion.canonical_pipeline import load_canonical_records_for_signal
266
+ # Reuses reprocess's resolver so a runtime-installed source rehydrates
267
+ # the same way it does for a manual reprocess.
268
+ from ..ingestion.reprocess import _resolve_source_def
269
+
270
+ try:
271
+ source_def = _resolve_source_def(source_id)
272
+ except ValueError:
273
+ return {"outcome": "skipped", "reason": "unknown source"}
274
+ records = load_canonical_records_for_signal(conn, source_def)
275
+ wanted = {str(r) for r in (record_ids or []) if r}
276
+ if wanted:
277
+ scoped = [
278
+ r
279
+ for r in records
280
+ if str(r.get("message_id") or r.get("record_id") or "") in wanted
281
+ ]
282
+ records = scoped or records
283
+ if not records:
284
+ return {"outcome": "skipped", "reason": "no records"}
285
+
286
+ from .orchestrator import SignalDerivationOrchestrator
287
+
288
+ result = await SignalDerivationOrchestrator().run_signal_derivation(
289
+ records, source_id, job_names=[job_name], sync_batch_id=sync_batch_id
290
+ )
291
+ if result.get("errors"):
292
+ return {
293
+ "outcome": "still_failing",
294
+ "error": result["errors"][0].get("error"),
295
+ }
296
+ # run_signal_derivation clears the debt itself on success.
297
+ return {
298
+ "outcome": "recovered",
299
+ "records": len(records),
300
+ "created": result.get("records_created", {}).get(job_name, 0),
301
+ }
302
+ except Exception as exc: # noqa: BLE001 — one bad debt must not stop the rest
303
+ logger.warning("[DERIVE:RETRY] retry failed job=%s source=%s: %s", job_name, source_id, exc)
304
+ return {"outcome": "still_failing", "error": str(exc)}
305
+
306
+
243
307
  async def retry_pending_derivations(
244
308
  conn: Optional[sqlite3.Connection] = None,
245
309
  *,
@@ -249,11 +313,6 @@ async def retry_pending_derivations(
249
313
  ) -> Dict[str, Any]:
250
314
  """Re-run derivation jobs that previously failed, clearing settled debts.
251
315
 
252
- Reloads each debt's canonical records and re-runs ONLY the job that failed,
253
- so a retry cannot disturb jobs that already succeeded. Jobs are idempotent
254
- per (batch, job) at the ledger level; a retry that fails again simply leaves
255
- the debt in place for the next attempt.
256
-
257
316
  ``dry_run`` reports what would run without touching anything.
258
317
  """
259
318
  from ..core.state import get_db_connection
@@ -278,61 +337,27 @@ async def retry_pending_derivations(
278
337
  ]
279
338
  return outcome
280
339
 
281
- from ..ingestion.canonical_pipeline import load_canonical_records_for_signal
282
- # Reuses reprocess's resolver so a runtime-installed source rehydrates the
283
- # same way it does for a manual reprocess.
284
- from ..ingestion.reprocess import _resolve_source_def
285
-
286
340
  for debt in pending:
287
341
  job_name = debt["job_name"]
288
342
  src = debt["source_id"]
289
343
  batch = debt["sync_batch_id"]
290
- if not job_name or not src:
291
- outcome["skipped"].append({**debt, "reason": "incomplete record"})
292
- continue
293
- try:
294
- try:
295
- source_def = _resolve_source_def(src)
296
- except ValueError:
297
- outcome["skipped"].append({"job_name": job_name, "source_id": src, "reason": "unknown source"})
298
- continue
299
- records = load_canonical_records_for_signal(conn, source_def)
300
- wanted = set(debt.get("record_ids") or [])
301
- if wanted:
302
- scoped = [
303
- r
304
- for r in records
305
- if str(r.get("message_id") or r.get("record_id") or "") in wanted
306
- ]
307
- records = scoped or records
308
- if not records:
309
- outcome["skipped"].append({"job_name": job_name, "source_id": src, "reason": "no records"})
310
- continue
311
-
312
- from .orchestrator import SignalDerivationOrchestrator
313
-
344
+ result = await retry_single_derivation(
345
+ conn,
346
+ source_id=src,
347
+ sync_batch_id=batch,
348
+ job_name=job_name,
349
+ record_ids=debt.get("record_ids") or [],
350
+ )
351
+ kind = result.pop("outcome")
352
+ entry = {"job_name": job_name, "source_id": src, **result}
353
+ if kind == "recovered":
314
354
  outcome["attempted"] += 1
315
- result = await SignalDerivationOrchestrator().run_signal_derivation(
316
- records, src, job_names=[job_name], sync_batch_id=batch
317
- )
318
- if result.get("errors"):
319
- outcome["still_failing"].append(
320
- {"job_name": job_name, "source_id": src, "error": result["errors"][0].get("error")}
321
- )
322
- else:
323
- # run_signal_derivation clears the debt itself on success.
324
- outcome["recovered"].append(
325
- {
326
- "job_name": job_name,
327
- "source_id": src,
328
- "batch": batch,
329
- "records": len(records),
330
- "created": result.get("records_created", {}).get(job_name, 0),
331
- }
332
- )
333
- except Exception as exc: # noqa: BLE001 — one bad debt must not stop the rest
334
- logger.warning("[DERIVE:RETRY] retry failed job=%s source=%s: %s", job_name, src, exc)
335
- outcome["still_failing"].append({"job_name": job_name, "source_id": src, "error": str(exc)})
355
+ outcome["recovered"].append({**entry, "batch": batch})
356
+ elif kind == "still_failing":
357
+ outcome["attempted"] += 1
358
+ outcome["still_failing"].append(entry)
359
+ else:
360
+ outcome["skipped"].append(entry)
336
361
 
337
362
  outcome["pending_after"] = len(list_pending_derivation_retries(conn, source_id=source_id, limit=1000))
338
363
  logger.info(
@@ -344,6 +369,67 @@ async def retry_pending_derivations(
344
369
  return outcome
345
370
 
346
371
 
372
+ #: How long a worker-claimed retry waits for an active derivation batch to end
373
+ #: before handing the job back to the queue. Debts are recorded MID-batch, and
374
+ #: the worker claims within its poll interval — re-running immediately would
375
+ #: re-contend for the same write gate that produced the original "database is
376
+ #: locked". The wait doubles as the requeue backoff: while a long batch runs,
377
+ #: the worker cycles claim → wait → requeue at this period instead of spinning.
378
+ _IN_FLIGHT_WAIT_SECONDS = 30.0
379
+ _IN_FLIGHT_POLL_SECONDS = 0.5
380
+
381
+
382
+ async def run_derivation_retry_job(payload: Dict[str, Any]) -> Dict[str, Any]:
383
+ """Worker executor for ``SIGNAL_DERIVE_RETRY_KIND`` pipeline jobs.
384
+
385
+ This is the "by the worker" half of the module contract: the debt record IS
386
+ the queue row, so the worker claims it and re-runs the one derivation it
387
+ describes. Success marks the row done (the orchestrator clears the debt,
388
+ then the worker completes the job). A retry that fails again returns an
389
+ error status, parking the row 'failed' — still visible in every debt
390
+ listing, re-queued by the next organic failure of the same (batch, job), and
391
+ re-runnable via ``POST /signal/derivation-debt/retry``. One claim is one
392
+ attempt; nothing here loops.
393
+ """
394
+ import asyncio
395
+
396
+ from .pipeline_activity import is_derivation_in_flight
397
+
398
+ waited = 0.0
399
+ while is_derivation_in_flight():
400
+ if waited >= _IN_FLIGHT_WAIT_SECONDS:
401
+ return {"status": "requeue", "reason": "derivation in flight"}
402
+ await asyncio.sleep(_IN_FLIGHT_POLL_SECONDS)
403
+ waited += _IN_FLIGHT_POLL_SECONDS
404
+
405
+ from ..core.state import get_db_connection
406
+
407
+ conn = get_db_connection()
408
+ if conn is None:
409
+ return {"status": "error", "error": "no database connection"}
410
+
411
+ job_name = str(payload.get("job_name") or "")
412
+ result = await retry_single_derivation(
413
+ conn,
414
+ source_id=str(payload.get("source_id") or ""),
415
+ sync_batch_id=str(payload.get("sync_batch_id") or "unknown"),
416
+ job_name=job_name,
417
+ record_ids=payload.get("record_ids") or [],
418
+ )
419
+ outcome = result.pop("outcome")
420
+ if outcome == "recovered":
421
+ return {
422
+ "status": "ok",
423
+ "records_created": {job_name: result.get("created", 0)},
424
+ **result,
425
+ }
426
+ if outcome == "skipped":
427
+ # A debt that cannot be re-run is still recorded data loss. Failing the
428
+ # job keeps it visible for a human instead of silently discharging it.
429
+ return {"status": "error", "error": f"cannot retry: {result.get('reason')}"}
430
+ return {"status": "error", "error": str(result.get("error") or "retry failed")}
431
+
432
+
347
433
  def pending_derivation_summary(conn: Optional[sqlite3.Connection]) -> Dict[str, Any]:
348
434
  """What derived data this node KNOWS it is missing, and since when it knew.
349
435
 
@@ -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
- conn = get_db_connection()
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 = run_daily_triage(conn, day_iso)
51
- logger.info("attention_triage %s: %s", day_iso, summary.get("quadrants"))
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
- try:
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
- fresh = award_badges(conn)
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:
@@ -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
- structured_result["conversation_context"] = (
137
- classify_untagged_conversations(conn)
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
- except Exception as exc: # noqa: BLE001 — never blocks enrichment
140
- logger.debug("conversation-context pass failed: %s", exc)
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
- store.merge_system_update(
203
- dimension,
204
- section_updates,
205
- source_id=source_id,
206
- model=result.output.get("model") if result.status == "completed" and result.output else None,
207
- provider=provider,
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
- self._resolve_into_spine(results, canonical_messages)
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