marvisx-cli 0.3.7b3__tar.gz → 0.3.8b1__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 (640) hide show
  1. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/PKG-INFO +1 -1
  2. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/config.py +49 -0
  3. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/learnings.py +45 -2
  4. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/search.py +9 -1
  5. marvisx_cli-0.3.8b1/core/api/services/chunking.py +277 -0
  6. marvisx_cli-0.3.8b1/core/api/services/dream_cycle.py +213 -0
  7. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/embedding_internal.py +13 -0
  8. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/embedding_service.py +152 -0
  9. marvisx_cli-0.3.8b1/core/api/services/grounding/__init__.py +65 -0
  10. marvisx_cli-0.3.8b1/core/api/services/grounding/citations.py +348 -0
  11. marvisx_cli-0.3.8b1/core/api/services/grounding/verifier.py +118 -0
  12. marvisx_cli-0.3.8b1/core/api/services/kg/communities.py +227 -0
  13. marvisx_cli-0.3.8b1/core/api/services/kg/community_summary.py +105 -0
  14. marvisx_cli-0.3.8b1/core/api/services/kg/graph_lane.py +235 -0
  15. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/hybrid_search.py +171 -7
  16. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/rrf.py +40 -0
  17. marvisx_cli-0.3.8b1/core/api/services/temporal_tiebreak.py +200 -0
  18. marvisx_cli-0.3.8b1/core/api/services/temporal_write.py +431 -0
  19. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/learnings.py +298 -7
  20. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/projects.py +14 -2
  21. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/search.py +12 -0
  22. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/PKG-INFO +1 -1
  23. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/SOURCES.txt +14 -0
  24. marvisx_cli-0.3.8b1/migrations/147_chunks.sql +32 -0
  25. marvisx_cli-0.3.8b1/migrations/147_chunks_down.sql +5 -0
  26. marvisx_cli-0.3.8b1/migrations/148_bitemporal_learnings.sql +47 -0
  27. marvisx_cli-0.3.8b1/migrations/148_bitemporal_learnings_down.sql +17 -0
  28. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/pyproject.toml +1 -1
  29. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/LICENSE +0 -0
  30. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/MANIFEST.in +0 -0
  31. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/README.md +0 -0
  32. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/__init__.py +0 -0
  33. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/agents/__init__.py +0 -0
  34. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/agents/session_health.py +0 -0
  35. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/agents/session_manager.py +0 -0
  36. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/bin/marvisx-state-hook.py +0 -0
  37. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/db.py +0 -0
  38. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/dependencies/__init__.py +0 -0
  39. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/dependencies/tenant.py +0 -0
  40. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/main.py +0 -0
  41. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/__init__.py +0 -0
  42. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/_adapter.py +0 -0
  43. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/server.py +0 -0
  44. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/__init__.py +0 -0
  45. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/brain.py +0 -0
  46. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/graph.py +0 -0
  47. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/handoffs.py +0 -0
  48. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/ingest.py +0 -0
  49. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/learnings.py +0 -0
  50. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/projects.py +0 -0
  51. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/pull_requests.py +0 -0
  52. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/safety.py +0 -0
  53. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/search.py +0 -0
  54. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/tasks.py +0 -0
  55. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/workflow_playbooks/brainstorm.md +0 -0
  56. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/workflow_playbooks/compound.md +0 -0
  57. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/workflow_playbooks/plan.md +0 -0
  58. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/mcp/tools/workflows.py +0 -0
  59. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/middleware/__init__.py +0 -0
  60. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/middleware/tool_call_audit.py +0 -0
  61. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/__init__.py +0 -0
  62. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/auth.py +0 -0
  63. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/brain.py +0 -0
  64. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/common.py +0 -0
  65. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/costs.py +0 -0
  66. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/graph.py +0 -0
  67. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/graph_cosmo.py +0 -0
  68. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/graph_pr_impact.py +0 -0
  69. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/graph_ux.py +0 -0
  70. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/inbox.py +0 -0
  71. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/ingest_keys.py +0 -0
  72. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/kg.py +0 -0
  73. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/llm_config.py +0 -0
  74. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/monitoring.py +0 -0
  75. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/projects.py +0 -0
  76. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/search.py +0 -0
  77. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/sessions.py +0 -0
  78. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/tasks.py +0 -0
  79. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/teams.py +0 -0
  80. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/models/users.py +0 -0
  81. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/observability/__init__.py +0 -0
  82. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/observability/tracing.py +0 -0
  83. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/paths.py +0 -0
  84. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/rate_limit.py +0 -0
  85. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/rbac.py +0 -0
  86. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/__init__.py +0 -0
  87. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/_adapter.py +0 -0
  88. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/admin_pr_impact.py +0 -0
  89. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/admin_settings.py +0 -0
  90. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/agent.py +0 -0
  91. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/agent_tokens.py +0 -0
  92. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/app_settings.py +0 -0
  93. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/audit.py +0 -0
  94. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/auth.py +0 -0
  95. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/bench.py +0 -0
  96. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/brain.py +0 -0
  97. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/brain_directions.py +0 -0
  98. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/ci_checks.py +0 -0
  99. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/comments.py +0 -0
  100. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/costs.py +0 -0
  101. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/docs_coverage.py +0 -0
  102. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/docs_governance.py +0 -0
  103. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/documents.py +0 -0
  104. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/files.py +0 -0
  105. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/finder.py +0 -0
  106. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/graph.py +0 -0
  107. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/handoffs.py +0 -0
  108. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/inbox.py +0 -0
  109. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/ingest_api_keys.py +0 -0
  110. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/ingest_triage.py +0 -0
  111. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/judge.py +0 -0
  112. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/kg.py +0 -0
  113. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/llm_config.py +0 -0
  114. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/monitoring.py +0 -0
  115. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/notifications.py +0 -0
  116. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/pr_impact.py +0 -0
  117. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/projects.py +0 -0
  118. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/pull_requests.py +0 -0
  119. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/push.py +0 -0
  120. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/raci.py +0 -0
  121. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/sessions.py +0 -0
  122. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/settings.py +0 -0
  123. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/share_repo.py +0 -0
  124. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/status_updates.py +0 -0
  125. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/tags.py +0 -0
  126. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/tasks.py +0 -0
  127. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/teams.py +0 -0
  128. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/terminal.py +0 -0
  129. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/users.py +0 -0
  130. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/routers/webhooks.py +0 -0
  131. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/runtime_settings.py +0 -0
  132. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/security.py +0 -0
  133. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/__init__.py +0 -0
  134. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/_fts.py +0 -0
  135. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/audit.py +0 -0
  136. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/auto_approval.py +0 -0
  137. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/__init__.py +0 -0
  138. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/baseline.py +0 -0
  139. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/capabilities.py +0 -0
  140. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/cascade_rollup.py +0 -0
  141. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/compound_bridge.py +0 -0
  142. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/cycle.py +0 -0
  143. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/cycle_snapshot.py +0 -0
  144. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/digest_collector.py +0 -0
  145. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/direction.py +0 -0
  146. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/drift.py +0 -0
  147. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/drift_router.py +0 -0
  148. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/edge_metrics.py +0 -0
  149. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/events_reader.py +0 -0
  150. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/findings.py +0 -0
  151. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/findings_reader.py +0 -0
  152. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/jobs.py +0 -0
  153. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/journal.py +0 -0
  154. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/knowledge_forms.py +0 -0
  155. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/__init__.py +0 -0
  156. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/_runner.py +0 -0
  157. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/base.py +0 -0
  158. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/cache.py +0 -0
  159. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/constants.py +0 -0
  160. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/direction_alignment.py +0 -0
  161. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/factory.py +0 -0
  162. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/finding_reasoning.py +0 -0
  163. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/finding_summary.py +0 -0
  164. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/grounding.py +0 -0
  165. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/journal_polish.py +0 -0
  166. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/local_gateway.py +0 -0
  167. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/parsers.py +0 -0
  168. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/llm/router_glue.py +0 -0
  169. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/memory_ops.py +0 -0
  170. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/models.py +0 -0
  171. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/owner_hint.py +0 -0
  172. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/recap.py +0 -0
  173. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/__init__.py +0 -0
  174. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/_signals.py +0 -0
  175. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr1_activity_without_status.py +0 -0
  176. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr2_decision_without_adr.py +0 -0
  177. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr3_stale_open_loop.py +0 -0
  178. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr4_docs_governance_drift.py +0 -0
  179. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr5_playbook_changed.py +0 -0
  180. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr6_external_update_unpropagated.py +0 -0
  181. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr7_claimed_decision_gap.py +0 -0
  182. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/rules/dr8_direction_misalignment.py +0 -0
  183. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/runs_reader.py +0 -0
  184. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/scope.py +0 -0
  185. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/__init__.py +0 -0
  186. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/base.py +0 -0
  187. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/git_kg.py +0 -0
  188. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/handoffs.py +0 -0
  189. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/ingestor.py +0 -0
  190. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/learnings.py +0 -0
  191. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/sources/pir_tasks.py +0 -0
  192. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/warehouse_consolidate.py +0 -0
  193. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/watermarks.py +0 -0
  194. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/brain/ws_emitter.py +0 -0
  195. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/cc_tasks_reader.py +0 -0
  196. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ci_service.py +0 -0
  197. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/claude_metrics.py +0 -0
  198. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/codex_metrics.py +0 -0
  199. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/conversation_reader.py +0 -0
  200. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/cost_service.py +0 -0
  201. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/crypto.py +0 -0
  202. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/__init__.py +0 -0
  203. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/confidence.py +0 -0
  204. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/config.py +0 -0
  205. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/enrichment.py +0 -0
  206. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/frontmatter_validator.py +0 -0
  207. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/hard_gates.py +0 -0
  208. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/docs_governance/triage_orchestrator.py +0 -0
  209. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/embedding_backends/__init__.py +0 -0
  210. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/event_dispatcher.py +0 -0
  211. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/events.py +0 -0
  212. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/git_ops.py +0 -0
  213. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/graph_cosmo_service.py +0 -0
  214. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/graph_ranker.py +0 -0
  215. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/graph_service.py +0 -0
  216. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox.py +0 -0
  217. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_digest.py +0 -0
  218. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_digest_deep_research.py +0 -0
  219. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_digest_jobs.py +0 -0
  220. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_gmail_sync.py +0 -0
  221. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_llm_classifier.py +0 -0
  222. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_source_identity.py +0 -0
  223. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_sources.py +0 -0
  224. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_taxonomy.py +0 -0
  225. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_tldr.py +0 -0
  226. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/inbox_triage.py +0 -0
  227. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/__init__.py +0 -0
  228. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/api_key_auth.py +0 -0
  229. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/auto_approve.py +0 -0
  230. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/classifier.py +0 -0
  231. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/confidence.py +0 -0
  232. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/dispatch.py +0 -0
  233. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/embedding_router.py +0 -0
  234. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/events.py +0 -0
  235. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/ignore_patterns.py +0 -0
  236. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/image_probe.py +0 -0
  237. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/ingress.py +0 -0
  238. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/insert_saga.py +0 -0
  239. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/__init__.py +0 -0
  240. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/anthropic_haiku.py +0 -0
  241. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/base.py +0 -0
  242. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/byok_provider.py +0 -0
  243. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/classification_context.py +0 -0
  244. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/config_store.py +0 -0
  245. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/factory.py +0 -0
  246. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/kg_enricher.py +0 -0
  247. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/local_gateway.py +0 -0
  248. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/local_vllm.py +0 -0
  249. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/llm/openai_nano.py +0 -0
  250. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/lock_advisory.py +0 -0
  251. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parser_router.py +0 -0
  252. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/__init__.py +0 -0
  253. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/docling_parser.py +0 -0
  254. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/docparse_gateway.py +0 -0
  255. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/docx_parser.py +0 -0
  256. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/folder_unpacker.py +0 -0
  257. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/gateway_aux.py +0 -0
  258. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/image_parser.py +0 -0
  259. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/internal_markdown.py +0 -0
  260. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/ocr_gateway.py +0 -0
  261. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/ocr_pdf_parser.py +0 -0
  262. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/pdf_types.py +0 -0
  263. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/transcript_parser.py +0 -0
  264. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/vision_gateway.py +0 -0
  265. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/xlsx_parser.py +0 -0
  266. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/parsers/zip_unpacker.py +0 -0
  267. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/preflight.py +0 -0
  268. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/routing_policy.py +0 -0
  269. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/serializers/__init__.py +0 -0
  270. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/serializers/xlsx_to_markdown.py +0 -0
  271. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/skip_log.py +0 -0
  272. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/ingest/watcher.py +0 -0
  273. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/__init__.py +0 -0
  274. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/audit.py +0 -0
  275. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/lens.py +0 -0
  276. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/pr_impact.py +0 -0
  277. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/queries.py +0 -0
  278. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg/ranking.py +0 -0
  279. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/kg_watcher_control.py +0 -0
  280. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/local_llm/__init__.py +0 -0
  281. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/local_llm/async_client.py +0 -0
  282. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/local_llm/client.py +0 -0
  283. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/local_llm/url_validator.py +0 -0
  284. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/metrics_collector.py +0 -0
  285. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/metrics_providers.py +0 -0
  286. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/model_registry.py +0 -0
  287. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/model_router.py +0 -0
  288. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/n8n_client.py +0 -0
  289. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/newsletter_llm_gateway.py +0 -0
  290. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/notification_service.py +0 -0
  291. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/openai_responses.py +0 -0
  292. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/opencode_metrics.py +0 -0
  293. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/opencode_sessions.py +0 -0
  294. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pii_redactor.py +0 -0
  295. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/__init__.py +0 -0
  296. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/differ.py +0 -0
  297. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/dispatcher.py +0 -0
  298. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/gc.py +0 -0
  299. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/languages.py +0 -0
  300. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/parser.py +0 -0
  301. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_impact_pipeline/writer.py +0 -0
  302. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/pr_service.py +0 -0
  303. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/project_paths.py +0 -0
  304. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/project_status_updates.py +0 -0
  305. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/providers.py +0 -0
  306. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/push_service.py +0 -0
  307. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/reminder_service.py +0 -0
  308. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/runas.py +0 -0
  309. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/salience_service.py +0 -0
  310. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/security_collector.py +0 -0
  311. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/session_catalog.py +0 -0
  312. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/session_metrics_service.py +0 -0
  313. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/session_ops.py +0 -0
  314. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/session_state.py +0 -0
  315. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/share_links.py +0 -0
  316. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/task_transitions.py +0 -0
  317. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/terminal_metrics.py +0 -0
  318. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/terminal_metrics_dump.py +0 -0
  319. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/tmux.py +0 -0
  320. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/webhook_service.py +0 -0
  321. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/services/workspace_sync.py +0 -0
  322. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/templates/__init__.py +0 -0
  323. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/templates/markdown_share.py +0 -0
  324. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/terminal.py +0 -0
  325. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/__init__.py +0 -0
  326. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_agent_facing_auth_dependencies.py +0 -0
  327. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_audit_permissions.py +0 -0
  328. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_backfill_session_conversations.py +0 -0
  329. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_backfill_working_seconds_msg.py +0 -0
  330. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_claude_metrics.py +0 -0
  331. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_codex_metrics.py +0 -0
  332. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_config_env_aliases.py +0 -0
  333. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_finder_paths.py +0 -0
  334. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_git_ops_merge.py +0 -0
  335. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_learnings_check_search.py +0 -0
  336. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_metrics_providers.py +0 -0
  337. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_migration_087.py +0 -0
  338. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_migration_088.py +0 -0
  339. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_migration_089.py +0 -0
  340. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_openai_responses.py +0 -0
  341. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_opencode_metrics.py +0 -0
  342. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_opencode_sessions.py +0 -0
  343. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_pr_workflow_e2e.py +0 -0
  344. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_projects_handoffs.py +0 -0
  345. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_providers.py +0 -0
  346. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_require_scope_empty_deny.py +0 -0
  347. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_safety_bridge.py +0 -0
  348. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_session_catalog.py +0 -0
  349. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_session_conversations.py +0 -0
  350. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_session_metrics_service.py +0 -0
  351. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_session_resume_paths.py +0 -0
  352. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_session_theme_mode_migration.py +0 -0
  353. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_sessions_rbac.py +0 -0
  354. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_share_edit.py +0 -0
  355. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_share_repo.py +0 -0
  356. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_terminal_session_manager.py +0 -0
  357. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_terminal_upload.py +0 -0
  358. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_tmux.py +0 -0
  359. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_workspace_sync.py +0 -0
  360. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/tests/test_ws_ticket_in_memory.py +0 -0
  361. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/__init__.py +0 -0
  362. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/_context.py +0 -0
  363. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/_errors.py +0 -0
  364. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/_roles.py +0 -0
  365. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/audit.py +0 -0
  366. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/brain.py +0 -0
  367. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/costs.py +0 -0
  368. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/graph.py +0 -0
  369. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/handoffs.py +0 -0
  370. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/ingest_triage.py +0 -0
  371. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/pull_requests.py +0 -0
  372. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/use_cases/tasks.py +0 -0
  373. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/api/visibility.py +0 -0
  374. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/README.md +0 -0
  375. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/__init__.py +0 -0
  376. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_brain_opportunistic.py +0 -0
  377. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_brain_schedule.py +0 -0
  378. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_index_source.py +0 -0
  379. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_runtime_ctx.py +0 -0
  380. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_transmute.py +0 -0
  381. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/_update_check.py +0 -0
  382. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/guides/__init__.py +0 -0
  383. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/guides/marvis-way.md +0 -0
  384. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_account.py +0 -0
  385. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_brain.py +0 -0
  386. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_doctor.py +0 -0
  387. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_feedback.py +0 -0
  388. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_governance.py +0 -0
  389. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_guide.py +0 -0
  390. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_hooks.py +0 -0
  391. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_init.py +0 -0
  392. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_mcp.py +0 -0
  393. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_runtime.py +0 -0
  394. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/cli/marvis_telemetry.py +0 -0
  395. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/platform/__init__.py +0 -0
  396. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/_drift_check.py +0 -0
  397. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/_frontmatter.py +0 -0
  398. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/_graph_writer.py +0 -0
  399. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/ast_parser.py +0 -0
  400. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/__init__.py +0 -0
  401. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/_config.sh +0 -0
  402. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/block-dangerous-bash.sh +0 -0
  403. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/block-db-direct-write.sh +0 -0
  404. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/block-push-no-task.sh +0 -0
  405. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/block-staging-to-prod.sh +0 -0
  406. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/block-subtree-push.sh +0 -0
  407. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/config.json +0 -0
  408. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/enforce-no-merge-main.sh +0 -0
  409. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/enforce-worktree.sh +0 -0
  410. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/quality-gate.sh +0 -0
  411. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/safety_bridge.py +0 -0
  412. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/install_hooks/secret-scan.sh +0 -0
  413. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/migrate_spike_node_ids.py +0 -0
  414. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_artifacts.py +0 -0
  415. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_cross_project.py +0 -0
  416. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_inbox_nodes.py +0 -0
  417. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_pr_impact.py +0 -0
  418. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_project_nodes.py +0 -0
  419. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/populate_touch_counter.py +0 -0
  420. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/reparse_failed.py +0 -0
  421. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/scripts/safety_bridge.py +0 -0
  422. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/__init__.py +0 -0
  423. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/client.py +0 -0
  424. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/entitlements.py +0 -0
  425. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/rollup.py +0 -0
  426. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/schema.py +0 -0
  427. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/telemetry/sender.py +0 -0
  428. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/__init__.py +0 -0
  429. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/byok_vault.py +0 -0
  430. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/defaults.py +0 -0
  431. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/state.py +0 -0
  432. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/steps.py +0 -0
  433. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/core/wizard/validation.py +0 -0
  434. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/dependency_links.txt +0 -0
  435. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/entry_points.txt +0 -0
  436. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/requires.txt +0 -0
  437. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/marvisx_cli.egg-info/top_level.txt +0 -0
  438. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/001_initial.sql +0 -0
  439. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/002_tasks.sql +0 -0
  440. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/003_session_management.sql +0 -0
  441. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/004_projects_comments.sql +0 -0
  442. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/005_session_intelligence.sql +0 -0
  443. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/006_settings.sql +0 -0
  444. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/007_task_scoring.sql +0 -0
  445. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/008_cost_tracking.sql +0 -0
  446. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/009_session_card_metrics.sql +0 -0
  447. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/010_monitoring.sql +0 -0
  448. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/012_agent_api.sql +0 -0
  449. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/013_session_complete.sql +0 -0
  450. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/015_pull_requests.sql +0 -0
  451. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/015_pull_requests_down.sql +0 -0
  452. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/016_users_raci.sql +0 -0
  453. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/017_task_cost_entries.sql +0 -0
  454. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/018_agents.sql +0 -0
  455. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/018_agents_down.sql +0 -0
  456. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/019_review_feedback.sql +0 -0
  457. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/020_pr_commit_sha.sql +0 -0
  458. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/021_webhook_events.sql +0 -0
  459. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/022_devx_agent_managed.sql +0 -0
  460. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/022_devx_agent_managed_down.sql +0 -0
  461. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/023_devx_p1_gate.sql +0 -0
  462. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/023_devx_p1_gate_down.sql +0 -0
  463. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/024_chat_messages.sql +0 -0
  464. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/024_pr_conversation_id.sql +0 -0
  465. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/024_task_indexes.sql +0 -0
  466. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/024_task_indexes_down.sql +0 -0
  467. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/025_audit_log.sql +0 -0
  468. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/026_agent_tokens.sql +0 -0
  469. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/027_teams_auth_phase_b.sql +0 -0
  470. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/028_learnings.sql +0 -0
  471. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/029_team_roles.sql +0 -0
  472. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/030_finder_pins.sql +0 -0
  473. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/031_pr_deploy_status.sql +0 -0
  474. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/032_task_reminders.sql +0 -0
  475. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/033_events_retry_count.sql +0 -0
  476. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/033_session_owner.sql +0 -0
  477. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/034_notifications.sql +0 -0
  478. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/035_shared_links.sql +0 -0
  479. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/036_session_index_upgrade.sql +0 -0
  480. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/037_pr_approval.sql +0 -0
  481. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/038_pr_submitted_by.sql +0 -0
  482. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/039_push_subscriptions.sql +0 -0
  483. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/040_semantic_search.sql +0 -0
  484. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/041_workspaces.sql +0 -0
  485. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/042_oidc_providers.sql +0 -0
  486. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/043_ci_checks.sql +0 -0
  487. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/044_agent_metrics.sql +0 -0
  488. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/045_documents_doc_type.sql +0 -0
  489. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/046_salience.sql +0 -0
  490. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/047_seed_missing_agents.sql +0 -0
  491. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/048_fix_agent_paths_roles.sql +0 -0
  492. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/049_agent_role_and_learnings_schema.sql +0 -0
  493. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/050_session_provider.sql +0 -0
  494. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/051_session_launch_profile.sql +0 -0
  495. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/052_session_theme_mode.sql +0 -0
  496. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/052_task_kind.sql +0 -0
  497. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/053_inbox_items.sql +0 -0
  498. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/054_inbox_triage_contract.sql +0 -0
  499. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/055_inbox_topic_treatment.sql +0 -0
  500. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/056_inbox_treatment_read_save.sql +0 -0
  501. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/057_session_theme_mode_backfill.sql +0 -0
  502. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/058_inbox_item_status_lifecycle.sql +0 -0
  503. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/059_inbox_tldr_and_source_scores.sql +0 -0
  504. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/060_newsletter.sql +0 -0
  505. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/061_inbox_redesign.sql +0 -0
  506. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/062_fix_inbox_sources_backfill.sql +0 -0
  507. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/063_task_completion_mode.sql +0 -0
  508. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/064_judge_mode_setting.sql +0 -0
  509. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/065_knowledge_graph_spike.sql +0 -0
  510. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/066_digest_ranking_inputs.sql +0 -0
  511. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/066_kg_artifact_nodes.sql +0 -0
  512. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/067_inbox_digest_selections.sql +0 -0
  513. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/067_kg_temporal.sql +0 -0
  514. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/068_inbox_digest_app_settings.sql +0 -0
  515. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/068_kg_touch_counter.sql +0 -0
  516. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/069_kg_doc_types.sql +0 -0
  517. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/070_digest_ranking_inputs_recovery.sql +0 -0
  518. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/071_inbox_digest_selections_recovery.sql +0 -0
  519. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/072_inbox_digest_app_settings_recovery.sql +0 -0
  520. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/073_kg_cross_project.sql +0 -0
  521. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/073_kg_cross_project_down.sql +0 -0
  522. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/074_kg_infra_types.sql +0 -0
  523. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/074_kg_infra_types_down.sql +0 -0
  524. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/075_kg_file_state_recovery.sql +0 -0
  525. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/075_kg_file_state_recovery_down.sql +0 -0
  526. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/076_kg_watcher_state.sql +0 -0
  527. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/076_kg_watcher_state_down.sql +0 -0
  528. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/077_kg_doc_types_extend.sql +0 -0
  529. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/077_kg_doc_types_extend_down.sql +0 -0
  530. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/078_kg_fts5.sql +0 -0
  531. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/078_kg_fts5_down.sql +0 -0
  532. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/079_kg_missing_indexes.sql +0 -0
  533. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/079_kg_missing_indexes_down.sql +0 -0
  534. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/080_kg_fts5_extended.sql +0 -0
  535. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/080_kg_fts5_extended_down.sql +0 -0
  536. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/081_kg_lens_indexes.sql +0 -0
  537. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/081_kg_lens_indexes_down.sql +0 -0
  538. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/082_kg_pins.sql +0 -0
  539. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/082_kg_pins_down.sql +0 -0
  540. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/083_kg_graph_nodes_degree.sql +0 -0
  541. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/083_kg_graph_nodes_degree_down.sql +0 -0
  542. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/084_drop_legacy_scheduler_tables.sql +0 -0
  543. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/084_drop_legacy_scheduler_tables_down.sql +0 -0
  544. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/085_kg_edge_resolves_to.sql +0 -0
  545. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/085_kg_edge_resolves_to_down.sql +0 -0
  546. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/086_project_status_updates_feed.sql +0 -0
  547. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/086_project_status_updates_feed_down.sql +0 -0
  548. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/087_session_metrics_dual.sql +0 -0
  549. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/087_session_metrics_dual_down.sql +0 -0
  550. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/088_rename_context_pct_legacy.sql +0 -0
  551. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/088_rename_context_pct_legacy_down.sql +0 -0
  552. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/089_session_metrics_equivalent_cost.sql +0 -0
  553. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/089_session_metrics_equivalent_cost_down.sql +0 -0
  554. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/090_kg_inbox_node_type.sql +0 -0
  555. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/090_kg_inbox_node_type_down.sql +0 -0
  556. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/091_kg_inbox_node_type_check.sql +0 -0
  557. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/091_kg_inbox_node_type_check_down.sql +0 -0
  558. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/092_sessions_activity_state_ts.sql +0 -0
  559. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/092_sessions_activity_state_ts_down.sql +0 -0
  560. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/093_sessions_activity_state_column.sql +0 -0
  561. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/093_sessions_activity_state_column_down.sql +0 -0
  562. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/094_ingest_pending.sql +0 -0
  563. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/094_ingest_pending_down.sql +0 -0
  564. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/095_kg_intent_first.sql +0 -0
  565. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/095_kg_intent_first_down.sql +0 -0
  566. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/096_kg_xlsx_artifact_prefix.sql +0 -0
  567. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/096_kg_xlsx_artifact_prefix_down.sql +0 -0
  568. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/097_ingest_change_history.sql +0 -0
  569. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/097_ingest_change_history_down.sql +0 -0
  570. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/098_kg_node_type_business.sql +0 -0
  571. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/098_kg_node_type_business_down.sql +0 -0
  572. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/099_kg_edges_restore_weight.sql +0 -0
  573. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/099_kg_edges_restore_weight_down.sql +0 -0
  574. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/100_kg_enriched_at.sql +0 -0
  575. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/100_kg_enriched_at_down.sql +0 -0
  576. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/101_local_llm_shadow_comparisons.sql +0 -0
  577. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/101_local_llm_shadow_comparisons_down.sql +0 -0
  578. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/102_promote_llm_costs.sql +0 -0
  579. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/102_promote_llm_costs_down.sql +0 -0
  580. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/103_ingest_skipped_log.sql +0 -0
  581. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/103_ingest_skipped_log_down.sql +0 -0
  582. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/120_docs_governance.sql +0 -0
  583. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/120_docs_governance_down.sql +0 -0
  584. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/121_notification_event_fk_cleanup.sql +0 -0
  585. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/121_notification_event_fk_cleanup_down.sql +0 -0
  586. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/122_docs_drift_history.sql +0 -0
  587. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/122_docs_drift_history_down.sql +0 -0
  588. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/123_ingest_parser_waiting_status.sql +0 -0
  589. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/123_ingest_parser_waiting_status_down.sql +0 -0
  590. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/124_heypocket_recordings.sql +0 -0
  591. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/124_heypocket_recordings_down.sql +0 -0
  592. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/125_kg_node_type_record.sql +0 -0
  593. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/125_kg_node_type_record_down.sql +0 -0
  594. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/126_ingest_terminal_upload_source_kind.sql +0 -0
  595. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/126_ingest_terminal_upload_source_kind_down.sql +0 -0
  596. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/127_brain_v1_substrate.sql +0 -0
  597. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/127_brain_v1_substrate_down.sql +0 -0
  598. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/128_brain_drift_signals.sql +0 -0
  599. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/128_brain_drift_signals_down.sql +0 -0
  600. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/129_brain_memory_operations.sql +0 -0
  601. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/129_brain_memory_operations_down.sql +0 -0
  602. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/130_brain_findings.sql +0 -0
  603. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/130_brain_findings_down.sql +0 -0
  604. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/132_kg_pr_modifies.sql +0 -0
  605. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/132_kg_pr_modifies_down.sql +0 -0
  606. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/133_brain_v1_2_direction_schema.sql +0 -0
  607. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/133_brain_v1_2_direction_schema_down.sql +0 -0
  608. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/134_brain_journal_narrative_polished.sql +0 -0
  609. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/134_brain_journal_narrative_polished_down.sql +0 -0
  610. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/135_kg_edges_provider.sql +0 -0
  611. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/136_documents_fts.sql +0 -0
  612. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/137_promote_llm_costs.sql +0 -0
  613. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/137_promote_llm_costs_down.sql +0 -0
  614. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/138_ingest_api_keys.sql +0 -0
  615. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/138_ingest_api_keys_down.sql +0 -0
  616. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/139_ingest_pending_ingress.sql +0 -0
  617. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/139_ingest_pending_ingress_down.sql +0 -0
  618. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/140_ingest_idempotency_quota.sql +0 -0
  619. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/140_ingest_idempotency_quota_down.sql +0 -0
  620. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/141_ingest_pending_metadata.sql +0 -0
  621. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/141_ingest_pending_metadata_down.sql +0 -0
  622. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/142_llm_function_config.sql +0 -0
  623. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/142_llm_function_config_down.sql +0 -0
  624. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/143_kg_code_embeddings.sql +0 -0
  625. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/143_kg_code_embeddings_down.sql +0 -0
  626. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/144_notifications_pending_sync_index.sql +0 -0
  627. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/145_audit_log_immutable.sql +0 -0
  628. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/145_audit_log_immutable_down.sql +0 -0
  629. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/146_drop_kg_backup_tables.sql +0 -0
  630. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/146_drop_kg_backup_tables_down.sql +0 -0
  631. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/migrations/__init__.py +0 -0
  632. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/context.md +0 -0
  633. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/docs/brainstorms/YYYY-MM-DD-example-brainstorm.md +0 -0
  634. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/docs/plans/YYYY-MM-DD-example-plan.md +0 -0
  635. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/docs/solutions/YYYY-MM-DD-example-solution.md +0 -0
  636. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/input/README.md +0 -0
  637. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/memory/handoff.md +0 -0
  638. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/output/README.md +0 -0
  639. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/projects/_template/project.yaml +0 -0
  640. {marvisx_cli-0.3.7b3 → marvisx_cli-0.3.8b1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marvisx-cli
3
- Version: 0.3.7b3
3
+ Version: 0.3.8b1
4
4
  Summary: MarvisX OSS — agent-native company-brain CLI runtime (init, status, brief, triage)
5
5
  Author: MarvisX maintainers
6
6
  License: BSL-1.1
@@ -439,6 +439,55 @@ class Settings(BaseSettings):
439
439
  False # pydantic-settings maps KG_HTTP_DEEP_DEFAULT env var
440
440
  )
