marvisx-cli 0.3.8b1__tar.gz → 0.3.8b2__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 (643) hide show
  1. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/PKG-INFO +1 -1
  2. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/config.py +7 -0
  3. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/db.py +7 -0
  4. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/main.py +14 -0
  5. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/server.py +42 -1
  6. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/graph.py +37 -14
  7. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/learnings.py +3 -3
  8. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/inbox.py +29 -1
  9. marvisx_cli-0.3.8b2/core/api/services/inbox_digest_deep_research.py +153 -0
  10. marvisx_cli-0.3.8b2/core/api/tests/test_graph_freshness.py +126 -0
  11. marvisx_cli-0.3.8b2/core/api/tests/test_learnings_create_pre148.py +95 -0
  12. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/graph.py +137 -1
  13. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/learnings.py +32 -20
  14. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/projects.py +21 -1
  15. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_doctor.py +49 -0
  16. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/validation.py +2 -2
  17. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/PKG-INFO +1 -1
  18. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/SOURCES.txt +2 -0
  19. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/pyproject.toml +1 -1
  20. marvisx_cli-0.3.8b1/core/api/services/inbox_digest_deep_research.py +0 -80
  21. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/LICENSE +0 -0
  22. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/MANIFEST.in +0 -0
  23. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/README.md +0 -0
  24. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/__init__.py +0 -0
  25. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/agents/__init__.py +0 -0
  26. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/agents/session_health.py +0 -0
  27. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/agents/session_manager.py +0 -0
  28. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/bin/marvisx-state-hook.py +0 -0
  29. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/dependencies/__init__.py +0 -0
  30. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/dependencies/tenant.py +0 -0
  31. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/__init__.py +0 -0
  32. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/_adapter.py +0 -0
  33. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/__init__.py +0 -0
  34. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/brain.py +0 -0
  35. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/handoffs.py +0 -0
  36. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/ingest.py +0 -0
  37. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/projects.py +0 -0
  38. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/pull_requests.py +0 -0
  39. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/safety.py +0 -0
  40. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/search.py +0 -0
  41. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/tasks.py +0 -0
  42. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/workflow_playbooks/brainstorm.md +0 -0
  43. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/workflow_playbooks/compound.md +0 -0
  44. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/workflow_playbooks/plan.md +0 -0
  45. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/mcp/tools/workflows.py +0 -0
  46. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/middleware/__init__.py +0 -0
  47. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/middleware/tool_call_audit.py +0 -0
  48. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/__init__.py +0 -0
  49. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/auth.py +0 -0
  50. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/brain.py +0 -0
  51. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/common.py +0 -0
  52. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/costs.py +0 -0
  53. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/graph.py +0 -0
  54. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/graph_cosmo.py +0 -0
  55. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/graph_pr_impact.py +0 -0
  56. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/graph_ux.py +0 -0
  57. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/inbox.py +0 -0
  58. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/ingest_keys.py +0 -0
  59. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/kg.py +0 -0
  60. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/llm_config.py +0 -0
  61. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/monitoring.py +0 -0
  62. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/projects.py +0 -0
  63. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/search.py +0 -0
  64. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/sessions.py +0 -0
  65. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/tasks.py +0 -0
  66. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/teams.py +0 -0
  67. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/models/users.py +0 -0
  68. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/observability/__init__.py +0 -0
  69. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/observability/tracing.py +0 -0
  70. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/paths.py +0 -0
  71. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/rate_limit.py +0 -0
  72. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/rbac.py +0 -0
  73. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/__init__.py +0 -0
  74. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/_adapter.py +0 -0
  75. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/admin_pr_impact.py +0 -0
  76. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/admin_settings.py +0 -0
  77. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/agent.py +0 -0
  78. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/agent_tokens.py +0 -0
  79. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/app_settings.py +0 -0
  80. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/audit.py +0 -0
  81. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/auth.py +0 -0
  82. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/bench.py +0 -0
  83. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/brain.py +0 -0
  84. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/brain_directions.py +0 -0
  85. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/ci_checks.py +0 -0
  86. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/comments.py +0 -0
  87. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/costs.py +0 -0
  88. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/docs_coverage.py +0 -0
  89. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/docs_governance.py +0 -0
  90. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/documents.py +0 -0
  91. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/files.py +0 -0
  92. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/finder.py +0 -0
  93. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/graph.py +0 -0
  94. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/handoffs.py +0 -0
  95. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/ingest_api_keys.py +0 -0
  96. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/ingest_triage.py +0 -0
  97. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/judge.py +0 -0
  98. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/kg.py +0 -0
  99. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/learnings.py +0 -0
  100. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/llm_config.py +0 -0
  101. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/monitoring.py +0 -0
  102. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/notifications.py +0 -0
  103. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/pr_impact.py +0 -0
  104. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/projects.py +0 -0
  105. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/pull_requests.py +0 -0
  106. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/push.py +0 -0
  107. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/raci.py +0 -0
  108. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/search.py +0 -0
  109. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/sessions.py +0 -0
  110. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/settings.py +0 -0
  111. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/share_repo.py +0 -0
  112. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/status_updates.py +0 -0
  113. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/tags.py +0 -0
  114. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/tasks.py +0 -0
  115. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/teams.py +0 -0
  116. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/terminal.py +0 -0
  117. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/users.py +0 -0
  118. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/routers/webhooks.py +0 -0
  119. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/runtime_settings.py +0 -0
  120. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/security.py +0 -0
  121. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/__init__.py +0 -0
  122. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/_fts.py +0 -0
  123. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/audit.py +0 -0
  124. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/auto_approval.py +0 -0
  125. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/__init__.py +0 -0
  126. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/baseline.py +0 -0
  127. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/capabilities.py +0 -0
  128. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/cascade_rollup.py +0 -0
  129. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/compound_bridge.py +0 -0
  130. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/cycle.py +0 -0
  131. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/cycle_snapshot.py +0 -0
  132. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/digest_collector.py +0 -0
  133. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/direction.py +0 -0
  134. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/drift.py +0 -0
  135. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/drift_router.py +0 -0
  136. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/edge_metrics.py +0 -0
  137. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/events_reader.py +0 -0
  138. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/findings.py +0 -0
  139. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/findings_reader.py +0 -0
  140. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/jobs.py +0 -0
  141. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/journal.py +0 -0
  142. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/knowledge_forms.py +0 -0
  143. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/__init__.py +0 -0
  144. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/_runner.py +0 -0
  145. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/base.py +0 -0
  146. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/cache.py +0 -0
  147. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/constants.py +0 -0
  148. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/direction_alignment.py +0 -0
  149. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/factory.py +0 -0
  150. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/finding_reasoning.py +0 -0
  151. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/finding_summary.py +0 -0
  152. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/grounding.py +0 -0
  153. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/journal_polish.py +0 -0
  154. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/local_gateway.py +0 -0
  155. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/parsers.py +0 -0
  156. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/llm/router_glue.py +0 -0
  157. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/memory_ops.py +0 -0
  158. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/models.py +0 -0
  159. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/owner_hint.py +0 -0
  160. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/recap.py +0 -0
  161. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/__init__.py +0 -0
  162. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/_signals.py +0 -0
  163. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr1_activity_without_status.py +0 -0
  164. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr2_decision_without_adr.py +0 -0
  165. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr3_stale_open_loop.py +0 -0
  166. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr4_docs_governance_drift.py +0 -0
  167. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr5_playbook_changed.py +0 -0
  168. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr6_external_update_unpropagated.py +0 -0
  169. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr7_claimed_decision_gap.py +0 -0
  170. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/rules/dr8_direction_misalignment.py +0 -0
  171. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/runs_reader.py +0 -0
  172. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/scope.py +0 -0
  173. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/__init__.py +0 -0
  174. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/base.py +0 -0
  175. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/git_kg.py +0 -0
  176. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/handoffs.py +0 -0
  177. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/ingestor.py +0 -0
  178. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/learnings.py +0 -0
  179. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/sources/pir_tasks.py +0 -0
  180. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/warehouse_consolidate.py +0 -0
  181. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/watermarks.py +0 -0
  182. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/brain/ws_emitter.py +0 -0
  183. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/cc_tasks_reader.py +0 -0
  184. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/chunking.py +0 -0
  185. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ci_service.py +0 -0
  186. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/claude_metrics.py +0 -0
  187. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/codex_metrics.py +0 -0
  188. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/conversation_reader.py +0 -0
  189. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/cost_service.py +0 -0
  190. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/crypto.py +0 -0
  191. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/__init__.py +0 -0
  192. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/confidence.py +0 -0
  193. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/config.py +0 -0
  194. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/enrichment.py +0 -0
  195. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/frontmatter_validator.py +0 -0
  196. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/hard_gates.py +0 -0
  197. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/docs_governance/triage_orchestrator.py +0 -0
  198. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/dream_cycle.py +0 -0
  199. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/embedding_backends/__init__.py +0 -0
  200. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/embedding_internal.py +0 -0
  201. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/embedding_service.py +0 -0
  202. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/event_dispatcher.py +0 -0
  203. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/events.py +0 -0
  204. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/git_ops.py +0 -0
  205. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/graph_cosmo_service.py +0 -0
  206. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/graph_ranker.py +0 -0
  207. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/graph_service.py +0 -0
  208. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/grounding/__init__.py +0 -0
  209. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/grounding/citations.py +0 -0
  210. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/grounding/verifier.py +0 -0
  211. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox.py +0 -0
  212. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_digest.py +0 -0
  213. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_digest_jobs.py +0 -0
  214. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_gmail_sync.py +0 -0
  215. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_llm_classifier.py +0 -0
  216. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_source_identity.py +0 -0
  217. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_sources.py +0 -0
  218. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_taxonomy.py +0 -0
  219. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_tldr.py +0 -0
  220. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/inbox_triage.py +0 -0
  221. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/__init__.py +0 -0
  222. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/api_key_auth.py +0 -0
  223. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/auto_approve.py +0 -0
  224. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/classifier.py +0 -0
  225. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/confidence.py +0 -0
  226. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/dispatch.py +0 -0
  227. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/embedding_router.py +0 -0
  228. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/events.py +0 -0
  229. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/ignore_patterns.py +0 -0
  230. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/image_probe.py +0 -0
  231. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/ingress.py +0 -0
  232. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/insert_saga.py +0 -0
  233. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/__init__.py +0 -0
  234. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/anthropic_haiku.py +0 -0
  235. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/base.py +0 -0
  236. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/byok_provider.py +0 -0
  237. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/classification_context.py +0 -0
  238. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/config_store.py +0 -0
  239. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/factory.py +0 -0
  240. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/kg_enricher.py +0 -0
  241. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/local_gateway.py +0 -0
  242. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/local_vllm.py +0 -0
  243. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/llm/openai_nano.py +0 -0
  244. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/lock_advisory.py +0 -0
  245. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parser_router.py +0 -0
  246. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/__init__.py +0 -0
  247. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/docling_parser.py +0 -0
  248. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/docparse_gateway.py +0 -0
  249. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/docx_parser.py +0 -0
  250. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/folder_unpacker.py +0 -0
  251. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/gateway_aux.py +0 -0
  252. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/image_parser.py +0 -0
  253. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/internal_markdown.py +0 -0
  254. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/ocr_gateway.py +0 -0
  255. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/ocr_pdf_parser.py +0 -0
  256. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/pdf_types.py +0 -0
  257. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/transcript_parser.py +0 -0
  258. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/vision_gateway.py +0 -0
  259. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/xlsx_parser.py +0 -0
  260. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/parsers/zip_unpacker.py +0 -0
  261. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/preflight.py +0 -0
  262. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/routing_policy.py +0 -0
  263. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/serializers/__init__.py +0 -0
  264. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/serializers/xlsx_to_markdown.py +0 -0
  265. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/skip_log.py +0 -0
  266. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/ingest/watcher.py +0 -0
  267. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/__init__.py +0 -0
  268. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/audit.py +0 -0
  269. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/communities.py +0 -0
  270. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/community_summary.py +0 -0
  271. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/graph_lane.py +0 -0
  272. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/hybrid_search.py +0 -0
  273. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/lens.py +0 -0
  274. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/pr_impact.py +0 -0
  275. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/queries.py +0 -0
  276. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/ranking.py +0 -0
  277. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg/rrf.py +0 -0
  278. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/kg_watcher_control.py +0 -0
  279. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/local_llm/__init__.py +0 -0
  280. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/local_llm/async_client.py +0 -0
  281. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/local_llm/client.py +0 -0
  282. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/local_llm/url_validator.py +0 -0
  283. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/metrics_collector.py +0 -0
  284. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/metrics_providers.py +0 -0
  285. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/model_registry.py +0 -0
  286. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/model_router.py +0 -0
  287. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/n8n_client.py +0 -0
  288. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/newsletter_llm_gateway.py +0 -0
  289. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/notification_service.py +0 -0
  290. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/openai_responses.py +0 -0
  291. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/opencode_metrics.py +0 -0
  292. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/opencode_sessions.py +0 -0
  293. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pii_redactor.py +0 -0
  294. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/__init__.py +0 -0
  295. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/differ.py +0 -0
  296. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/dispatcher.py +0 -0
  297. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/gc.py +0 -0
  298. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/languages.py +0 -0
  299. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/parser.py +0 -0
  300. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_impact_pipeline/writer.py +0 -0
  301. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/pr_service.py +0 -0
  302. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/project_paths.py +0 -0
  303. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/project_status_updates.py +0 -0
  304. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/providers.py +0 -0
  305. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/push_service.py +0 -0
  306. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/reminder_service.py +0 -0
  307. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/runas.py +0 -0
  308. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/salience_service.py +0 -0
  309. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/security_collector.py +0 -0
  310. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/session_catalog.py +0 -0
  311. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/session_metrics_service.py +0 -0
  312. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/session_ops.py +0 -0
  313. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/session_state.py +0 -0
  314. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/share_links.py +0 -0
  315. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/task_transitions.py +0 -0
  316. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/temporal_tiebreak.py +0 -0
  317. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/temporal_write.py +0 -0
  318. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/terminal_metrics.py +0 -0
  319. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/terminal_metrics_dump.py +0 -0
  320. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/tmux.py +0 -0
  321. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/webhook_service.py +0 -0
  322. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/services/workspace_sync.py +0 -0
  323. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/templates/__init__.py +0 -0
  324. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/templates/markdown_share.py +0 -0
  325. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/terminal.py +0 -0
  326. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/__init__.py +0 -0
  327. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_agent_facing_auth_dependencies.py +0 -0
  328. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_audit_permissions.py +0 -0
  329. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_backfill_session_conversations.py +0 -0
  330. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_backfill_working_seconds_msg.py +0 -0
  331. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_claude_metrics.py +0 -0
  332. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_codex_metrics.py +0 -0
  333. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_config_env_aliases.py +0 -0
  334. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_finder_paths.py +0 -0
  335. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_git_ops_merge.py +0 -0
  336. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_learnings_check_search.py +0 -0
  337. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_metrics_providers.py +0 -0
  338. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_migration_087.py +0 -0
  339. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_migration_088.py +0 -0
  340. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_migration_089.py +0 -0
  341. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_openai_responses.py +0 -0
  342. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_opencode_metrics.py +0 -0
  343. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_opencode_sessions.py +0 -0
  344. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_pr_workflow_e2e.py +0 -0
  345. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_projects_handoffs.py +0 -0
  346. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_providers.py +0 -0
  347. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_require_scope_empty_deny.py +0 -0
  348. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_safety_bridge.py +0 -0
  349. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_session_catalog.py +0 -0
  350. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_session_conversations.py +0 -0
  351. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_session_metrics_service.py +0 -0
  352. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_session_resume_paths.py +0 -0
  353. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_session_theme_mode_migration.py +0 -0
  354. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_sessions_rbac.py +0 -0
  355. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_share_edit.py +0 -0
  356. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_share_repo.py +0 -0
  357. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_terminal_session_manager.py +0 -0
  358. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_terminal_upload.py +0 -0
  359. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_tmux.py +0 -0
  360. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_workspace_sync.py +0 -0
  361. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/tests/test_ws_ticket_in_memory.py +0 -0
  362. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/__init__.py +0 -0
  363. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/_context.py +0 -0
  364. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/_errors.py +0 -0
  365. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/_roles.py +0 -0
  366. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/audit.py +0 -0
  367. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/brain.py +0 -0
  368. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/costs.py +0 -0
  369. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/handoffs.py +0 -0
  370. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/ingest_triage.py +0 -0
  371. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/pull_requests.py +0 -0
  372. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/search.py +0 -0
  373. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/use_cases/tasks.py +0 -0
  374. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/api/visibility.py +0 -0
  375. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/README.md +0 -0
  376. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/__init__.py +0 -0
  377. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_brain_opportunistic.py +0 -0
  378. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_brain_schedule.py +0 -0
  379. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_index_source.py +0 -0
  380. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_runtime_ctx.py +0 -0
  381. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_transmute.py +0 -0
  382. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/_update_check.py +0 -0
  383. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/guides/__init__.py +0 -0
  384. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/guides/marvis-way.md +0 -0
  385. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_account.py +0 -0
  386. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_brain.py +0 -0
  387. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_feedback.py +0 -0
  388. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_governance.py +0 -0
  389. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_guide.py +0 -0
  390. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_hooks.py +0 -0
  391. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_init.py +0 -0
  392. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_mcp.py +0 -0
  393. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_runtime.py +0 -0
  394. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/cli/marvis_telemetry.py +0 -0
  395. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/platform/__init__.py +0 -0
  396. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/_drift_check.py +0 -0
  397. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/_frontmatter.py +0 -0
  398. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/_graph_writer.py +0 -0
  399. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/ast_parser.py +0 -0
  400. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/__init__.py +0 -0
  401. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/_config.sh +0 -0
  402. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/block-dangerous-bash.sh +0 -0
  403. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/block-db-direct-write.sh +0 -0
  404. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/block-push-no-task.sh +0 -0
  405. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/block-staging-to-prod.sh +0 -0
  406. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/block-subtree-push.sh +0 -0
  407. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/config.json +0 -0
  408. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/enforce-no-merge-main.sh +0 -0
  409. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/enforce-worktree.sh +0 -0
  410. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/quality-gate.sh +0 -0
  411. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/safety_bridge.py +0 -0
  412. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/install_hooks/secret-scan.sh +0 -0
  413. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/migrate_spike_node_ids.py +0 -0
  414. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_artifacts.py +0 -0
  415. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_cross_project.py +0 -0
  416. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_inbox_nodes.py +0 -0
  417. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_pr_impact.py +0 -0
  418. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_project_nodes.py +0 -0
  419. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/populate_touch_counter.py +0 -0
  420. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/reparse_failed.py +0 -0
  421. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/scripts/safety_bridge.py +0 -0
  422. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/__init__.py +0 -0
  423. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/client.py +0 -0
  424. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/entitlements.py +0 -0
  425. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/rollup.py +0 -0
  426. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/schema.py +0 -0
  427. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/telemetry/sender.py +0 -0
  428. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/__init__.py +0 -0
  429. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/byok_vault.py +0 -0
  430. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/defaults.py +0 -0
  431. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/state.py +0 -0
  432. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/core/wizard/steps.py +0 -0
  433. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/dependency_links.txt +0 -0
  434. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/entry_points.txt +0 -0
  435. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/requires.txt +0 -0
  436. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/marvisx_cli.egg-info/top_level.txt +0 -0
  437. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/001_initial.sql +0 -0
  438. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/002_tasks.sql +0 -0
  439. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/003_session_management.sql +0 -0
  440. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/004_projects_comments.sql +0 -0
  441. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/005_session_intelligence.sql +0 -0
  442. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/006_settings.sql +0 -0
  443. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/007_task_scoring.sql +0 -0
  444. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/008_cost_tracking.sql +0 -0
  445. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/009_session_card_metrics.sql +0 -0
  446. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/010_monitoring.sql +0 -0
  447. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/012_agent_api.sql +0 -0
  448. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/013_session_complete.sql +0 -0
  449. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/015_pull_requests.sql +0 -0
  450. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/015_pull_requests_down.sql +0 -0
  451. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/016_users_raci.sql +0 -0
  452. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/017_task_cost_entries.sql +0 -0
  453. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/018_agents.sql +0 -0
  454. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/018_agents_down.sql +0 -0
  455. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/019_review_feedback.sql +0 -0
  456. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/020_pr_commit_sha.sql +0 -0
  457. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/021_webhook_events.sql +0 -0
  458. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/022_devx_agent_managed.sql +0 -0
  459. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/022_devx_agent_managed_down.sql +0 -0
  460. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/023_devx_p1_gate.sql +0 -0
  461. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/023_devx_p1_gate_down.sql +0 -0
  462. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/024_chat_messages.sql +0 -0
  463. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/024_pr_conversation_id.sql +0 -0
  464. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/024_task_indexes.sql +0 -0
  465. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/024_task_indexes_down.sql +0 -0
  466. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/025_audit_log.sql +0 -0
  467. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/026_agent_tokens.sql +0 -0
  468. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/027_teams_auth_phase_b.sql +0 -0
  469. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/028_learnings.sql +0 -0
  470. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/029_team_roles.sql +0 -0
  471. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/030_finder_pins.sql +0 -0
  472. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/031_pr_deploy_status.sql +0 -0
  473. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/032_task_reminders.sql +0 -0
  474. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/033_events_retry_count.sql +0 -0
  475. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/033_session_owner.sql +0 -0
  476. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/034_notifications.sql +0 -0
  477. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/035_shared_links.sql +0 -0
  478. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/036_session_index_upgrade.sql +0 -0
  479. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/037_pr_approval.sql +0 -0
  480. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/038_pr_submitted_by.sql +0 -0
  481. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/039_push_subscriptions.sql +0 -0
  482. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/040_semantic_search.sql +0 -0
  483. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/041_workspaces.sql +0 -0
  484. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/042_oidc_providers.sql +0 -0
  485. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/043_ci_checks.sql +0 -0
  486. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/044_agent_metrics.sql +0 -0
  487. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/045_documents_doc_type.sql +0 -0
  488. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/046_salience.sql +0 -0
  489. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/047_seed_missing_agents.sql +0 -0
  490. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/048_fix_agent_paths_roles.sql +0 -0
  491. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/049_agent_role_and_learnings_schema.sql +0 -0
  492. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/050_session_provider.sql +0 -0
  493. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/051_session_launch_profile.sql +0 -0
  494. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/052_session_theme_mode.sql +0 -0
  495. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/052_task_kind.sql +0 -0
  496. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/053_inbox_items.sql +0 -0
  497. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/054_inbox_triage_contract.sql +0 -0
  498. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/055_inbox_topic_treatment.sql +0 -0
  499. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/056_inbox_treatment_read_save.sql +0 -0
  500. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/057_session_theme_mode_backfill.sql +0 -0
  501. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/058_inbox_item_status_lifecycle.sql +0 -0
  502. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/059_inbox_tldr_and_source_scores.sql +0 -0
  503. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/060_newsletter.sql +0 -0
  504. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/061_inbox_redesign.sql +0 -0
  505. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/062_fix_inbox_sources_backfill.sql +0 -0
  506. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/063_task_completion_mode.sql +0 -0
  507. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/064_judge_mode_setting.sql +0 -0
  508. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/065_knowledge_graph_spike.sql +0 -0
  509. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/066_digest_ranking_inputs.sql +0 -0
  510. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/066_kg_artifact_nodes.sql +0 -0
  511. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/067_inbox_digest_selections.sql +0 -0
  512. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/067_kg_temporal.sql +0 -0
  513. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/068_inbox_digest_app_settings.sql +0 -0
  514. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/068_kg_touch_counter.sql +0 -0
  515. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/069_kg_doc_types.sql +0 -0
  516. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/070_digest_ranking_inputs_recovery.sql +0 -0
  517. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/071_inbox_digest_selections_recovery.sql +0 -0
  518. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/072_inbox_digest_app_settings_recovery.sql +0 -0
  519. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/073_kg_cross_project.sql +0 -0
  520. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/073_kg_cross_project_down.sql +0 -0
  521. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/074_kg_infra_types.sql +0 -0
  522. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/074_kg_infra_types_down.sql +0 -0
  523. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/075_kg_file_state_recovery.sql +0 -0
  524. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/075_kg_file_state_recovery_down.sql +0 -0
  525. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/076_kg_watcher_state.sql +0 -0
  526. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/076_kg_watcher_state_down.sql +0 -0
  527. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/077_kg_doc_types_extend.sql +0 -0
  528. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/077_kg_doc_types_extend_down.sql +0 -0
  529. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/078_kg_fts5.sql +0 -0
  530. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/078_kg_fts5_down.sql +0 -0
  531. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/079_kg_missing_indexes.sql +0 -0
  532. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/079_kg_missing_indexes_down.sql +0 -0
  533. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/080_kg_fts5_extended.sql +0 -0
  534. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/080_kg_fts5_extended_down.sql +0 -0
  535. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/081_kg_lens_indexes.sql +0 -0
  536. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/081_kg_lens_indexes_down.sql +0 -0
  537. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/082_kg_pins.sql +0 -0
  538. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/082_kg_pins_down.sql +0 -0
  539. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/083_kg_graph_nodes_degree.sql +0 -0
  540. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/083_kg_graph_nodes_degree_down.sql +0 -0
  541. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/084_drop_legacy_scheduler_tables.sql +0 -0
  542. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/084_drop_legacy_scheduler_tables_down.sql +0 -0
  543. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/085_kg_edge_resolves_to.sql +0 -0
  544. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/085_kg_edge_resolves_to_down.sql +0 -0
  545. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/086_project_status_updates_feed.sql +0 -0
  546. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/086_project_status_updates_feed_down.sql +0 -0
  547. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/087_session_metrics_dual.sql +0 -0
  548. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/087_session_metrics_dual_down.sql +0 -0
  549. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/088_rename_context_pct_legacy.sql +0 -0
  550. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/088_rename_context_pct_legacy_down.sql +0 -0
  551. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/089_session_metrics_equivalent_cost.sql +0 -0
  552. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/089_session_metrics_equivalent_cost_down.sql +0 -0
  553. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/090_kg_inbox_node_type.sql +0 -0
  554. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/090_kg_inbox_node_type_down.sql +0 -0
  555. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/091_kg_inbox_node_type_check.sql +0 -0
  556. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/091_kg_inbox_node_type_check_down.sql +0 -0
  557. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/092_sessions_activity_state_ts.sql +0 -0
  558. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/092_sessions_activity_state_ts_down.sql +0 -0
  559. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/093_sessions_activity_state_column.sql +0 -0
  560. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/093_sessions_activity_state_column_down.sql +0 -0
  561. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/094_ingest_pending.sql +0 -0
  562. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/094_ingest_pending_down.sql +0 -0
  563. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/095_kg_intent_first.sql +0 -0
  564. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/095_kg_intent_first_down.sql +0 -0
  565. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/096_kg_xlsx_artifact_prefix.sql +0 -0
  566. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/096_kg_xlsx_artifact_prefix_down.sql +0 -0
  567. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/097_ingest_change_history.sql +0 -0
  568. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/097_ingest_change_history_down.sql +0 -0
  569. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/098_kg_node_type_business.sql +0 -0
  570. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/098_kg_node_type_business_down.sql +0 -0
  571. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/099_kg_edges_restore_weight.sql +0 -0
  572. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/099_kg_edges_restore_weight_down.sql +0 -0
  573. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/100_kg_enriched_at.sql +0 -0
  574. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/100_kg_enriched_at_down.sql +0 -0
  575. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/101_local_llm_shadow_comparisons.sql +0 -0
  576. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/101_local_llm_shadow_comparisons_down.sql +0 -0
  577. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/102_promote_llm_costs.sql +0 -0
  578. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/102_promote_llm_costs_down.sql +0 -0
  579. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/103_ingest_skipped_log.sql +0 -0
  580. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/103_ingest_skipped_log_down.sql +0 -0
  581. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/120_docs_governance.sql +0 -0
  582. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/120_docs_governance_down.sql +0 -0
  583. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/121_notification_event_fk_cleanup.sql +0 -0
  584. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/121_notification_event_fk_cleanup_down.sql +0 -0
  585. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/122_docs_drift_history.sql +0 -0
  586. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/122_docs_drift_history_down.sql +0 -0
  587. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/123_ingest_parser_waiting_status.sql +0 -0
  588. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/123_ingest_parser_waiting_status_down.sql +0 -0
  589. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/124_heypocket_recordings.sql +0 -0
  590. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/124_heypocket_recordings_down.sql +0 -0
  591. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/125_kg_node_type_record.sql +0 -0
  592. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/125_kg_node_type_record_down.sql +0 -0
  593. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/126_ingest_terminal_upload_source_kind.sql +0 -0
  594. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/126_ingest_terminal_upload_source_kind_down.sql +0 -0
  595. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/127_brain_v1_substrate.sql +0 -0
  596. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/127_brain_v1_substrate_down.sql +0 -0
  597. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/128_brain_drift_signals.sql +0 -0
  598. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/128_brain_drift_signals_down.sql +0 -0
  599. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/129_brain_memory_operations.sql +0 -0
  600. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/129_brain_memory_operations_down.sql +0 -0
  601. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/130_brain_findings.sql +0 -0
  602. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/130_brain_findings_down.sql +0 -0
  603. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/132_kg_pr_modifies.sql +0 -0
  604. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/132_kg_pr_modifies_down.sql +0 -0
  605. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/133_brain_v1_2_direction_schema.sql +0 -0
  606. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/133_brain_v1_2_direction_schema_down.sql +0 -0
  607. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/134_brain_journal_narrative_polished.sql +0 -0
  608. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/134_brain_journal_narrative_polished_down.sql +0 -0
  609. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/135_kg_edges_provider.sql +0 -0
  610. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/136_documents_fts.sql +0 -0
  611. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/137_promote_llm_costs.sql +0 -0
  612. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/137_promote_llm_costs_down.sql +0 -0
  613. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/138_ingest_api_keys.sql +0 -0
  614. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/138_ingest_api_keys_down.sql +0 -0
  615. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/139_ingest_pending_ingress.sql +0 -0
  616. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/139_ingest_pending_ingress_down.sql +0 -0
  617. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/140_ingest_idempotency_quota.sql +0 -0
  618. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/140_ingest_idempotency_quota_down.sql +0 -0
  619. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/141_ingest_pending_metadata.sql +0 -0
  620. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/141_ingest_pending_metadata_down.sql +0 -0
  621. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/142_llm_function_config.sql +0 -0
  622. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/142_llm_function_config_down.sql +0 -0
  623. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/143_kg_code_embeddings.sql +0 -0
  624. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/143_kg_code_embeddings_down.sql +0 -0
  625. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/144_notifications_pending_sync_index.sql +0 -0
  626. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/145_audit_log_immutable.sql +0 -0
  627. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/145_audit_log_immutable_down.sql +0 -0
  628. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/146_drop_kg_backup_tables.sql +0 -0
  629. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/146_drop_kg_backup_tables_down.sql +0 -0
  630. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/147_chunks.sql +0 -0
  631. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/147_chunks_down.sql +0 -0
  632. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/148_bitemporal_learnings.sql +0 -0
  633. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/148_bitemporal_learnings_down.sql +0 -0
  634. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/migrations/__init__.py +0 -0
  635. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/context.md +0 -0
  636. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/docs/brainstorms/YYYY-MM-DD-example-brainstorm.md +0 -0
  637. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/docs/plans/YYYY-MM-DD-example-plan.md +0 -0
  638. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/docs/solutions/YYYY-MM-DD-example-solution.md +0 -0
  639. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/input/README.md +0 -0
  640. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/memory/handoff.md +0 -0
  641. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/output/README.md +0 -0
  642. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/projects/_template/project.yaml +0 -0
  643. {marvisx_cli-0.3.8b1 → marvisx_cli-0.3.8b2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marvisx-cli
3
- Version: 0.3.8b1
3
+ Version: 0.3.8b2
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
@@ -453,6 +453,13 @@ class Settings(BaseSettings):
453
453
  graph_lane_weight: float = Field(
454
454
  default=0.12, alias="MARVIS_GRAPH_LANE_WEIGHT"
455
455
  )
456
+ # #13: when a graph read finds its index stale/behind HEAD, surface the
457
+ # reindex as an EXPLICIT next action (command + auto_reindex marker). Default
458
+ # off; even when on, a read NEVER fires the (heavy, repo-re-parsing) KG
459
+ # reindex itself — re-indexing stays an explicit operation.
460
+ graph_autoreindex_on_drift: bool = Field(
461
+ default=False, alias="MARVIS_GRAPH_AUTOREINDEX_ON_DRIFT"
462
+ )
456
463
 
457
464
  # Track 2 #1 — bi-temporal memory READ path (DEFAULT OFF). When False every
458
465
  # learnings read is byte-identical to today (no invalid_at filter, no as_of):
@@ -118,6 +118,13 @@ async def init_pool(size: int = 2) -> None:
118
118
 
119
119
  Pool size=8 supports concurrent deep=true requests (4 parallel KG subqueries × 2 concurrent requests).
120
120
  """
121
+ # Apply any pending schema migrations before opening the pool, so EVERY
122
+ # entry point (CLI, MCP, brain, API) lands on a current schema — not only
123
+ # `marvis init` and the API lifespan. Idempotent and cheap when already
124
+ # current (the API path migrates explicitly first, so this finds nothing).
125
+ # Fail-loud here is a clearer signal than a later "no such column" on the
126
+ # first write against a half-upgraded DB. (#12)
127
+ run_migrations()
121
128
  global _pool, _pool_size, _writer
122
129
  actual_size = 8 # read-only pool: expanded for KG lens 4-subquery parallel pattern (Phase 7.0)
123
130
  _pool = asyncio.Queue(maxsize=actual_size)
@@ -931,6 +931,20 @@ async def _periodic_inbox_digest() -> None:
931
931
  result.get("overflow", 0),
932
932
  result.get("expired", 0),
933
933
  )
934
+ # Invariant guard: every VISIBLE item must be deepened. The 6 UTC
935
+ # precompute is best-effort/one-shot; this sweep catches its failures
936
+ # and items promoted into visible later in the day.
937
+ from core.api.services.inbox_digest_deep_research import (
938
+ sweep_visible_missing_deep_research,
939
+ )
940
+
941
+ sweep = await sweep_visible_missing_deep_research()
942
+ if sweep.get("missing"):
943
+ logger.info(
944
+ "Digest deep-research sweep: deepened %d/%d missing visible items",
945
+ sweep.get("generated", 0),
946
+ sweep.get("missing", 0),
947
+ )
934
948
  except asyncio.CancelledError:
935
949
  break
936
950
  except Exception:
@@ -34,10 +34,51 @@ from core.api.mcp.tools import register_all
34
34
  # `app.state` equivalent for a server with no FastAPI `app`). Tools register on
35
35
  # this at import time so `from core.api.mcp.server import mcp` already carries the
36
36
  # full tool set — the smoke test introspects it without launching stdio.
37
- mcp = FastMCP("marvis")
37
+ _INSTRUCTIONS = (
38
+ "Marvis is a company-brain MCP for cross-project orchestration and institutional memory.\n"
39
+ "Route by task type (prefer these structured tools over re-deriving context from raw files):\n"
40
+ "- Cold-start / 'state of project X': session_brief(slug) — it also suggests the next tool when the project is cross-project.\n"
41
+ "- 'If I pause / close / de-prioritize project X, what blocks?': project_impact(slug) — the project-level blast radius. "
42
+ "(graph_impact on a 'project:artifact:<slug>' node with depends_on does the same.)\n"
43
+ "- 'What breaks if I change function X' (code level): graph_impact / graph_neighbors on a 'py:function:...' node.\n"
44
+ "- 'What do we already know / what bit us before' (decisions and risky actions): check_learnings(q).\n"
45
+ "- Cross-project discovery by meaning: search(q). Body of ONE known project: get_project(slug) — do not layer search on top of get_project.\n"
46
+ )
47
+
48
+ mcp = FastMCP("marvis", instructions=_INSTRUCTIONS)
38
49
 
39
50
  register_all(mcp)
40
51
 
52
+ # mcp-ergonomics (tiering): mark the cold-start core always-loaded so clients with
53
+ # MCP tool-search (e.g. Claude Code — the agent that drives the brain) keep these in
54
+ # context and defer the other ~60 tools on demand. A 70-tool surface is well over the
55
+ # ~20-30 threshold where tool-selection accuracy degrades. Additive: clients without
56
+ # tool-search still see every tool (no regression). Best-effort — a FastMCP registry
57
+ # shape change degrades to a no-op, never a boot failure.
58
+ _CORE_TOOLS = frozenset(
59
+ {
60
+ "session_brief",
61
+ "search",
62
+ "check_learnings",
63
+ "list_tasks",
64
+ "get_task",
65
+ "create_task",
66
+ "update_task",
67
+ "get_project",
68
+ "graph_impact",
69
+ "graph_neighbors",
70
+ "project_impact",
71
+ }
72
+ )
73
+ try:
74
+ for _name, _tool in mcp._tool_manager._tools.items():
75
+ if _name in _CORE_TOOLS:
76
+ _m = dict(_tool.meta or {})
77
+ _m["anthropic/alwaysLoad"] = True
78
+ _tool.meta = _m
79
+ except Exception: # pragma: no cover - FastMCP internal-shape guard
80
+ pass
81
+
41
82
 
42
83
  def main() -> None:
43
84
  """Run the MCP server over stdio (the OSS runtime entrypoint).
@@ -123,10 +123,10 @@ def register(mcp) -> None:
123
123
  rank: NeighborRank = "none",
124
124
  as_of: Annotated[str, Field(pattern=_AS_OF_PATTERN, max_length=32)] | None = None,
125
125
  ) -> dict[str, Any]:
