topos-node 1.3.51__tar.gz → 1.3.53__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 (779) hide show
  1. {topos_node-1.3.51/topos_node.egg-info → topos_node-1.3.53}/PKG-INFO +1 -9
  2. {topos_node-1.3.51 → topos_node-1.3.53}/README.md +0 -8
  3. {topos_node-1.3.51 → topos_node-1.3.53}/pyproject.toml +3 -3
  4. {topos_node-1.3.51 → topos_node-1.3.53}/topos/__version__.py +2 -2
  5. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/messenger_communities.py +10 -0
  6. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/person_graph.py +161 -1
  7. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/relationship_reads.py +55 -6
  8. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/messenger_analytics.py +98 -0
  9. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/signal.py +13 -3
  10. topos_node-1.3.53/topos/cli/assets/topos_blk_rounded.png +0 -0
  11. topos_node-1.3.53/topos/cli/assets/topos_white.png +0 -0
  12. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/derivation.py +11 -2
  13. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/messenger_analytics.py +13 -2
  14. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/derivation_job.py +26 -5
  15. topos_node-1.3.53/topos/features/derivation/bundled_packs/net.character.yaml +119 -0
  16. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/obligations.commitments.yaml +5 -3
  17. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/personality.traits.yaml +1 -0
  18. topos_node-1.3.53/topos/features/derivation/commitments.py +294 -0
  19. topos_node-1.3.53/topos/features/derivation/person_reading.py +617 -0
  20. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/registry.py +6 -0
  21. topos_node-1.3.53/topos/features/derivation/social_kernels.py +590 -0
  22. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/surfaces.py +178 -16
  23. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/template.py +59 -4
  24. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/verify.py +47 -4
  25. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/writer.py +16 -0
  26. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/relationships.json +2 -1
  27. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/signal_object_store.py +1 -1
  28. {topos_node-1.3.51 → topos_node-1.3.53}/topos/protocol/handled_message_types.json +1 -0
  29. {topos_node-1.3.51 → topos_node-1.3.53}/topos/protocol/narrowing_vocabulary.json +5 -0
  30. topos_node-1.3.53/topos/protocol/retrieval_text_contract.json +1013 -0
  31. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/narrowing.py +14 -3
  32. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/retrieval.py +118 -2
  33. {topos_node-1.3.51 → topos_node-1.3.53}/topos/upgrades/manifests.json +12 -0
  34. {topos_node-1.3.51 → topos_node-1.3.53/topos_node.egg-info}/PKG-INFO +1 -9
  35. {topos_node-1.3.51 → topos_node-1.3.53}/topos_node.egg-info/SOURCES.txt +4 -0
  36. topos_node-1.3.51/topos/cli/assets/topos_blk_rounded.png +0 -0
  37. topos_node-1.3.51/topos/cli/assets/topos_white.png +0 -0
  38. topos_node-1.3.51/topos/features/derivation/social_kernels.py +0 -221
  39. {topos_node-1.3.51 → topos_node-1.3.53}/LICENSE +0 -0
  40. {topos_node-1.3.51 → topos_node-1.3.53}/MANIFEST.in +0 -0
  41. {topos_node-1.3.51 → topos_node-1.3.53}/setup.cfg +0 -0
  42. {topos_node-1.3.51 → topos_node-1.3.53}/shared/__init__.py +0 -0
  43. {topos_node-1.3.51 → topos_node-1.3.53}/shared/filtering.py +0 -0
  44. {topos_node-1.3.51 → topos_node-1.3.53}/shared/schema_registry.py +0 -0
  45. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_active_database_binding.py +0 -0
  46. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_active_ingestion_binding.py +0 -0
  47. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_extensions.py +0 -0
  48. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_gate_leg_hermeticity.py +0 -0
  49. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_llm_integrations_storage.py +0 -0
  50. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_local_gate_composition.py +0 -0
  51. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_owner_database_hermeticity.py +0 -0
  52. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_prewarm_first_run.py +0 -0
  53. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_profile_hygiene.py +0 -0
  54. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_profiles.py +0 -0
  55. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_protocol_handled_types.py +0 -0
  56. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_query_field_contract.py +0 -0
  57. {topos_node-1.3.51 → topos_node-1.3.53}/tests/test_system_computer_name.py +0 -0
  58. {topos_node-1.3.51 → topos_node-1.3.53}/topos/__init__.py +0 -0
  59. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/__init__.py +0 -0
  60. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/dataset_resolution.py +0 -0
  61. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/duckdb_adapter.py +0 -0
  62. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/luck_surface.py +0 -0
  63. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/messenger_directed.py +0 -0
  64. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/messenger_graph.py +0 -0
  65. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/messenger_labels.py +0 -0
  66. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/person_overlay.py +0 -0
  67. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/profiles.py +0 -0
  68. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/query_engine.py +0 -0
  69. {topos_node-1.3.51 → topos_node-1.3.53}/topos/analytics/raw_queries.py +0 -0
  70. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/__init__.py +0 -0
  71. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/analytics.py +0 -0
  72. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/app_registry.py +0 -0
  73. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/backup.py +0 -0
  74. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/community_naming_config.py +0 -0
  75. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/compute_remote.py +0 -0
  76. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/connected_apps.py +0 -0
  77. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/conversation_context.py +0 -0
  78. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/data_commit.py +0 -0
  79. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/data_explorer_table_prefs.py +0 -0
  80. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/database_explorer.py +0 -0
  81. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/db.py +0 -0
  82. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/device.py +0 -0
  83. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/disk_space_config.py +0 -0
  84. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/engine_run.py +0 -0
  85. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/enrichment.py +0 -0
  86. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/enrichment_lab.py +0 -0
  87. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/facts_llm_config.py +0 -0
  88. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/filter_lab.py +0 -0
  89. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/health.py +0 -0
  90. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/home_chat.py +0 -0
  91. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/ingestion_api.py +0 -0
  92. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/ingestion_compat.py +0 -0
  93. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/ingestion_sources.py +0 -0
  94. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/intelligence_lifecycle.py +0 -0
  95. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/llm.py +0 -0
  96. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/local_mcp.py +0 -0
  97. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/privacy_disclose.py +0 -0
  98. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/query_api.py +0 -0
  99. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/runtime_bootstrap.py +0 -0
  100. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/sanitization_ollama_config.py +0 -0
  101. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/shell.py +0 -0
  102. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/signal_extraction_config.py +0 -0
  103. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/source_install.py +0 -0
  104. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/source_scrub.py +0 -0
  105. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/sources.py +0 -0
  106. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/sources_overview.py +0 -0
  107. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/sync.py +0 -0
  108. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/tool_index.py +0 -0
  109. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/ui_config.py +0 -0
  110. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/uma_data.py +0 -0
  111. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/upgrades.py +0 -0
  112. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/usage.py +0 -0
  113. {topos_node-1.3.51 → topos_node-1.3.53}/topos/api/user_identity.py +0 -0
  114. {topos_node-1.3.51 → topos_node-1.3.53}/topos/app.py +0 -0
  115. {topos_node-1.3.51 → topos_node-1.3.53}/topos/auth.py +0 -0
  116. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/__init__.py +0 -0
  117. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/declared_field_map.py +0 -0
  118. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/__init__.py +0 -0
  119. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/base.py +0 -0
  120. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
  121. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
  122. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/demo_mappers.py +0 -0
  123. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/documents_mapper.py +0 -0
  124. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
  125. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
  126. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  127. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
  128. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/mappers/transcript_mapper.py +0 -0
  129. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/models.py +0 -0
  130. {topos_node-1.3.51 → topos_node-1.3.53}/topos/canonicalization/resolver.py +0 -0
  131. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/__init__.py +0 -0
  132. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/__main__.py +0 -0
  133. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/commands.py +0 -0
  134. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/profile_cmd.py +0 -0
  135. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/reprocess_cmd.py +0 -0
  136. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/setup_models_cmd.py +0 -0
  137. {topos_node-1.3.51 → topos_node-1.3.53}/topos/cli/tray.py +0 -0
  138. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/__init__.py +0 -0
  139. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/conversation_context_llm.py +0 -0
  140. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/facts_llm.py +0 -0
  141. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/local_model_builds.py +0 -0
  142. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/model_packs.py +0 -0
  143. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/node_function_providers.py +0 -0
  144. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/sanitization_ollama.py +0 -0
  145. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/settings.py +0 -0
  146. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/signal_extraction.py +0 -0
  147. {topos_node-1.3.51 → topos_node-1.3.53}/topos/config/uvicorn_logging.json +0 -0
  148. {topos_node-1.3.51 → topos_node-1.3.53}/topos/contacts/__init__.py +0 -0
  149. {topos_node-1.3.51 → topos_node-1.3.53}/topos/contacts/identity.py +0 -0
  150. {topos_node-1.3.51 → topos_node-1.3.53}/topos/control_plane_client.py +0 -0
  151. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/__init__.py +0 -0
  152. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/api_models.py +0 -0
  153. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/connection_resilience.py +0 -0
  154. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/db_health.py +0 -0
  155. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/device_helpers.py +0 -0
  156. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/errors.py +0 -0
  157. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/events.py +0 -0
  158. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/__init__.py +0 -0
  159. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/aggregate.py +0 -0
  160. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/common.py +0 -0
  161. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/complexity.py +0 -0
  162. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/config.py +0 -0
  163. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/contacts_import.py +0 -0
  164. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/database_explorer.py +0 -0
  165. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/device.py +0 -0
  166. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/enrichment.py +0 -0
  167. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/enrichment_lab.py +0 -0
  168. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/filter_lab.py +0 -0
  169. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/graph_query.py +0 -0
  170. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/graph_summary.py +0 -0
  171. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/home_chat.py +0 -0
  172. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/ingest.py +0 -0
  173. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/mcp_client_elevations.py +0 -0
  174. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/mcp_clients.py +0 -0
  175. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/messages.py +0 -0
  176. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/query.py +0 -0
  177. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/registry.py +0 -0
  178. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/routines.py +0 -0
  179. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/signal_features.py +0 -0
  180. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/sources.py +0 -0
  181. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/timeline_daily.py +0 -0
  182. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/tool_index.py +0 -0
  183. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/handlers/uma.py +0 -0
  184. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/logging.py +0 -0
  185. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/metrics.py +0 -0
  186. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/routine_access.py +0 -0
  187. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/startup_banner.py +0 -0
  188. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/state.py +0 -0
  189. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/table_layers.py +0 -0
  190. {topos_node-1.3.51 → topos_node-1.3.53}/topos/core/types.py +0 -0
  191. {topos_node-1.3.51 → topos_node-1.3.53}/topos/data_explorer_row_delete.py +0 -0
  192. {topos_node-1.3.51 → topos_node-1.3.53}/topos/data_explorer_table_prefs.py +0 -0
  193. {topos_node-1.3.51 → topos_node-1.3.53}/topos/data_explorer_tables.py +0 -0
  194. {topos_node-1.3.51 → topos_node-1.3.53}/topos/defaults.py +0 -0
  195. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/__init__.py +0 -0
  196. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/canonical_writer.py +0 -0
  197. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/content_policy.py +0 -0
  198. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/field_registry.py +0 -0
  199. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/privacy_layer.py +0 -0
  200. {topos_node-1.3.51 → topos_node-1.3.53}/topos/disclosure/tier.py +0 -0
  201. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/__init__.py +0 -0
  202. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/__init__.py +0 -0
  203. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/base.py +0 -0
  204. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/generative_prompts.py +0 -0
  205. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/generative_response.py +0 -0
  206. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/huggingface.py +0 -0
  207. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/ollama.py +0 -0
  208. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/openai.py +0 -0
  209. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/openai_compatible.py +0 -0
  210. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/redpill.py +0 -0
  211. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/backends/stub.py +0 -0
  212. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/client.py +0 -0
  213. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/disk_space.py +0 -0
  214. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/engine.py +0 -0
  215. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/hosted_llm_wallet.py +0 -0
  216. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/intake.py +0 -0
  217. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/memory_utils.py +0 -0
  218. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/model_cache.py +0 -0
  219. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/model_manager.py +0 -0
  220. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/ollama_install.py +0 -0
  221. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/ollama_pull.py +0 -0
  222. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/ollama_runtime.py +0 -0
  223. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/ollama_setup_guidance.py +0 -0
  224. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/pipeline_memory.py +0 -0
  225. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/queue_manager.py +0 -0
  226. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/registration.py +0 -0
  227. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/result_formatter.py +0 -0
  228. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/router.py +0 -0
  229. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/scoped_token.py +0 -0
  230. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/tasks.py +0 -0
  231. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/torch_runtime.py +0 -0
  232. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/transport.py +0 -0
  233. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/usage_guard.py +0 -0
  234. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/usage_observation.py +0 -0
  235. {topos_node-1.3.51 → topos_node-1.3.53}/topos/engine/validator.py +0 -0
  236. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/__init__.py +0 -0
  237. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/catalog.py +0 -0
  238. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/derivation_recovery.py +0 -0
  239. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/derived_tables.py +0 -0
  240. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/job_readiness.py +0 -0
  241. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/job_writer.py +0 -0
  242. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/__init__.py +0 -0
  243. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/base.py +0 -0
  244. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  245. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
  246. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
  247. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/attention_triage_job.py +0 -0
  248. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
  249. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
  250. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/complexity_snapshot_job.py +0 -0
  251. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/derived_object_embeddings_job.py +0 -0
  252. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
  253. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
  254. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
  255. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
  256. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
  257. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
  258. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
  259. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
  260. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
  261. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
  262. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
  263. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
  264. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
  265. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/raw/__init__.py +0 -0
  266. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  267. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/raw/language_job.py +0 -0
  268. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  269. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  270. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/model_overrides.py +0 -0
  271. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/models/__init__.py +0 -0
  272. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/models/manager.py +0 -0
  273. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/models/mvp_defaults.py +0 -0
  274. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/models/registry.py +0 -0
  275. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/models/versioning.py +0 -0
  276. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/orchestrator.py +0 -0
  277. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/pipeline_activity.py +0 -0
  278. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/processor.py +0 -0
  279. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/progress_bar.py +0 -0
  280. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/record_progress.py +0 -0
  281. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/registry_contract.py +0 -0
  282. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/signal_derivation_config.json +0 -0
  283. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment/source_overrides.py +0 -0
  284. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/__init__.py +0 -0
  285. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/bundles.py +0 -0
  286. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/model_resolve.py +0 -0
  287. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/schema.py +0 -0
  288. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/service.py +0 -0
  289. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/store.py +0 -0
  290. {topos_node-1.3.51 → topos_node-1.3.53}/topos/enrichment_lab/worker.py +0 -0
  291. {topos_node-1.3.51 → topos_node-1.3.53}/topos/evals/__init__.py +0 -0
  292. {topos_node-1.3.51 → topos_node-1.3.53}/topos/evals/enrichment_eval.py +0 -0
  293. {topos_node-1.3.51 → topos_node-1.3.53}/topos/extensions.py +0 -0
  294. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/__init__.py +0 -0
  295. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/canonical.py +0 -0
  296. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/engine.py +0 -0
  297. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/entropy.py +0 -0
  298. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/focus.py +0 -0
  299. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/graph_metrics.py +0 -0
  300. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/influence.py +0 -0
  301. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/projection.py +0 -0
  302. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/snapshots.py +0 -0
  303. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/store.py +0 -0
  304. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/topic_merge.py +0 -0
  305. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/topics.py +0 -0
  306. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/topics_daily.py +0 -0
  307. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/complexity/volatility.py +0 -0
  308. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/__init__.py +0 -0
  309. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/_scales.yaml +0 -0
  310. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/admin.legal.yaml +0 -0
  311. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/aspirations.goals.yaml +0 -0
  312. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/behavior.habits.yaml +0 -0
  313. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/behavior.preferences.yaml +0 -0
  314. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/beliefs.civic.yaml +0 -0
  315. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/beliefs.spiritual.yaml +0 -0
  316. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/communication.style.yaml +0 -0
  317. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/community.membership.yaml +0 -0
  318. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/craft.tooling.yaml +0 -0
  319. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/expertise.knowledge.yaml +0 -0
  320. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/finances.economics.yaml +0 -0
  321. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/health.lifestyle.yaml +0 -0
  322. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/health.mental.yaml +0 -0
  323. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/health.physical.yaml +0 -0
  324. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/household.pets.yaml +0 -0
  325. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/identity.core.yaml +0 -0
  326. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/interests.taste.yaml +0 -0
  327. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/life.events.yaml +0 -0
  328. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/narrative.self.yaml +0 -0
  329. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/net.capability.yaml +0 -0
  330. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/places.mobility.yaml +0 -0
  331. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/possessions.assets.yaml +0 -0
  332. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/relationships.social.yaml +0 -0
  333. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/values.motivation.yaml +0 -0
  334. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/dispositions.yaml +0 -0
  335. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/expertise.yaml +0 -0
  336. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/habits.yaml +0 -0
  337. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/interests.yaml +0 -0
  338. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/preferences.yaml +0 -0
  339. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/stances.yaml +0 -0
  340. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/tools.yaml +0 -0
  341. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/vocab/values.yaml +0 -0
  342. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/bundled_packs/work.career.yaml +0 -0
  343. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/candidates.py +0 -0
  344. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/guard.py +0 -0
  345. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/kernels.py +0 -0
  346. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/net_subject_policy.py +0 -0
  347. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/packs.py +0 -0
  348. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/person_bridge.py +0 -0
  349. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/prefilter.py +0 -0
  350. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/report_card.py +0 -0
  351. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/router.py +0 -0
  352. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/social_bench.py +0 -0
  353. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/derivation/synthesize.py +0 -0
  354. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/__init__.py +0 -0
  355. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/affinity.py +0 -0
  356. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/affinity_owner.py +0 -0
  357. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/affinity_quality.py +0 -0
  358. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/chatgpt_declared.py +0 -0
  359. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/community_names.py +0 -0
  360. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/community_naming.py +0 -0
  361. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/consolidation.py +0 -0
  362. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/context_vectors.py +0 -0
  363. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/cypher.py +0 -0
  364. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/declared_mappings.py +0 -0
  365. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/discourse_graph.py +0 -0
  366. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/dossier.py +0 -0
  367. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/edges.py +0 -0
  368. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/fact_materializer.py +0 -0
  369. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/graph_enrichers.py +0 -0
  370. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/graph_refresh.py +0 -0
  371. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/graph_search.py +0 -0
  372. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/linking.py +0 -0
  373. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/maintenance.py +0 -0
  374. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/owner.py +0 -0
  375. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/reads.py +0 -0
  376. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/rebuild_subprocess.py +0 -0
  377. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/resolver.py +0 -0
  378. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/entities/structured_fields.py +0 -0
  379. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/__init__.py +0 -0
  380. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/extract.py +0 -0
  381. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/llm_extract.py +0 -0
  382. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/reads.py +0 -0
  383. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/store.py +0 -0
  384. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/facts/verdicts.py +0 -0
  385. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/fit/evaluator.py +0 -0
  386. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/fit/opportunity_types.json +0 -0
  387. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/__init__.py +0 -0
  388. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/blackhole.py +0 -0
  389. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/blackhole_guard.py +0 -0
  390. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/blackhole_llm.py +0 -0
  391. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/blackhole_rebuild.py +0 -0
  392. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/derived_scrub.py +0 -0
  393. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/exclusions.py +0 -0
  394. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/lifecycle/gc.py +0 -0
  395. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/provenance/__init__.py +0 -0
  396. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/provenance/posture.py +0 -0
  397. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/provenance/roles.py +0 -0
  398. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/__init__.py +0 -0
  399. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/brief_canonical_loader.py +0 -0
  400. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/brief_ontology.py +0 -0
  401. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/brief_renderer.py +0 -0
  402. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/brief_schemas.py +0 -0
  403. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/chunking.py +0 -0
  404. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/cluster_labels.py +0 -0
  405. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/conversation_context.py +0 -0
  406. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/conversation_windows.py +0 -0
  407. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/data_health.py +0 -0
  408. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/brief_ontologies.json +0 -0
  409. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/intentions.json +0 -0
  410. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/interests.json +0 -0
  411. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/memory.json +0 -0
  412. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/places.json +0 -0
  413. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/profile.json +0 -0
  414. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/resources.json +0 -0
  415. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
  416. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/time.json +0 -0
  417. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/wellbeing.json +0 -0
  418. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/definitions/work.json +0 -0
  419. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/derived_index.py +0 -0
  420. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/derived_spec.py +0 -0
  421. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/dimension_briefs.py +0 -0
  422. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/dimension_definition_loader.py +0 -0
  423. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/dimension_profiles.py +0 -0
  424. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/dimension_registry.py +0 -0
  425. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/embed_context.py +0 -0
  426. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/extraction/artifact_router.py +0 -0
  427. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/extraction/artifact_store.py +0 -0
  428. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/extraction/rule_extractors.py +0 -0
  429. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/graph_sanitize.py +0 -0
  430. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/hybrid_search.py +0 -0
  431. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/incremental_clustering.py +0 -0
  432. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/model_recommendations.py +0 -0
  433. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/query_embed_cache.py +0 -0
  434. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/schemas.py +0 -0
  435. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/service.py +0 -0
  436. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/source_hydration.py +0 -0
  437. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/structured_signal.py +0 -0
  438. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/tool_index.py +0 -0
  439. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/topic_clustering.py +0 -0
  440. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/typed_stores/aggregates.py +0 -0
  441. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/typed_stores/commitments.py +0 -0
  442. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/typed_stores/rhythm.py +0 -0
  443. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
  444. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/vector_codec.py +0 -0
  445. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/vector_math.py +0 -0
  446. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/signal/vector_settings.py +0 -0
  447. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/stats/__init__.py +0 -0
  448. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/stats/definitions.py +0 -0
  449. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/stats/engine.py +0 -0
  450. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/stats/fold.py +0 -0
  451. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/stats/insights.py +0 -0
  452. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/timeline_projection.py +0 -0
  453. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/timeline_rollup.py +0 -0
  454. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/__init__.py +0 -0
  455. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/badges.py +0 -0
  456. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/daily.py +0 -0
  457. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/dashboard.py +0 -0
  458. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/instruments.py +0 -0
  459. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/intents.py +0 -0
  460. {topos_node-1.3.51 → topos_node-1.3.53}/topos/features/triage/readiness.py +0 -0
  461. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/__init__.py +0 -0
  462. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/bundles.py +0 -0
  463. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/schema.py +0 -0
  464. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/service.py +0 -0
  465. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/store.py +0 -0
  466. {topos_node-1.3.51 → topos_node-1.3.53}/topos/filter_lab/worker.py +0 -0
  467. {topos_node-1.3.51 → topos_node-1.3.53}/topos/home_chat/__init__.py +0 -0
  468. {topos_node-1.3.51 → topos_node-1.3.53}/topos/home_chat/schema.py +0 -0
  469. {topos_node-1.3.51 → topos_node-1.3.53}/topos/home_chat/store.py +0 -0
  470. {topos_node-1.3.51 → topos_node-1.3.53}/topos/hosted_pool_lease.py +0 -0
  471. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/__init__.py +0 -0
  472. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/canonical_pipeline.py +0 -0
  473. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/checkpoints/__init__.py +0 -0
  474. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  475. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  476. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/inbox_crypto.py +0 -0
  477. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/inbox_drain.py +0 -0
  478. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/ingest_helpers.py +0 -0
  479. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/jobs.py +0 -0
  480. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/journal_location_fanout.py +0 -0
  481. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/journal_time_log_normalize.py +0 -0
  482. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/local_exports.py +0 -0
  483. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/local_sync.py +0 -0
  484. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/log_preview.py +0 -0
  485. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/manager.py +0 -0
  486. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parser.py +0 -0
  487. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/__init__.py +0 -0
  488. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/base.py +0 -0
  489. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/browser_parser.py +0 -0
  490. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/calendar_parser.py +0 -0
  491. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  492. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/chatgpt_export.py +0 -0
  493. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  494. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
  495. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/documents_parser.py +0 -0
  496. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/github_activity_parser.py +0 -0
  497. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
  498. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/grok_parser.py +0 -0
  499. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/messenger_parser.py +0 -0
  500. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/transcript_parser.py +0 -0
  501. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/parsers/voxterm_parser.py +0 -0
  502. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/progress.py +0 -0
  503. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/reprocess.py +0 -0
  504. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/__init__.py +0 -0
  505. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/base.py +0 -0
  506. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/calendar.py +0 -0
  507. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/chatgpt.py +0 -0
  508. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/contact_importers.py +0 -0
  509. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/grok.py +0 -0
  510. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/imessage_reader.py +0 -0
  511. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/signal_export_parser.py +0 -0
  512. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/sources/signal_reader.py +0 -0
  513. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/state_machine.py +0 -0
  514. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/triggers/__init__.py +0 -0
  515. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/triggers/file_trigger.py +0 -0
  516. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  517. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/usage_inbox_dedupe.py +0 -0
  518. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/validation/__init__.py +0 -0
  519. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/validation/base.py +0 -0
  520. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/validation/schema_registry.py +0 -0
  521. {topos_node-1.3.51 → topos_node-1.3.53}/topos/ingestion/validation/schema_validator.py +0 -0
  522. {topos_node-1.3.51 → topos_node-1.3.53}/topos/lineage/__init__.py +0 -0
  523. {topos_node-1.3.51 → topos_node-1.3.53}/topos/lineage/provenance.py +0 -0
  524. {topos_node-1.3.51 → topos_node-1.3.53}/topos/lineage/tracker.py +0 -0
  525. {topos_node-1.3.51 → topos_node-1.3.53}/topos/llm_integrations_storage.py +0 -0
  526. {topos_node-1.3.51 → topos_node-1.3.53}/topos/mcp_clients.py +0 -0
  527. {topos_node-1.3.51 → topos_node-1.3.53}/topos/mcp_stdio_proxy.py +0 -0
  528. {topos_node-1.3.51 → topos_node-1.3.53}/topos/observability/__init__.py +0 -0
  529. {topos_node-1.3.51 → topos_node-1.3.53}/topos/observability/alerts.py +0 -0
  530. {topos_node-1.3.51 → topos_node-1.3.53}/topos/observability/metrics.py +0 -0
  531. {topos_node-1.3.51 → topos_node-1.3.53}/topos/observability/tracing.py +0 -0
  532. {topos_node-1.3.51 → topos_node-1.3.53}/topos/openai_client.py +0 -0
  533. {topos_node-1.3.51 → topos_node-1.3.53}/topos/owner_key.py +0 -0
  534. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/__init__.py +0 -0
  535. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/audit.py +0 -0
  536. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/envelope.py +0 -0
  537. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/job_runner.py +0 -0
  538. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/job_store.py +0 -0
  539. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/stages.py +0 -0
  540. {topos_node-1.3.51 → topos_node-1.3.53}/topos/pipeline/stub_enqueue.py +0 -0
  541. {topos_node-1.3.51 → topos_node-1.3.53}/topos/principal.py +0 -0
  542. {topos_node-1.3.51 → topos_node-1.3.53}/topos/profiles.py +0 -0
  543. {topos_node-1.3.51 → topos_node-1.3.53}/topos/projections/__init__.py +0 -0
  544. {topos_node-1.3.51 → topos_node-1.3.53}/topos/projections/vector_index/__init__.py +0 -0
  545. {topos_node-1.3.51 → topos_node-1.3.53}/topos/projections/vector_index/base.py +0 -0
  546. {topos_node-1.3.51 → topos_node-1.3.53}/topos/projections/vector_index/builders.py +0 -0
  547. {topos_node-1.3.51 → topos_node-1.3.53}/topos/projections/vector_index/health_checks.py +0 -0
  548. {topos_node-1.3.51 → topos_node-1.3.53}/topos/protocol/__init__.py +0 -0
  549. {topos_node-1.3.51 → topos_node-1.3.53}/topos/protocol/query_field_contract.json +0 -0
  550. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/__init__.py +0 -0
  551. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/aggregate.py +0 -0
  552. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/audit.py +0 -0
  553. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/closeness.py +0 -0
  554. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/cohort_resolvers.py +0 -0
  555. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/collaborators.py +0 -0
  556. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/ddr.py +0 -0
  557. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/disclosure.py +0 -0
  558. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/entity_window.py +0 -0
  559. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/exclusion.py +0 -0
  560. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/facts_direct.py +0 -0
  561. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/fingerprint.py +0 -0
  562. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/game_layer.py +0 -0
  563. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/grant_cache.py +0 -0
  564. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/graph_lane.py +0 -0
  565. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/inference.py +0 -0
  566. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/intent.py +0 -0
  567. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/manifest.py +0 -0
  568. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/manifest_validation.py +0 -0
  569. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/minimizer.py +0 -0
  570. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/negotiation.py +0 -0
  571. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/overheard.py +0 -0
  572. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/packet_resolution.py +0 -0
  573. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/pipeline.py +0 -0
  574. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/planner.py +0 -0
  575. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/runtime.py +0 -0
  576. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_arbiter.py +0 -0
  577. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_classifier.py +0 -0
  578. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_head.py +0 -0
  579. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_registry.json +0 -0
  580. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_registry_loader.py +0 -0
  581. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/scope_shadow.py +0 -0
  582. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/session.py +0 -0
  583. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/session_utils.py +0 -0
  584. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/source_generation.py +0 -0
  585. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/truth_facts.py +0 -0
  586. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/truth_prompts.py +0 -0
  587. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/turn_classifier.py +0 -0
  588. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/types.py +0 -0
  589. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/verify.py +0 -0
  590. {topos_node-1.3.51 → topos_node-1.3.53}/topos/query/verify_modes.py +0 -0
  591. {topos_node-1.3.51 → topos_node-1.3.53}/topos/rate_limit.py +0 -0
  592. {topos_node-1.3.51 → topos_node-1.3.53}/topos/relay_stamp.py +0 -0
  593. {topos_node-1.3.51 → topos_node-1.3.53}/topos/routines/__init__.py +0 -0
  594. {topos_node-1.3.51 → topos_node-1.3.53}/topos/routines/schema.py +0 -0
  595. {topos_node-1.3.51 → topos_node-1.3.53}/topos/routines/store.py +0 -0
  596. {topos_node-1.3.51 → topos_node-1.3.53}/topos/runtime_housekeeping.py +0 -0
  597. {topos_node-1.3.51 → topos_node-1.3.53}/topos/runtime_shutdown.py +0 -0
  598. {topos_node-1.3.51 → topos_node-1.3.53}/topos/runtime_update.py +0 -0
  599. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sanitization/__init__.py +0 -0
  600. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sanitization/nsfw_classifier.py +0 -0
  601. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sanitization/ollama_transforms.py +0 -0
  602. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sanitization/prewarm.py +0 -0
  603. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sanitization/privacy_filter.py +0 -0
  604. {topos_node-1.3.51 → topos_node-1.3.53}/topos/scope_resolution.py +0 -0
  605. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/__init__.py +0 -0
  606. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/container.py +0 -0
  607. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/embeddings/__init__.py +0 -0
  608. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/embeddings/base.py +0 -0
  609. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/embeddings/local.py +0 -0
  610. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/embeddings/remote.py +0 -0
  611. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/interfaces.py +0 -0
  612. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/llm/__init__.py +0 -0
  613. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/llm/base.py +0 -0
  614. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/llm/openai.py +0 -0
  615. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/local.py +0 -0
  616. {topos_node-1.3.51 → topos_node-1.3.53}/topos/services/postgres.py +0 -0
  617. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/__init__.py +0 -0
  618. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/bundled_canonical_triples.py +0 -0
  619. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/canonical_signal_defaults.py +0 -0
  620. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/declared_field_map_spec.py +0 -0
  621. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/definitions.py +0 -0
  622. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/install_service.py +0 -0
  623. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/registry.py +0 -0
  624. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/runtime_install.py +0 -0
  625. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/scrub_attribution.py +0 -0
  626. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sources/scrub_service.py +0 -0
  627. {topos_node-1.3.51 → topos_node-1.3.53}/topos/startup_banner.py +0 -0
  628. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/__init__.py +0 -0
  629. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/__init__.py +0 -0
  630. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/factory.py +0 -0
  631. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/fakes.py +0 -0
  632. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/postgres/stores.py +0 -0
  633. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/protocols.py +0 -0
  634. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/sqlite/__init__.py +0 -0
  635. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/sqlite/stores.py +0 -0
  636. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/adapters/sqlite/vector_search.py +0 -0
  637. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/__init__.py +0 -0
  638. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/activity_tables.py +0 -0
  639. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  640. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
  641. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  642. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/ai_chat/model.py +0 -0
  643. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/ai_chat/tables.py +0 -0
  644. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
  645. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/canonical_store.py +0 -0
  646. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/conversations_tables.py +0 -0
  647. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/journal_repair.py +0 -0
  648. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/mapping_store.py +0 -0
  649. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/canonical/postgres.py +0 -0
  650. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/__init__.py +0 -0
  651. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/client.py +0 -0
  652. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/connection_tuning.py +0 -0
  653. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/__init__.py +0 -0
  654. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
  655. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/actor_role_v1.py +0 -0
  656. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/affinity_pair_labels_v1.py +0 -0
  657. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/attention_triage_v1.py +0 -0
  658. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/attention_triage_v2.py +0 -0
  659. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/backup.py +0 -0
  660. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/backup_custody.py +0 -0
  661. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
  662. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
  663. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
  664. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
  665. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/community_names_v1.py +0 -0
  666. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/complexity_v1.py +0 -0
  667. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/conflict_provenance_v1.py +0 -0
  668. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/conversation_context_v1.py +0 -0
  669. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/derivation_factory_v1.py +0 -0
  670. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
  671. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/derivation_provenance_v1.py +0 -0
  672. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/derived_row_identity_v1.py +0 -0
  673. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/documents_v1.py +0 -0
  674. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/enrichment_record_progress_v1.py +0 -0
  675. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/enrichment_spec_version_v1.py +0 -0
  676. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_affinity_v1.py +0 -0
  677. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_blackhole_v1.py +0 -0
  678. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_context_vectors_v1.py +0 -0
  679. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_context_vectors_v2.py +0 -0
  680. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
  681. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_mentions_authored_v1.py +0 -0
  682. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_review_candidate_bar_v1.py +0 -0
  683. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_review_dedup_v1.py +0 -0
  684. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/entity_review_provenance_v1.py +0 -0
  685. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/episodes_v1.py +0 -0
  686. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
  687. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/fact_dimension_by_entity_type_v1.py +0 -0
  688. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
  689. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
  690. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
  691. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
  692. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
  693. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/journal_origin_dimension_v1.py +0 -0
  694. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/mention_table_stamp_backfill_v1.py +0 -0
  695. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/message_emotions_role_backfill_v1.py +0 -0
  696. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/message_emotions_role_v1.py +0 -0
  697. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/net_subject_policy_v1.py +0 -0
  698. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/pack_registry_v1.py +0 -0
  699. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
  700. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/query_artifacts_duration_ms_v1.py +0 -0
  701. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/registry.py +0 -0
  702. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/registry_checksums.json +0 -0
  703. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/remediation_person_model.py +0 -0
  704. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/retire_url_classification_v1.py +0 -0
  705. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/scope_source_generation.py +0 -0
  706. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
  707. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
  708. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_objects.py +0 -0
  709. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
  710. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
  711. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/signal_summaries_drop_v1.py +0 -0
  712. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  713. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/transcripts_v1.py +0 -0
  714. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
  715. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
  716. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
  717. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
  718. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
  719. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
  720. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
  721. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
  722. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
  723. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
  724. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
  725. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
  726. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
  727. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
  728. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
  729. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
  730. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
  731. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
  732. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/paths.py +0 -0
  733. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/postgres.py +0 -0
  734. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/schema.py +0 -0
  735. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/schema_probe.py +0 -0
  736. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/storage_breakdown.py +0 -0
  737. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/db/write_gate.py +0 -0
  738. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/derived_row_identity.py +0 -0
  739. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/enrichment/__init__.py +0 -0
  740. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  741. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  742. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/normalized/__init__.py +0 -0
  743. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/normalized/normalized_store.py +0 -0
  744. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/oplog/__init__.py +0 -0
  745. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/oplog/decision.py +0 -0
  746. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/oplog/oplog_store.py +0 -0
  747. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/oplog/postgres.py +0 -0
  748. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/person/identity_resolver.py +0 -0
  749. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/projections/__init__.py +0 -0
  750. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/projections/index_ops_store.py +0 -0
  751. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/projections/vector_index_store.py +0 -0
  752. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/__init__.py +0 -0
  753. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/browser_flat_tables.py +0 -0
  754. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/file_store.py +0 -0
  755. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/raw_store.py +0 -0
  756. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/raw_tables_manager.py +0 -0
  757. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/raw/sqlite_raw_store.py +0 -0
  758. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/security/encryption.py +0 -0
  759. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/signal_identity.py +0 -0
  760. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/source_settings.py +0 -0
  761. {topos_node-1.3.51 → topos_node-1.3.53}/topos/storage/user_identity.py +0 -0
  762. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sync/__init__.py +0 -0
  763. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sync/client.py +0 -0
  764. {topos_node-1.3.51 → topos_node-1.3.53}/topos/sync_handlers.py +0 -0
  765. {topos_node-1.3.51 → topos_node-1.3.53}/topos/testing/__init__.py +0 -0
  766. {topos_node-1.3.51 → topos_node-1.3.53}/topos/testing/lifespan.py +0 -0
  767. {topos_node-1.3.51 → topos_node-1.3.53}/topos/uds.py +0 -0
  768. {topos_node-1.3.51 → topos_node-1.3.53}/topos/uma_contact_enrichment.py +0 -0
  769. {topos_node-1.3.51 → topos_node-1.3.53}/topos/uma_filters.py +0 -0
  770. {topos_node-1.3.51 → topos_node-1.3.53}/topos/uma_resource_id.py +0 -0
  771. {topos_node-1.3.51 → topos_node-1.3.53}/topos/uma_rpt.py +0 -0
  772. {topos_node-1.3.51 → topos_node-1.3.53}/topos/upgrades/__init__.py +0 -0
  773. {topos_node-1.3.51 → topos_node-1.3.53}/topos/upgrades/runner.py +0 -0
  774. {topos_node-1.3.51 → topos_node-1.3.53}/topos/utils/base_object.py +0 -0
  775. {topos_node-1.3.51 → topos_node-1.3.53}/topos/websocket_client.py +0 -0
  776. {topos_node-1.3.51 → topos_node-1.3.53}/topos_node.egg-info/dependency_links.txt +0 -0
  777. {topos_node-1.3.51 → topos_node-1.3.53}/topos_node.egg-info/entry_points.txt +0 -0
  778. {topos_node-1.3.51 → topos_node-1.3.53}/topos_node.egg-info/requires.txt +0 -0
  779. {topos_node-1.3.51 → topos_node-1.3.53}/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.51