441
441
 
442
+ # Track 2 #3a — STRUCTURAL graph-lane in the RRF fusion (DEFAULT OFF).
443
+ # When False the fused ranking is byte-identical to today (5 lanes). When
444
+ # True a 6th lane (seeded 1-hop edge-weighted KG expansion) joins the blend.
445
+ # graph_lane_hops / graph_lane_fanout / graph_lane_weight / graph_lane_seeds
446
+ # tune the lane without code changes. Edge-type subset = all 15 by default.
447
+ graph_lane_enabled: bool = Field(
448
+ default=False, alias="MARVIS_GRAPH_LANE"
449
+ )
450
+ graph_lane_hops: int = Field(default=1, alias="MARVIS_GRAPH_LANE_HOPS")
451
+ graph_lane_fanout: int = Field(default=25, alias="MARVIS_GRAPH_LANE_FANOUT")
452
+ graph_lane_seeds: int = Field(default=10, alias="MARVIS_GRAPH_LANE_SEEDS")
453
+ graph_lane_weight: float = Field(
454
+ default=0.12, alias="MARVIS_GRAPH_LANE_WEIGHT"
455
+ )
456
+
457
+ # Track 2 #1 — bi-temporal memory READ path (DEFAULT OFF). When False every
458
+ # learnings read is byte-identical to today (no invalid_at filter, no as_of):
459
+ # the temporal helper emits NO extra SQL. When True the default learnings
460
+ # reads (check/list/get + the learnings retrieval lane in search) add
461
+ # ``AND invalid_at IS NULL`` — a MECHANICAL, BINARY exclusion (superseded rows
462
+ # never reach the LLM; never a down-weight, which would still let the model
463
+ # cite the stale value). An explicit ``as_of=<ISO>`` relaxes the filter to the
464
+ # point-in-time window ``valid_from <= as_of AND (invalid_at IS NULL OR
465
+ # invalid_at > as_of)`` for audit. S3/S4/S5 (write path / LLM tiebreak / dream
466
+ # cycle) reuse this SAME flag. Requires migration 148 columns when enabled.
467
+ temporal_memory_enabled: bool = Field(
468
+ default=False, alias="MARVIS_TEMPORAL_MEMORY"
469
+ )
470
+
471
+ # Track 2 #3c — community summaries in the brief (GraphRAG global-search,
472
+ # DEFAULT OFF). When False the brief is byte-identical to today: the
473
+ # communities/community_summary modules are a flag-gated library + seam,
474
+ # never imported into session_brief. When True (off-host wiring), the KG is
475
+ # partitioned (deterministic label propagation, NO LLM) and per-community
476
+ # summaries enter the brief AFTER #2 so they inherit span-citation + NLI
477
+ # verification (a summary is itself a claim to ground, not free text).
478
+ community_summaries_enabled: bool = Field(
479
+ default=False, alias="MARVIS_COMMUNITY_SUMMARIES"
480
+ )
481
+
482
+ # Track 2 #2: span-citation + grounding-verification layer for the brief.
483
+ # DEFAULT OFF — the layer exists as a flag-gated library; when off the
484
+ # session_brief output is byte-for-byte unchanged (the seam is never entered).
485
+ # See core/api/services/grounding/. Wiring the NLI head (MiniCheck) is a
486
+ # separate, deliberate, off-host step (NoopVerifier is the default).
487
+ brief_citations_enabled: bool = Field(
488
+ default=False, alias="MARVIS_BRIEF_CITATIONS"
489
+ )
490
+
442
491
  # WIP limit: max tasks in_progress per project (doc/none tasks count as 0.5)