126
- """[Power-user] Surgical 1-hop neighbour query for a KG node (calls/imports/defines/mentions/...) per context completo su un nodo usa get_task/get_project/get_handoff/get_learning(deep=true). Usa questo tool solo quando hai bisogno di ispezionare il vicinato topologico diretto senza il bundle completo.
127
- QUANDO USARLO: refactor impact assessment su una singola function; verificare se un nodo ha caller inattesi; time-travel as_of su commit specifico; rank=suspect_write per bug write-through-read.
128
- QUANDO NON USARLO: NOT per context di un task/handoff/learning -> usa get_*(deep=true). NOT per BFS transitivo -> usa graph_impact.
129
- RESTITUISCE: list of {node_id, relation, direction, rank_score?} cap 200."""
126
+ """1-hop: chi tocca / dipende direttamente da un nodo. Funziona su codice ('py:function:...') E su progetti ('project:artifact:<slug>').
127
+ ORCHESTRAZIONE: per i vicini diretti di un PROGETTO (chi dipende da X) passa node_id='project:artifact:<slug>' con edge_types=['depends_on']. Codice: caller/callee 1-hop di una function.
128
+ QUANDO USARLO: vicinato diretto senza il bundle completo; caller inattesi; time-travel as_of; rank=suspect_write per bug write-through-read. Per il blast radius transitivo usa graph_impact / project_impact.
129
+ RESTITUISCE: list of {node_id, relation, direction, rank_score?, freshness} cap 200."""
130
130
  try:
131
131
  async with acquire_db() as db:
132
132
  # Node proxy hardcodes limit=200 (the surface exposes no limit param).
@@ -152,7 +152,7 @@ def register(mcp) -> None:
152
152
  limit: Annotated[int, Field(ge=1, le=100)] = 20,
153
153
  type_filter: HotspotTypeFilter = "file",
154
154
  ) -> dict[str, Any]:
155
- """[Power-user] DORA-style churn ranking: files/functions sorted by touch_count 7d/30d with bus-factor warning — per context completo su un progetto usa get_project(deep=true). Usa questo tool per analisi architetturale di rischio o pianificazione refactor.
155
+ """DORA-style churn ranking: files/functions sorted by touch_count 7d/30d with bus-factor warning — per context completo su un progetto usa get_project(deep=true). Usa questo tool per analisi architetturale di rischio o pianificazione refactor.
156
156
  QUANDO USARLO: identificare moduli ad alto rischio prima di una release; trovare ownership gaps (bus_factor=1); pianificare tech debt.
157
157
  QUANDO NON USARLO: NOT per context di un progetto specifico -> usa get_project(deep=true). NOT per BFS da un nodo -> usa graph_impact.
158
158
  RESTITUISCE: list of {node_id, touch_count_7d, touch_count_30d, authors[], bus_factor} top N."""
@@ -178,10 +178,10 @@ def register(mcp) -> None:
178
178
  edge_types: list[EdgeType] | None = None,
179
179
  project: Annotated[str, Field(max_length=50, pattern=_PROJECT_PATTERN)] | None = None,
180
180
  ) -> dict[str, Any]:
181
- """[Power-user] BFS impact analysis: 'cosa si rompe se cambio X?' con ranker su direct callers + transitive list per context completo usa get_task(deep=true). Usa questo tool per delete/rename risk assessment o pre-refactor sweep.
182
- QUANDO USARLO: prima di eliminare/rinominare una function critica; misurare blast radius di una migration; dependency cascade analysis.
183
- QUANDO NON USARLO: NOT per context standard -> usa get_*(deep=true). NOT per 1-hop only -> usa graph_neighbors.
184
- RESTITUISCE: {direct_callers[], transitive_list[], rank_score} depth configurabile."""
181
+ """Impact / blast radius: 'cosa si rompe o quali progetti si bloccano se cambio / pauso / chiudo X?'. BFS sui rami transitivi + ranker sui diretti.
182
+ ORCHESTRAZIONE DI PORTAFOGLIO: per sapere quali PROGETTI si bloccano se pausi/chiudi un progetto, passa node_id='project:artifact:<slug>' con edge_types=['depends_on','mentions','refers_to'] oppure usa il tool dedicato project_impact(slug). Livello-codice: per 'cosa si rompe se cambio questa function' passa un node 'py:function:...'.
183
+ QUANDO USARLO: prima di pausare/chiudere/de-prioritizzare un progetto (blast radius cross-project); prima di eliminare/rinominare una function critica; dependency cascade analysis; sequenziare lavoro (cosa sblocca cosa).
184
+ RESTITUISCE: {direct (callers/dependents)[], transitive_list[], rank_score, freshness (indexed_sha vs HEAD)} depth configurabile."""
185
185
  try:
186
186
  async with acquire_db() as db:
187
187
  result = await graph_uc.graph_impact(
@@ -197,15 +197,38 @@ def register(mcp) -> None:
197
197
  except ServiceError as e:
198
198
  raise_mcp_error(e)
199
199
 
200
+ @mcp.tool()
201
+ async def project_impact(
202
+ slug: Annotated[str, Field(max_length=50, pattern=_PROJECT_PATTERN)],
203
+ depth: Annotated[int, Field(ge=1, le=5)] = 2,
204
+ ) -> dict[str, Any]:
205
+ """Portfolio blast radius: 'se pauso / chiudo / de-prioritizzo questo PROGETTO, quali altri progetti si bloccano?'. Il tool di prima classe per l'orchestrazione cross-progetto — distinto dal grafo-codice.
206
+ Risolve 'project:artifact:<slug>' e fa l'impact BFS sui soli edge progetto->progetto (depends_on / mentions / refers_to). La response porta il segnale freshness (indexed_sha vs HEAD) per non fidarsi di un indice stantio.
207
+ QUANDO USARLO: prima di pausare/chiudere/de-prioritizzare un progetto; sequenziare un portafoglio (cosa sblocca cosa); capire le dipendenze cross-progetto di una decisione.
208
+ RESTITUISCE: {direct_dependents[], transitive_list[], rank_score, freshness}."""
209
+ try:
210
+ async with acquire_db() as db:
211
+ result = await graph_uc.graph_impact(
212
+ LOCAL_CTX,
213
+ db,
214
+ node_id=f"project:artifact:{slug}",
215
+ depth=depth,
216
+ limit=100,
217
+ edge_types=["depends_on", "mentions", "refers_to"],
218
+ project=None,
219
+ )
220
+ return dump(result)
221
+ except ServiceError as e:
222
+ raise_mcp_error(e)
223
+
200
224
  @mcp.tool()
201
225
  async def graph_context(
202
226
  node_id: Annotated[str, Field(pattern=_NODE_ID_PATTERN, max_length=256)],
203
227
  per_category_limit: Annotated[int, Field(ge=1, le=20)] = 5,
204
228
  project: Annotated[str, Field(max_length=50, pattern=_PROJECT_PATTERN)] | None = None,
205
229
  ) -> dict[str, Any]:
206
- """[Power-user] Rationale chain: function→commit→PR→task→handoff→learning in 1 call — per context su un singolo artefatto usa get_task/get_handoff/get_learning(deep=true). Usa questo tool quando hai un node_id e vuoi la storia completa del PERCHE'.
207
- QUANDO USARLO: archeologia di codice legacy ('perche esiste questa function?'); audit trail pre-refactor; linkare codice a decision record.
208
- QUANDO NON USARLO: NOT per workflow standard su task/handoff -> usa get_*(deep=true). NOT per vicinato topologico -> usa graph_neighbors.
230
+ """Rationale chain di un nodo: function/progetto commit PR task handoff learning in 1 call. Il PERCHE' dietro qualcosa.
231
+ QUANDO USARLO: perche' esiste / da dove viene una function o una decisione di progetto; audit trail; linkare codice o progetto a un decision record.
209
232
  RESTITUISCE: chain {commits[], PR?, task?, handoffs[], learnings[]} per_category_limit configurabile."""