3
+ Version: 1.3.53
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
@@ -128,14 +128,6 @@ Topos Engine uses both local and model-hub paths so users can choose flexibility
128
128
 
129
129
  The `shared/` package in this repo is part of the node runtime contract. It contains common schema and filtering definitions used by both API and engine paths.
130
130
 
131
- ### Architecture notes (where truth lives)
132
-
133
- This README is orientation, not the architecture ledger. Prefer:
134
-
135
- - **As-built / why:** sibling `topos-research-wiki` → `20_ARCHITECTURE/` (`As_Built_Node`, firewall, query, MCP, graph, …)
136
- - **As-is invariants / checks:** sibling `topos-ops-wiki` → `25_SYSTEMS/` (`SYS-node`, `SYS-cognitive-firewall`, …)
137
- - **Target design:** `topos-data-wiki` (`status: target`) — do not implement from it without checking as-built
138
-
139
131
  ## Quick Start
140
132
 
141
133
  ### 1) Install
@@ -61,14 +61,6 @@ Topos Engine uses both local and model-hub paths so users can choose flexibility
61
61
 
62
62
  The `shared/` package in this repo is part of the node runtime contract. It contains common schema and filtering definitions used by both API and engine paths.
63
63
 
64
- ### Architecture notes (where truth lives)
65
-
66
- This README is orientation, not the architecture ledger. Prefer:
67
-
68
- - **As-built / why:** sibling `topos-research-wiki` → `20_ARCHITECTURE/` (`As_Built_Node`, firewall, query, MCP, graph, …)
69
- - **As-is invariants / checks:** sibling `topos-ops-wiki` → `25_SYSTEMS/` (`SYS-node`, `SYS-cognitive-firewall`, …)
70
- - **Target design:** `topos-data-wiki` (`status: target`) — do not implement from it without checking as-built
71
-
72
64
  ## Quick Start