443
492
  wip_max_in_progress: int = 3
444
493
 
@@ -46,6 +46,8 @@ from core.api.use_cases.learnings import ( # noqa: F401 (re-export surface)
46
46
  VALID_CATEGORIES,
47
47
  VALID_SEVERITIES,
48
48
  LearningCheckResponse,
49
+ LearningHistoryLink,
50
+ LearningHistoryResponse,
49
51
  LearningResponse,
50
52
  _extract_check_terms,
51
53
  _learning_match_score,
@@ -158,13 +160,20 @@ async def check_learnings(
158
160
  None, description="Filter by module (exact or LIKE match)"
159
161
  ),
160
162
  deep: bool = Query(False, description="Attach KG context to each result (Phase 7.0)"),
163
+ as_of: str | None = Query(
164
+ None,
165
+ description=(
166
+ "Point-in-time audit (Track 2 #1). ISO timestamp; returns learnings live "
167
+ "at that instant. Only effective when MARVIS_TEMPORAL_MEMORY is enabled."
168
+ ),
169
+ ),
161
170
  user: UserInfo = Depends(get_current_user_or_agent),
162
171
  db: aiosqlite.Connection = Depends(get_db),
163
172
  ) -> LearningCheckResponse:
164
173
  """Search learnings relevant to a keyword/module. Used by MCP before risky actions."""