210
233
  try:
211
234
  async with acquire_db() as db:
@@ -225,7 +248,7 @@ def register(mcp) -> None:
225
248
  scope: Annotated[str, Field(max_length=256)],
226
249
  limit: Annotated[int, Field(ge=1, le=100)] = 20,
227
250
  ) -> dict[str, Any]:
228
- """[Power-user] Learnings scoped a un modulo/path specifico via KG — per learnings generici usa check_learnings. Usa questo tool per learnings chirurgici su un file/modulo specifico prima di toccare codice in quella area.
251
+ """Learnings scoped a un modulo/path specifico via KG — per learnings generici usa check_learnings. Usa questo tool per learnings chirurgici su un file/modulo specifico prima di toccare codice in quella area.
229
252
  QUANDO USARLO: 'quali learnings esistono per api.db?' prima di toccare il DB module; scoping pre-deployment di un servizio specifico.
230
253
  QUANDO NON USARLO: NOT per ricerca semantica generica pre-azione -> usa check_learnings. NOT per context di un nodo -> usa graph_context.
231
254
  RESTITUISCE: list of {learning_id, title, prevention, severity, scope_match_score}."""
@@ -240,7 +263,7 @@ def register(mcp) -> None:
240
263
 
241
264
  @mcp.tool()
242
265
  async def graph_capabilities() -> dict[str, Any]:
243
- """[Power-user] KG schema metadata per agent discovery (edge_types + node_kinds + prefixes + versions).
266
+ """KG schema metadata per agent discovery (edge_types + node_kinds + prefixes + versions).
244
267
  QUANDO USARLO: prima di costruire query graph_* o validare node_id pattern; cold-start agent discovery.
245
268
  QUANDO NON USARLO: per query topologiche -> usa graph_neighbors/impact/context.
246
269
  RESTITUISCE: {edge_types[], node_kinds[], node_prefixes[], schema_version}.
@@ -47,10 +47,10 @@ def register(mcp) -> None:
47
47
  q: Annotated[str, Field(min_length=1, max_length=500)],
48
48
  module: str | None = None,
49
49
  ) -> dict[str, Any]:
50
- """Search learnings DB (past post-mortems + prevention rules) for a risky action.
50
+ """Cosa sappiamo gia' / cosa ci ha morso: cerca nei learnings (post-mortem + regole di prevenzione) prima di una decisione o di un'azione.
51
51
 
52
- QUANDO USARLO: PRIMA di qualunque azione production-affecting (deploy, migration, auth change, push to main, dependency upgrade) Quality Gate 9.4. BOUNDARY: create_learning vs check_learnings = create scrive nuovo; check cerca rilevante PRE-azione rischiosa. BOUNDARY: check_learnings vs list_learnings = check = semantic match su situazione; list = enumerazione filtrata.
53
- QUANDO NON USARLO: NOT quando hai gia' un file/module path e vuoi learnings scoped -> usa graph_pattern. NOT per scrivere un nuovo learning -> usa create_learning.
52
+ QUANDO USARLO: prima di qualunque azione production-affecting (deploy, migration, auth change, push, dependency upgrade); E prima di una DECISIONE o di un piano (per non ripetere errori noti e riusare cio' che ha funzionato). Non e' solo un gate pre-deploy: e' la memoria istituzionale a cui attingere quando ragioni. BOUNDARY: create_learning scrive nuovo; check_learnings = semantic match sulla situazione; list_learnings = enumerazione filtrata.
53
+ QUANDO NON USARLO: se hai gia' un file/module path e vuoi learnings scoped -> graph_pattern. Per scrivere un nuovo learning -> create_learning.
54
54
  RESTITUISCE: list of {id, title, prevention, severity, module} ranked per rilevanza."""