73
65
 
74
66
  ### 1) Install
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "topos-node"
7
- version = "1.3.51"
7
+ version = "1.3.53"
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"
@@ -128,8 +128,8 @@ filterwarnings = [
128
128
  "ignore:on_event is deprecated.*:DeprecationWarning:fastapi.*",
129
129
  ]
130
130
  markers = [
131
- "journey: binds this test to a J-* journey note in topos-ops-wiki (the id is the marker arg)",
132
- "check: binds this test to a C-* check note in topos-ops-wiki (the id is the marker arg)",
131
+ "journey: binds this test to a J-* journey note (the id is the marker arg)",
132
+ "check: binds this test to a C-* check note (the id is the marker arg)",
133
133
  "gap: gap verification test (sprint pack); must pass after sprint lands",
134
134
  "qq_eval: live query quality/latency eval against owner database",
135
135
  "acceptance: Wiki MVP acceptance test (AT-1 through AT-8)",
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "1.3.51"
4
- __version_info__ = (1, 3, 51)
3
+ __version__ = "1.3.53"
4
+ __version_info__ = (1, 3, 53)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -448,6 +448,16 @@ def compute_and_persist_messenger_analytics(
448
448
  directed_totals["error"] = str(exc)[:200]
449
449
  totals.update(directed_totals)
450
450
 
451
+ # The readings lane hangs off this pass rather than off a request: a recompute means
452
+ # the dyads moved, so the evidence behind every reading may have. Debounced and
453
+ # single-flight inside; a failure to schedule never fails the analytics.
454
+ try:
455
+ from ..features.derivation.person_reading import mark_readings_due
456
+
457
+ mark_readings_due(dataset_id)
458
+ except Exception as exc: # noqa: BLE001
459
+ logger.debug("readings not scheduled: %s", exc)
460
+
451
461
  return {
452
462
  "dataset_id": dataset_id,
453
463
  "period_granularity": period_granularity,
@@ -1183,6 +1183,7 @@ def _merge_appearances(
1183
1183
  participation_total: int,
1184
1184
  *,
1185
1185
  show: int,
1186
+ keep_record_ids: bool = False,
1186
1187
  ) -> Tuple[List[Dict[str, Any]], int]:
1187
1188
  merged: List[Dict[str, Any]] = []
1188
1189
  seen: Set[Tuple[str, str, str]] = set()
@@ -1218,7 +1219,12 @@ def _merge_appearances(
1218
1219
  chosen = merged[:show]
1219
1220
  for row in chosen:
1220
1221
  row.pop("_rich", None)
1221
- row.pop("record_id", None)
1222
+ # The card's provenance list never wanted the raw id. The reading does: it is the
1223
+ # record its evidence row cites, and without it the reading's provenance ref
1224
+ # collapsed to the subject's spine ref alone (measured 2026-09-05 — every
1225
+ # message-backed evidence row carried a source and no record).
1226
+ if not keep_record_ids:
1227
+ row.pop("record_id", None)
1222
1228
  return chosen, max(total, len(merged))
1223
1229
 
1224
1230
 
@@ -1228,6 +1234,7 @@ def batch_person_appearances(
1228
1234
  *,
1229
1235
  show: int = APPEARANCE_SHOW,
1230
1236
  fetch: int = APPEARANCE_FETCH,
1237
+ keep_record_ids: bool = False,
1231
1238
  ) -> Dict[str, Dict[str, Any]]:
1232
1239
  """Connector-agnostic appearances for many people. Batched IN queries, never N+1.
1233
1240
 
@@ -1247,6 +1254,7 @@ def batch_person_appearances(
1247
1254
  participated.get(nid, []),
1248
1255
  part_totals.get(nid, 0),
1249
1256
  show=show,
1257
+ keep_record_ids=keep_record_ids,
1250
1258
  )
1251
1259
  out[nid] = {
1252
1260
  "mentions": mentions,
@@ -1504,6 +1512,34 @@ def structural_metrics(conn: Any, dataset_id: str, nodes: List[Dict[str, Any]],
1504
1512
  for member in component:
1505
1513
  brokerage_ok[str(member)] = big_enough
1506
1514
 
1515
+ # EXCLUSIVE REACH — what this person is the only way to. Two facts per node, both read
1516
+ # from the tie graph alone (who you know, never shared subjects): the people whose ONLY
1517
+ # connection into your network is this person (their leaf neighbours), and how many
1518
+ # people would lose their path to the rest of their corner if this person were absent
1519
+ # (articulation). Measured on the live node: 74 of 224 structural people are the only
1520
+ # link to at least one other, 48 are articulation points, the largest cut-off is 14.
1521
+ # Orgs and places a person alone carries measured ZERO on the same node — entity_edges
1522
+ # attach them to nobody in the structural set — so that half is not computed, rather
1523
+ # than reported as a confident zero.
1524
+ reach: Dict[str, Dict[str, int]] = {}
1525
+ for component in nx.connected_components(ties):
1526
+ sub = ties.subgraph(component)
1527
+ size = len(component)
1528
+ cut_by: Dict[str, int] = {}
1529
+ if size >= 3:
1530
+ for p in nx.articulation_points(sub):
1531
+ rest = sub.copy()
1532
+ rest.remove_node(p)
1533
+ pieces = sorted((len(c) for c in nx.connected_components(rest)), reverse=True)
1534
+ # everyone outside the largest remaining piece has lost their way to it
1535
+ cut_by[str(p)] = sum(pieces[1:])
1536
+ for p in component:
1537
+ leaves = sum(1 for q in sub.neighbors(p) if sub.degree(q) == 1)
1538
+ cut = cut_by.get(str(p), 0)
1539
+ if leaves or cut:
1540
+ reach[str(p)] = {"exclusive_people": leaves, "cut_off_if_absent": cut,
1541
+ "component_size": size}
1542
+
1507
1543
  # Communities from greedy modularity, falling back to connected components — the point
1508
1544
  # is a stable grouping to lay out by, not a claim about social clubs.
1509
1545
  try:
@@ -1561,6 +1597,9 @@ def structural_metrics(conn: Any, dataset_id: str, nodes: List[Dict[str, Any]],
1561
1597
  # A score from a four-person component is arithmetic; the flag says which ones are
1562
1598
  # worth showing as a finding rather than as a number.
1563
1599
  "brokerage_meaningful": brokerage_ok,
1600
+ # Only the nodes with something to say; a missing key means "no exclusive reach",
1601
+ # not "not computed" — every node in `ties` was looked at.
1602
+ "reach": reach,
1564
1603
  "coverage": {
1565
1604
  "basis": ("connections BETWEEN your people, with you removed — you are connected "
1566
1605
  "to everyone here, so leaving you in makes you the only broker and "
@@ -1570,6 +1609,9 @@ def structural_metrics(conn: Any, dataset_id: str, nodes: List[Dict[str, Any]],
1570
1609
  "communities_from": ("who you know, plus what people have in common — the second "
1571
1610
  "is never drawn and never counted as a connection"),
1572
1611
  "centrality_from": "who you know only",
1612
+ "reach_from": ("who you know only — leaf neighbours are people whose sole tie into "
1613
+ "your network is this person; cut-off counts who would lose their "
1614
+ "path to the rest of their corner without them"),
1573
1615
  "context_pairs_joined": context_added,
1574
1616
  "excluded": ("semantic similarity between two people is not evidence they know "
1575
1617
  "each other"),
@@ -2120,6 +2162,124 @@ def attach_coactivity(conn: Any, nodes: List[Dict[str, Any]]) -> Dict[str, int]:
2120
2162
  return {"attached": attached}
2121
2163
 
2122
2164
 
2165
+ def person_disposition_facts(conn: Any, nodes: List[Dict[str, Any]]) -> Dict[str, int]:
2166
+ """The owner's informant ratings of a person's Big Five domains, onto their node.
2167
+
2168
+ Only `trait.bfi2_domain` facts whose SUBJECT is this person, and the card labels every
2169
+ one "your read": on this node they are all owner-stated, because the model's estimate
2170
+ is gated behind a validation it has not passed (plan §2.2). Negative Emotionality is
2171
+ named as withheld rather than left blank — a missing slider reads as "not rated yet",
2172
+ a withheld one reads as the decision it is.
2173
+ """
2174
+ by_entity = {str(n["entity_id"]): n for n in nodes if n.get("entity_id") and not n.get("is_owner")}
2175
+ if not by_entity:
2176
+ return {"attached": 0}
2177
+ try:
2178
+ rows = conn.execute(
2179
+ "SELECT payload_json, valid_from FROM signal_objects"
2180
+ " WHERE object_type='fact' AND valid_to IS NULL"
2181
+ " AND payload_json LIKE '%trait.bfi2_domain%'").fetchall()
2182
+ except sqlite3.Error:
2183
+ return {"attached": 0}
2184
+ attached = 0
2185
+ for payload, valid_from in rows:
2186
+ try:
2187
+ fact = json.loads(payload or "{}")
2188
+ except (TypeError, ValueError):
2189
+ continue
2190
+ if str(fact.get("predicate") or "") != "trait.bfi2_domain":
2191
+ continue
2192
+ node = by_entity.get(str(fact.get("subject_entity_id") or ""))
2193
+ if node is None:
2194
+ continue
2195
+ struct = fact.get("value_struct") or fact.get("value") or {}
2196
+ domain, level = str(struct.get("domain") or ""), str(struct.get("level") or "")
2197
+ if not domain or not level:
2198
+ continue
2199
+ disp = node.setdefault("disposition", {
2200
+ "domains": {},
2201
+ "excluded": ["negative_emotionality"],
2202
+ "basis": ("your read — an informant rating you gave on this card; the model's "
2203
+ "estimate is not shown until it passes validation"),
2204
+ })
2205
+ if domain not in disp["domains"]:
2206
+ attached += 1
2207
+ disp["domains"][domain] = {
2208
+ "level": level,
2209
+ "at": str(valid_from or "")[:10] or None,
2210
+ "stated_by_owner": str(fact.get("asserted_by") or "") == "owner",
2211
+ }
2212
+ return {"attached": attached}
2213
+
2214
+
2215
+ def attach_heard_about(conn: Any, dataset_id: str, nodes: List[Dict[str, Any]]) -> Dict[str, int]:
2216
+ """What of the OWNER'S OWN WORK this person has heard about, from the owner's DMs to them.
2217
+
2218
+ The Luck screen already computes this per body of work — "told two people" — and never
2219
+ per person, so a card could not answer the question an ask begins with: can I bring
2220
+ this up without cold-starting? Measured on the live node before this existed: 99
2221
+ owner-authored messages named a work item to 19 people, and none of those 19 cards said
2222
+ so. Reuses the luck rail's resolver end to end rather than a second surface matcher,
2223
+ so the two screens cannot disagree about who has heard what.
2224
+
2225
+ First-party by construction — the events are messages the OWNER wrote (`is_from_self`)
2226
+ in a DM, so this is the owner's record of what they said, never a claim about what the
2227
+ other person knows or repeated. One message is one telling; the chip carries the count
2228
+ and the date so a single mention a year ago reads as exactly that.
2229
+ """
2230
+ from . import luck_surface as L
2231
+
2232
+ for table in ("entity_mentions", "conversation_messages"):
2233
+ if not _appearance_table_exists(conn, table):
2234
+ return {"attached": 0, "events": 0}
2235
+ try:
2236
+ items = L.compile_surfaces(conn, dataset_id, L.build_work_items(conn))
2237
+ except sqlite3.Error:
2238
+ return {"attached": 0, "events": 0}
2239
+ if not items:
2240
+ return {"attached": 0, "events": 0}
2241
+ try:
2242
+ tells = L.build_telling_events(conn, dataset_id, items)
2243
+ except sqlite3.Error:
2244
+ return {"attached": 0, "events": 0}
2245
+ if not tells:
2246
+ return {"attached": 0, "events": 0}
2247
+
2248
+ labels = {i["work_item_id"]: i["label"] for i in items}
2249
+ by_key: Dict[str, Dict[str, Any]] = {}
2250
+ for n in nodes:
2251
+ if n.get("is_owner"):
2252
+ continue
2253
+ for k in n.get("messenger_keys") or []:
2254
+ by_key[str(k)] = n
2255
+ # node_id -> work_item_id -> event times; merged across a person's handles so a person
2256
+ # with two numbers is told once, not twice.
2257
+ merged: Dict[str, Dict[str, List[str]]] = {}
2258
+ for work_item_id, _mid, recipient, _comm, event_at, _period, _n in tells:
2259
+ node = by_key.get(str(recipient))
2260
+ if node is None:
2261
+ continue
2262
+ merged.setdefault(str(node["node_id"]), {}).setdefault(
2263
+ str(work_item_id), []).append(str(event_at or ""))
2264
+ by_node = {str(n["node_id"]): n for n in nodes}
2265
+ attached = 0
2266
+ for node_id, per_item in merged.items():
2267
+ node = by_node.get(node_id)
2268
+ if node is None:
2269
+ continue
2270
+ entries = sorted(((len(times), labels.get(wid, wid), max(times)) for wid, times in per_item.items()),
2271
+ key=lambda e: (-e[0], e[1]))
2272
+ node["heard_about"] = {
2273
+ "items": [{"label": label, "events": count, "last_at": (last[:10] if last else None)}
2274
+ for count, label, last in entries[:4]],
2275
+ "events": sum(e[0] for e in entries),
2276
+ "basis": ("your own direct messages to them that name the work — "
2277
+ "never what they said"),
2278
+ }
2279
+ attached += 1
2280
+ return {"attached": attached, "events": len(tells)}
2281
+
2282
+
2123
2283
  def attach_shared_with_owner(conn: Any, nodes: List[Dict[str, Any]]) -> Dict[str, int]:
2124
2284
  """What the owner and this person BOTH engage with, and what KIND of thing it is.
2125
2285
 
@@ -197,9 +197,13 @@ def read_directed_edges(
197
197
 
198
198
 
199
199
  def read_relationship_signals(conn: Any, *, dataset_id: str, signal: str = "all") -> Dict[str, Any]:
200
- """The derived read: warmth / drift / reciprocity, calibrated against the owner's own
201
- distribution, with what was NOT judged reported rather than hidden."""
202
- from ..features.derivation.social_kernels import (_dyad_rows, apply_evidence_floor,
200
+ """The derived read: warmth / drift / reciprocity / archetype, calibrated against the
201
+ owner's own distribution, with what was NOT judged reported rather than hidden.
202
+
203
+ The archetype reads the directed edges as well as the dyads (766 rows on the live node,
204
+ one pass, no DDL); it is the one signal that names its unmeasured axes per row."""
205
+ from ..features.derivation.social_kernels import (_dyad_rows, _edge_rows,
206
+ apply_evidence_floor, compute_archetype,
203
207
  compute_drift, compute_reciprocity,
204
208
  compute_warmth)
205
209
  from .messenger_directed import MESSENGER_DYAD_STATS_TABLE
@@ -221,11 +225,13 @@ def read_relationship_signals(conn: Any, *, dataset_id: str, signal: str = "all"
221
225
  out["drift_alarms"] = compute_drift(rows)
222
226
  if signal in ("all", "reciprocity"):
223
227
  out["reciprocity"] = compute_reciprocity(rows)
228
+ if signal in ("all", "archetype"):
229
+ out["archetypes"] = compute_archetype(rows, _edge_rows(conn, dataset_id))
224
230
 
225
- labels_for = {r["peer_key"] for k in ("warmth", "drift_alarms", "reciprocity")
231
+ labels_for = {r["peer_key"] for k in ("warmth", "drift_alarms", "reciprocity", "archetypes")
226
232
  for r in out.get(k, [])}
227
233
  labels = peer_labels(conn, dataset_id, sorted(labels_for))
228
- for k in ("warmth", "drift_alarms", "reciprocity"):
234
+ for k in ("warmth", "drift_alarms", "reciprocity", "archetypes"):
229
235
  for r in out.get(k, []):
230
236
  r["label"] = labels.get(r["peer_key"]) or r["peer_key"]
231
237
  return out
@@ -280,7 +286,8 @@ def read_person_graph(conn: Any, *, dataset_id: str,
280
286
  """
281
287
  from .dataset_resolution import resolve_messaging_dataset
282
288
  from .person_graph import (attach_closeness, attach_coactivity, attach_fact_closeness,
283
- attach_shared_with_owner,
289
+ attach_heard_about, attach_shared_with_owner,
290
+ person_disposition_facts,
284
291
  auto_link_duplicates,
285
292
  build_person_edges, build_person_nodes, group_ambient_people,
286
293
  merge_suggestions, resolve_owner_identity,
@@ -328,6 +335,29 @@ def read_person_graph(conn: Any, *, dataset_id: str,
328
335
  # different question of what the two of them WORK ON. Run after the duplicate fold, for
329
336
  # the same reason the facts are: the edge must land on the surviving node.
330
337
  attach_coactivity(conn, nodes)
338
+ # What of the owner's OWN work this person has heard about — the owner's DMs to them
339
+ # that name a body of work, through the luck rail's resolver. Per person here, per
340
+ # work item there; same events, so the two screens agree.
341
+ heard_stats = attach_heard_about(conn, dataset_id, nodes)
342
+ # The owner's informant ratings — stated facts about this person, labelled as such.
343
+ disposition_stats = person_disposition_facts(conn, nodes)
344
+ # The commitment ledger, owner's half: what the owner promised this person, in the
345
+ # owner's own words, and what the record says became of it.
346
+ from ..features.derivation.commitments import attach_commitments, attach_status_signals
347
+
348
+ commitment_stats = attach_commitments(conn, nodes)
349
+ # What they told you their situation is, in their words, expiring at 90 days.
350
+ status_stats = attach_status_signals(conn, nodes)
351
+ # The stored reading, when one exists: computed on the deferred lane, never here.
352
+ from ..features.derivation.person_reading import load_person_readings
353
+
354
+ readings = load_person_readings(conn)
355
+ for n in nodes:
356
+ r = readings.get(str(n.get("node_id") or ""))
357
+ if r:
358
+ n["reading"] = {k: r.get(k) for k in ("sentences", "strengths", "evidence", "coverage",
359
+ "computed_at", "model", "reason",
360
+ "dropped_uncited", "version")}
331
361
  # Ambient is 173 of 437 and reads as an undifferentiated fringe, but it holds classical
332
362
  # poets, GitHub collaborators, LinkedIn contacts and several pieces of software mistaken
333
363
  # for people. Grouping by what each name was seen ALONGSIDE separates them.
@@ -353,6 +383,11 @@ def read_person_graph(conn: Any, *, dataset_id: str,
353
383
  n["centrality_degree"] = structure["degree"].get(nid, 0.0)
354
384
  n["centrality_betweenness"] = structure["betweenness"].get(nid, 0.0)
355
385
  n["brokerage_meaningful"] = bool(structure.get("brokerage_meaningful", {}).get(nid))
386
+ reach = (structure.get("reach") or {}).get(nid)
387
+ if reach:
388
+ # `meaningful` carries the same component-size rule as brokerage: a cut-off
389
+ # claim inside a four-person corner is arithmetic, a leaf count is a fact.
390
+ n["reach"] = {**reach, "meaningful": bool(n["brokerage_meaningful"])}
356
391
  # People who turn up in the same subjects. A pull on the LAYOUT only: not an edge, not a
357
392
  # community, nothing that changes a colour or a count. The graph places people by their
358
393
  # relationship to the owner and to each other through messages, and neither of those
@@ -389,6 +424,11 @@ def read_person_graph(conn: Any, *, dataset_id: str,
389
424
  "behaviour understates it, and can only pull someone closer, "
390
425
  "never push them away: silence is not evidence of distance"),
391
426
  "fact_closeness_applied": fact_stats.get("applied", 0),
427
+ "heard_about": heard_stats,
428
+ "readings": {"attached": sum(1 for n in nodes if n.get("reading"))},
429
+ "disposition": disposition_stats,
430
+ "commitments": commitment_stats,
431
+ "status_signals": status_stats,
392
432
  "ambient_groups": {k: ambient_stats.get(k) for k in ("grouped", "ungrouped", "groups")},
393
433
  "context_affinity": context["pairs"],
394
434
  "context_coverage": context["coverage"],
@@ -423,6 +463,15 @@ def read_person_graph(conn: Any, *, dataset_id: str,
423
463
  }
424
464
 
425
465
 
466
+ def rate_person(conn: Any, *, subject_entity_id: str, domain: str, level: str,
467
+ note: str = "") -> Dict[str, Any]:
468
+ """The owner's informant rating of a person's Big Five domain (plan §2.2)."""
469
+ from ..features.derivation.surfaces import rate_person_disposition
470
+
471
+ return rate_person_disposition(conn, subject_entity_id=subject_entity_id,
472
+ domain=domain, level=level, note=note)
473
+
474
+
426
475
  def read_naming_queue(conn: Any, *, dataset_id: str, limit: int = 25) -> Dict[str, Any]:
427
476
  """Unnamed human peers, busiest first."""
428
477
  from .dataset_resolution import resolve_messaging_dataset
@@ -436,6 +436,84 @@ def get_relationship_signals(
436
436
  return read_relationship_signals(conn, dataset_id=dataset_id, signal=signal)
437
437
 
438
438
 
439
+ @router.post("/messenger-analytics/readings/refresh", dependencies=[Depends(require_api_key)])
440
+ def post_readings_refresh(
441
+ dataset_id: str = Query(...),
442
+ force: bool = Query(False),
443
+ limit: int = Query(60, ge=1, le=500),
444
+ ) -> Dict[str, Any]:
445
+ """Run the readings pass now, on a background thread (single-flight). Engine-only."""
446
+ import threading
447
+
448
+ from ..features.derivation import person_reading as PR
449
+
450
+ def _go() -> None:
451
+ from ..core.state import close_thread_db_connection
452
+
453
+ with PR._LOCK:
454
+ if PR._RUNNING:
455
+ return
456
+ PR._RUNNING = True
457
+ try:
458
+ conn = get_db_connection()
459
+ if conn is None:
460
+ return
461
+ PR._LAST.update(PR.refresh_person_readings(conn, dataset_id, limit=limit, force=force))
462
+ except Exception as exc: # noqa: BLE001
463
+ PR._LAST["error"] = str(exc)[:200]
464
+ finally:
465
+ with PR._LOCK:
466
+ PR._RUNNING = False
467
+ close_thread_db_connection()
468
+
469
+ if PR._RUNNING:
470
+ return {"status": "running", **PR.readings_status()}
471
+ t = threading.Thread(target=_go, name="topos-person-readings-manual", daemon=True)
472
+ t.start()
473
+ return {"status": "started", "dataset_id": dataset_id, "force": force, "limit": limit}
474
+
475
+
476
+ @router.post("/messenger-analytics/commitments/refresh", dependencies=[Depends(require_api_key)])
477
+ def post_commitments_refresh(limit: int = Query(40, ge=1, le=400)) -> Dict[str, Any]:
478
+ """The commitment ledger's owner half: run `obligations.commitments` over the owner's
479
+ promise-shaped records only (engine-only; the pack must be enabled by the owner)."""
480
+ import threading
481
+
482
+ from ..features.derivation import commitments as C
483
+ from ..features.derivation import person_reading as PR
484
+
485
+ def _go() -> None:
486
+ from ..core.state import close_thread_db_connection
487
+
488
+ with PR._LOCK:
489
+ if PR._RUNNING:
490
+ return
491
+ PR._RUNNING = True
492
+ try:
493
+ conn = get_db_connection()
494
+ if conn is None:
495
+ return
496
+ PR._LAST.update({"commitments": C.refresh_commitments(conn, limit=limit)})
497
+ except Exception as exc: # noqa: BLE001
498
+ PR._LAST["commitments_error"] = str(exc)[:200]
499
+ finally:
500
+ with PR._LOCK:
501
+ PR._RUNNING = False
502
+ close_thread_db_connection()
503
+
504
+ if PR._RUNNING:
505
+ return {"status": "running", **PR.readings_status()}
506
+ threading.Thread(target=_go, name="topos-commitments-manual", daemon=True).start()
507
+ return {"status": "started", "limit": limit}
508
+
509
+
510
+ @router.get("/messenger-analytics/readings/status", dependencies=[Depends(require_api_key)])
511
+ def get_readings_status() -> Dict[str, Any]:
512
+ from ..features.derivation.person_reading import readings_status
513
+
514
+ return readings_status()
515
+
516
+
439
517
  @router.get("/messenger-analytics/bench", dependencies=[Depends(require_api_key)])
440
518
  def get_bench() -> Dict[str, Any]:
441
519
  conn = get_db_connection()
@@ -517,6 +595,26 @@ def post_person_curate(payload: Dict[str, Any]) -> Dict[str, Any]:
517
595
  action=str(payload.get("action") or ""), value=payload.get("value"))
518
596
 
519
597
 
598
+ @router.post("/messenger-analytics/person-rate", dependencies=[Depends(require_api_key)])
599
+ def post_person_rate(payload: Dict[str, Any]) -> Dict[str, Any]:
600
+ """The owner's informant rating of a person's Big Five domain — a stated fact through
601
+ the consent path. 400 with the reason when the rating is refused."""
602
+ from fastapi import HTTPException
603
+
604
+ conn = get_db_connection()
605
+ if conn is None:
606
+ return {"error": "no database"}
607
+ from ..analytics.relationship_reads import rate_person
608
+
609
+ try:
610
+ return rate_person(
611
+ conn, subject_entity_id=str(payload.get("subject_entity_id") or ""),
612
+ domain=str(payload.get("domain") or ""), level=str(payload.get("level") or ""),
613
+ note=str(payload.get("note") or ""))
614
+ except ValueError as bad:
615
+ raise HTTPException(status_code=400, detail={"reason": "rating_refused", "error": str(bad)}) from bad
616
+
617
+
520
618
  @router.post("/messenger-analytics/person-undo", dependencies=[Depends(require_api_key)])
521
619
  def post_person_undo(payload: Dict[str, Any]) -> Dict[str, Any]:
522
620
  conn = get_db_connection()
@@ -1100,13 +1100,23 @@ async def get_derivation_packs(_api_key: str = Depends(require_api_key)):
1100
1100
  async def put_derivation_pack(
1101
1101
  pack_id: str,
1102
1102
  enabled: bool = Body(..., embed=True),
1103
+ consent: bool = Body(False, embed=True),
1104
+ consent_note: str = Body("", embed=True),
1103
1105
  _api_key: str = Depends(require_api_key),
1104
1106
  ):
1105
- from ..features.derivation.surfaces import set_pack_enabled
1107
+ """Enabling an outward pack (`net_subject: allow`) needs `consent: true`; without it
1108
+ the route answers 409 with the terms the owner must be shown."""
1109
+ from ..features.derivation.surfaces import ConsentRequired, set_pack_enabled
1106
1110
 
1107
- if not set_pack_enabled(_entities_conn(), pack_id, enabled):
1111
+ try:
1112
+ ok = set_pack_enabled(_entities_conn(), pack_id, enabled,
1113
+ consent=consent, consent_note=consent_note)
1114
+ except ConsentRequired as need:
1115
+ raise HTTPException(status_code=409, detail={"reason": "consent_required",
1116
+ "terms": need.terms}) from need
1117
+ if not ok:
1108
1118
  raise HTTPException(status_code=404, detail=f"unknown pack {pack_id}")
1109
- return {"pack_id": pack_id, "enabled": enabled}
1119
+ return {"pack_id": pack_id, "enabled": enabled, "consented": bool(consent and enabled)}
1110
1120
 
1111
1121
 
1112
1122
  @router.get("/facts/conflicts")
@@ -34,8 +34,17 @@ async def handle_put_derivation_pack(message: Dict[str, Any]) -> Optional[Dict[s
34
34
  if not pack_id or not isinstance(enabled, bool):
35
35
  return {"id": req_id, "status": "error", "error": "pack_id and enabled (bool) required"}
36
36
  try:
37
- from ...features.derivation.surfaces import set_pack_enabled
38
- if not set_pack_enabled(conn, pack_id, enabled):
37
+ from ...features.derivation.surfaces import ConsentRequired, set_pack_enabled
38
+ try:
39
+ ok = set_pack_enabled(conn, pack_id, enabled,
40
+ consent=bool(payload.get("consent")),
41
+ consent_note=str(payload.get("consent_note") or ""))
42
+ except ConsentRequired as need:
43
+ # Not an error in the transport sense: the answer is "show the owner this and
44
+ # ask". The terms ride back so the client can render them verbatim.
45
+ return {"id": req_id, "status": "error", "error": str(need),
46
+ "reason": "consent_required", "terms": need.terms}
47
+ if not ok:
39
48
  return {"id": req_id, "status": "error", "error": f"unknown pack {pack_id}"}
40
49
  return {"id": req_id, "status": "ok",
41
50
  "payload": {"status": "ok", "pack_id": pack_id, "enabled": enabled}}
@@ -492,7 +492,8 @@ async def handle_messenger_analytics_periods(message: Dict[str, Any]) -> Optiona
492
492
  "messenger_directed_edges", "messenger_bench", "messenger_luck_surface",
493
493
  "messenger_person_graph", "messenger_naming_queue",
494
494
  "messenger_person_provenance", "messenger_person_curate",
495
- "messenger_person_undo", "messenger_curation_history")
495
+ "messenger_person_undo", "messenger_curation_history",
496
+ "messenger_person_rate")
496
497
  async def handle_relationship_reads(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
497
498
  req_id = message.get("id")
498
499
  if not req_id:
@@ -518,7 +519,7 @@ async def handle_relationship_reads(message: Dict[str, Any]) -> Optional[Dict[st
518
519
  "messenger_luck_surface", "messenger_person_graph",
519
520
  "messenger_naming_queue", "messenger_person_provenance",
520
521
  "messenger_person_curate", "messenger_person_undo",
521
- "messenger_curation_history"):
522
+ "messenger_curation_history", "messenger_person_rate"):
522
523
  return {"id": req_id, "status": "error", "error": "dataset_id required"}
523
524
  if msg_type == "messenger_relationships":
524
525
  result = reads.read_relationships(
@@ -547,6 +548,16 @@ async def handle_relationship_reads(message: Dict[str, Any]) -> Optional[Dict[st
547
548
  conn, dataset_id=dataset_id,
548
549
  subject_ids=payload.get("subject_ids") or payload.get("subject_id") or [],
549
550
  action=str(payload.get("action") or ""), value=payload.get("value"))
551
+ elif msg_type == "messenger_person_rate":
552
+ try:
553
+ result = reads.rate_person(
554
+ conn, subject_entity_id=str(payload.get("subject_entity_id") or ""),
555
+ domain=str(payload.get("domain") or ""),
556
+ level=str(payload.get("level") or ""),
557
+ note=str(payload.get("note") or ""))
558
+ except ValueError as bad:
559
+ return {"id": req_id, "status": "error", "error": str(bad)[:300],
560
+ "reason": "rating_refused"}
550
561
  elif msg_type == "messenger_person_undo":
551
562
  result = reads.undo_curation(
552
563
  conn, overlay_ids=payload.get("overlay_ids")