165
174
  ctx = CallerContext.from_user_info(user, is_human_session=False)
166
175
  try:
167
- result = await uc.check_learnings(ctx, db, query=q, module=module)
176
+ result = await uc.check_learnings(ctx, db, query=q, module=module, as_of=as_of)
168
177
  except ServiceError as e:
169
178
  raise to_http(e)
170
179
 
@@ -194,6 +203,13 @@ async def list_learnings(
194
203
  limit: int = Query(50, ge=1, le=200),
195
204
  offset: int = Query(0, ge=0),
196
205
  deep: bool = Query(False, description="Attach KG context (aggregate deferred to Phase 7.1)"),
206
+ as_of: str | None = Query(
207
+ None,
208
+ description=(
209
+ "Point-in-time audit (Track 2 #1). ISO timestamp; lists learnings live "
210
+ "at that instant. Only effective when MARVIS_TEMPORAL_MEMORY is enabled."
211
+ ),
212
+ ),
197
213
  user: UserInfo = Depends(get_current_user_or_agent),
198
214
  db: aiosqlite.Connection = Depends(get_db),
199
215
  ) -> list[LearningResponse]:
@@ -225,22 +241,49 @@ async def list_learnings(
225
241
  limit=limit,
226
242
  offset=offset,
227
243
  visible_projects=visible_projects,
244
+ as_of=as_of,
228
245
  )