55
55
  try:
56
56
  async with acquire_db() as db:
@@ -1,6 +1,7 @@
1
1
  # v1.1.0 - 2026-04-14 - Single-writer: reclassify_inbox_items uses get_write_db (batch 5/6)
2
2
  from __future__ import annotations
3
3
 
4
+ import asyncio
4
5
  import logging
5
6
  import time
6
7
  from collections import defaultdict
@@ -62,6 +63,20 @@ from core.api.services.inbox_triage import (
62
63
 
63
64
  logger = logging.getLogger(__name__)
64
65
 
66
+
67
+ # Strong refs to fire-and-forget on-read deep-research sweeps so the event loop
68
+ # does not garbage-collect them mid-flight; discarded when each completes.
69
+ _background_sweeps: set[asyncio.Task] = set()
70
+
71
+
72
+ def _on_sweep_done(task: asyncio.Task) -> None:
73
+ _background_sweeps.discard(task)
74
+ if task.cancelled():
75
+ return
76
+ exc = task.exception()
77
+ if exc is not None:
78
+ logger.warning("on-read digest deep-research sweep failed: %s", exc)
79
+
65
80
  router = APIRouter(prefix="/api/v1/inbox", tags=["inbox"])
66
81
 
67
82
  # ---------------------------------------------------------------------------
@@ -306,13 +321,26 @@ async def get_current_digest_items(
306
321
  db: aiosqlite.Connection = Depends(get_db),
307
322
  ) -> list[dict]:
308
323
  workspace_id = user.workspace_id or "ws_default"
309
- return await list_digest_items(
324
+ items = await list_digest_items(
310
325
  db,
311
326
  workspace_id,
312
327
  state="visible",
313
328
  domain_key=domain_key,
314
329
  limit=limit,
315
330
  )
331
+ # On-read safety net (A): kick off deepening of any visible item still
332
+ # missing deep research, non-blocking, so it is ready by the time the user
333
+ # opens it. Idempotent + lock-guarded (no overlap with the scheduler sweep).
334
+ from core.api.services.inbox_digest_deep_research import (
335
+ sweep_visible_missing_deep_research,
336
+ )
337
+
338
+ sweep_task = asyncio.create_task(
339
+ sweep_visible_missing_deep_research(workspace_id=workspace_id)
340
+ )
341
+ _background_sweeps.add(sweep_task)
342
+ sweep_task.add_done_callback(_on_sweep_done)
343
+ return items
316
344
 
317
345
 
318
346
  @router.get("/digest/overflow")
@@ -0,0 +1,153 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ from typing import Any
6
+
7
+ from fastapi import HTTPException
8
+
9
+ from core.api.services.inbox_tldr import get_or_generate_deep_research
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Serializes the on-read trigger and the periodic scheduler so two sweeps never
14
+ # overlap and hammer the gateway for the same items.
15
+ _sweep_lock = asyncio.Lock()
16
+
17
+
18
+ async def precompute_deep_research_for_items(
19
+ *,
20
+ inbox_item_ids: list[str],
21
+ workspace_id: str,
22
+ cycle_key: str,
23
+ concurrency: int = 1,
24
+ allow_cloud_fallback: bool = False,
25
+ ) -> dict[str, Any]:
26
+ """Best-effort Deep Analysis precompute for a prepared digest cycle."""
27
+ stats: dict[str, Any] = {
28
+ "cycle_key": cycle_key,
29
+ "attempted": 0,
30
+ "generated": 0,
31
+ "cached": 0,
32
+ "failed": 0,
33
+ "skipped": 0,
34
+ "errors": [],
35
+ }
36
+ item_ids = [item_id for item_id in inbox_item_ids if item_id]
37
+ stats["skipped"] = len(inbox_item_ids) - len(item_ids)
38
+ if not item_ids:
39
+ return stats
40
+
41
+ semaphore = asyncio.Semaphore(max(1, concurrency))
42
+
43
+ async def precompute_one(item_id: str) -> None:
44
+ async with semaphore:
45
+ stats["attempted"] += 1
46
+ try:
47
+ result = await get_or_generate_deep_research(
48
+ item_id,
49
+ workspace_id,
50
+ force=False,
51
+ allow_cloud_fallback=allow_cloud_fallback,
52
+ )
53
+ except HTTPException as exc:
54
+ stats["failed"] += 1
55
+ stats["errors"].append(
56
+ {"item_id": item_id, "status_code": exc.status_code}
57
+ )
58
+ logger.warning(
59
+ "Digest Deep Analysis precompute failed for %s cycle=%s status=%s",
60
+ item_id,
61
+ cycle_key,
62
+ exc.status_code,
63
+ )
64
+ return
65
+ except Exception as exc:
66
+ stats["failed"] += 1
67
+ stats["errors"].append(
68
+ {"item_id": item_id, "error": type(exc).__name__}
69
+ )
70
+ logger.warning(
71
+ "Digest Deep Analysis precompute failed for %s cycle=%s: %s",
72
+ item_id,
73
+ cycle_key,
74
+ exc,
75
+ )
76
+ return
77
+
78
+ if result.get("cached"):
79
+ stats["cached"] += 1
80
+ else:
81
+ stats["generated"] += 1
82
+
83
+ await asyncio.gather(*(precompute_one(item_id) for item_id in item_ids))
84
+ return stats
85
+
86
+
87
+ async def sweep_visible_missing_deep_research(
88
+ *,
89
+ workspace_id: str = "ws_default",
90
+ limit: int = 50,
91
+ ) -> dict[str, Any]:
92
+ """Deepen any current-cycle VISIBLE digest item still missing deep research.
93
+
94
+ Enforces the invariant "an item shown in the daily visible digest must be
95
+ deepened". Catches both 6 UTC precompute failures (gateway slow/down, no
96
+ retry) and items promoted into the visible set later in the day. Idempotent
97
+ (only targets rows where deep_research is NULL/empty) and serialized by
98
+ ``_sweep_lock`` so the periodic scheduler and the on-read trigger never run
99
+ overlapping sweeps. Honors the same digest settings as the 6 UTC run
100
+ (mode/deep_research_enabled/concurrency/allow_cloud_fallback).
101
+ """
102
+ if _sweep_lock.locked():
103
+ return {"status": "already_running", "attempted": 0}
104
+
105
+ async with _sweep_lock:
106
+ from core.api.db import acquire_db
107
+ from core.api.services.inbox_digest import get_current_digest_cycle_key
108
+ from core.api.services.inbox_digest_jobs import _load_digest_settings
109
+
110
+ async with acquire_db() as db:
111
+ settings = await _load_digest_settings(db)
112
+ if settings.mode == "false" or not settings.deep_research_enabled:
113
+ return {"status": "disabled", "attempted": 0}
114
+ cycle_key = await get_current_digest_cycle_key(db, workspace_id)
115
+
116
+ where = ["s.workspace_id = ?", "s.state = 'visible'"]
117
+ params: list[Any] = [workspace_id]
118
+ if cycle_key:
119
+ where.append("s.digest_cycle_key = ?")
120
+ params.append(cycle_key)
121
+ params.append(limit)
122
+ rows = await (
123
+ await db.execute(
124
+ "SELECT s.inbox_item_id FROM inbox_digest_selections s "
125
+ "JOIN inbox_items i ON i.id = s.inbox_item_id "
126
+ f"WHERE {' AND '.join(where)} "
127
+ "AND (i.deep_research IS NULL OR i.deep_research = '') "
128
+ "ORDER BY s.rank_in_domain ASC LIMIT ?",
129
+ tuple(params),
130
+ )
131
+ ).fetchall()
132
+
133
+ missing_ids = [row[0] for row in rows]
134
+ if not missing_ids:
135
+ return {"status": "ok", "attempted": 0, "missing": 0}
136
+
137
+ stats = await precompute_deep_research_for_items(
138
+ inbox_item_ids=missing_ids,
139
+ workspace_id=workspace_id,
140
+ cycle_key=cycle_key or "sweep",
141
+ concurrency=settings.concurrency,
142
+ allow_cloud_fallback=settings.allow_cloud_fallback,
143
+ )
144
+ stats["status"] = "ok"
145
+ stats["missing"] = len(missing_ids)
146
+ logger.info(
147
+ "Digest deep-research sweep: %d visible missing -> generated=%d cached=%d failed=%d",
148
+ len(missing_ids),
149
+ stats.get("generated", 0),
150
+ stats.get("cached", 0),
151
+ stats.get("failed", 0),
152
+ )
153
+ return stats
@@ -0,0 +1,126 @@
1
+ """Unit tests for the KG freshness/staleness signal (#13).
2
+
3
+ graph_impact / graph_neighbors must not return an authoritative-looking blast
4
+ radius with no hint that the index is stale or partial. compute_index_freshness
5
+ surfaces, per the queried node's project, whether the graph is indexed / has git
6
+ provenance / matches HEAD — and NEVER mutates (no reindex from a read).
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import aiosqlite
12
+ import pytest
13
+
14
+ import core.api.use_cases.graph as graph_mod
15
+ from core.api.use_cases.graph import compute_index_freshness
16
+
17
+ _SCHEMA = """
18
+ CREATE TABLE graph_nodes (
19
+ id TEXT PRIMARY KEY,
20
+ project_id TEXT,
21
+ last_modified_git_sha TEXT,
22
+ touch_last_at TEXT
23
+ );
24
+ """
25
+
26
+
27
+ async def _db(rows):
28
+ conn = await aiosqlite.connect(":memory:")
29
+ conn.row_factory = aiosqlite.Row
30
+ await conn.executescript(_SCHEMA)
31
+ for r in rows:
32
+ await conn.execute(
33
+ "INSERT INTO graph_nodes (id, project_id, last_modified_git_sha, touch_last_at) "
34
+ "VALUES (?, ?, ?, ?)",
35
+ r,
36
+ )
37
+ await conn.commit()
38
+ return conn
39
+
40
+
41
+ @pytest.mark.asyncio
42
+ async def test_not_indexed_is_stale():
43
+ db = await _db([])
44
+ try:
45
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
46
+ assert out["reason"] == "not_indexed"
47
+ assert out["stale"] is True
48
+ assert "index" in out["hint"]
49
+ finally:
50
+ await db.close()
51
+
52
+
53
+ @pytest.mark.asyncio
54
+ async def test_not_git_linked_is_not_stale(monkeypatch):
55
+ monkeypatch.setattr("core.api.routers.projects._find_git_path", lambda slug: None)
56
+ db = await _db([("py:function:x.y", "alpha", "abc1234", "2026-05-01")])
57
+ try:
58
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
59
+ assert out["reason"] == "not_git_linked"
60
+ assert out["stale"] is False
61
+ finally:
62
+ await db.close()
63
+
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_sha_unpopulated_is_stale(monkeypatch):
67
+ # The real-world case from the issue: nodes exist + repo linked, but commit
68
+ # provenance was never populated (distinct git_sha = 0).
69
+ monkeypatch.setattr("core.api.routers.projects._find_git_path", lambda slug: "/tmp/repo")
70
+ monkeypatch.setattr(graph_mod, "_git_head_sha", lambda repo: "deadbee")
71
+ db = await _db(
72
+ [
73
+ ("py:function:x.y", "alpha", "", "2026-05-01"),
74
+ ("py:file:x", "alpha", None, "2026-05-02"),
75
+ ]
76
+ )
77
+ try:
78
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
79
+ assert out["reason"] == "sha_unpopulated"
80
+ assert out["stale"] is True
81
+ assert out["indexed_node_count"] == 2
82
+ finally:
83
+ await db.close()
84
+
85
+
86
+ @pytest.mark.asyncio
87
+ async def test_behind_head_is_stale(monkeypatch):
88
+ monkeypatch.setattr("core.api.routers.projects._find_git_path", lambda slug: "/tmp/repo")
89
+ monkeypatch.setattr(graph_mod, "_git_head_sha", lambda repo: "newsha9")
90
+ db = await _db([("py:function:x.y", "alpha", "oldsha1", "2026-05-01")])
91
+ try:
92
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
93
+ assert out["reason"] == "behind_head"
94
+ assert out["stale"] is True
95
+ assert out["indexed_git_sha"] == "oldsha1"
96
+ assert out["head_git_sha"] == "newsha9"
97
+ finally:
98
+ await db.close()
99
+
100
+
101
+ @pytest.mark.asyncio
102
+ async def test_fresh_when_indexed_sha_matches_head(monkeypatch):
103
+ monkeypatch.setattr("core.api.routers.projects._find_git_path", lambda slug: "/tmp/repo")
104
+ monkeypatch.setattr(graph_mod, "_git_head_sha", lambda repo: "abc1234")
105
+ db = await _db([("py:function:x.y", "alpha", "abc1234", "2026-05-01")])
106
+ try:
107
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
108
+ assert out["reason"] == "fresh"
109
+ assert out["stale"] is False
110
+ finally:
111
+ await db.close()
112
+
113
+
114
+ @pytest.mark.asyncio
115
+ async def test_autoreindex_flag_marks_command_but_never_executes(monkeypatch):
116
+ monkeypatch.setattr(
117
+ "core.api.config.settings.graph_autoreindex_on_drift", True, raising=False
118
+ )
119
+ db = await _db([]) # not_indexed → stale
120
+ try:
121
+ out = await compute_index_freshness(db, node_id="py:function:x.y", project="alpha")
122
+ assert out["stale"] is True
123
+ assert out.get("auto_reindex") == "suggested"
124
+ assert out["reindex_command"] == "marvis project index alpha"
125
+ finally:
126
+ await db.close()