229
246
  except ServiceError as e:
230
247
  raise to_http(e)
231
248
 
232
249
 
250
+ @router.get("/{learning_id}/history", response_model=LearningHistoryResponse)
251
+ async def get_learning_history(
252
+ learning_id: str,
253
+ user: UserInfo = Depends(get_current_user_or_agent),
254
+ db: aiosqlite.Connection = Depends(get_db),
255
+ ) -> LearningHistoryResponse:
256
+ """Walk a learning's supersede chain (Track 2 #1 audit trail, READ-ONLY).
257
+
258
+ Returns every link (the row + each ``superseded_by`` hop) with valid_from /
259
+ invalid_at / supersede_reason. Always walks the full chain regardless of the
260
+ ``MARVIS_TEMPORAL_MEMORY`` flag — this is the deliberate audit surface.
261
+ """
262
+ ctx = CallerContext.from_user_info(user, is_human_session=False)
263
+ try:
264
+ return await uc.get_learning_history(ctx, db, learning_id=learning_id)
265
+ except ServiceError as e:
266
+ raise to_http(e)
267
+
268
+
233
269
  @router.get("/{learning_id}", response_model=LearningResponse)
234
270
  async def get_learning(
235
271
  learning_id: str,
236
272
  deep: bool = Query(False, description="Attach KG context (Phase 7.0)"),
273
+ as_of: str | None = Query(
274
+ None,
275
+ description=(
276
+ "Point-in-time audit (Track 2 #1). ISO timestamp; returns the row iff it "
277
+ "was live at that instant. Only effective when MARVIS_TEMPORAL_MEMORY is enabled."
278
+ ),
279
+ ),
237
280
  user: UserInfo = Depends(get_current_user_or_agent),
238
281
  db: aiosqlite.Connection = Depends(get_db),
239
282
  ) -> LearningResponse:
240
283
  """Get a single learning by ID."""
241
284
  ctx = CallerContext.from_user_info(user, is_human_session=False)
242
285
  try:
243
- result = await uc.get_learning(ctx, db, learning_id=learning_id)
286
+ result = await uc.get_learning(ctx, db, learning_id=learning_id, as_of=as_of)
244
287
  except ServiceError as e:
245
288
  raise to_http(e)
246
289
 
@@ -96,6 +96,14 @@ async def search(
96
96
  description="True (default): RRF fusion semantic + KG FTS5. False: semantic-only (legacy v1.5 behavior).",
97
97
  ),
98
98
  limit: int = Query(20, ge=1, le=50),
99
+ as_of: str | None = Query(
100
+ None,
101
+ description=(
102
+ "Point-in-time audit (Track 2 #1). ISO timestamp; reconstructs the "
103
+ "learnings live at that instant. Only effective when "
104
+ "MARVIS_TEMPORAL_MEMORY is enabled; ignored otherwise."
105
+ ),
106
+ ),
99
107
  user: UserInfo = Depends(get_current_user_or_agent),
100
108
  ) -> SearchResponse:
101
109
  """Hybrid (default) or semantic search across the KG and embedding index."""
@@ -104,7 +112,7 @@ async def search(
104
112
 
105
113
  ctx = CallerContext.from_user_info(user, is_human_session=False)
106
114
  try:
107
- return await uc.search(ctx, q=q, hybrid=hybrid, limit=limit)
115
+ return await uc.search(ctx, q=q, hybrid=hybrid, limit=limit, as_of=as_of)
108
116
  except ServiceError as e:
109
117
  raise to_http(e)
110
118
 
@@ -0,0 +1,277 @@
1
+ # v1.0.0 - 2026-06-04 - Track 2 #4: fixed-size prose chunker (flag MARVIS_CHUNKING)
2
+ """Pure, model-free fixed-size prose chunker (Track 2 #4).
3
+
4
+ Splits a prose document into fixed-size, overlapping, sentence-aware windows
5
+ BEFORE it is embedded, so a long handoff/plan no longer collapses to a single
6
+ over-compressed CLS vector (the embedder is a 32k-context ModernBert with CLS
7
+ pooling — there is no truncation pressure, the motivation is over-compression,
8
+ not truncation; see the roadmap "Research Insights — #4").
9
+
10
+ Design constraints (all load-bearing):
11
+
12
+ * **Model-free + pure.** No ONNX session, no model load, no I/O. The only
13
+ dependency is a *tokenizer* injected by the caller (``tokenizer`` param), so
14
+ this is unit-testable with a FAKE tokenizer and the real path reuses Granite's
15
+ already-loaded Rust ``tokenizers.Tokenizer`` (no second tokenizer, no second
16
+ model). The tokenizer is only asked for ``encode(text)`` exposing ``.ids`` and
17
+ ``.offsets`` (per-token ``(char_start, char_end)`` into the ORIGINAL string —
18
+ exactly what the Rust ``tokenizers`` package returns).
19
+ * **UTF-8 BYTE offsets.** ``span_start`` / ``span_end`` are byte offsets into the
20
+ original text encoded as UTF-8, NOT character indices. Byte offsets round-trip
21
+ losslessly through multibyte Italian accents (à/è/ù) for the #2 span-citation
22
+ layer: ``text.encode("utf-8")[span_start:span_end].decode("utf-8")`` reproduces
23
+ the chunk content exactly.
24
+ * **Sentence-aware.** Window edges snap to the nearest sentence boundary within a
25
+ ``±boundary_slack_tokens`` slack, so a chunk rarely cuts mid-sentence. The
26
+ splitter is a punkt-lite regex (no spaCy / nltk — those are host-pressure wheel
27
+ bloat; at ~15% overlap an imperfect boundary heals across the overlap).
28
+ * **Per-chunk content hash.** ``content_hash`` = sha256 of the chunk's byte span,
29
+ so a re-index re-embeds only the chunks that actually changed (editing one
30
+ paragraph churns ~1-2 chunks, not the whole doc).
31
+
32
+ Scope: PROSE ONLY. Code is already chunked per-symbol in
33
+ ``core/cli/_index_source.py`` (``_embed_symbols``); a token windower over code
34
+ would split mid-symbol and break the KG anchors. This module is never invoked on
35
+ code.
36
+ """
37
+ from __future__ import annotations
38
+
39
+ import hashlib
40
+ import re
41
+ from dataclasses import dataclass
42
+ from typing import Protocol, Sequence, runtime_checkable
43
+
44
+ __all__ = [
45
+ "Chunk",
46
+ "TokenizerLike",
47
+ "chunk_prose",
48
+ "DEFAULT_TARGET_TOKENS",
49
+ "DEFAULT_OVERLAP_TOKENS",
50
+ ]
51
+
52
+ # Mirror of the F2 EMBEDDING_* knobs: defaults chosen for retrieval precision
53
+ # (recall peaks ~400 tokens per the Chroma/firecrawl ablation), ~15% overlap.
54
+ DEFAULT_TARGET_TOKENS = 400
55
+ DEFAULT_OVERLAP_TOKENS = 64
56
+ DEFAULT_BOUNDARY_SLACK_TOKENS = 32
57
+
58
+
59
+ @dataclass(frozen=True, slots=True)
60
+ class Chunk:
61
+ """One prose chunk.
62
+
63
+ ``span_start`` / ``span_end`` are UTF-8 BYTE offsets into the ORIGINAL text
64
+ (half-open ``[start, end)``). ``content_hash`` is the sha256 hex of the chunk
65
+ byte span — the idempotency key (re-embed only changed chunks).
66
+ """
67
+
68
+ chunk_idx: int
69
+ span_start: int
70
+ span_end: int
71
+ content_hash: str
72
+
73
+
74
+ @runtime_checkable
75
+ class TokenizerLike(Protocol):
76
+ """Minimal surface of the Rust ``tokenizers.Tokenizer`` this chunker needs.
77
+
78
+ The real Granite tokenizer (``tokenizers.Tokenizer.from_file(...)``) satisfies
79
+ this: ``encode(text)`` returns an ``Encoding`` whose ``.offsets`` is a list of
80
+ ``(char_start, char_end)`` tuples — one per token — into the ORIGINAL string.
81
+ A FAKE tokenizer in tests implements the same two attributes, so the chunker
82
+ is exercised with zero model load.
83
+ """
84
+
85
+ def encode(self, text: str) -> "EncodingLike": ...
86
+
87
+
88
+ @runtime_checkable
89
+ class EncodingLike(Protocol):
90
+ ids: Sequence[int]
91
+ # (char_start, char_end) per token, into the ORIGINAL (unencoded) string.
92
+ offsets: Sequence[tuple[int, int]]
93
+
94
+
95
+ # Punkt-lite sentence splitter: a boundary is sentence-final punctuation
96
+ # (. ! ? plus their typographic variants … ; and the IT/EN newline) followed by
97
+ # whitespace. Intentionally simple — overlap heals the misses (an abbreviation
98
+ # like "es." that splits early is recovered in the next window's prefix).
99
+ _SENTENCE_END = re.compile(r"[.!?…;\n]+[\s\"')\]]*")
100
+
101
+
102
+ def _utf8_byte_offsets(text: str) -> list[int]:
103
+ """Map char index -> UTF-8 byte offset (length == len(text) + 1).
104
+
105
+ ``out[i]`` = byte offset where character ``i`` starts; ``out[len(text)]`` =
106
+ total byte length. Computed once per doc so char→byte conversion of every
107
+ token offset is O(1). Multibyte-safe: an accented char advances the byte
108
+ cursor by its UTF-8 width (2 for à/è/ù), so byte spans round-trip losslessly.
109
+ """
110
+ out = [0] * (len(text) + 1)
111
+ byte = 0
112
+ for i, ch in enumerate(text):
113
+ out[i] = byte
114
+ byte += len(ch.encode("utf-8"))
115
+ out[len(text)] = byte
116
+ return out
117
+
118
+
119
+ def _sentence_boundary_chars(text: str) -> list[int]:
120
+ """Character indices that are sentence boundaries (end of a sentence).
121
+
122
+ Returns the char index just AFTER each sentence-final punctuation run (i.e. a
123
+ valid place to start the next chunk). Always includes 0 and len(text) so the
124
+ snap logic has terminal anchors.
125
+ """
126
+ bounds = {0, len(text)}
127
+ for m in _SENTENCE_END.finditer(text):
128
+ bounds.add(m.end())
129
+ return sorted(bounds)
130
+
131
+
132
+ def _snap_to_boundary(
133
+ token_char_pos: int,
134
+ boundaries: Sequence[int],
135
+ *,
136
+ text_char_pos_window: tuple[int, int],
137
+ slack_chars: int,
138
+ ) -> int:
139
+ """Snap a proposed cut (char index) to the nearest sentence boundary in slack.
140
+
141
+ ``token_char_pos`` is the char index the token-window would cut at. If a
142
+ sentence boundary lies within ``±slack_chars`` AND inside the allowed window
143
+ ``text_char_pos_window`` (so we never snap past the doc edge or before the
144
+ chunk start), use the closest one; otherwise keep the token cut (hard split).
145
+ """
146
+ lo, hi = text_char_pos_window
147
+ best = token_char_pos
148
+ best_dist = slack_chars + 1
149
+ for b in boundaries:
150
+ if b < lo or b > hi:
151
+ continue
152
+ dist = abs(b - token_char_pos)
153
+ if dist <= slack_chars and dist < best_dist:
154
+ best = b
155
+ best_dist = dist
156
+ return best
157
+
158
+
159
+ def chunk_prose(
160
+ text: str,
161
+ tokenizer: TokenizerLike,
162
+ *,
163
+ target_tokens: int = DEFAULT_TARGET_TOKENS,
164
+ overlap_tokens: int = DEFAULT_OVERLAP_TOKENS,
165
+ boundary_slack_tokens: int = DEFAULT_BOUNDARY_SLACK_TOKENS,
166
+ ) -> list[Chunk]:
167
+ """Split ``text`` into fixed-size, overlapping, sentence-aware prose chunks.
168
+
169
+ Windowing is in TOKEN space (reusing the injected tokenizer's per-token char
170
+ offsets), so the window size is stable across mixed IT/EN text where char
171
+ windows over/under-fill. Each window edge is snapped to the nearest sentence
172
+ boundary within ``±boundary_slack_tokens`` (converted to a char slack via the
173
+ local token density). Span offsets are emitted as UTF-8 BYTE offsets.
174
+
175
+ Returns ``[]`` for empty/whitespace-only input. A short doc (<= target_tokens)
176
+ yields a single chunk covering the whole byte range.
177
+ """
178
+ if not text or not text.strip():
179
+ return []
180
+ if target_tokens <= 0:
181
+ raise ValueError("target_tokens must be > 0")
182
+ if overlap_tokens < 0 or overlap_tokens >= target_tokens:
183
+ # overlap must leave forward progress; clamp defensively rather than loop.
184
+ overlap_tokens = max(0, min(overlap_tokens, target_tokens - 1))
185
+
186
+ enc = tokenizer.encode(text)
187
+ offsets = list(enc.offsets)
188
+ n_tokens = len(offsets)
189
+ byte_at = _utf8_byte_offsets(text)
190
+ total_bytes = byte_at[len(text)]
191
+
192
+ # Degenerate: tokenizer produced no usable offsets → one chunk, whole doc.
193
+ if n_tokens == 0:
194
+ return [
195
+ Chunk(
196
+ chunk_idx=0,
197
+ span_start=0,
198
+ span_end=total_bytes,
199
+ content_hash=_hash_byte_span(text, 0, total_bytes),
200
+ )
201
+ ]
202
+
203
+ boundaries = _sentence_boundary_chars(text)
204
+ stride = target_tokens - overlap_tokens # > 0 (overlap clamped above)
205
+
206
+ # Mean chars/token for this doc → convert the token-space slack to char slack
207
+ # for the boundary snap (the boundary list is in char space).
208
+ mean_chars_per_token = max(1.0, len(text) / n_tokens)
209
+ slack_chars = int(round(boundary_slack_tokens * mean_chars_per_token))
210
+
211
+ chunks: list[Chunk] = []
212
+ chunk_idx = 0
213
+ tok_start = 0
214
+ while tok_start < n_tokens:
215
+ tok_end = min(tok_start + target_tokens, n_tokens)
216
+
217
+ # Char window for THIS chunk: start at the first token's char-start, end
218
+ # at the last covered token's char-end.
219
+ char_start = offsets[tok_start][0]
220
+ char_end = offsets[tok_end - 1][1]
221
+
222
+ is_last = tok_end >= n_tokens
223
+
224
+ # Snap the chunk START to a sentence boundary at/just-before it (only when
225
+ # this is NOT the first chunk — chunk 0 must begin at 0 to cover the head).
226
+ if chunk_idx > 0:
227
+ char_start = _snap_to_boundary(
228
+ char_start,
229
+ boundaries,
230
+ text_char_pos_window=(0, char_end),
231
+ slack_chars=slack_chars,
232
+ )
233
+
234
+ # Snap the chunk END to a sentence boundary near it (never on the last
235
+ # chunk — the tail must reach len(text) so no bytes are dropped).
236
+ if not is_last:
237
+ char_end = _snap_to_boundary(
238
+ char_end,
239
+ boundaries,
240
+ text_char_pos_window=(char_start + 1, len(text)),
241
+ slack_chars=slack_chars,
242
+ )
243
+
244
+ span_start = byte_at[char_start]
245
+ span_end = byte_at[char_end] if not is_last else total_bytes
246
+
247
+ if span_end > span_start:
248
+ chunks.append(
249
+ Chunk(
250
+ chunk_idx=chunk_idx,
251
+ span_start=span_start,
252
+ span_end=span_end,
253
+ content_hash=_hash_byte_span(text, span_start, span_end),
254
+ )
255
+ )
256
+ chunk_idx += 1
257
+
258
+ if is_last:
259
+ break
260
+ tok_start += stride
261
+
262
+ return chunks
263
+
264
+
265
+ def _hash_byte_span(text: str, span_start: int, span_end: int) -> str:
266
+ """sha256 of the chunk's UTF-8 byte span (the per-chunk idempotency key)."""
267
+ raw = text.encode("utf-8")[span_start:span_end]
268
+ return hashlib.sha256(raw).hexdigest()
269
+
270
+
271
+ def chunk_text_bytes(text: str, span_start: int, span_end: int) -> bytes:
272
+ """Round-trip helper: the exact bytes a chunk's byte span refers to.
273
+
274
+ ``chunk_text_bytes(text, c.span_start, c.span_end).decode("utf-8")`` is the
275
+ chunk content (used by the #2 citation resolver and by the round-trip test).
276
+ """
277
+ return text.encode("utf-8")[span_start:span_end]
@@ -0,0 +1,213 @@
1
+ # v1.0.0 - 2026-06-05 - Track 2 #1-S5: nightly dream-cycle consolidation (SHADOW/dry-run)
2
+ """Nightly dream-cycle consolidation — SHADOW / dry-run only (Track 2 #1-S5).
3
+
4
+ Plan ``docs/plans/2026-06-04-track2-engine-moat-roadmap-plan.md`` (#1, sub-increment
5
+ S5, lines 343/350). This is the *batch* analogue of the S3 write-time gate. Where S3
6
+ decides ADD / NOOP / SUPERSEDE_CANDIDATE for ONE just-inserted learning, the dream
7
+ cycle scans the WHOLE live learnings store and, for each near-match pair in the
8
+ supersede band, writes a pending SUPERSEDE_CANDIDATE proposal into the SAME approval
9
+ gate the brain cycle drains (``brain_memory_operations``, mig 129).
10
+
11
+ DRY-RUN, NON-NEGOTIABLE. This module is SHADOW only — it ``propose``s, it NEVER
12
+ ``apply``s:
13
+ * it NEVER calls :func:`temporal_write.apply_supersede`;
14
+ * it NEVER sets ``invalid_at`` / ``superseded_by`` on any row;
15
+ * it NEVER deletes a learning (no NOOP-style hard-remove like the write path does).
16
+ The verdict surfaces ONLY as a pending proposal for the human/Triage gate. Diffing
17
+ those proposals against the gold set (and only then enabling an auto-apply
18
+ high-confidence tier) is a deliberate, eval-gated, OFF-host follow-up — see plan
19
+ lines 341/343.
20
+
21
+ Reuses S3 verbatim (does NOT modify ``temporal_write`` / ``learnings``):
22
+ * :func:`temporal_write.decide_write_action` + the pinned 0.80 / 0.97 bands;
23
+ * :func:`temporal_write.propose_supersede_candidate` (the ``INSERT OR IGNORE`` on a
24
+ stable BLAKE2b ``operation_id`` is what makes a re-run idempotent — no duplicate
25
+ proposals);
26
+ * default vector source = :func:`temporal_write.fetch_learning_vector` +
27
+ :func:`temporal_write.fetch_live_neighbor_vectors`, which read PRE-COMPUTED
28
+ vectors back from the search-index mirror. **NO embedding model is EVER run.**
29
+
30
+ Flag gate: the SAME ``settings.temporal_memory_enabled`` (alias
31
+ ``MARVIS_TEMPORAL_MEMORY``, default False). When OFF, :func:`run_dream_cycle_shadow`
32
+ is a no-op that returns an empty report and scans nothing.
33
+
34
+ Host-safety + testability: the neighbour/vector source is INJECTABLE via the
35
+ ``neighbor_provider`` callable. Tests pass FAKE vectors of known cosine through it,
36
+ so the unit suite needs neither sqlite-vec nor a model. The default provider only
37
+ reads mirrored bytes — still model-free.
38
+
39
+ What this module deliberately does NOT do: it does NOT build or run a real nightly
40
+ scheduler (cron/launchd), and it does NOT run a real cycle over the prod store.
41
+ Wiring this STEP to the nightly schedule and flipping the (default-off)
42
+ warehouse-consolidation pass on are separate, eval-gated, off-host steps. This is the
43
+ pure batch step + its dry-run guarantee, unit-testable in isolation.
44
+ """
45
+ from __future__ import annotations
46
+
47
+ from collections.abc import Awaitable, Callable
48
+ from dataclasses import dataclass
49
+
50
+ import aiosqlite
51
+
52
+ from core.api.config import settings
53
+ from core.api.services import temporal_write as tw
54
+
55
+ # A neighbour provider resolves, for a given live learning id, the pair
56
+ # ``(its_vector, [(neighbor_id, neighbor_vector), ...])`` that the PURE band decision
57
+ # consumes. ``None`` for the vector means "no mirrored embedding yet" → skip that row
58
+ # (mirrors the S3 write-path fallback: stay ADD, catch it on a later run). Injectable
59
+ # so tests feed FAKE vectors and the default reads mirrored bytes — neither runs a model.
60
+ NeighborProvider = Callable[
61
+ [aiosqlite.Connection, str, str],
62
+ Awaitable[tuple[list[float] | None, list[tuple[str, list[float]]]]],
63
+ ]
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class DreamCycleReport:
68
+ """Outcome of one SHADOW dream-cycle pass.
69
+
70
+ ``scanned`` — live learnings examined (``invalid_at IS NULL``).
71
+ ``proposed`` — DISTINCT supersede-candidate pairs proposed this pass (the pair is
72
+ canonicalised by id, so the reverse-direction scan of the same pair
73
+ does NOT double-count). On a fresh store this equals the rows added
74
+ to the gate; on a re-run the gate's ``INSERT OR IGNORE`` on a stable
75
+ ``operation_id`` keeps it duplicate-free, so re-running adds zero
76
+ gate rows even though it re-proposes (``proposed`` may be > 0 again).
77
+ ``skipped`` — scanned learnings that produced NO new proposal: no mirrored vector
78
+ yet, no neighbours, a non-band verdict (ADD / NOOP), or the closest
79
+ neighbour forms a pair already proposed earlier in THIS pass.
80
+
81
+ Invariant: ``scanned == proposed + skipped``.
82
+ """
83
+
84
+ scanned: int
85
+ proposed: int
86
+ skipped: int
87
+
88
+
89
+ async def _default_neighbor_provider(
90
+ db: aiosqlite.Connection,
91
+ workspace_id: str,
92
+ learning_id: str,
93
+ ) -> tuple[list[float] | None, list[tuple[str, list[float]]]]:
94
+ """Default vector source — reads PRE-COMPUTED vectors back. NEVER runs a model.
95
+
96
+ Mirrors the S3 write path exactly: pull the learning's own mirrored vector, then
97
+ its top-k LIVE (``invalid_at IS NULL``) neighbours via sqlite-vec kNN. Returns
98
+ ``(None, [])`` when the mirror isn't present yet so the caller skips the row.
99
+ """
100
+ new_vec = await tw.fetch_learning_vector(db, learning_id)
101
+ if new_vec is None:
102
+ return None, []
103
+ neighbors = await tw.fetch_live_neighbor_vectors(
104
+ db, workspace_id, new_vec, exclude_learning_id=learning_id
105
+ )
106
+ return new_vec, neighbors
107
+
108
+
109
+ async def _live_learning_ids(
110
+ db: aiosqlite.Connection, workspace_id: str
111
+ ) -> list[tuple[str, str | None]]:
112
+ """All LIVE learnings (``invalid_at IS NULL``) for the workspace: (id, project).
113
+
114
+ Workspace-scoped with the same ``COALESCE(workspace_id, 'ws_default')`` default as
115
+ the S3 neighbour fetch, so a row and its neighbours live in one scope. Stable order
116
+ so a re-run walks the store identically.
117
+ """
118
+ cur = await db.execute(
119
+ """
120
+ SELECT id, project
121
+ FROM learnings
122
+ WHERE invalid_at IS NULL
123
+ AND COALESCE(workspace_id, 'ws_default') = ?
124
+ ORDER BY id
125
+ """,
126
+ [workspace_id],
127
+ )
128
+ rows = await cur.fetchall()
129
+ return [(row["id"], row["project"]) for row in rows]
130
+
131
+
132
+ async def run_dream_cycle_shadow(
133
+ db: aiosqlite.Connection,
134
+ workspace_id: str,
135
+ *,
136
+ neighbor_provider: NeighborProvider | None = None,
137
+ ) -> DreamCycleReport:
138
+ """Scan the full LIVE learnings store and PROPOSE supersede candidates. DRY-RUN.
139
+
140
+ For each live learning, resolve ``(its_vector, live_neighbours)`` via the injected
141
+ ``neighbor_provider`` (default = mirrored-vector reader, no model), run the PURE
142
+ two-band cosine :func:`temporal_write.decide_write_action`, and on a
143
+ ``SUPERSEDE_CANDIDATE`` verdict write ONE pending proposal into the existing
144
+ approval gate via :func:`temporal_write.propose_supersede_candidate`.
145
+
146
+ SHADOW guarantee: this only ever PROPOSES. It NEVER calls ``apply_supersede``,
147
+ NEVER stamps ``invalid_at`` / ``superseded_by``, NEVER deletes a row — not even on
148
+ a NOOP verdict (the write path retires a brand-new duplicate; a batch pass over the
149
+ persisted store must not, so NOOP here is a skip).
150
+
151
+ Idempotency: the (old, new) pair is canonicalised by sorted id BEFORE proposing, so
152
+ scanning A→B and later B→A target the SAME proposal. Combined with
153
+ ``propose_supersede_candidate``'s stable ``operation_id`` + ``INSERT OR IGNORE``, a
154
+ re-run adds zero duplicate rows to the gate.
155
+
156
+ Flag OFF (``settings.temporal_memory_enabled`` False): no-op — returns an empty
157
+ report and scans nothing.
158
+ """
159
+ if not settings.temporal_memory_enabled:
160
+ return DreamCycleReport(scanned=0, proposed=0, skipped=0)
161
+
162
+ provider = neighbor_provider or _default_neighbor_provider
163
+
164
+ scanned = 0
165
+ proposed = 0
166
+ skipped = 0
167
+ seen_pairs: set[tuple[str, str]] = set()
168
+
169
+ for learning_id, project in await _live_learning_ids(db, workspace_id):
170
+ scanned += 1
171
+
172
+ new_vec, neighbors = await provider(db, workspace_id, learning_id)
173
+ if new_vec is None or not neighbors:
174
+ skipped += 1
175
+ continue
176
+
177
+ decision = tw.decide_write_action(new_vec, neighbors)
178
+ if (
179
+ decision.action is not tw.WriteAction.SUPERSEDE_CANDIDATE
180
+ or decision.neighbor_id is None
181
+ ):
182
+ # ADD (distinct) / NOOP (near-dup) verdicts produce no proposal in shadow.
183
+ skipped += 1
184
+ continue
185
+
186
+ # Canonicalise the pair by id so A→B and B→A collapse to ONE proposal. The
187
+ # in-run ``seen_pairs`` guard makes ``proposed`` count DISTINCT pairs this pass
188
+ # (the reverse-direction scan is a skip, not a second proposal); the persisted
189
+ # gate is *also* dedup'd by propose_supersede_candidate's stable operation_id +
190
+ # INSERT OR IGNORE, so a re-run across passes adds nothing either.
191
+ pair = tuple(sorted((learning_id, decision.neighbor_id)))
192
+ if pair in seen_pairs:
193
+ skipped += 1
194
+ continue
195
+ seen_pairs.add(pair)
196
+
197
+ a, b = pair
198
+ score = decision.score if decision.score is not None else 0.0
199
+ await tw.propose_supersede_candidate(
200
+ db,
201
+ old_id=a,
202
+ new_id=b,
203
+ score=score,
204
+ summary=(
205
+ f"Dream-cycle near-match between learnings '{a}' and '{b}' "
206
+ f"(cosine={score:.4f}) — confirm supersede or keep both."
207
+ ),
208
+ project=project,
209
+ )
210
+ proposed += 1
211
+
212
+ await db.commit()
213
+ return DreamCycleReport(scanned=scanned, proposed=proposed, skipped=skipped)